Rust Hypervisor Firmware内存布局与分页机制:地址空间设计的底层逻辑
【免费下载链接】rust-hypervisor-firmware 项目地址: https://gitcode.com/gh_mirrors/ru/rust-hypervisor-firmware
Rust Hypervisor Firmware(RHF)是一款用 Rust 编写的轻量级虚拟机固件,它的内存布局与分页机制决定了固件能否在 x86_64、aarch64、riscv64 三种架构上稳定启动。本文将带你从链接脚本、内存描述符到页表建立,一步步拆解这个开源固件的地址空间设计底层逻辑,理解它如何用不到几千行代码完成传统 BIOS 的启动工作。
什么是 Rust Hypervisor Firmware?🧱
Rust Hypervisor Firmware 是一个极简固件,专为 PVH 启动标准设计,可直接从磁盘镜像加载引导器(Boot Loader)或内核,无需依赖复杂的 edk2/TianoCore 固件。它支持 virtio 块设备、GPT 分区解析、FAT 文件系统读取、bzImage 与 PE32+ 加载,甚至能启动 Ubuntu 的 shim + GRUB2 链。
固件体积小、启动快,全部核心逻辑用 Rust 编写,天然具备内存安全优势——而这一切都建立在一个精心设计的内存布局之上。
内存布局的源头:链接脚本如何定义地址空间 📐
固件的内存布局并非凭空而来,它的起点是各架构下的链接脚本(Linker Script)。链接脚本通过符号(如 code_start、code_end)标记出代码段、数据段和栈段的边界,这些符号随后在 Rust 代码中被读取,转化为统一的内存描述符。
以 x86_64 为例,x86_64-unknown-none.ld 中定义了:
ram_min = 1M:由于加载器喜欢占用 1M 以下的低内存,固件从 1MB 开始布局code_start到code_end:代码段范围,按 4K 对齐data_start到data_end:数据段与 BSS 段范围stack_start到stack_end:向下增长的 128K 栈空间
值得注意的是,链接脚本中还有一行关键断言:
ASSERT((. <= 2M), "Stack overflows initial identity-mapped memory region")
这保证了栈必须落在启动阶段映射的 2MiB 初始内存区域内,否则固件无法在分页开启前正常运行。
统一的内存描述符:一视同仁的区域管理 🗂️
链接脚本符号在 Rust 侧被封装成统一的结构。核心定义位于 src/layout.rs,它提供了 MemoryAttribute(Code / Data / Unusable / Mmio)和 MemoryDescriptor 两个基础类型:
range_start()/range_end():返回对齐到 4K 页边界的区间端点page_count():计算该区域包含的页数(PAGE_SIZE = 0x1000)
每个架构只需用这些描述符声明自己的内存区域即可,上层代码(如加载内核、传递 bootinfo)无需关心具体架构差异。这就是"一次抽象,三架构复用"的设计精髓。
x86_64 内存布局:4 个区域撑起整个固件 🖥️
x86_64 的内存布局定义在 src/arch/x86_64/layout.rs,包含 4 个描述符:
| 区域名称 | 属性 | 说明 |
|---|---|---|
| PVH Header | Data | 供 PVH 加载器识别固件格式的头部 |
| Code | Code | 固件代码段,从 code_start 开始 |
| Data | Data | 数据段、BSS 段 |
| Stack | Data | 向下增长的栈空间 |
同时,KERNEL_START = 0x20_0000(2MiB)标记了内核加载的起始地址,这也是 Linux 内核传统的加载位置约定。
aarch64 内存布局:2TB 地址空间的分区艺术 💠
aarch64 版本更复杂,定义在 src/arch/aarch64/layout.rs,它构建了一个 2TB(0x20_0000_0000)的虚拟地址空间,分为两大区域:
MMIO 区(0x0000_0000 ~ 0x4000_0000):包含 PL011 串口(0x0900_0000)和 PL031 实时时钟(0x0901_0000),标记为 Device 属性、禁止执行(execute_never)。
DRAM 区(0x4000_0000 起):内部再细分为 FDT(设备树)、ACPI 表和内核区域:
| 区域 | 起始地址 | 大小 |
|---|---|---|
| FDT | 0x4000_0000 | 2MB |
| ACPI | 0x4020_0000 | 2MB |
| KERNEL | 0x4040_0000 | 2MB(payload 加载区) |
这些地址与 aarch64-unknown-none.ld 中的 ram_min = 0x40600000 严格对应,固件本体从 0x4060_0000 开始放置。
riscv64 内存布局:为 OpenSBI 预留空间 🦾
riscv64 目前作为 OpenSBI 的 payload 运行,布局定义在 src/arch/riscv64/layout.rs。它除了 Code / Data / Stack 三个常规区域外,还显式将 0x8000_0000 ~ 0x8020_0000 标记为 SBI(Unusable) 保留区,避免固件覆盖 OpenSBI 的运行空间。
分页机制:x86_64 如何建立 4GiB 恒等映射 🔑
分页的核心实现在 src/arch/x86_64/paging.rs,思路非常清晰:
- 静态页表:
L4_TABLE、L3_TABLE、L2_TABLES全部声明为静态变量,避免动态分配内存 - 2MiB 大页:用 2MiB 大页(huge page)直接填充 L2 表,只需 2048 个条目即可覆盖 4GiB 空间
- 逐级链接:L3 指向 4 个 L2 表,L4[0] 指向 L3,形成完整四级页表
- 写回 CR3:最后将 L4 表物理地址写入 CR3 寄存器,CPU 立即启用新页表
代码中的关键点:
// Setup Identity map using L2 huge pages
for l2 in l2s.iter_mut() {
for l2e in l2.iter_mut() {
l2e.set_addr(next_addr, pt_flags | PageTableFlags::HUGE_PAGE);
next_addr += Size2MiB::SIZE;
}
}
这套**恒等映射(Identity Mapping)**方案让虚拟地址等于物理地址,简化了启动早期"物理地址直接可用"的需求,无需复杂的地址转换表。
aarch64 分页机制:MMU 与缓存的一键开启 ⚙️
aarch64 的分页由 src/arch/aarch64/paging.rs 负责,流程同样环环相扣:
- 校验 granule:确认硬件支持 64KiB 翻译粒度(
ID_AA64MMFR0_EL1) - 配置 MAIR_EL1:定义 Device 与 Cacheable Normal 两类内存属性
- 填充翻译表:根据 src/arch/aarch64/translation.rs 的
TranslationTable逐级填充条目 - 设置 TTBR0_EL1:指向翻译表物理地址
- 配置 TCR_EL1:设定 48 位虚拟地址空间、64KiB 粒度
- 开启 MMU:修改
SCTLR_EL1的 M/C/I 位,同时打开数据与指令缓存
整个流程用 isb 屏障指令保证顺序,避免乱序执行导致页表未生效。
内存布局如何支撑内核加载 🚀
内存布局与分页机制并非孤立存在,它们共同服务于内核加载流程:
- bootinfo 传递:src/bootinfo.rs 会把内存区域信息整理成 bootinfo 结构,供后续加载的内核使用
- E820 映射:src/boot.rs 定义了 E820Entry,将内存区域转换为标准 E820 格式(RAM / Reserved / ACPI 等类型)
- 零页填充:boot.rs 中的
Params结构体(zeropage)会填充 ACPI RSDP 地址、内存大小等信息,让 Linux 内核无需重新探测硬件
总结:小而美的地址空间设计哲学 🎯
回顾整个 Rust Hypervisor Firmware 的内存布局与分页机制,可以发现三条设计主线:
- 链接脚本驱动布局:用符号定义区域边界,Rust 侧统一封装为描述符,架构差异被隔离在
arch/目录内 - 静态页表 + 恒等映射:x86_64 用静态大页表覆盖 4GiB,aarch64 用翻译描述符描述 2TB 空间,启动期间不依赖动态内存分配
- 一处抽象、三架构复用:
layout.rs提供统一抽象,上层 bootinfo / loader 逻辑完全架构无关
对于想学习嵌入式 Rust、操作系统底层原理或虚拟化固件设计的开发者来说,这个项目的地址空间设计是一份难得的"小而完整"的参考教材。想要深入阅读源码,可以 clone 仓库 https://gitcode.com/gh_mirrors/ru/rust-hypervisor-firmware 后,从 src/arch/ 目录下的 layout.rs 与 paging.rs 开始你的探索之旅。
【免费下载链接】rust-hypervisor-firmware 项目地址: https://gitcode.com/gh_mirrors/ru/rust-hypervisor-firmware
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



