livaの雑記帳

livaの雑記帳

OSとか作ってみたい

uio_pci_genericでデバドラを書く<その1>

男もすなるuioといふものを、女もしてみむとてするなり。

 

uio、流行ってますね。というか、今時Ring0でデバイスを制御しても新鮮味がないです。

なのでuioを使ってパパっとデバドラを書けるようにならなきゃなぁ、というぼんやりとした焦りを感じていたのですが、いろいろな都合でuioでデバドラを書く流れになったので、調べつつ知見を軽くブログにアウトプットしていこうかと思います。あんまり資料も無さそうですし。

一応の前提として、僕は主にPCIバイスのドライバを書く事が多いので、Linuxのuio_pci_genericを使って、PCIデバドラを作るというのがこのシリーズのテーマです。あと、PCIの仕様を既に理解している人向けです。

 

uio_pci_genericのカーネルモジュールは既にロードされているとして、実際にコードを書く所から始めます。今回は、Vendor IDとDevice IDを取得する所まで。

 

実験に使うPCIバイスXHCI(USB3.0 Host Controller)なのですが、まずはXHCIのデバドラをuio_pci_genericに割り当てる作業です。

 

# echo "8086 1e31" > /sys/bus/pci/drivers/uio_pci_generic/new_id

echo -n 0000:00:0c.0 > /sys/bus/pci/drivers/xhci_hcd/unbind

echo -n 0000:00:0c.0 > /sys/bus/pci/drivers/uio_pci_generic/bind

 

参考:Chapter 5. Generic PCI UIO driver

 

 

で、uio_pci_genericを用いたとても小さなコードを書きます。

まあ、このページの劣化版ですね。

Example code using uio_pci_generic

 

こんな感じ。エラー処理とかはきちんとやっていませんが悪しからず。

#include <stdio.h>

#include <unistd.h>

#include <stdint.h>

#include <fcntl.h>

#include <errno.h>

 

int main()

{

  int uiofd = open("/dev/uio0", O_RDONLY);

  int configfd = open("/sys/class/uio/uio0/device/config", O_RDWR);

 

  uint16_t vendor_id, device_id;

  pread(configfd, &vendor_id, 2, 0);

  pread(configfd, &device_id, 2, 2);

  printf("Vendor ID: %x, Device ID: %x\n", vendor_id, device_id);

  return 0;

}

 

Vendor IDはPCI Configuration Spaceの0byte目からの2byte、Device IDは2byte目からの2byteなので、preadを用いて、configfdから該当オフセットと該当サイズ分だけ読んでいます。

 

これをコンパイルしてroot権限で実行すれば、

Vendor ID: 8086, Device ID: 1e31

 

簡単ですね。

 

その2へ続く