【问题标题】:Software initialization code at 0xFFFFFFF0H0xFFFFFFF0H 处的软件初始化代码
【发布时间】:2012-03-01 21:21:57
【问题描述】:

英特尔表示,复位后处理器处于实模式,软件初始化代码从 0xFFFFFFF0H 开始。我的问题:

  • 如果处理器处于实模式,它如何访问内存 > 1MB (0xFFFFFFF0H)

  • 这是如何发生的,或者当 RAM

  • 如果 BIOS 在 0x000FFFFFH 映射,为什么处理器会在 0xFFFFFFF0H 开始执行

请帮我解决这些问题。 谢谢。

【问题讨论】:

  • 你有一些文件可以链接或引用吗?听起来确实是个误会。
  • 英特尔软件开发人员手册,系统编程指南 3A 第 1 部分,第 9-20 页(253668.pdf)
  • 您需要了解段寄存器如何在实模式下工作。有效地址 = CS
  • @Hans Passant:实模式:最大 {cs
  • 不,这意味着,比如说,CS=0xffff 和 IP=0x10 将产生一个有效的总线地址 0。

标签: operating-system x86 computer-architecture bios


【解决方案1】:

如果处理器处于实模式,它如何访问内存 > 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 区域。

【讨论】:

  • 我认为在最初的 286 个 IBM AT 上,前 4 条地址线一直保持在高位,直到第一个 FAR JMP 被拉低。
  • “固件将自身的一小部分从 ROM(在以物理地址 0xFFFFFFFF 结尾的区域)复制到 RAM(在以物理地址 0x000FFFFF 结尾的区域)”这似乎与 @987654321 的内容相矛盾@ 说:“英特尔芯片组通常具有内存别名功能,允许访问低于 1 MB 的内存,并通过 DRAM 或位于 4 GB 以下的非易失性存储进行访问。”
  • @wmjdgla:这篇文章是对的(芯片组确实能够将低于 1 MiB 的不同范围的访问路由到系统总线而不是 RAM,它很慢,可以使用“在 RAM 中阴影”加快速度);但是“在 RAM 中的阴影”通常总是会完成,并且大多数情况下都不会使用该功能(除了在未内置在固件/主板中的设备上初始化设备 ROM 时,例如 PCI 视频卡、PCI RAID 控制器卡等)。
  • 但是执行shadowing的是固件,所以系统必须先执行一些非shadowing的固件代码。在固件切换到保护/长模式之前,系统只能访问 1MB 内存。那么这是否意味着映射到高内存区域的非阴影固件代码(以便复位向量可以放置在 0xFFFF FFF0 处)必须别名为内存的前 1MB?
  • @wmjdgla:可能更容易将其视为 2 个独立的固件——“平台初始化代码”(以 0xFFFFFFFF 结尾),它做了很多事情,包括为另一部分设置阴影,以及被遮蔽的“旧版 BIOS 运行时代码”(以 0x000FFFFF 结尾)(在第一块设置之后)。当然,对于“混合 BIOS 加 UEFI”,您将拥有 3 个部分(相同的初始化代码,然后是 BIOS 或 UEFI 运行时环境,具体取决于固件设置)。
【解决方案2】:

我终于在Coreboot documentation找到了答案:

只要 x86 CPU 在复位后唤醒,它就会在实模式下进行。此模式仅限于 1MiB 地址空间和 64k 偏移量,原始 8086/88 的复位向量位于 0xFFFF0。

即使我们运行像 P3 这样的当前处理器也没有任何变化,这些较新的 CPU 也感觉它们在重置后从 0xF000:0xFFF0 开始。但他们没有。复位后代码段寄存器的基址为0xFFFF0000,因此CPU生成一个0xFFFFFFF0的物理地址给芯片组。芯片组负责将此区域转发到引导 ROM。令人困惑的是:CPU“认为”它在 0xF000:0xFFF0 处运行代码,但实际上它使用的是 0xFFFFFFF0 处的代码。当开发人员将这种设计实现到硅片中时,他们一定已经气死了。

因此,英特尔文档似乎谈到了“在线”使用的物理地址,即访问真实总线时。这与 CPU 模式无关(总线不知道也不关心 CPU 模式,翻译这些东西是 CPU 的职责)。

【讨论】:

  • 当我运行 Qemu 时,我看到它从 0xFFFF0 开始。这是否意味着 Qemu 仍然不知道当前主板上的 CPU 生成 0xFFFFFFF0 的事实?还是只是 Qemu 开发人员没有气馁,决定走正常的“实模式”8086/88 路线?
  • 这和wiki.osdev.org/Unreal_Mode 是同一类东西——一个 CS 基础,而不是在实模式下通过写入 CS(使用 far jmp)可以获得的东西。就像你可以通过切换到保护模式并返回来做的那样。
【解决方案3】:

要查看实际问题,您需要一个硬件调试器。正确的文档来自英特尔,引用:http://download.intel.com/design/processor/manuals/253668.pdf,第 9.1.4 节:

在 a 之后获取并执行的第一条指令 硬件复位位于物理地址 FFFFFFF0H。这个地址 比处理器最高物理地址低 16 个字节。这 包含软件初始化代码的 EPROM 必须位于 这个地址。

这意味着 BIOS ROM,仅供参考,而不是您的普通 RAM,即内容是硬连线的。请记住,在这个阶段,RAM 内存还没有设置好,VGA 内存(与 RAM 不同)甚至都不可用和初始化。

地址 FFFFFFF0H 超出 1-MByte 可寻址范围 处理器的范围,而在实地址模式。处理器是 初始化到这个起始地址如下。 CS寄存器有 两部分:可见段选择器部分和隐藏基部 地址部分。在实地址模式下,基地址通常为 通过将 16 位段选择器值 4 位移到 剩下来产生一个 20 位的基地址。然而,在硬件 复位后,CS寄存器中的段选择器加载F000H 并且基地址加载了FFFF0000H。起始地址 因此,通过将基地址添加到 EIP 中的值来形成 寄存器(即 FFFF0000 + FFF0H = FFFFFFF0H)。第一次 CS 寄存器在硬件复位后加载一个新值, 处理器将遵循正常的地址转换规则 实地址模式(即[CS基地址=CS段选择符* 16])。确保 CS 寄存器中的基地址保持不变 直到基于 EPROM 的软件初始化代码保持不变 已完成,代码不得包含远跳转或远调用或允许 发生中断(这将导致 CS 选择器值 改变)

在此期间,BIOS 本质上是在初始化硬件和内存本身,同时仍以实模式执行。然后最后执行 VGA BIOS(存在于您的 VGA 卡中,可在 0xc700 寻址)等等。但这超出了当前的问题。但是上面引用的评论基本上回答了你的问题。

【讨论】:

  • 来自您引用的文档:CS register is loaded with F000H and the base address is loaded with FFFF0000H。添加时为FFFF0000 + FFF0H = FFFFFFF0HF000 是如何变成 FFF0 的?将F000 向左移动 4 位使其成为F0000,不是吗?我错过了什么?
猜你喜欢
  • 2022-01-21
  • 2011-12-19
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-17
  • 1970-01-01
  • 2014-08-15
相关资源
最近更新 更多