TripTheWorld

PCIe总线何去何从? 实际的需求催生了技术的变革。 PCIe就像是计算机王国里的一场“交通革命”,它替代了PCI成为计算机领域主要的互联总线。那么它的发展趋势如何?让我们一步一步揭开它神秘的面纱。欢迎关注微信公众号“硬件工程师宝典”,获取更多资讯。

PCIe从入门到精通之十:PCIe配置空间的访问方式详解

0
阅读(363)

0,引言

在上一篇文章《PCIe从入门到精通之九:利用lspci和PCIe设备的ID查看配置空间》中我们介绍了可以通过PCIe设备的身份证ID(Bus No, Device No, Function No)和OS里的命令来显示PCIe配置空间的值。

在这一篇文章中我们继续介绍是PCIe配置空间是如何通过PCIe设备的身份证ID来读取访问的、其内部流程和具体实现是怎么样的。

所有PCIe主题的文章都会收录在《深入浅出聊PCIe》合集里,欢迎评阅。

需要下载PCIe学习资料标准的朋友(pdf格式),请关注本微信公众号“硬件工程师宝典”,在对话框内回复“PCIe”,将获取标准下载链接。

一,如何访问PCIe配置空间?

在《PCIe从入门到精通之七:PCIe设备的配置空间简介》那一章我们介绍了两种方式来访问PCIe的配置空间,分别是:

·        PCI-compatible Configuration Access Mechanism(CAM)

通过IO port CONFIG_ADDRESS(CF8h)和CONFIG_DATA(CFCh)访问PCI 兼容的配置空间(Byte 00h~ffh)。但是这种方式不能用来访问PCI Express扩展配置空间(Byte 100h~FFFh)。

·        PCI Express Enhanced Configuration Access Mechanism (ECAM)

所有的PCIe配置空间的寄存器都会被map到标准的memory空间里(flat memory-mapped address space),我们只要找到它们在memory空间里的address,我们就可以通过对memory空间的直接访问进而转化成对PCIe配置空间的访问。

ECAM既可以对PCI 兼容的配置空间进行访问,又可以对PCIe扩展配置空间进行访问。

二,CAM方式详解

在PCI兼容系统中,可以通过I/O端口0xCF8和0xCFC来访问PCIe配置空间,这是一种传统的访问机制,称为配置访问机制(CAM)。 尽管PCI Express引入了内存映射配置空间(ECAM)这种更高效的访问方式,但为了向后兼容,系统仍然支持通过0xCF8和0xCFC端口访问PCIe设备的传统配置空间(前256字节)。

以下是使用I/O端口0xCF8和0xCFC访问PCIe配置空间的详细解释:

1. 0xCF8 (CONFIG_ADDRESS) 端口

0xCF8是一个32位的I/O端口,用于指定要访问的PCI/PCIe配置空间中的地址。 向此端口写入一个32位的值,该值包含了目标设备的总线号、设备号、功能号以及配置寄存器的偏移地址。

0xCF8寄存器格式(从高位到低位),如下图所示:

37.png

·        31 (Enable Bit): 启用位。必须设置为1,表示启用配置访问。

·        30-24 (Reserved): 保留位,通常设置为0。

·        23-16 (Bus Number): PCI总线号,范围通常为0-255。

·        15-11 (Device Number): 设备号(或槽号),范围通常为0-31。

·        10-8 (Function Number): 功能号,一个PCI设备可以有多个功能(例如,一个网卡可能同时包含以太网和光纤通道功能),范围为0-7。

·        7-2 (Register Number/Offset): 配置寄存器的偏移地址,表示要访问的32位(DWORD)寄存器在配置空间中的位置。由于所有读写操作都必须是32位对齐的,因此这个偏移量是以DWORD为单位的,即实际字节偏移量是 (Register Number) * 4。共8bit配置寄存器的偏移地址,因此只能访问PCIe 配置空间的前256字节。

·        1-0 (Reserved): 保留位,必须为00b,以确保32位对齐。

构造0xCF8值的公式: 0xCF8_Value = (1 << 31) | (Bus_Number << 16) | (Device_Number << 11) | (Function_Number << 8) | ((Register_Offset / 4) << 2)

其中 Register_Offset 是字节偏移量,例如,如果想访问偏移量为0x04的寄存器,那么 (Register_Offset / 4) 就是1,((Register_Offset / 4) << 2)就是4。这样多此一举的目的是为了确保偏移量按照32位(DWORD)对齐。

2. 0xCFC (CONFIG_DATA) 端口

0xCFC是一个32位的I/O端口,用于实际的数据传输。在向0xCF8端口写入配置地址后,对0xCFC端口的读写操作将执行实际的配置空间访问。

·        读取操作: 从0xCFC端口读取32位数据,即可获得0xCF8中指定地址的配置寄存器内容。

·        写入操作: 将32位数据写入0xCFC端口,即可将数据写入0xCF8中指定地址的配置寄存器。

3. 访问流程(读/写)

读取PCIe配置空间寄存器的步骤:

·        CAM构造地址: 根据目标设备的 总线号 (Bus_Number)、设备号 (Device_Number)、功能号 (Function_Number) 和要读取的 寄存器字节偏移量 (Register_Offset),构造一个32位的地址值。 例如,要读取总线0、设备0、功能0、偏移量为0x00的寄存器(通常是Vendor ID和Device ID),构造的地址值将是: 0x80000000 | (0 << 16) | (0 << 11) | (0 << 8) | ((0 / 4) << 2),即 0x80000000。

·        写入0xCF8: 将构造好的32位地址值写入I/O端口0xCF8。

·        读取0xCFC: 从I/O端口0xCFC读取32位数据。这个数据就是目标配置寄存器的内容。

写入PCIe配置空间寄存器的步骤:

·        构造地址: 与读取操作相同,构造目标配置寄存器的32位地址值。

·        写入0xCF8: 将构造好的32位地址值写入I/O端口0xCF8。

·        写入0xCFC: 将要写入的32位数据写入I/O端口0xCFC。

4. 注意事项

·        权限: 直接访问I/O端口0xCF8和0xCFC通常需要操作系统的内核权限(Ring 0)。

·        PCIe扩展配置空间: 这种通过0xCF8/0xCFC端口的传统方法只能访问PCI/PCIe设备配置空间的前256字节(即兼容PCI 3.0的部分)。 PCIe规范将配置空间从256字节扩展到了4096字节(4KB)。 要访问扩展的配置空间(从偏移量0x100开始的部分),需要使用增强配置访问机制(ECAM),它是一种内存映射(MMIO)的方式,而不是通过I/O端口。

通过0xCF8和0xCFC端口访问PCIe配置空间是底层系统编程和硬件调试中常见的方法,尤其是在操作系统启动初期或固件(BIOS/UEFI)层面。

三,ECAM方式详解

1.  什么是ECAM?

PCI Express引入了增强型配置访问机制(Enhanced Configuration Access Mechanism, ECAM)。它将PCIe设备的配置空间直接映射到系统物理内存地址空间中的一个连续区域。这意味着CPU可以通过简单的内存读写指令来访问PCIe设备的配置寄存器,而无需使用特殊的I/O端口指令。ECAM是一种内存映射(Memory-Mapped I/O, MMIO)的方式,与传统的通过I/O端口0xCF8和0xCFC访问PCI配置空间的方法相比,它允许访问每个设备功能完整的4KB配置空间,并提供更快的访问速度。

2.  ECAM与传统0xCF8/0xCFC方式的区别

传统的0xCF8/0xCFC I/O端口访问方式只能访问PCI/PCIe设备配置空间的前256字节。 随着PCIe设备的复杂性增加,需要更多的配置寄存器来描述设备能力和功能,因此PCIe将配置空间扩展到了4KB(4096字节)。ECAM正是为了访问这扩展的4KB配置空间而设计的。

3.  ECAM工作机制

1)   内存映射: ECAM的核心思想是将PCIe配置空间视为一段物理内存。系统会预留一段连续的物理内存区域专门用于映射所有PCIe设备的配置空间。通常,每个PCIe段(Segment)需要256MB的连续内存区域来容纳其所有可能的设备配置空间。

2)   ECAM构造地址 在ECAM内存区域内,每个PCIe设备的配置空间地址是根据其总线号(Bus Number)、设备号(Device Number)、功能号(Function Number)以及寄存器偏移量(Register Offset)来计算的。

下图是ECAM方式下,PCIe ID地址的布局:

38.png

  • PCIe段(Segment): PCIe架构支持多个独立的PCIe层次结构,每个层次结构被称为一个段。每个段都有自己的ECAM内存区域。

  • 总线号(Bus Number): 标识设备所在的总线,范围通常为0-255。

  • 设备号(Device Number): 标识总线上的设备,范围为0-31。

  • 功能号(Function Number): 标识设备上的特定功能,范围为0-7。

  • 寄存器偏移量(Register Offset): 标识功能配置空间内的具体寄存器地址,范围为0x000到0xFFF(4KB)。

3)   基地址获取: 

每个PCIe device有4kB的配置空间被映射到memory空间里,那么memory地址空间就像茫茫宇宙那么无边无际,那么一个渺小的PCI额 device的配置空间被具体映射到哪一个memory地址?这里就涉及到一个基地址,每一个PCIe device的被映射的具体位置是基地址加上它自己的配置空间的地址决定(ECAM Base Address + ECAM构造地址)。

操作系统或固件(BIOS/UEFI)在系统启动时,会通过ACPI(高级配置和电源接口)表的MCFG(Memory Mapped Configuration)表来获取ECAM内存区域的基地址(ECAM Base Address)。 MCFG表会告诉操作系统PCIe配置空间从哪个物理内存地址开始。

4)   地址计算: 一旦获得了ECAM的基地址,就可以通过以下公式计算出任何给定PCIe设备功能中特定寄存器的物理内存地址: 物理地址 = ECAM Base Address + ECAM构造地址= ECAM_Base_Address + (Bus_Number << 20) + (Device_Number << 15) + (Function_Number << 12) + Register_Offset

  • (Bus_Number << 20):每个总线被分配1MB(2^20字节)的地址空间。

  • (Device_Number << 15):每个设备被分配32KB(2^15字节)的地址空间(8个功能 * 4KB/功能 = 32KB)。

  • (Function_Number << 12):每个功能被分配4KB(2^12字节)的地址空间。

  • Register_Offset:寄存器在4KB功能配置空间内的字节偏移量。

4.  如何通过ECAM访问PCIe配置空间

由于ECAM是内存映射的,访问过程与访问普通内存类似:

1)   获取ECAM基地址: 操作系统通过解析ACPI MCFG表来获取ECAM的物理基地址。

2)   映射内存: 操作系统需要将这段物理内存区域映射到其虚拟地址空间中,以便应用程序或驱动程序可以访问。这通常涉及设置页表。

3)   计算目标寄存器地址: 根据目标设备的PCIe段、总线号、设备号、功能号以及要访问的寄存器偏移量,使用上述公式计算出其在ECAM内存区域中的实际物理地址。

4)   执行内存操作:

·        读取: 直接从计算出的内存地址读取相应大小(如32位或64位)的数据。

·        写入: 将数据直接写入计算出的内存地址。

系统中的Root Complex(根联合体,通常是CPU的一部分)会负责将对ECAM内存区域的内存访问请求转换为相应的PCIe配置事务(Configuration Transaction),并通过PCIe总线发送给目标设备。

5.  ECAM的优势

·        访问范围广: 允许访问每个PCIe设备功能完整的4KB配置空间,支持PCIe扩展能力。

·        效率高: 作为内存映射I/O,ECAM的访问速度通常比I/O端口访问更快,因为它直接利用了CPU的内存访问机制。

·        编程模型简单: 对于软件来说,访问ECAM就像访问普通内存一样,简化了驱动程序和固件的开发。

·        支持多段PCIe: ECAM能够支持多个PCIe段,每个段拥有独立的256MB配置空间,从而扩展了系统可寻址的PCIe设备数量。

注意事项

·        权限: 尽管ECAM是内存映射的,但在操作系统环境下,直接访问ECAM内存区域仍然需要内核级权限。

·        固件支持: ECAM的可用性依赖于系统固件(BIOS/UEFI)是否提供了MCFG表来描述ECAM内存区域的基地址和范围。

·        地址对齐: 访问ECAM时,通常需要注意数据访问的对齐方式,以确保正确读取和写入寄存器。

通过ECAM,现代操作系统和驱动程序能够高效、灵活地管理和配置PCIe设备,这是PCIe架构实现即插即用和高性能的关键组成部分。

四,抛砖引玉

每个PCIe设备的配置空间有4KB大小,其中基本的配置空间有256B,其他的都是扩展的配置空间。那么配置空间的寄存器的值都具体代表什么含义?它们有什么不同?它们都可以被读和写吗?它们的作用是什么?

敬请关注下一篇:PCIe从入门到精通之十一:PCIe设备的配置空间header详解1

五,参考文献:

需要以下参考文献(PCIe标准)的朋友,请关注本微信公众号“硬件工程师宝典”,在对话框内回复“PCIe”,将获取标准下载链接。

15_baidu_file.png

百度网盘分享的文件