3. BAR空间地址映射:MMIO与PIO的区别及大小计算
BAR(Base Address Register)是PCIe设备与主机软件交互的“窗口”。操作系统或BIOS通过配置BAR寄存器,为设备分配一段连续的地址空间,驱动程序则通过该地址空间访问设备内部的寄存器或内存。本章深入剖析BAR空间的两种映射方式——内存映射IO(MMIO)与IO映射IO(PIO),并详细讲解BAR空间大小的计算原理。
3.1 MMIO与PIO的核心区别
MMIO和PIO是两种截然不同的地址映射与访问机制,它们在性能、地址空间、指令使用等方面存在显著差异。下表从多个维度进行对比:
| 对比维度 | MMIO(Memory-Mapped IO) | PIO(Port IO / IO-Mapped IO) |
|---|---|---|
| 地址空间 | 共享系统物理内存地址空间(32位或64位) | 独立的IO地址空间(x86为16位,64KB) |
| 访问指令 | 普通内存访问指令(MOV, LOAD, STORE) | 专用IO指令(IN, OUT, ins, outs) |
| 性能 | 高,支持CPU缓存、乱序执行、批量传输 | 低,通常为同步、串行化操作,无缓存 |
| 地址粒度 | 字节、字、双字、四字均可 | 通常为32位端口(x86) |
| 适用场景 | 高性能数据传输、控制寄存器、帧缓冲 | 传统设备控制、状态查询、低速配置 |
| PCIe支持 | 主流,所有现代PCIe设备均支持 | 可选,部分传统兼容设备支持 |
3.2 MMIO映射原理与SVG架构图
MMIO将设备内部的寄存器或内存区域直接映射到系统的物理地址空间中。CPU访问这些地址时,地址译码逻辑将事务路由到PCIe总线,最终到达目标设备。下图展示了MMIO映射的完整路径:
pci_ioremap_bar() 或 ioremap() 将BAR物理地址映射到内核虚拟地址空间。之后,驱动即可通过指针直接读写设备寄存器,无需调用 inl()/outl() 等IO指令。
3.3 PIO映射原理与局限
PIO使用独立的IO地址空间,通过专用的IN/OUT指令进行访问。在x86架构中,IO地址空间仅有64KB(0x0000 - 0xFFFF),且访问是串行化的,性能远低于MMIO。PCIe规范虽然保留了IO空间的支持,但许多现代平台(如ARM、RISC-V)根本不实现IO地址空间。
3.4 BAR空间大小计算
BAR寄存器的大小不是由软件任意指定的,而是由硬件设计决定的。PCIe规范定义了一种“写全1再读回”的探测机制,软件通过该机制可以确定BAR所需地址空间的大小。理解这一机制对驱动开发和设备调试至关重要。
3.4.1 大小探测原理
- 软件写入0xFFFFFFFF 到BAR寄存器(低4位或低6位保留位不变)。
- 硬件返回实际需要的地址掩码:设备内部将不需要的位强制清零,需要的位保持为1。
- 软件读取BAR值,通过分析被清零的位范围计算出所需空间大小。
例如:读回值为 0xFFF00000,则低20位可编程,大小为 220 = 1MB。
3.4.2 大小计算示例表
| 写入BAR的值 | 读回的值(掩码) | 连续可编程位数 | 所需地址空间大小 | 对齐要求 |
|---|---|---|---|---|
0xFFFFFFFF |
0xFFFF0000 |
16位(bit 15-0) | 64 KB | 64 KB |
0xFFFFFFFF |
0xFFF00000 |
20位(bit 19-0) | 1 MB | 1 MB |
0xFFFFFFFF |
0xFE000000 |
25位(bit 24-0) | 32 MB | 32 MB |
0xFFFFFFFF |
0xC0000000 |
30位(bit 29-0) | 1 GB | 1 GB |
0xFFFFFFFF |
0x00000000 |
0位 | 0(未实现) | N/A |
3.4.3 64位BAR的大小计算
对于64位BAR,需要连续探测两个32位寄存器(BARn 和 BAR(n+1))。探测时,先写高32位,再写低32位,然后分别读回。大小计算方式与32位BAR相同,但地址空间可达264字节。
3.5 驱动兼容性设计要点
在编写跨平台或兼容多种硬件版本的驱动时,BAR空间的处理需要特别注意以下几点:
- 优先使用MMIO:在
pci_select_bars()中优先选择IORESOURCE_MEM类型的BAR。 - 动态探测BAR大小:不要硬编码BAR大小,应使用
pci_resource_len()获取实际分配的大小。 - 处理64位BAR:使用
pci_resource_start()获取起始地址时,注意64位地址可能跨越两个BAR索引。 - IO BAR回退:如果设备同时提供MMIO和IO BAR,优先使用MMIO;仅在MMIO不可用时回退到IO BAR。
- 地址对齐检查:确保
ioremap()的虚拟地址与BAR的物理地址对齐,避免缓存一致性问题。
3.6 本章小结
本章详细阐述了MMIO与PIO两种地址映射机制的原理、性能差异及适用场景,并通过SVG架构图直观展示了地址路由路径。BAR空间大小计算是PCIe设备枚举的核心步骤,理解“写全1读回”的探测机制有助于驱动开发者正确配置设备地址窗口。在驱动兼容性设计中,优先使用MMIO、动态获取资源长度、正确处理64位BAR是保证驱动健壮性的关键。