本文共 3286 字,大约阅读时间需要 10 分钟。
<ol>
<li><div><span style="color:#17365d; font-size:15pt"><strong>PCI BAR简介</strong></span></div><p>PCI设备都有独立的配置空间,HOST主桥通过配置读写事务访问这段空间。PCI设备的配置空间大小为256字节,其中头部64字节为PCI标准规定,剩余部分为PCI设备自定义的。PCI配置空间头部包含6个BAR(Base Address Registers)寄存器,BAR寄存器保存了PCI设备使用的地址空间的类型(Memory 空间或者I/O 空间),基地址以及其他属性。其中基地址保存的是该设备在PCI总线域中的地址,但在x86中一般与存储器域地址直接相等。</p><p>PCI设备复位之后,该寄存器将存放PCI设备需要使用的基址空间大小,这段空间是I/O空间还是Memory空间,如果是Memory空间该空间是否预取。当BAR寄存器映射到Memory空间时,Bit 0等于0,如图1.1所示。当BAR寄存器映射到I/O空间时,Bit 0等于1,如图1.2所示。</p><p style="text-align:center"><img src="" alt="" /></p><p style="text-align:center"><span style="font-size:9pt"><span style="font-family:黑体">图</span><span style="font-family:Arial"> 1.1 Memory Space</span><span style="font-family:黑体">的</span><span style="font-family:Arial">BAR</span><span style="font-family:黑体">寄存器</span><span style="font-family:Arial"></span></span></p><p> </p><p style="text-align:center"><img src="" alt="" /></p><p style="text-align:center"><span style="font-size:9pt"><span style="font-family:黑体">图</span><span style="font-family:Arial"> 1.2 I/O Space</span><span style="font-family:黑体">的</span><span style="font-family:Arial">BAR</span><span style="font-family:黑体">寄存器</span><span style="font-family:宋体"></span></span></p><p>I/O 空间是x86系统上面的专用空间,与内存独立编址,使用专用指令进行读写。现在的I/O空间大小是64KB,从0x0000到0xFFFF,可以供设备使用。目前多数PCI设备都不支持I/O空间,而仅支持Memory空间,但是仍有部分PCI设备同时包含I/O空间和Memory空间。</p><p>系统软件对PCI总线进行配置时,首先获得BAR寄存器中的初始化信息,之后根据处理器系统的配置,将合理的基地址写入相应的BAR寄存器中。系统软件还可以使用该寄存器,获得PCI设备使用的BAR空间的长度,其方法是向BAR寄存器写入0xFFFF_FFFF,之后再读取该寄存器。</p></li><li><div><span style="color:#17365d; font-size:15pt"><strong>技术实现</strong></span></div><p>当BAR寄存器映射到Memory空间时,I/O地址空间是物理主存的一部分,对于编程而言,我们只能操作虚拟内存,所以,访问的第一步就是要把设备所处的物理地址映射到虚拟地址。然后,我们可以直接通过指针访问这些地址,一般的使用过程如程序清单2.1所示。</p><p style="text-align:center"><span style="font-size:9pt"><span style="font-family:黑体">程序清单</span><span style="font-family:Arial"> 2.1 Memory</span><span style="font-family:黑体">资源使用流程</span><span style="font-family:Arial"></span></span></p><p></p><pre name="code" class="cpp"> hResource = API_PciDevResourceGet(hPciDevHandle, PCI_IORESOURCE_MEM, 0);if (!hResource) { return (PX_ERROR);}ulBaseAddr = (ULONG)(PCI_RESOURCE_START(hResource));stBaseSize = (size_t)(PCI_RESOURCE_SIZE(hResource));pvBaseAddr = API_PciDevIoRemap((PVOID)ulBaseAddr, stBaseSize);if (!pvBaseAddr) { return (PX_ERROR);}
</pre>
<br />当BAR寄存器映射到I/O空间时,有2种访问途径,即I/O映射方式(I/O - mapped)和内存映射方式(Memory - mapped)。前一种途径不映射到内存空间,直接使用in8/out8之类的函数进行访问I/O端口;后一种途径是先把I/O端口映射到I/O内存,再使用访问I/O内存的函数来访问I/O端口。其中第一种途径的使用流程如程序清单2.2所示。<p></p><p style="text-align:center"><span style="font-size:9pt"><span style="font-family:黑体">程序清单</span><span style="font-family:Arial"> 2.2 I/O</span><span style="font-family:黑体">资源使用流程</span></span></p><pre name="code" class="cpp"> hResource = API_PciDevResourceGet(hPciDevHandle, PCI_IORESOURCE_IO, 0);if (!hResource) { return (PX_ERROR);}ulBaseAddr = (ULONG)(PCI_RESOURCE_START(hResource));stBaseSize = (size_t)(PCI_RESOURCE_SIZE(hResource));out8(0x1, ulBaseAddr + 0x10);
</pre>
<br /><span style="font-family:Arial"></span><p></p></li><li><div><span style="color:#17365d; font-size:15pt"><strong>参考资料</strong></span></div><p>无 </p></li></ol>转载于:https://blog.51cto.com/12557713/2043939