ax-plat-riscv64-qemu-virt
路径:
platforms/ax-plat-riscv64-qemu-virt类型:库 crate 分层:组件层 / 可复用基础组件 版本:0.3.1-pre.6文档依据:Cargo.toml、README.md、src/lib.rs、src/boot.rs、src/init.rs、src/mem.rs、src/console.rs、src/time.rs、src/irq.rs、src/power.rs
ax-plat-riscv64-qemu-virt 是 axplat 在 QEMU RISC-V virt 机型上的具体实现。它把 SBI、PLIC、UART、Goldfish RTC、固定物理内存布局以及多 hart 启动这些板级细节,整理成 axplat 约定的 InitIf、MemIf、ConsoleIf、TimeIf、PowerIf 和可选 IrqIf 接口,是 RISC-V 平台进入 ArceOS 运行时的第一层板级 glue。
架构设计
设计定位
这个 crate 的核心职责不是实现通用 HAL,而是把 virt 板级假设固化为一套可被 ax-hal 和运行时稳定调用的接口:
- 向下,它直接面对 SBI、PLIC、16550 UART、Goldfish RTC 和固定的 MMIO/内存布局。
- 向上,它并不直接服务应用,而是通过
axplattrait 接口被ax-hal、ax-runtime和平台示例内核复用。 - 在启动期,它负责最早期页表、栈、MMU 与主核/从核入口桥接;在运行期,它继续承担时间、中断、控制台、电源和内存区间查询。
因此,ax-plat-riscv64-qemu-virt 应被理解为“RISC-V virt 板级 bring-up 实现”,而不是“可移植的架构抽象层”。
模块结构
src/lib.rs:平台入口总装。定义config、rust_entry、rust_entry_secondary,并汇总各个*IfImpl。src/boot.rs:最早期启动路径。定义启动栈、静态 Sv39 页表、_start/_start_secondary与 MMU 打开流程。src/init.rs:实现InitIf,把早期 trap、串口、时间初始化和后期 per-CPU 初始化串接起来。src/mem.rs:实现MemIf,定义物理内存范围、MMIO 区间、内核地址空间范围以及phys_to_virt/virt_to_phys。src/console.rs:实现ConsoleIf,通过uart_16550访问 NS16550 MMIO 串口。src/time.rs:实现TimeIf,提供单调时间、可选墙钟偏移和可选 one-shot timer。src/irq.rs:在irqfeature 下实现IrqIf,负责 PLIC 初始化、scause分发、IPI 和定时器处理。src/power.rs:实现PowerIf,提供关机、CPU 数查询和可选 HSM 启动从核逻辑。
1.3 关键数据结构与全局对象
BOOT_STACK:主核启动栈,位于.bss.stack。BOOT_PT_SV39:最早期静态页表,用 1GiB 大页把低地址与高半部虚拟地址窗口映射起来。UART:LazyInit<SpinNoIrq<MmioSerialPort>>,早期串口与运行期控制台共用。PLIC:irq打开时的全局 PLIC 对象。IRQ_HANDLER_TABLE:按 IRQ 号索引的处理函数表。TIMER_HANDLER/IPI_HANDLER:定时器和 IPI 的注册入口。RTC_EPOCHOFFSET_NANOS:启用rtc时,用 Goldfish RTC 标定的墙钟偏移。
1.4 启动与初始化主线
主核路径由 boot.rs 和 init.rs 共同构成:
更具体地说:
_start从引导器拿到hartid与 DTB 指针后,先建立启动栈。init_boot_page_table()构造最早期 Sv39 页表,把内核物理区和高半部虚拟地址窗口都映射出来。init_mmu()写 SATP、刷新 TLB,再把栈指针和入口跳转地址整体平移到高半部虚拟地址。- 跳入
ax_plat::call_main(),与上层#[ax_plat::main]标注的运行时入口契约衔接。 InitIf::init_early()先做 trap、串口和时间源初始化;InitIf::init_later()再做中断和 per-CPU 时间设施初始化。