livaの雑記帳

livaの雑記帳

OSとか作ってみたい

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

その1はこちら。

 

今回はxHCIレジスタ空間を触ってみる。

 

参考になるのは、DPDKのソースとか。

 

前回やった通り、PCIレジスタ空間は/sys/class/uio/uio0/device/configをopenしてread/writeすれば良かったのだが、BARが指すPCIバイスレジスタ空間についてはまた別の方法を用いてアクセスする。

 

BAR0のI/O空間であれば、/sys/class/uio/uio0/device/resource0をmmapして、メモリアクセスすれば良い。

 

実際に使えている事を試したいので、XHCIをenableして、USB Status RegisterのHCHaltedフラグが1から0に落ちる事を確認してみる。

 

コードは以下の通り。例によってエラー処理はしていない。

#include <stdio.h>

#include <unistd.h>

#include <stdint.h>

#include <fcntl.h>

#include <errno.h>

#include <assert.h>

#include <sys/mman.h>

 

int main()

{

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

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

 

  // read bar0                                                                                                                                                                                              

  uint32_t bar0;

  pread(configfd, &bar0, 4, 0x10);

 

  // write 0xFFFFFFFF to BAR0 and get size                                                                                                                                                                  

  uint32_t tmp = 0xFFFFFFFF;

  pwrite(configfd, &tmp, 4, 0x10);

  uint32_t size;

  pread(configfd, &size, 4, 0x10);

  size = ~size + 1;

 

  // write back bar0                                                                                                                                                                                        

  pwrite(configfd, &bar0, 4, 0x10);

 

 

  int fd = open("/sys/class/uio/uio0/device/resource0", O_RDWR);

  void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE,

                    MAP_SHARED, fd, 0);

  close(fd);

 

 

  // get Capability Registers Length                                                                                                                                                                        

  uint8_t caplen = ((uint8_t *)addr)[0];

 

  // clear bit 0(Run/Stop) of USB Command Register                                                                                                                                                          

  ((uint32_t *)addr)[caplen/4 + 0] &= ~1;

 

  usleep(1000);

 

  // read USB Status Register                                                                                                                                                                               

  printf("%08x\n",((uint32_t *)addr)[caplen/4 + 1]);

 

  // set 1 to bit 0(Run/Stop) of USB Command Register                                                                                                                                                       

  ((uint32_t *)addr)[caplen/4 + 0] |= 1;

 

  usleep(1000);

 

  // read USB Status Register                                                                                                                                                                               

  printf("%08x\n",((uint32_t *)addr)[caplen/4 + 1]);

 

  return 0;

}

 

これを実行すると、一回目のprintfでは1が表示され、二回目のprintfでは0が表示される。きちんとMMIOを用いたデバイス制御ができている事が分かる。

 

続きはその3