我的目标是找到AMD显卡的PCI区域大小,以便将该卡的PCI内存映射到用户空间,以便进行i2c传输并查看来自各种传感器的信息.
为了扫描PCI总线,我在一年前下载并编译了pciutils 3.1.7 for Windows x64.据说它使用DirectIO.
这是我的代码.
int scan_pci_bus() { struct pci_access *pci; struct pci_dev *dev; int i; pci = pci_alloc(); pci_init(pci); pci_scan_bus(pci); for(dev = pci->devices; dev; dev = dev->next) { pci_fill_info(dev,PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_PHYS_SLOT); if(dev->vendor_id == 0x1002 && dev->device_id == 0x6899) { //Vendor is AMD,Device ID is a AMD HD5850 GPU for(i = 0; i < 6; i++) { printf("Region Size %d %x ID %x\n",dev->size[i],dev->base_addr[i],dev->device_id); } } } pci_cleanup(pci); return 0; }
正如您在我的printf行中看到的,我尝试打印一些数据,我成功打印了device_id和base_addr,但是应该包含此设备的PCI区域大小的大小始终为0.我预计,至少有一个来自循环的循环显示尺寸> 0.
我的代码基于一个使用相同代码的Linux应用程序,尽管它使用Linux附带的pci.h头文件(pciutils看起来有相同的API).
显然,Windows(在我的情况下是Windows 7 x64)没有显示此信息,或者至少没有暴露给PCIUtils.
假设E2000000是基址寄存器的地址.如果我们将其转换为二进制,我们得到:
11100010000000000000000000000000
现在总共有32位,如果必须,你可以计算它们.现在,如果你不熟悉这些位
一个BAR被打好了,看这里 – > http://wiki.osdev.org/PCI,特别是“基地址寄存器”,更具体地说
读取“Memory Space BAR Layout”的图像.现在让我们开始读取从右端到左端的位并使用
链接中的图像我指出你作为指导.
因此从右侧开始的第一位(位0)为0,表示这是存储器地址BAR.
位(1-2)为0,表示它是32位(注意这不是大小)内存BAR.
位3为0,表示它不是Prefetchable内存.
现在我们消除了无用的位让我们继续保持良好的位置,位4-31.如果你看看位的4 -31你会
注意第一位是“1”是位24.这是一些数学发挥作用的地方.首先我们必须找到
Bit 24的二进制加权值,即16777216,也是16777216字节,即16 MB,告诉我们
BAR分配的内存大小为16 MB.如果你想知道我如何得到第24位的二进制加权值,它就像这样:2(二进制是基数2)乘以
本身24(位24)次,或2到24的幂,或2 ^ 24.
另一种方法是使用设备管理器:开始 – >“设备管理器” – >显示适配器 – >右键单击视频卡 – >属性 – >资源.标记的每种资源类型“Memory Range”应该是一个内存BAR,你可以看到[start address]到[end address].例如,让我们说它读取[00000000E2000000 – 00000000E2FFFFFF],从[end address]获取[start address]的大小:00000000E2FFFFFF – 00000000E2000000 = FFFFFF,十进制的FFFFFF = 16777215 = 16777215字节= 16MB.