注:本文主要内容来自系统虚拟化,再加上自己的一些理解,希望能将PCI设备的内容解释清楚。

何为PCI(Peripheral Component Interconnect)总线?PCI总线是CPU与外部设备沟通的桥梁。PCI总线的优点:速度快、具有动态配置功能、独立于CPU架构等,因而迅速被各种平台接受,成为一种通用的总线架构。

1. PCI总线架构

PCI总线是一种典型的树结构。把北桥中HOST-PCI桥看作根,总线中其他PCI-PCI桥、PCI-ISA桥等桥设备和直接接PCI总线的设备看作节点,整个PCI架构可以概括为下图所示。

设备标识符

2. PCI设备枚举过程

PCI设备和总线一起构成了树结构,其中桥设备是子树的根节点,设备枚举的过程就是要在内存中建立一颗和实际总线情况相符合的设备树。枚举过程中最关键的步骤就是发现桥设备。
PCI Basics and Bus Enumeration很好地阐述了此动态过程,看完视频之后都理解的话,那么对PCI设备枚举过程也就理解了。

3. PCI configeration space

通过BDF,我们可以唯一标志一个设备。每个设备,都有自己PCI configeration space,而PCI configeration space本质是registers。PCI设备规范规定,设备的配置空间最多为256个字节,其中前64个字节的格式和用途是统一的,如下图所示。

例1:假设设备1的BDF编号是(0,3,2),当我们需要定位其Expansion ROM Base Address寄存器时,应输入(0,3,2,30h)。

x86架构把I/O端口地址空间中的0xCF8~0xCFF段预留给了PCI总线,用于访问设备的配置空间。其中,前32位的寄存器为”地址寄存器“,后32位为”值寄存器“。软件通过把设备的BDF和要访问的配置空间的字节偏移量写入”地址寄存器“中,就可以通过”值寄存器“读写该配置空间了。

BDF占据16bits,而PCI configeration space最多为256个字节,也就是64个DWORD(Double WORD,WORD占16位,DWORD即占32位),所以Config. Addr只需占用6bits(能定位到64个DWORD)。具体位数含义可参见下图:

如例1所示,我们将(0,3,2,30h)写入pio的0xCF8h,就可以通过读0xCFCh来获取设备1的Expansion ROM Base Address寄存器值了。

讲完Accessing PCIe Config Registers后,我们需要介绍下程序员最关心的Base Address Registers和Interrupt Line了。

  • Base Address Registers:基地址寄存器,也就是常说的PCI Bar。它报告设备寄存器或者设备RAM在I/O端口地址空间(或物理地址空间中)的地址。地址是由软件(BIOS或操作系统)动态设置的。通常枚举PCI设备的软件(BIOS或操作系统)会在获得平台所有PCI设备后,根据设备数量,依照固定的算法为每个设备的PCI Bar分配I/O端口(或物理地址)。设备的电子线路负责把这些端口(或地址)映射到自身的寄存器(设备RAM)上,这样CPU就可以通过端口号(Port I/O方式)、物理地址(MMIO方式)访问到设备了。
  • Interupt Line:设备的中断线。BIOS通常用它来保存设备所连的PIC/IOAPIC的管脚号。

参考资料:

  1. 系统虚拟化
  2. PCI configuration mechanism
  3. PCI Basics and Bus Enumeration
  4. Accessing PCIe Config Registers