[轉] 如何讀取PCI device Bar的type,base address,以及size

出處:http://blog.sina.com.cn/s/blog_6488248f0100thnn.html

PCI标准定义了三种物理地址空间,分别是IO address, Memory address space以及Configuration address space。其中Configuration address space专门用于配置PCI设备,PCI标准规定了标准的configuration space header,每个PCI设备都必须实现,软件通过configuration address space,来访问device的configuration space header,从而可以对device进行配置。



PCI标准要求device将内部寄存器,片上内存等资源map到IO space或者Memory space,从而软件可以通过发起IO/Memory space的读写来访问device的内部资源。PCI标准在configuration space header里预留了6个32-bit的Base address (BAR),系统软件可以通过往BAR里设置IO/Memory space的基地址,来实现对device内部资源的影射。在设置好这些BAR后,一旦软件发起对这些地址的读写,都会被device截获。

PCI规定32位BAR的低4位为read-only,标识了这个device资源在IO space,32-bit的Memory space还是64-bit的Memory space,以及访问时是否prefetchable。BAR的最后一位标识了是IO space还是Memory space。


    BAR[bit:0] = 1 — IO space
                     = 0 — Memory space



在OS启动前,BIOS会预先program好device的各个BAR的基地址,所以一般OS不需要重新去program BAR,但是当device资源出现冲突时,系统也可以通过写BAR的值,来重新修改device的资源影射。

PCI标准规定,先往32位BAR里写0xffffffff,再读取该BAR,就可以得到该BAR的size。如果读到的size为0,说明该BAR没有被device使用。

Power-up software can determine how much address space the device requires by writing a
value of all 1’s to the register and then reading the value back. The device will return 0’s in
all don’t-care address bits, effectively specifying the address space required. Unimplemented
Base Address registers are hardwired to zero.

如果该BAR是64-bit Memory space,则下一个BAR被认为是64位的高32位,64位size的高32位,也可以通过同样的方法得到。

64-bit (memory) Base Address registers can be handled the same, except that the second
32-bit register is considered an extension of the first; i.e., bits 32-63. Software writes
0FFFFFFFFh to both registers, reads them back, and combines the result into a 64-bit value.
Size calculation is done on the 64-bit value.

读取base,size以及type的伪代码:

    u32 base, size;
    pci_resource_type type;    (io_space, mem32_space, mem64_space)
    boolean  prefetchable;
    
    //得到base address
    pci_config_read(device, BARi, &base);    

    //得到size
    pci_config_write(device, BAR, 0xffffffff);    
    pci_config_read(device, BAR, &size);

    //重新写回base address,有需要也可以是其他的地址
    pci_config_write(device, BAR, base);    

    //确定type
    if (base & 0x1)
        type = io_space;
    else if((base & 0x6) == 0x4)
        type = mem64_space;
    else
        type = mem32_space;

    prefetchable = (base & 0x8) ? true : false;

    //如果是64-bit Memory space,得到base address和size的高32位,方法相同
    if (type == mem64_space) {
        u64 base64 = base;
        u64 size64 = size;

        //BAR+4指向下一个BAR的位置,此时被认为是64位的高32位
        pci_config_read(device, BAR+4, &base);    

        base64 |= ((u64)base << 32);
        
        pci_config_write(device, BAR+4,    0xffffffff);
        pci_config_read(device, BAR+4, &size);

        size64 |= ((u64)size << 32);
    }

未經允許不得轉載:GoMCU » [轉] 如何讀取PCI device Bar的type,base address,以及size

評論 搶沙發

  • 昵稱 (必填)
  • 郵箱 (必填)
  • 網址