繁体   English   中英

如何知道或设置一个 PCI/PCIe 设备地址 map?

[英]How to know or set a PCI/PCIe device address map?

我试图了解如何指示 CPU 指示 PCI 设备 map 其 memory 到 CPU 的物理地址。

我已阅读https://wiki.osdev.org/PCI#Memory_Mapped_PCI_Configuration_Space_Access并且了解如何通过 CPU 的 IO 端口配置 PCI 设备:

使用了两个 32 位 I/O 位置,第一个位置 (0xCF8) 命名为 CONFIG_ADDRESS,第二个位置 (0xCFC) 命名为 CONFIG_DATA。 CONFIG_ADDRESS 指定需要访问的配置地址,而对 CONFIG_DATA 的访问将实际生成配置访问,并将数据传输到 CONFIG_DATA 寄存器或从 CONFIG_DATA 寄存器传输数据。

因此,为了配置 PCI 设备,我只需要放置我想要配置的配置地址,而 CONFIG_DATA 就是我放置数据的位置。 这两个都是 I/O 位置,所以我将 I/O 指令放在 CPU 中。

这两个 I/O 位置让我可以访问一个 256 字节的“大寄存器”,我可以用它来配置 PCI 设备。 OSDEV 页面中描述了这个大寄存器的所有字段。 这 2 位很有趣:

Memory 空间 - 如果设置为 1,设备可以响应 Memory 空间访问; 否则,设备的响应被禁用。

I/O Space - 如果设置为 1,设备可以响应 I/O Space 访问; 否则,设备的响应被禁用。

但是除此之外,不清楚如何获取或设置每个 PCI 设备将响应的物理地址空间

这两个 I/O 位置让我可以访问一个 256 字节的“大寄存器”,我可以用它来配置 PCI 设备。

那个“大寄存器”是一个包含许多字段的结构。 其中一个字段是“命令寄存器”,它包含全局启用/禁用标志,可用于禁用设备向总线发送内容的能力(IRQ、从设备写入 memory 等)并响应来自总线(从 CPU 写入设备等)。

其他字段包括“BAR”(基地址寄存器,从设备配置空间中的偏移量 0x10 开始),它告诉设备应该接受哪个地址范围(在 IO 端口空间或物理地址空间中)。 对于这些,设备将被硬连线以使用 IO 端口或物理地址(并且无法更改),并且区域的大小也将被硬连线(并且也无法更改)。 因为这些东西是硬连线的,您可以将零写入 BAR 并找出硬连线的内容(以确定区域的大小,以及设备是否需要 IO 端口空间或物理地址空间)。

幸运的是,固件负责配置 BAR,因此(不包括热插拔设备和“异常情况”)操作系统不需要自己设置 BAR,只需从 BAR 中读取值(由固件设置) ) 来确定设备已配置为使用的地址(在 IO 端口空间或物理地址空间中)。 可悲的是,如果操作系统需要确定区域的大小(例如,并且不能依赖设备驱动程序已经知道其设备的大小),操作系统可能需要读取固件的值,然后执行“写入零到找出区域的大小”,然后恢复固件的值。

当然,PCI 配置空间不会说明 BAR 的用途——由设备驱动程序知道每个区域(由每个 BAR 描述)的用途。

如果操作系统出于某种原因想要(重新)配置 BAR 本身; 那么它要复杂得多,因为您还必须确保任何网桥正确转发对设备的访问(如果网桥后面有多个设备,那么这些设备必须使用网桥将转发的单个更大范围内的子范围); 并且您必须确保 CPU 的缓存不会破坏所有内容(这主要意味着通过特殊同步同时在所有 CPU 上重新配置 MTRR/内存类型范围寄存器); 并且您必须确保您不会踩到任何东西(例如,固件、RAM、CPU 等已使用的范围); 并且必须确保所有内容都在 CPU 可以访问的物理地址空间的一部分中(即使 CPU 有勘误表并通过 CPUID 报告错误的“物理地址位数”)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM