如何访问 PCIe 配置 space? (ECAM)

How to access PCIe configuration space? (ECAM)

为了访问PCI ConfigurationSpace,I/O端口地址0xCF8,根据各种文章使用0xCFC。

mov eax, dword 0x80000000

mov dx, word 0x0CF8
out dx, eax
mov dx, word 0x0CFC
in eax, dx

上面代码中eax的值为0x12378086,即vendor ID = 0x8086device ID = 0x1237

这是问题。

Q1。我已经看到此方法仅适用于 PCI 配置 Space。那么,访问 PCIe 配置的另一种方法是什么 Space?

"This extended configuration space cannot be accessed using the legacy PCI method (through ports 0xCF8 and 0xCFC)"

https://wiki.osdev.org/PCI_Express

但是其他一些文章说这种传统方法也与 PCIe 配置兼容 Space。

这令人困惑。

Q2。如果旧版 0xCF8、0xCFC 也适用于 PCIe 配置 Space,NASM 详细的汇编源代码(而不是关于 linux)将不胜感激,因为我已经看过很多 ECAM (Enhanced Configuration Access Mechanism)文章,但都是概念性内容。

硬件规格:

Motherboard : P775TM1
Processor : Intel i7 8700K

Q1. I've seen this method only works for PCI Configuration Space. Then, what is the other method to access PCIe Configuration Space?

对于 80x86 PC,实际上有 3 种机制来访问 PCI 配置 space。您提到的旧机制(使用 IO 端口 0x0CF8 和 0x0xCFC)是 "mechanism #1"。还有另一种称为 "mechanism #2" 的遗留机制,它也使用了 0x0CF8 和 0x0xCFC;但它并没有被许多芯片组使用,并且(对于现代计算机)可以被认为是过时的。

最初每个 PCI "function" 的 PCI 配置 space 大小为 256 字节;对于这两种旧机制,您只能访问 256 个字节。当他们发明 PCI-E 时,他们添加了第三种机制(内存映射 ECAM),并且他们还将每个 PCI-E "function" 的 PCI 配置 space 大小增加到 4096 字节。旧版 "mechanism #1" 仍然有效,但仍然只能访问前 256 个字节(在 PCI-E "function" 可以拥有的 4096 个字节中)。幸运的是,硬件制造商足够聪明,可以确保旧操作系统需要访问的内容在前 256 个字节以内,因此不支持 PCI-E 的旧操作系统仍然可以工作(使用 "mechanism #1"),其余 4096 字节(没有 ECAM 无法访问)主要用于 PCI-E 扩展功能等。

注意:可以有一个 "PCI-E to PCI conventional" 桥,桥后面有 PCI 常规设备。在这种情况下,PCI 常规 devices/functions 将仅提供 256 字节的 PCI 配置 space,即使它仍在使用 ECAM。

使用ECAM;您需要使用 ACPI 的 "index of tables"(RSDT 或 XSDT)来查找名为 "MCFG" 的 table。可悲的是(除非自从我上次查看后它发生了变化)这个 table 没有在它所属的 ACPI 规范中描述;而是在锁定在 "maliciously expensive" PCI SIG 付费专区后面的 PCI 规范中进行了描述。希望你能在某处找到可靠的第三方描述。

一般; MCFG table 由描述用于一系列总线编号的地址范围的条目组成;并且对于多个独立的总线编号范围可能有多个不同的地址范围。这个想法是使用设备的总线号来找到正确区域的地址;然后组合“address_of_area + ((bus - first_bus_for_area) << 20) | (device << 15) | (function << 12)”找到函数的 PCI 配置的起始地址 space。找到后,您可以在该物理页面中 read/write 到 offset/s 访问函数的 PCI 配置中的相应偏移量 space.

您阅读了引用

This extended configuration space cannot be accessed using the legacy PCI method (through ports 0xCF8 and 0xCFC)

断章取意。
这是上下文中的引用(强调我的):

The PCI Express bus extends the Configuration Space from 256 bytes to 4096 bytes. This extended configuration space cannot be accessed using the legacy PCI method (through ports 0xCF8 and 0xCFC).

作者说的是从 0x100 开始的 PCIe 配置 space 的 部分

一开始有一个配置 space,每个 PCI 设备功能,256 字节。
此 space 是使用 PCI 遗留机制(我们可以忽略存在两种机制的事实)在端口 0xcf8 和 0xcfc 访问的。

PCIe 将此 space 从 256 字节扩展到 4KiB,并引入了一种新机制来访问配置 space(所有)。

所以,回顾一下:

  • 有一个 4KiB 的 PCI 配置 space。它分为PCI 3.0兼容区域(从0x000到0x0ff)和PCIe扩展配置区域(从0x100到0xfff)。
  • 有两种访问 PCI 配置的机制 space。一个是 0xcf8/0xcfc 处的遗留机制,另一个是内存映射区域。
  • Legacy 机制只能访问兼容区域(前 256 个字节)。
  • ECAM 可以访问所有 space。

引用PCIe规范:

PCI Express extends the Configuration Space to 4096 bytes per Function as compared to 256 bytes allowed by PCI Local Bus Specification.

PCI Express Configuration Space is divided into a PCI 3.0 compatible region, which consists of the first 256 bytes of a Function’s Configuration Space, and a PCI Express Extended Configuration Space which consists of the remaining Configuration Space (see Figure 7-3).

The PCI 3.0 compatible Configuration Space can be accessed using either the mechanism defined in the PCI Local Bus Specification [NdR: The legacy configuration mechanism] or the PCI Express Enhanced Configuration Access Mechanism (ECAM) described later in this section.

Accesses made using either access mechanism are equivalent. The PCI Express Extended Configuration Space can only be accessed by using the ECAM.


非常(非常)可能英特尔的 CPUs 将在未来许多年内支持旧版 PCI 配置机制。
在内部,生成 PCI 配置事务的非核心部分(即系统 Agent/UBox)已经仅使用 PCIe 配置事务(即由 ECAM 生成的相同 MMCFG 类型)但遗留软件接口未被删除.

由于 PCIe 根复合体在 CPU 中,CPU 是遗留 PCI 软件 兼容性(遗留 PCI需要一个 PCIe 到 PCI 的桥,它可能会暴露一个配置机制)。

简而言之,您可以安全地使用旧版 PCI 机制访问 PCIe 配置的前 256 个字节(每个功能)space。
实际上,除非 Intel 找到一种新的方法来配置非核心设备,否则遗留机制永远不会消失,因为它需要配置 ECAM 本身。


遗留机制可以直接使用,您已经发布了一些使用它的代码。我不确定还需要什么。

你可以这样使用它:

%define CFG(bus, dev, fun, reg) (0x80000000 | (bus << 16) | (dev << 11) | (fun << 8) | reg)

%macro cfg_arm 4
  mov dx, 0cf8h
  mov eax, CFG(%1, %2, %3, %4)
  out dx, eax
%endmacro

%macro cfg_read 4
  cfg_arm %1, %2, %3, %4
  mov dx, 0cfch
  in eax, dx
%endmacro

%macro cfg_write 5
  cfg_arm %1, %2, %3, %4
  mov dx, 0cfch
  mov eax, %5
  out dx, eax
%endmacro

 cfg_read 0, 0, 0, 0   ;eax <- VID:DID of dev 0, fun 0 on bus 0

此代码未经测试

如果您指的是配置 space 的 内容(即要设置的内容),那太宽泛了。
您可以阅读感兴趣的设备的数据表,它们通常甚至记录了 PCI 规范中定义的标准寄存器。
或者,您可以阅读 PCI 规范本身。

如果您询问如何使用 ECAM,请阅读 Brendan 的回答。
我唯一可以补充的是,对于您的 CPU,您可以通过从 iMC 的(传统)PCI 配置 space 读取寄存器 PCIEXBAR(偏移量 60h)来找到 ECAM 的基础CPU(总线 0,开发 0,乐趣 0)。
像这样:

cfg_read 0, 0, 0, 60h       ;Low 32-bit
mov ebx, eax                
cfg_read 0, 0, 0, 64h       ;high 32-bit
shl rax, 32
or rax, rbx                 ;RAX = ptr to ECAM area 

固件已经配置好一切以正确使用这个区域。