1. 基址寄存器的作用
一般的,每个 PCIe 设备内部都会有一部分资源需要提供给系统软件访问。与此同时,不同的 PCIe 设备可供系统软件访问的资源大小、资源类型也不一样。在计算机系统中,只有系统软件可以为 PCIe 设备内部的资源指定合适的地址,而 PCIe 设备能做的就是告诉系统软件该设备内部可访问的资源大小、资源类型和资源特性。
基址寄存器(Base Address Registers)就是 PCIe 协议提供的、用于向系统软件展示 PCIe 设备内部资源大小、资源类型和资源属性的机制。
2. 基址寄存器在哪儿
基址寄存器(Base Address Registers)位于 PCIe 设备配置空间(configuration space)的配置头(configuration header)中。众所周知,PCIe 设备有两种类型的配置头,分别为 0 型配置头(Type 0 configuration header)和 1 型配置头(Type 1 configuration header)。在两种配置头中,基址寄存器的位置如下图所示:
从图中可以看出,0 型配置头(Type 0 configuration header)包含 6 个基址寄存器,而 1 型配置头(Type 1 configuration header)只包含 2 个基址寄存器。
PCIe 桥类型设备,即 PCIe Root Complex 和 PCIe Switch,包含 1 型配置头(Type 1 configuration header)。
PCIe 非桥类型设备,例如 PCIe Endpoint,包含 0 型配置头(Type 0 configuration header)。
3. 基址寄存器的工作原理
之前提到过,基址寄存器(Base Address Registers)的作用就是向系统软件展示 PCIe 设备内部资源的类型、属性和大小。
3.1 类型
基址寄存器的第 0 位(Bit 0)用于表示 PCIe 设备内部资源的类型。PCIe 设备制造商在生产该设备时会根据实际情况配置该值。对于系统软件来说,该位是只读的。
- 如果 bit 0 = 1,表明系统软件需要在系统的 IO space 中为该资源分配地址。
- 如果 bit 0 = 0,表明系统软件需要在系统的 memory-mapped IO space 中为该资源分配地址。
3.2 属性
如果该资源是 IO 类型,即 bit 0 = 1,那就不需要任何属性展示。
如果该资源是 MMIO (memory-mapped IO)类型,那么 bit[3:1] 用来展示对应的属性。
- 如果 bit[2:1] = 00b,表明系统软件需要为该资源分配一个 32 位的地址。
- 如果 bit[2:1] = 10b,表明系统软件需要为该资源分配一个 64 位的地址。
注意:当 bit[2:1] = 10b 时,相邻的两个基址寄存器(Base Address Registers)会合并为 1 个,即 BAR0 和 BAR1 合并为 1 个,BAR2 和 BAR3 合并为 1 个,BAR4 和 BAR5 合并为 1 个。其中,BAR1、BAR3 和 BAR5 用保存 64 位地址的高 32 位。
- 如果 bit[3] = 1b,表明该资源是 prefetchable 的。
- 如果 bit[3] = 0b,表明该资源是 non-prefetchable 的。
需要注意的是,当资源是 MMIO (memory-mapped IO) 类型时,bit[3:1] 中的属性值是设别制造商在生产设备是指定的,系统软件对 bit[3:1] 的只有读取权限。
3.3 资源大小
当资源是 IO 类型,即 bit[0] = 1 时,bit[1] 会固定为 0,而 bit[31:7] 会用于指示资源大小。
当资源是 MMIO (memory-mapped IO) 类型,即 bit[0] = 1 时,bit[3:1] 用于指示资源属性,bit [31:7] (用于 32 位地址)或者 bit[63:7](用于 64 位地址)用于指示资源大小。
注:PCIe 协议规定,基址寄存器的 bit[6:4] 是不可更改的,必须设置为 0 。
为了便于描述,我们将用于指示资源大小的位,即 bit[31:7] 或者 bit[63:7],称为 BAR Size Mask。PCIe 设备上生产商在生产设备时,会根据内部资源的大小将 BAR Size Mask 的低位的某些 bits 设置为 0,并且不允许系统软件修改。
系统软件确认资源大小的思路如下:
- 系统软件在找到 PCIe 设备之后,向该设备的 BAR0 ~ BAR5 写入 0xFFFF FFFF。
- 系统软件依次读取 BAR0 ~ BAR5 的值,根据 bit [3:0] 判定资源类型和资源属性。
- 对于 IO 资源类型或者 32 为地址 MMIO 资源类型,系统软件检测基址寄存器的 bit[31:7],找到第一个非 0 位。
- 对于 64 位地址 MMIO 资源类型,系统软件检测基址寄存器的 bit[63:7],找到第一个非 0 位。
- 假设 bit 10 的值是 1,而 bit[9:7] 都是0,那么 bit 10 就是第一个非 0 位。资源的大小就是:2^10 = 1024 字节。
注:鉴于 PCIe 协议规定 bit[6:4] 必须是 0,那么 bit[7] 就是允许出现非 0 值的最低位,这也就意味着,PCIe 基址寄存器(Base Address Registers)能够制定的最小资源大小为 2^7 = 128 字节。
4. 并不是每个基址寄存器都是有效的
对于 PCIe 设备来说,并不是说有的基址寄存器都是有效的。
例如,某个 PCIe Endpoint 设备内部只有 2 个资源可以供系统软件访问,那么该设备制造商只要使用 BAR0 和 BAR1 两个基址寄存器就可以了。其他的 BAR2~BAR5 都可以全部设置为0,并且不允许系统软件修改。