PCI地址空间是什么?其在PCIe设备MMIO映射中的作用与位置解析
理解PCIe的PCI地址空间:作用、位置与示例
嘿,这个问题问得特别到位——刚入门PCIe的时候,确实很容易把系统物理地址空间和PCI地址空间搞混,我当初琢磨了好几天才理清!咱们一步一步来拆解:
先明确两个核心地址空间的区别
首先得把两个概念掰清楚:
- 系统物理地址空间:这是CPU直接能“看到”的地址范围,涵盖了物理内存、外设MMIO区域等,比如x86平台上可能从
0x00000000到0xFFFFFFFF(32位)或者更大范围。你提到的BIOS把设备MMIO映射到这个空间,就是让CPU能通过这个地址直接发起访问。 - PCI地址空间:这是PCIe总线体系内部的抽象地址空间,是PCIe设备之间、设备与根复合体(Root Complex,连接CPU和PCIe总线的核心部件)沟通的“通用语言”,和CPU的物理地址没有直接关联,需要映射才能对接。
PCI地址空间到底发挥什么作用?
它的核心价值是解耦设备和CPU架构:
不同CPU架构(x86、ARM、RISC-V)的系统物理地址布局差异极大,甚至同架构的不同主板布局也不一样。如果让PCIe设备直接依赖系统物理地址,那设备就得针对每个平台做适配,完全不现实。
而PCI地址空间给了设备一个“中立的请求方式”:设备只需要在自己的配置空间里通过**BAR(Base Address Register)**告诉固件(BIOS/UEFI)“我需要多大的MMIO空间,期望在PCI地址空间的哪个位置(通常初始值是0,让固件分配)”,剩下的映射工作交给固件和根复合体来完成。这样同一个PCIe设备就能在不同平台上正常工作,不用修改硬件或驱动。
PCI地址空间“存在”在哪里?
它不是一块实际的物理内存,而是由**根复合体里的地址转换单元(ATU,Address Translation Unit)**来维护的一套映射关系。简单说:
- 当CPU发起系统物理地址的访问时,根复合体的ATU会把这个地址转换成对应的PCI地址,再通过PCIe总线发给目标设备;
- 当PCIe设备发起DMA请求时,也会先给出PCI地址,ATU再把它转换成系统物理地址,访问内存。
结合你的1MB MMIO例子来走一遍流程
咱们把你说的场景细化,完整走一遍:
- 设备请求资源:PCIe端点设备的配置空间里,BAR0寄存器被设置为「MMIO类型,长度1MB,初始PCI地址
0x00000000」。这表示设备期望在PCI地址空间的0x00000000 - 0x000FFFFF这段区域被访问。 - 固件分配PCI地址:BIOS枚举设备时,检查发现这个初始PCI地址已经被其他设备占用了,于是给它分配一个空闲的PCI地址段,比如
0x10000000 - 0x100FFFFF,并把这个值写入设备的BAR0寄存器。 - 映射到系统物理地址:BIOS接着在系统物理地址空间里找一块空闲的1MB区域,比如
0xF0000000 - 0xF00FFFFF,然后把「系统物理地址0xF0000000↔ PCI地址0x10000000」的映射关系配置到根复合体的ATU中。 - CPU访问流程:当CPU要读写
0xF0000000这个地址时,请求先到根复合体,ATU把系统物理地址转换成PCI地址0x10000000,然后通过PCIe总线发送给端点设备;设备收到0x10000000的PCI地址请求,就知道是访问自己的MMIO空间,进而做出响应。
额外补充:为什么不直接用系统物理地址?
举个简单的例子:x86平台的系统物理地址可能把0xF0000000留给外设,而ARM平台可能把这段地址分给了内存。如果PCIe设备直接硬编码使用0xF0000000,那在ARM平台上就会冲突。有了PCI地址空间,设备只需要说“我要1MB MMIO”,固件负责分配合适的PCI地址并映射到当前平台的空闲系统物理地址,完美解决兼容性问题。
内容的提问来源于stack exchange,提问作者Usr1
相关产品推荐
相关产品推荐

