3. x86/x64 体系结构基础:CPU 模式、内存与 I/O

在 BIOS 开发中,CPU 的三种运行模式——实模式、保护模式与长模式——构成了固件启动与操作系统加载的底层基石。理解这些模式下的内存分段、分页机制以及 I/O 空间模型,是编写可靠固件代码的前提。本章将系统梳理这些核心概念,并辅以结构图与对比表格,帮助你建立清晰的硬件抽象视图。

3.1 CPU 运行模式:实模式、保护模式与长模式

x86/x64 处理器从上电复位到操作系统运行,会经历多种运行模式的切换。每种模式决定了 CPU 的寻址能力、指令集可用性以及内存保护策略。

特性 实模式 (Real Mode) 保护模式 (Protected Mode) 长模式 (Long Mode)
寻址位数 20 位 32 位 64 位
最大物理内存 1 MB 4 GB 16 EB (理论)
段机制 段基址:偏移 (CS:IP) 段选择子 + 描述符表 段选择子 + 描述符表 (简化)
分页机制 无 可选 (CR0.PG=1) 强制启用
特权级 无 (实为 Ring 0) Ring 0 ~ Ring 3 Ring 0 ~ Ring 3
典型用途 BIOS POST、Bootloader 早期 32 位 OS、UEFI DXE 阶段 64 位 OS、UEFI 64-bit
BIOS 开发要点: 绝大多数 BIOS 代码在实模式下启动,完成硬件初始化后,通过设置控制寄存器 CR0 的 PE 位切换到保护模式。UEFI 固件则会在早期进入保护模式或直接进入长模式,以利用 64 位寻址能力。

3.2 内存分段机制

分段是 x86 体系结构最基础的内存管理方式。在实模式和保护模式下,CPU 都使用段寄存器来定位内存地址,但两者的计算方式截然不同。

3.2.1 实模式分段

实模式下,物理地址由段基址左移 4 位加上偏移量得到:物理地址 = (段基址 << 4) + 偏移量。段基址存储在 CS、DS、ES、SS 等段寄存器中,偏移量由 IP、BX、SI、DI 等寄存器提供。这种模式只能访问 1 MB 地址空间,且没有保护机制。

3.2.2 保护模式分段

保护模式下,段寄存器不再直接存储基址,而是存储一个指向全局描述符表 (GDT) 或局部描述符表 (LDT) 的段选择子。段选择子包含索引、表指示位 (TI) 和请求特权级 (RPL)。CPU 通过段选择子查找描述符,从中获取段基址、段限长和访问权限,然后进行地址转换与保护检查。

关键数据结构: 全局描述符表 (GDT) 是保护模式和长模式下必须配置的核心表。每个描述符占 8 字节,包含段基址 (32 位)、段限长 (20 位)、类型、DPL、P 位等字段。BIOS 在切换到保护模式前,必须在内存中正确构建 GDT。

3.3 内存分页机制

分页是保护模式和长模式下实现虚拟内存、进程隔离和按需分页的基础。分页机制将线性地址转换为物理地址,并支持 4 KB、2 MB 和 1 GB 等多种页面大小。

3.3.1 32 位分页 (保护模式)

当 CR0.PG=1 且 CR4.PAE=0 时,启用 32 位分页。线性地址被拆分为页目录索引 (10 位)、页表索引 (10 位) 和页内偏移 (12 位)。CPU 通过 CR3 寄存器指向页目录基址,两级查表完成地址转换。

3.3.2 PAE 分页与长模式分页

物理地址扩展 (PAE) 允许 32 位 CPU 访问超过 4 GB 的物理内存。长模式下强制使用 PAE 风格的分页结构,但线性地址扩展为 48 位 (实际实现) 或 57 位 (5 级分页)。典型 4 级分页结构如下:

  • PML4 (Page Map Level 4):CR3 指向 PML4 表,9 位索引。
  • PDPT (Page Directory Pointer Table):9 位索引。
  • PD (Page Directory):9 位索引。
  • PT (Page Table):9 位索引。
  • 页内偏移:12 位 (4 KB 页面)。
常见陷阱: 在长模式下,段寄存器的基址计算被忽略 (CS、DS、ES、SS 的基址被强制为 0),但 FS 和 GS 的基址仍可通过 MSR 设置,常用于线程本地存储 (TLS)。分页是长模式下唯一的内存保护与地址转换手段。
实模式、保护模式、长模式地址转换对比 三种 CPU 模式下的地址转换流程 实模式 段基址 << 4 + 偏移 CS = 0xF000 IP = 0x7C00 物理地址 = 0xF0000 + 0x7C00 0xFC000 (1MB 内) 无保护检查,直接访问 保护模式 段选择子 → GDT → 基址 + 偏移 CS = 0x08 EIP = 0x1000 GDT 索引 1 → 基址 0x100000 0x101000 (4GB 内) 特权级检查、段限长检查 长模式 PML4 → PDPT → PD → PT + 偏移 CR3 = PML4 RIP = 0x1000 4 级页表转换 物理地址 (任意) 分页强制启用,段基址忽略

3.4 I/O 空间与内存映射 I/O

x86 体系结构提供了两种独立的 I/O 访问方式:I/O 端口空间和内存映射 I/O (MMIO)。BIOS 在初始化硬件时,需要根据设备类型选择合适的访问方法。

3.4.1 I/O 端口空间

I/O 端口空间是一个独立的 64 KB 地址空间 (0x0000 ~ 0xFFFF),通过 IN 和 OUT 指令访问。每个端口可以读写 8 位、16 位或 32 位数据。典型设备包括:

  • PIC (8259A):端口 0x20/0x21 (主片),0xA0/0xA1 (从片)。
  • PIT (8254):端口 0x40 ~ 0x43。
  • RTC (CMOS):端口 0x70 (索引),0x71 (数据)。
  • 串口 (UART):端口 0x3F8 ~ 0x3FF (COM1)。

3.4.2 内存映射 I/O (MMIO)

MMIO 将设备寄存器映射到物理内存地址空间,CPU 使用普通的 MOV 指令即可访问。这种方式简化了编程模型,但需要确保该内存区域被标记为不可缓存 (Uncacheable),以避免 CPU 缓存导致的数据不一致。典型 MMIO 设备包括:

  • PCIe 配置空间:映射到内存地址 0xE0000000 附近 (具体由 MCFG ACPI 表指定)。
  • 帧缓冲 (Framebuffer):显卡显存映射到物理地址空间。
  • APIC 寄存器:本地 APIC 映射到 0xFEE00000。
BIOS 开发实践: 在实模式下访问 MMIO 时,需要确保段基址 + 偏移量能够覆盖目标物理地址。例如,访问 0xFEE00000 处的 APIC 寄存器,可能需要将段基址设为 0xFEE0,偏移设为 0x0000。在保护模式或长模式下,则需确保页表正确映射该物理地址。
I/O 端口空间与内存映射 I/O 地址布局 I/O 空间与 MMIO 地址布局 I/O 端口空间 (64 KB) 0x0000 - 0x001F: DMA 控制器 0x0020 - 0x003F: PIC 主片 0x0040 - 0x0043: PIT 定时器 0x00A0 - 0x00A1: PIC 从片 ... 其他设备 (串口、并口、PS/2 ...) 内存地址空间 (MMIO 区域) 0xFEE00000: 本地 APIC 0xFEC00000: I/O APIC 0xE0000000: PCIe 配置空间 (MCFG) 0xA0000 - 0xBFFFF: VGA 帧缓冲 ... 其他设备 (SMM、HPET ...) I/O 端口使用 IN/OUT 指令;MMIO 使用 MOV 指令,需标记为 Uncacheable

3.5 模式切换流程与 BIOS 初始化

BIOS 在启动过程中,会按照以下典型路径切换 CPU 模式:

  1. 上电复位:CPU 处于实模式,CS=0xF000, IP=0xFFF0,执行 BIOS 入口代码。
  2. 实模式初始化:设置堆栈、中断向量表 (IVT)、检测内存、初始化芯片组。
  3. 切换到保护模式:构建 GDT,设置 CR0.PE=1,远跳转刷新 CS 缓存。
  4. 保护模式初始化:设置页表 (可选)、加载 IDT、初始化 APIC、枚举 PCI 设备。
  5. 切换到长模式 (UEFI 64-bit):设置 EFER.LME=1,启用 PAE 分页,设置 CR0.PG=1。
  6. 长模式初始化:加载 64 位 IDT,执行 DXE 与 BDS 阶段。
模式切换注意事项:
  • 从实模式切换到保护模式前,必须确保 GDT 已正确设置,且代码段描述符的 DPL 与当前 CPL 匹配。
  • 从保护模式切换到长模式时,必须先启用 PAE 分页,且页表必须覆盖当前执行地址。
  • 切换过程中,通常需要禁用中断 (CLI),避免在模式切换期间响应中断导致异常。

3.6 本章小结

本章覆盖了 x86/x64 体系结构的三大核心主题:CPU 运行模式、内存分段与分页、I/O 访问模型。实模式提供最直接的硬件访问能力,保护模式引入特权级与段保护,长模式则通过强制分页实现 64 位寻址。理解这些底层机制,是后续编写 BIOS 初始化代码、配置内存映射、以及实现固件服务的基础。在下一章中,我们将深入 BIOS 启动流程,从 POST 到 Boot Selection 的完整路径。