4. PCIe地址空间与映射
在PCIe体系结构中,“地址”并不是一个单一概念。CPU发出的一个物理地址,可能最终落到DDR内存、设备内部的寄存器、甚至另一个PCIe设备的功能配置中。理解PCIe地址空间与映射机制,是掌握DMA传输与数据搬移的前提。本节将围绕内存空间、IO空间、配置空间、BAR寄存器、地址转换与TLP路由六个核心概念展开,帮助读者建立完整的地址视图。
一、PCIe的三大地址空间
PCIe沿用了PCI的地址空间模型,将访问对象划分为三类:内存空间(Memory Space)、IO空间(IO Space)和配置空间(Configuration Space)。三者通过不同的TLP类型和路由方式区分,互不混淆。
- 内存空间:用于访问设备的内存映射寄存器(MMIO)以及DMA读写的主存区域。CPU通过普通的load/store指令即可访问,是PCIe中最主要的访问方式。
- IO空间:早期x86用于访问设备IO端口,空间仅64KB,访问效率低。现代PCIe设备基本不再使用IO空间,但协议仍保留以兼容传统设备。
- 配置空间:每个PCIe功能拥有4KB配置空间,前256字节与PCI兼容,后256~4KB为PCIe扩展配置空间。配置空间用于枚举设备、分配BAR、配置MSI/MSI-X等。
/dev/mem或mmap映射的BAR区域;配置空间访问对应lspci、setpci以及/sys/bus/pci/devices/.../config文件。
二、配置空间与BAR寄存器
配置空间是PCIe设备的“身份证”和“控制面板”。其中BAR(Base Address Register)是最关键的寄存器组。每个PCIe功能最多有6个32位BAR(64位BAR占用两个)。BAR的作用是:设备向系统声明“我需要多大一块地址空间”,系统在枚举时为其分配一段物理地址,并将基地址写回BAR。
BAR的低位具有特殊含义:最低位为0表示内存BAR,为1表示IO BAR;对于内存BAR,bit1~bit2表示类型(32位、64位或可预取)。系统通过向BAR写入全1再读回,可以探测设备请求的空间大小。
# 查看设备BAR分配情况
lspci -vv -s 01:00.0 | grep -A 6 "Region"
# 典型输出:
# Region 0: Memory at f7c00000 (32-bit, non-prefetchable) [size=16K]
# Region 1: Memory at f7c10000 (32-bit, non-prefetchable) [size=4K]
# Region 2: Memory at f7c20000 (64-bit, prefetchable) [size=8M]
BAR分配完成后,CPU访问该物理地址区间,就会被PCIe Root Complex转换为对应的Memory TLP,发往目标设备。因此,BAR是“CPU地址”与“设备内部资源”之间的桥梁。
三、地址转换与TLP路由
PCIe采用基于地址的路由和基于ID的路由两种方式。内存请求和IO请求使用地址路由,配置请求使用ID路由(Bus/Device/Function号)。
当CPU访问一段物理地址时,Root Complex根据地址范围判断该地址属于哪个PCIe设备,并生成相应的TLP。TLP头部包含目标地址,交换机(Switch)根据地址范围将TLP转发到正确的下行端口。设备收到TLP后,将地址与自身BAR比较,若命中则处理请求。
对于DMA方向,设备发起Memory Write/Read TLP,地址指向系统主存。Root Complex收到后,将TLP转换为对DDR控制器的访问,完成数据搬移。这一过程涉及地址映射:设备看到的“系统地址”与CPU看到的物理地址必须一致,否则DMA会写错位置。
四、典型场景:DMA传输中的地址视图
假设一个PCIe网卡需要将接收到的数据DMA写入主机内存。流程如下:
- 驱动在主机内存中分配DMA缓冲区,得到物理地址
0x1A000000。 - 驱动将该物理地址写入网卡的DMA描述符寄存器(通过BAR映射的MMIO)。
- 网卡发起Memory Write TLP,目标地址为
0x1A000000。 - Root Complex接收TLP,将其转换为对DDR的写操作,数据写入缓冲区。
- 网卡发送MSI-X中断,驱动读取缓冲区数据。
整个过程中,BAR负责CPU访问设备寄存器,DMA地址负责设备访问主机内存,两者方向相反但都依赖地址映射的正确性。
五、地址空间与路由对照表
| 地址空间 | 访问方向 | TLP类型 | 路由方式 | 典型用途 |
|---|---|---|---|---|
| 内存空间 | CPU→设备 / 设备→CPU | MemRd / MemWr | 地址路由 | MMIO寄存器、DMA缓冲区 |
| IO空间 | CPU→设备 | IORd / IOWr | 地址路由 | 传统IO端口(已少用) |
| 配置空间 | CPU→设备 | CfgRd / CfgWr | ID路由(BDF) | 枚举、BAR分配、MSI配置 |
六、复盘与排障要点
在实际调试中,地址映射问题往往表现为DMA数据错位、设备无响应或系统崩溃。以下是常见排查思路:
- 用
lspci -vv确认BAR是否成功分配,是否有“Region ... not assigned”提示。 - 检查DMA地址是否使用了物理地址,是否经过IOMMU转换。若启用IOMMU,需确保驱动正确设置DMA映射。
- 确认TLP路由是否正确:交换机端口配置、Bus号分配是否冲突。
- 对于64位BAR,注意高低32位寄存器的读写顺序,避免地址截断。
- 使用PCIe协议分析仪抓取TLP,观察地址字段与预期是否一致。
/proc/iomem中的PCI Bus资源对比,可快速定位地址映射错误。
总结来看,PCIe地址空间与映射的核心在于“三个空间、一个BAR、两条路径”。内存空间承载MMIO与DMA,配置空间负责枚举与BAR分配,IO空间仅作兼容保留。BAR是设备资源对系统可见的窗口,地址转换与TLP路由则确保访问请求准确到达目标。掌握这些概念后,后续的DMA描述符配置、地址对齐、IOMMU映射等实战内容才能顺利展开。