bochs 中文文档 下载 App

内存模型与地址空间——物理内存、虚拟内存和 BOCHS 的映射关系

物理内存模型

bochsrc 里的 memory: guest=64 给 Bochs 模拟一块 64MB 的物理内存——就是一个从 0x00000000 到 0x03ffffff 的线性数组。这是 Bochs 模拟的 PC 硬件能看到的所有物理 RAM。

这块内存里,部分地址被硬件保留(映射到 BIOS ROM、VGA VRAM、PCI 设备的 MMIO 区域),真正可用的 RAM 是:

物理地址范围用途
0x00000000 ~ 0x0009ffff常规 RAM(低 640KB,DOS 传统区)
0x000a0000 ~ 0x000bffffVGA VRAM(64KB,0xa0000-0xbffff)
0x000c0000 ~ 0x000dffffISA ROM(128KB)
0x000e0000 ~ 0x000fffffBIOS shadow RAM
0x00100000 ~ guest 上限扩展 RAM(1MB 以上)
0xfffc0000 ~ 0xffffffffBIOS ROM(128KB)
PCI 设备 BAR 区PCI MMIO(由 PCI 枚举决定具体范围)

OS 内核在做内存管理时必须了解这些保留区域——不能把 BIOS 区域或 VGA VRAM 当作普通 RAM 分配给用户进程。

虚拟内存:CR3 和页表

内核打开分页后,CR3 寄存器指向当前进程的页表根(32 位下是 PDG,x86-64 下是 PML4)。每次 CPU 访问虚拟地址时:

  1. 查询 CR3 找到页表根的物理地址
  2. 多级遍历页表(根据模式不同:2 级、3 级、4 级、5 级)
  3. 最后一级页表项给出物理页框号 + 权限标志
  4. 把虚拟地址低 12 位偏移加到物理页框号上,得到最终物理地址

Bochs 在每次内存访问时都做这个遍历——精度极高,但也是 Bochs 慢的原因之一。QEMU 会直接把虚拟地址翻译成宿主机地址跳过去,VirtualBox/VMware 让硬件做。

调试器里的内存查看

Bochs 调试器提供两种前缀查看内存:

命令前缀含义
xp <addr>xp查看物理地址(Physical)
x <addr>x查看虚拟地址(由当前 CR3 页表翻译)
wx <addr> <value>wx写入物理地址
w <addr> <value>w写入虚拟地址

示例:

bochs:1> xp 0x7c00           # 看物理地址 0x7c00(Bootloader 入口)
bochs:2> x 0x100000          # 看虚拟地址 0x100000(经过 CR3 翻译)
bochs:3> xp /32bx 0x0        # 看中断向量表(物理)
bochs:4> w /4bx 0x7c00 0x00  # 往 Bootloader 开头写入 4 个 0

注意 x 命令依赖当前 CR3 页表有效——如果内核还没初始化 CR3(实模式或保护模式刚开始),虚拟地址翻译会出错。此时用 xp 看物理地址更可靠。

bochsrc 里的 memory 字段详解

memory: guest=64, host=64, slots=2
字段说明
guest客户机能看到的物理内存大小(MB)
host宿主机分配给 Bochs 的内存(MB)
slots内存槽数(可选,影响 BIOS 报告的物理 DIMM 布局)

通常 guest == host。如果你要精确模拟"客户机 64MB RAM 但宿主机只给 Bochs 32MB 工作内存"的极端情况,也可以让 host < guest——但通常没必要,反而会影响性能(Bochs 会更频繁地 swap)。

内存与 BIOS 的关系

BIOS 自检时会枚举物理内存布局,并把结果写到 E820 内存映射表(BIOS 调用 int 0x15 AX=0xE820 返回)。OS 内核启动时读这个表来决定哪些地址是可用 RAM、哪些被保留。

Bochs 正确实现了 E820——它会根据 bochsrc 里的 memory: 大小自动生成一份合理的内存映射表,和真实硬件一致。OS 开发者不需要手动构造 E820,Bochs 会给你一份"看起来像真的"。

64 位模式的内存映射

x86-64 模式下物理地址空间可以到 1TB 甚至更大(取决于 bochsrc 里 CPU model 和 guest 内存)。但内核在初始化时会把物理内存拆成不同区域:

调试 64 位内核时,x 命令看直接映射区特别有用——可以直接用"物理地址 + 固定偏移"的方式访问任何物理内存。