如果处理器处于实模式,它如何访问内存 > 1MB (0xFFFFFFF0H)
CPU 内部几乎没有人关心“CPU 模式”。执行正常指令时;真正重要的是默认代码大小、段基数、段限制、段类型等,而 CPU 模式无关紧要。只有像段寄存器加载和中断处理程序这样的 CPU 模式很重要(事实上,除了分页,如果唯一关心 CPU 模式的事情是在微代码中实现的事情,我不会感到惊讶)。
因为 CPU 模式与普通指令大多无关(并且因为默认代码大小、段基数、段限制、段类型等是唯一真正重要的事情);在上电或复位时,CPU 可以将“异常”值(CPU 模式下通常不可能的值)设置到段寄存器中,而 CPU 的其余部分不会关心。具体来说;它可以执行“CS.base_address = 0xFFFF0000”(这对于 CS 段寄存器加载执行“CS.base_address = 16_bit_CS.value << 4”的实模式是不可能的)。
最终结果是所有涉及 CS(并通过段限制检查)的内存访问最终都会到达(线性)地址“0xFFFF0000 + offset”,即使 CPU 处于“实模式”并且即使这不是'在实模式下通常是不可能的。
请注意,实模式下的地址不限于 1 MiB。例如,如果您将 0xFFFF 加载到段寄存器中,那么 CPU 会将该段寄存器的隐藏信息设置为“segment.base = 0x000FFFF0”,并且使用该段的地址将以从 0x000FFFF0 到 0x0010FFEF 的(线性)地址结束。这就是为什么(当 80286 发布时)我们需要“A20 门”以与古代软件兼容(在 CPU 不知情的情况下强制第 20 位地址位为零)。
还要注意,虽然“CS.base_address = 0xFFFF0000”对于实模式是不正常的;软件可以切换到保护模式并加载“代码大小 = 16 位,段限制
64 KiB,段基数 = 0xFFFF000" 描述符到 CS;然后切换回实模式而不重新加载 CS。最终结果将与 CPU 在上电或复位时设置的“异常 CS 基数”相同。
当然(不管异常值如何进入 CS.base)任何在实模式下执行的正常 CS 段寄存器加载都会导致“CS.base”设置为正常值;因此固件必须确保在异常地址以“实模式”执行时不会发生 CS 段寄存器加载。
这是如何发生的,或者当 RAM
物理地址空间用于 RAM、ROM 和内存映射设备。 ROM(而不是 RAM)将位于“4 GiB”地址的下方。例如,如果 ROM 为 2 MiB,那么它将位于 0xFFE00000 到 0xFFFFFFFF 的物理地址范围内。请注意,固件在开机时不能使用 RAM(它必须弄清楚安装的内存模块的类型和大小并配置内存控制器以适应,然后才能期望 RAM 工作)。
如果 BIOS 在 0x000FFFFFH 映射,为什么处理器会在 0xFFFFFFF0H 开始执行
最初(80286 和更早的 CPU)BIOS 实际上映射在 0x000FFFFF。对于(某些)80386 和更高版本的 CPU,这仅出于兼容性原因进行仿真。反而;固件将自身的一小部分从 ROM(以物理地址 0xFFFFFFFF 结尾的区域)复制到 RAM(以物理地址 0x000FFFFF 结尾的区域);然后配置内存控制器,以便忽略对该 RAM 区域的写入(因此内存控制器不会将这些写入转发到 RAM 芯片)。
请注意,对于“纯 UEFI”系统(不包括“混合 BIOS + UEFI”系统),固件没有理由设置以物理地址 0x000FFFFF 结尾的“传统 BIOS 区域”;并且该区域中的 RAM 可能是可用 RAM(在内存控制器中配置为“允许写入”等)。同样,“纯 UEFI”也不需要其他遗留区域(用于 VGA 和设备 ROM);并且理论上(对于具有 2 GiB 或更少 RAM 的计算机)没有理由(除了 SMM 偷一点)你不能只拥有从 0x00000000 到 0x7FFFFFFF 的单个连续正常 RAM 区域。