5

为了访问PCI Configuration Space,根据各种文章使用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 配置空间。那么,访问 PCIe 配置空间的另一种方法是什么?

“无法使用传统 PCI 方法(通过端口 0xCF8 和 0xCFC)访问此扩展配置空间”

https://wiki.osdev.org/PCI_Express

但是其他一些文章说这种遗留方法也与 PCIe 配置空间兼容。

这令人困惑。

Q2。如果遗留的 0xCF8、0xCFC 也适用于 PCIe 配置空间,那么详细的 NASM 汇编源代码(不是关于 linux 的)将不胜感激,因为我看过很多 ECAM(增强型配置访问机制)文章,但它们都是关于概念性内容。

硬件规格:

Motherboard : P775TM1
Processor : Intel i7 8700K
4

2 回答 2

13

Q1。我见过这种方法只适用于 PCI 配置空间。那么,访问 PCIe 配置空间的另一种方法是什么?

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

最初每个 PCI“功能”的 PCI 配置空间大小为 256 字节;对于这两种遗留机制,您只能访问 256 个字节。当他们发明 PCI-E 时,他们添加了第三种机制(内存映射 ECAM),他们还将每个 PCI-E“功能”的 PCI 配置空间的大小增加到 4096 字节。传统的“机制#1”仍然有效,但仍然只能访问前 256 个字节(PCI-E“功能”可以拥有的 4096 个字节中)。幸运的是,硬件制造商足够聪明,可以确保旧操作系统需要访问的内容在前 256 个字节内,因此不支持 PCI-E 的旧操作系统仍然可以工作(使用“机制 #1”),和 4096 字节的剩余部分(可以'

注意:可以有一个“PCI-E 到 PCI 常规”桥,桥后面有 PCI 常规设备。在这种情况下,PCI 常规设备/功能将仅提供 256 字节的 PCI 配置空间,即使它仍在使用 ECAM。

使用 ECAM;您需要使用 ACPI 的“表索引”(RSDT 或 XSDT)来查找名为“MCFG”的表。遗憾的是(除非自从我上次查看后它发生了变化)该表在它所属的 ACPI 规范中没有描述;而是在 PCI 规范中描述,该规范被锁定在“恶意昂贵”的 PCI SIG 付费墙后面。希望您能在某处找到可靠的第三方描述。

一般来说; MCFG 表由描述用于一系列总线编号的地址范围的条目组成;对于多个不同的总线编号范围,可能有多个不同的地址范围。想法是使用设备的总线号来查找正确区域的地址;然后结合“ address_of_area + ((bus - first_bus_for_area) << 20) | (device << 15) | (function << 12)”来查找函数的 PCI 配置空间的起始地址。一旦找到,您就可以读取/写入该物理页面中的偏移量,以访问函数的 PCI 配置空间中的相应偏移量。

于 2019-08-12T09:26:59.343 回答
9

你读了报价

无法使用传统 PCI 方法访问此扩展配置空间(通过端口 0xCF8 和 0xCFC)

你离题了。
这是上下文中的引用(强调我的):

PCI Express 总线将配置空间从 256 字节扩展到 4096 字节。使用传统 PCI 方法(通过端口 0xCF8 和 0xCFC)无法访问此扩展配置空间。

作者说的是从 0x100 开始的 PCIe 配置空间 部分。

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

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

所以,回顾一下:

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

引用 PCIe 规范:

PCI Express 将每个功能的配置空间扩展到 4096 字节,而 PCI 本地总线规范允许 256 字节。

PCI Express 配置空间分为一个 PCI 3.0 兼容区域,它由功能配置空间的前 256 个字节组成,以及一个 PCI Express 扩展配置空间,它由剩余的配置空间组成(见图 7-3)。

可以使用 PCI 本地总线规范[NdR:传统配置机制]中定义的机制或本节后面描述的 PCI Express 增强配置访问机制 (ECAM) 来访问与 PCI 3.0 兼容的配置空间。

使用任一访问机制进行的访问是等效的。PCI Express 扩展配置空间只能使用 ECAM 访问。


英特尔的CPU很有可能在未来很多年都支持传统的 PCI 配置机制。
在内部,生成 PCI 配置事务(即系统代理/UBox)的非核心部分已经仅使用 PCIe 配置事务(即由 ECAM 生成的相同 MMCFG 类型),但未删除旧软件接口。

由于 PCIe 根复合体位于 CPU 内,因此 CPU 是遗留 PCI软件兼容性的唯一关注点(遗留 PCI 需要 PCIe 到 PCI 桥接器,这可能会暴露配置机制)。

简而言之,您可以安全地使用传统 PCI 机制来访问 PCIe 配置空间的前 256 个字节(每个功能)。
实际上,除非英特尔找到配置非核心设备的新方法,否则旧机制永远不会消失,因为它需要配置 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

此代码未经测试

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

如果您问如何使用 ECAM,请阅读 Brendan 的回答。
我唯一可以补充的是,对于您的 CPU,您可以通过从 CPU 的 iMC(总线 0,dev 0)的(传统)PCI 配置空间读取寄存器 PCIEXBAR(偏移 60h)来找到 ECAM 的基础, 有趣 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 

固件已经配置了一切以正确使用该区域。

于 2019-08-12T12:56:17.213 回答