配置空间简介

配置寄存器的前64字节是标准的,称为配置空间头,有3种配置空间头,type0用于标准的 PCI 设备,type 1 用于 PCI 桥,type 2 用于 PCI CardBus 桥,基地址寄存器(BAR)在配置空间(Configuration Space)中的位置如下图所示:

  1. 其中Type0 Header最多有6个BAR,而Type1 Header最多有两个BAR。这就意味着,对于PCI设备来说,最多可以拥有6个不同的地址空间。但是实际应用中基本上不会用到6个,通常1~3个BAR比较常见

  2. 主要注意的是,如果某个设备的BAR没有被全部使用,则对应的BAR应被硬件全被设置为0,并且告知软件这些BAR是不可以操作的。对于被使用的BAR来说,其部分低比特位是不可以被软件操作的,只有其高比特位才可以被软件操作。而这些不可操作的低比特决定了当前BAR支持的操作类型和可申请的地址空间的大小

  3. 一旦BAR的值确定了(Have been programmed),其指定范围内的当前设备中的内部寄存器(或内部存储空间)就可以被访问了。当该设备确认某一个请求(Request)中的地址在自己的BAR的范围内,便会接受这请求。

基地址寄存器(BAR)详解

每个PCI设备在BAR中描述自己需要占用多少地址空间,bios通过所有设备的这些信息构建一张address map,描述系统中资源的分配情况,然后在合理的将地址空间配置给每个PCI设备。这里主要分为几个部分描述:

PCI设备占用的地址空间大小:

这个是根据PCI设备的需求而不同的,这个映射空间不同于配置空间,一般像网卡等设备占用较大的地址空间,而一些串口等设备占用较少的地址空间,而我们知道X86中地址空间又MEM和IO两类,因此PCI 的BAR在bit0来表示该设备是映射到memory还是IO,bar的bit0是readonly
的,也就是说,设备寄存器是映射到memory还是IO是由设备制造商决定的,其他人无法修改。

bit0:表示设备寄存器是映射到memory(0)还是IO(1)空间。
bit1: reserved 0
bit2: 在memory BAR中0表示32位地址空间,1表示64位地址空间。
bit3:在memory BAR中用来表示该设备是否允许prefetch,1表示可以预取,0表示不可以预取。

其余的bit用来表示设备需要占用的地址空间大小。

BAR通过将某些位设置为只读,且0来表示需要的地址空间大小,比如一个PCI设备需要占用1MB的地址空间,那么这个BAR就需要实现高12bit是可读写的,而20-4bit是只读且位0。地址空间大小的计算方法如下:

  1. 向BAR寄存器写全1
  2. 读回寄存器里面的值,然后clear 上图中特殊编码的值,(IO 中bit0,bit1, memory中bit0-3)。
  3. 对读回来的值去反,加一就得到了该设备需要占用的地址内存空间。

BIOS将系统中所有的PCI设备需要的地址空间大小读出来,然后计算得到一张address map。
BIOS可以为设备预留大于BAR要求的地址空间,而PCI规范中建议为需要的地址空间少于4KB的设备分配4KB的地址空间。
映射到IO空间的设备每个BAR不能占用大于256byte,在X86系统中IO编址是16位的,此时BAR中的高16bit需要hardware to zero。

在x86/x64架构中,PCI配置寄存器可通过两个32位的I/O端口访问: I/O端口CF8h-CFBh充当地址端口,而I/O端口CFCh-CFFh充当数据端口,用于将值读/写到PCI配置寄存器中