PCIe BAR

张开发
2026/6/7 2:23:53 15 分钟阅读
PCIe BAR
PCIe BARBase Address Register是设备配置空间中用于声明资源需求并建立与主机物理地址映射的核心寄存器是 CPU / 系统访问设备寄存器或本地内存的 “窗口”。核心定位与数量位于标准配置头前 64 字节Type 0 HeaderEndpoint最多 6 个 BARBAR0~BAR5Type 1 HeaderBridge最多 2 个。常见设备通常使用 1~3 个 BAR。位字段与类型编码32 位寄存器位段含义编码说明bit 0空间类型0 内存空间主流1I/O 空间遗留极少用bit 1~2地址宽度0032 位1064 位需连续两个 BAR 组合01/11 保留bit 3可预取1 可预取如显存允许缓存 / 合并写0 不可预取如控制寄存器禁止缓存bit 4~31基地址 / 大小掩码未分配时为大小掩码分配后为系统分配的主机物理基地址三类 BAR 类型与用途类型地址宽度最大范围典型场景32 位内存 BAR32 位4GB小规模控制寄存器访问64 位内存 BAR64 位16EBGPU、高速网卡、FPGA 等大本地内存需求I/O 空间 BAR32 位4GB传统设备现代几乎不用初始化与分配流程枚举阶段探测大小向 BAR 写全 10xFFFFFFFF→ 读回掩码低位 0 的连续个数决定大小2 的幂最小 128 字节。分配地址系统在主机物理地址空间分配不重叠的基地址写入 BAR 高比特位。建立映射设备内部资源与主机物理地址建立映射CPU 通过该地址访问设备。关键实践要点64 位 BAR需连续两个 BAR 组合如 BAR0BAR1低位存低 32 位高位存高 32 位。可预取性影响缓存策略数据缓冲区常用可预取控制寄存器必须不可预取。驱动访问读取 BAR 偏移如 0x10~0x24获取基地址通过ioremap映射到虚拟地址后访问。常见工具Linux 下lspci -v查看 BAR 映射/proc/iomem查看主机 IO 内存分配。BAR 空间大小绝大多数情况下BAR 空间大小是硬件固化的驱动和系统只能 “探测”不能修改。BAR 的大小本质是设备硬件实际拥有多少寄存器 / 存储空间决定的。比如设备内部有 256KB 寄存器 → 硬件就固定 BAR 大小 256KB设备有 2GB 片上 RAM → 硬件固定 BAR 大小 2GBGPU 有 16GB 显存 → BAR 大小就是 16GB这些在芯片设计 / FPGA 逻辑里写死了上电就不变。硬件是怎么 “告诉” 系统大小的系统枚举 PCIe 设备时向 BAR 写入0xFFFFFFFF硬件会把低位全部置 0返回连续 0 的位数 大小2 的幂例如硬件返回0xFFFF0000→ 低 16 位为 0 → 大小 64KB硬件返回0xFF000000→ 大小 16MB这个掩码是硬件硬编码的软件改不了。那软件能不能改 BAR 大小不能。你不能让 256KB 的设备变成 512KB你不能让 1GB 的 BAR 缩成 512MB你不能让非 2 的幂大小变成合法 BAR因为设备内部地址译码是固定的超过大小的地址会无响应 / 误触发 / 总线错误PCIe 规范要求大小必须是2 的幂且对齐所以系统只能分配基地址不能改大小。有没有例外有但不是普通 BAR而是两类特殊机制可伸缩 BARResizable BAR / ReBAR现代显卡、NVMe、FPGA 支持。硬件内部有一大块显存 / 内存硬件支持动态选择映射大小128MB / 256MB / 1GB / 2GB / 4GB…驱动通过扩展配置空间PCIe Extended Capability通知硬件切换大小但注意仍然是硬件支持哪些大小软件才能选哪些不能随便设。BAR 与 PCI 窗映射Bridge WindowPCI 桥PCI Bridge的窗大小可配置但不是 Endpoint BAR。Endpoint BAR 本身依然固定。核心要点普通 BAR 大小 硬件固化软件不可改系统只能分配基地址不能改大小只有ReBAR可伸缩 BAR能在硬件支持的档位里切换大小大小必须是2 的幂硬件决定64 位内存 BAR核心作用让设备把大容量片上内存 / 寄存器 / 显存映射到主机的64 位物理地址空间主机可以直接读写速度极快。特点必须占用两个连续的 BAR例如 BAR0BAR1BAR2BAR3支持超过 4GB 的物理地址必须是内存空间非 I/O支持可预取 / 不可预取大小必须是2 的幂如 1MB、32MB、256MB、1GB、8GB…64 位 BAR 的硬件寄存器格式一个 64 位内存 BAR 低 32 位 BAR 高 32 位 BAR低位 BAR 格式例如 BAR0位含义64 位内存 BAR 固定值0空间类型0 内存空间1~2地址类型10 64 位内存3可预取1 可预取0 不可预取4~31地址 / 大小未分配时是大小掩码分配后是基地址低 32 位高位 BAR 格式例如 BAR1纯地址位没有任何控制位只存储 64 位地址的高 32 位64 位 BAR 的硬件设计规则如果你是做 FPGA/ASIC 设备设计必须满足必须成对使用BAR0BAR1、BAR2BAR3、BAR4BAR5不能中间断开不能用 BAR0BAR2系统会枚举失败低位 BAR 必须配置为 64 位内存类型硬件写死0b10bit1~2高位 BAR 硬件必须全 0除了地址位大小必须是 2 的幂如 256MB 0x10000000地址必须对齐到自身大小256MB 的空间基地址必须是 256MB 对齐系统枚举 64 位 BAR主机上电后PCIe 枚举流程自动探测 64 位 BAR步骤 1写全 1 探测大小向低位 BAR写入0xFFFFFFFF读回 → 低位连续 0 的数量 空间大小例如读回0xFFFF0000→ 低 16 位是 0 → 大小 64KB因为是 64 位 BAR系统自动跳过下一个 BAR高位 BAR 不单独探测步骤 2分配 64 位物理地址系统从高位内存分配一个64 位地址例如0x00000008 80000000(8GB 起始)步骤 3写入高低 BAR低 32 位 → 写入低位 BAR高 32 位 → 写入高位 BAR完成后设备就把内部地址映射到主机物理地址。64 位 BAR 的两种类型1. 不可预取No-Prefetchablebit3 0用于控制寄存器禁止 CPU 缓存读写必须严格按顺序每次读写都直达硬件2. 可预取Prefetchablebit3 1用于大数据缓冲区、显存、DMA 内存允许 CPU 缓存、批量读写、写合并性能极高但不能用于控制寄存器99% 的设备一个 64 位不可预取 BAR → 寄存器一个 64 位可预取 BAR → 大容量存储Linux 驱动如何使用 64 位 BAR获取设备 PCI 资源请求 BAR 区域防止冲突ioremap 映射到内核虚拟地址读写访问寄存器 / 内存I/O 空间 BARI/O 空间 BAR 用来把设备寄存器映射到 CPU 的 I/O 地址空间而不是内存地址空间的 BAR。内存 BAR用mov指令访问MMIOI/O BAR用in / out指令访问PIO驱动层面的访问不需要 ioremap直接用端口号 偏移x86 下使用inb, inw, inl读outb, outw, outl写ARM / 其他架构很多根本不支持独立 I/O 空间要么模拟要么干脆不能用。限制没有 64 位 I/O BAR不能预取空间很小x86 总共只有 64KB I/O 空间性能差不支持批量、不支持缓存现代 PCIe 设备基本不用只用于兼容老设备典型示例GPU通常 1 个 64 位可预取 BAR 映射显存1 个不可预取 BAR 映射控制寄存器。网卡1 个 64 位 BAR 映射描述符环与数据缓冲区部分控制寄存器用 32 位 BAR。常见误区误以为 BAR 是设备自身的物理地址实际是系统分配的主机物理地址。忽略对齐要求大小必须为 2 的幂基地址需对齐至大小边界。64 位 BAR 未连续使用导致地址分配失败。总结BAR 是 PCIe 设备资源抽象的核心其设计实现了设备需求声明与系统动态分配的解耦。理解 BAR 的位字段、类型与初始化流程是开发、调试 PCIe 设备如 GPU、网卡、FPGA的基础前提。

更多文章