xv6の力を借りてPCIデバイスの情報を取得しよう

xv6の力を借りてPCIデバイスの情報を取得しよう


コンピュータには周辺機器とやり取りするためにPCIという仕組みがあります。

OSはこの仕組みでデバイスの初期化や設定をしてusbやネットワークデバイスなどを利用できるように環境を整備します。

PCIについての情報は以下のページに載っています。
https://www.intel.com/content/dam/www/programmable/us/en/pdfs/literature/ug/ug_a10_pcie_avmm.pdf

https://wiki.osdev.org/PCI

今回はxv6に処理を追加してqemuで実行します。
qemuがエミュレートするPCIデバイスの情報を取得するということです。

xv6の用意


ますはxv6を手に入れます。
https://github.com/mit-pdos/xv6-public

今更言う必要はないと思いますが、xv6はunixv6をx86アーキテクチャ用に書き直したものです。

xv6への処理の追加


PCIへはout命令とin命令を使ってアクセスします。
使うI/OPortは0xcf8と0xcfcです。


Bus Number,Device Number,Function Number, Offsetを指定してポート0xcf8に書き込み、
in命令でポート0xcfcからデータを取得します。
どちらも32bitのデータを扱います。

これらをソースコードにするとこのようになりました。


この関数自体はどのファイルに追加しても問題ないと思いますが、main.cにでも追加しておきましょうか。

xv6には32bitのデータをやり取りするためのout命令とin命令の記述が見つからなかったのでこれも実装しておきました。
追加したファイルはx86.hです


これらの関数を呼び出してpciデバイスを出力する処理です。
この関数をmain.cのmain関数内などで呼び出します。
とりあえず重要そうな情報を取得して出力しています。

実行


実行するとこうなりました。


vendor idが8086のものが3つありますがこれはintelのことを指しているそうです。

そして一番下にdeviceが100eのものがありますがこれは82540EM Gigabit Ethernet Controllerという名前のデバイスを指しています。
以下のページにその記述がありました。
https://pci-ids.ucw.cz/read/PC/8086/100e

classコードが2、sub classコードが0となっているため、このデバイスがNetworkControllerというクラスに属するEthernetControllerであるということがわかります。
https://wiki.osdev.org/PCI#The_PCI_Bus

他にもclassが6となっているものはBridgeDevice、3となっているものはDisplayControllerを表しているみたいですね。

これらの情報はすべてインターネットから集めたものなので間違いがないとは言えませんが、
vendor idやdevice idなど実際に該当するものもあるので大丈夫でしょう。

今回実装した方法以外にもPCIへアクセスするためのメカニズムはいろいろあるみたいです。
I/OPortは使わずにメモリを通してアクセスもできるみたいです。

ただあんまりいろいろと方法を用意するのはやめて欲しいんですよね。



コメントする