x86_64 上的 linux 如何恢复被内存映射 IO 屏蔽的“丢失”物理内存?

x86_64 上的 linux 如何恢复被内存映射 IO 屏蔽的“丢失”物理内存?

/proc/iomem表示重要的地址空间映射到 PCI 设备,例如我机器上的视频卡:e0000000-efffffff : 0000:01:00.0如果我的数学正确的话,它是 250MB。在只有 16GB RAM 的 64 位桌面上,我假设 Linux 或所有现代内核可以使用一些技巧来恢复这部分物理内存,但具体是如何恢复的呢?

一个有点相关的问题 - 如果北桥/内存控制器根据某些可编程规则路由内存/io 访问,这样对于内存映射区域(例如,pci 设备)的写访问,RAM 甚至不知道这些写操作,因为它们是路由走了,那么应该有某种“路由表”?这样的桌子在哪里? Linux内核如何访问这个表?

答案1

刚刚发现有几个与此主题相关的 wiki 页面:PCI_孔3_GB_barrier

如今在 x86 上,可以通过内存重新映射来处理 PCI 漏洞,但这并不能恢复 MMIO 窃取的所有 RAM 地址,例如 16M 以下的多个小区域 - 芯片组仅具有重新映射有限数量区域的功能。

答案2

由于您拥有 64 位操作系统,因此您可以启用 BIOS 设置“Above 4G Decoding”、“64 位 I/O 地址解码”或您的系统/主板供应商所称的任何设置。启用该设置后,任何能够处理 64 位地址的 MMIO 硬件都会映射到传统 32 位范围之外的地址,从而最大限度地减少与内存的冲突,从而减少重新映射插槽的需要。

在我的系统上,生成的 GPU 映射如下所示:

6000000000-600fffffff : 0000:01:00.0

此外,250MB 大约只是 16 GB 的 1.5%;如果获得最后 1.5% 的内存确实至关重要,那么如果可能的话,获得更多 RAM 可能会带来显着的性能优势。只是说...

据我所知,用于内存重新映射的“路由表”至少部分在芯片组硬件中实现,并且是特定于芯片组的,因此通常由系统固件在启动时设置。如果可以进行任何运行时访问,我希望它可以通过 ACPI 固件例程进行;否则内核必须为每个芯片组提供特定的例程。

(是的,内核具有特定于硬件模型的怪异例程来解决已知的硬件错误;但是比这更深入并绕过系统固件提供的 ACPI 抽象将需要付出更多的努力,例如核心引导.)

相关内容