内核为 BIOS 保留 CONFIG_X86_RESERVE_LOW 内存有什么意义?

内核为 BIOS 保留 CONFIG_X86_RESERVE_LOW 内存有什么意义?

从至少 2.6 内核开始,Kconfig 提供了选项 CONFIG_X86_RESERVE_LOW,描述为“为 BIOS 保留的低内存量(以千字节为单位)”。 (据我理解,从物理地址0开始,范围从4K到640K)

在我的系统上启动时,我的日志在启动过程即将开始时通知我:

BIOS-provided physical RAM map:
BIOS-e820: [mem 0x0000000000000000-0x000000000009ebff] usable

由此我推断 BIOS 正在告诉内核 ram 的第一个 0x9ec00 (~640K) 字节是可用的。 (不保留)

再看几行,我可以读到:

e820: update [mem 0x00000000-0x00000fff] usable ==> reserved

我理解这是我的设置的结果:CONFIG_X86_RESERVE_LOW = 4K

但是,考虑到 BIOS 本身断言 0-0x9ebff 范围可用,内核为 BIOS“保留”<~640K 的低内存量有什么意义呢?

答案1

您应该会看到此配置选项的更长帮助文本。它提供了两个原因。

config X86_RESERVE_LOW
int "为 BIOS 保留的低内存量(以千字节为单位)"
默认 64
范围 4 640
帮助

指定为 BIOS 保留的低内存量。

第一页包含内核不得使用的 BIOS 数据结构,因此该页必须始终保留。

[剪]

网上也有类似的评论代码:

     * A special case is the first 4Kb of memory;
     * This is a BIOS owned area, not kernel ram, but generally
     * not listed as such in the E820 table.

传统 BIOS 将使用前 1280 个字节 (0x500)。 Linux 以 MMU 页大小(4096 字节)为单位分配 RAM。 操作系统开发指出 -

在调用所有 BIOS 函数并且将内核加载到内存中的某个位置后,引导加载程序或内核可能会永远退出实模式(通常会进入 32 位保护模式)。如果内核不再使用实模式,则 PC 中前 0x500 字节的内存可能会被重用并覆盖。

Linux 通常无法调用 BIOS。然而,它可能会在一些可怕的时刻这样做:提前启动、关机和从睡眠模式恢复。如果您的系统是使用 UEFI 启动的,那么就 Linux 所知,它没有可以调用的 BIOS。

此外,保留第一页意味着成功的物理内存分配永远不会返回值 0。C 编程传统上保留地址 0 来表示“NULL 指针”。我们可以看到这反映在memblock_phys_alloc_range()。在这一点上,改变它似乎不太可能得到回报(和风险:-)。

 * Return: physical address of the allocated memory block on success,
 * %0 on failure.
 */
phys_addr_t __init memblock_phys_alloc_range(

这是第二个原因:

默认情况下,我们保留前 64K 物理 RAM,因为已知许多 BIOS 会在挂起/恢复或监视器电缆插入等事件期间破坏该内存范围,因此内核不得使用它。

如果您绝对确信 BIOS 能够正确保留所有内存并使用它,则可以将其设置为 4。如果您知道 BIOS 在默认 64K 区域之外存在问题,则可以将其设置为 640 以避免使用整个低内存范围。

如果您对 BIOS 有疑问(例如,挂起/恢复不起作用或在某些硬件热插拔事件后出现内核崩溃),那么您可能需要启用 X86_CHECK_BIOS_CORRUPTION=y 以允许内核检查典型的损坏模式。

如果您不确定,请将此值保留为默认值 64。

最安全的假设是,这也适用于 UEFI 固件,就像适用于 BIOS 一样:-)。

从 v3.9 开始,超低保留不会显示在内核日志消息中。它也没有显示在/proc/iomem。内核仅显示保留的前 4k,尽管其余内存仍应保留。它只是没有添加到 e820 地图中。它被添加到不同的列表中。此更改的补丁在这里:x86,mm:稍后在初始化时移动保留低内存

如果您想了解有关额外保留的更多信息,以及需要它的悲惨故事,请参阅以下补丁消息:

x86:为 AMI BIOS 添加 DMI 怪癖,这会在恢复期间损坏地址 0xc000

Alan Jenkins 和 Andy Wettstein 报告了一个暂停/恢复内存损坏错误,并在此处进行了详细记录:

http://bugzilla.kernel.org/show_bug.cgi?id=11237

该错误在于 BIOS 覆盖了 0xc000 物理地址处的 1K 内存,而没有将其在 e820 中注册为保留,也没有让内核对此有任何了解。

检测 AMI BIOSen 并保留该 1K。

我们用非常广泛的画笔来描绘这个错误(在所有 AMI BIOS 系统上保留 1K),因为该错误非常难以发现,并且需要数周时间以及大量的调试和修补。

该错误是通过 CONFIG_X86_CHECK_BIOS_CORRUPTION=y 调试功能发现的,如果怀疑存在类似错误,则也可以在其他系统上启用此功能,以扫描低内存以查找损坏的内存。

x86:添加 X86_RESERVE_LOW_64K

这个bugzilla:

http://bugzilla.kernel.org/show_bug.cgi?id=11237

记录了 BIOS 在挂起/恢复和其他硬件事件期间使用前 64K 物理内存的各种系统。

目前,我们在所有 AMI 和 Phoenix BIOS 系统上保留此内存。生命太短暂,无法追寻像这样微妙的内存损坏问题,因此我们在默认情况下尝试保持稳健。

不过,允许覆盖此设置:允许希望内核可使用前 64K 内存的用户通过 CONFIG_X86_RESERVE_LOW_64K=n 禁用该怪癖。

x86、BIOS:默认情况下,为所有 BIOS 保留低 64K

需要保留低 64K 的 BIOS 清单越来越长,因此请将其设为所有 BIOS 的默认值。这也使得代码得以简化并与前 4K 的预留代码统一。

这解决了内核 bugzilla 16661 以及谁知道还有什么......

Bug 16661 - 低内存损坏

[...]这意味着我们应该将他的BIOS(请提供dmidecode信息)添加到arch/x86/kernel/setup.c中的黑名单bad_bios_dmi_table中。然而,最重要的是,64K 内存量很小,而且该列表现在涵盖了大量现有 BIOS,因此我们应该将其设为无条件。

据我所知,Windows 7 实际上保留了 1 MiB 以下的所有内存,以避免 BIOS 错误。

相关内容