概述
1 概述
Axvisor 的启动是一个精心设计的多阶段过程,从引导加载程序到完整的 Hypervisor 运行时环境。
启动流程架构图
┌─────────────────────────────────────────────────────────────────┐
│ Axvisor 启动时序 │
├─────────────────────────────────────────────────────────────────┤
│ 1. 硬件引导 → 启动代码 → rust_main() │
│ 2. 早期初始化:BSS清理、CPU初始化、平台配置 │
│ 3. 内存发现:内存嗅探、区域分类、安全验证 │
│ 4. 分配器初始化:TLSF设置、区域选择、堆管理 │
│ 5. 虚拟化建立:MMU配置、Stage-2页表、vCPU设置 │
│ 6. 运行就绪:调度器启动、虚拟机加载 │
└─────────────────────────────────────────────── ──────────────────┘
2 启动入口和早期初始化
2.1 入口点与平台抽象
启动入口的原理机制
Axvisor 通过 #[axplat::main] 属性实现平台无关的启动入口:
// axruntime/src/lib.rs
#[axplat::main] // ← 编译时生成特殊符号,供平台启动代码调用
pub fn rust_main(cpu_id: usize, arg: usize) -> ! {
// 启动主逻辑
}
核心原理:
- 符号生成:
axplat::main宏在编译时创建名为_start的导出符号 - 平台绑定:不同平台的启动汇编(如
start.S)直接调用_start - 参数传递:
cpu_id和arg由启动代码传递,标识CPU核心和启动参数
2.2 早期平台初始化原理
硬件抽象层初始化
axhal::init_early() 负责平台特定的早期硬件配置:
// axruntime/src/lib.rs
pub fn rust_main(cpu_id: usize, arg: usize) -> ! {
unsafe { axhal::mem::clear_bss() };
axhal::init_percpu(cpu_id);
// 3. 早期平台初始化
axhal::init_early(cpu_id, arg);
// 4. 启动信息输出
ax_println!("{}", LOGO);
ax_println!("smp = {}", cpu_count());
// 5. 日志系统初始化
axlog::init();
log::set_max_level(log::LevelFilter::Trace);
}
早期初始化的 核心任务:
-
CPU 模式设置:
- 配置异常级别(EL2 for Hypervisor)
- 设置栈指针和中断向量
- 启用基本特权模式
-
基础页表映射:
- 建立最小化的虚拟地址映射
- 确保内核代码可执行
- 为后续内存管理做准备
-
串口配置:
- 初始化调试输出设备
- 设置波特率和通信参数
- 提供早期调试能力
3 内存发现和初始化
3.1 内存嗅探的核心原理
3.1.1 内存嗅探的动机与目的
内存嗅探是 Hypervisor 启动的关键环节,其原理是通过分析设备树和硬件配置,识别所有可用的物理内存区域,为后续的内存管理和虚拟化建立基础。
// axruntime/src/lib.rs
#[cfg(feature = "alloc")]
fn init_allocator() {
info!("Initialize global memory allocator...");
info!(" use {} allocator.", axalloc::global_allocator().name());
// 关键:执行完整的内存嗅探
axhal::mem::init();
// 输出发现的内存区域信息
info!("Found physical memory regions:");
for r in axhal::mem::memory_regions() {
info!(" [{:#x?}, {:#x?}) {} ({:?})",
r.paddr,
r.paddr + r.size,
r.name,
r.flags);
}
}