refactor(axvm): handle vCPU exits in arch adapters#1528
Conversation
0b9ab68 to
7d4575a
Compare
There was a problem hiding this comment.
审查总结
改动概述
本 PR 将 axvm 运行层的 vCPU exit 处理从通用层(vm.rs / vcpu_run())重构到各架构适配器内部,是一次结构清晰的关注点分离重构:
VmArchVcpuOps新增关联类型Exit,run()返回架构本地 exit 类型而非统一的VmExit。AxVM::run_vcpu()简化为通用骨架:bind → inject pending IRQ →vcpu.run()→CurrentArch::handle_vcpu_exit()→ 按VcpuRunAction决定 continue/yield/wait/stop → unbind。vcpu_run()从原来 150+ 行的大 match 缩减为 5 个 action 的处理。- AArch64 直接 match
ArmVmExit,消除中间的arm_exit_to_ax转换层。 - x86/RISC-V/LoongArch 暂通过
handle_transitional_vm_exit处理 legacyVmExit,为后续拆分预留空间。 - 公共 MMIO/PIO/sysreg/hypercall/CPU up/IPI/NPT fallback 逻辑抽取为
arch/mod.rs中可复用的 helper 函数。
设计评价
重构方向正确:通用层不再解释架构语义(MPIDR、hart、APIC、IOCSR),arch 模块自主决定如何消费本地 exit 并映射到通用 action。VcpuRunAction 五个变体(Continue、HostInterrupt、Yield、Wait、Stop)精简且语义清晰。
过渡方案合理:非 AArch64 后端先复用 legacy VmExit 通过 handle_transitional_vm_exit 处理,避免一次性拆分所有后端 raw exit enum 的风险。VmExit 保留为兼容类型并带文档标注。
验证结果
本地验证全部通过:
cargo fmt --check✓cargo test -p axvm-types✓ (2 tests passed)cargo test -p axvm✓ (90 tests passed)cargo clippy -p axvm-types --all-features -- -D warnings✓cargo clippy -p axvm -- -D warnings✓cargo check -p axvm --target aarch64-unknown-none-softfloat✓(仅一个dead_codewarning:HostInterrupt变体在 AArch64 上未使用,属预期行为)cargo check -p axvm --target x86_64-unknown-none✓cargo check -p axvm --target riscv64gc-unknown-none-elf✓cargo check -p axvm --target loongarch64-unknown-none-softfloat✓
CI 状态
PR CI(run 28850794710)仍在运行中。当前 Detect changed paths 和 Cancel stale CI runs 已通过;Check formatting / run_host 和 lint 相关 jobs 正在执行。由于本 PR 仅修改 virtualization/ 下的 axvm 相关 crate,各 Test jobs 按 path filter 正确标记为 skipped。本地 fmt/clippy/test/cross-check 均已覆盖 PR 声明的验证项。
重复/重叠分析
- 搜索 open PR:仅本 PR #1528 和 #1451(IRQ runtime 重构,完全不重叠)涉及 axvm 相关改动,无冲突或重复风险。
- base 分支检查:
origin/dev上最近的 axvm 重构(#1477 generic NPT、#1471 axvisor arch 解耦、#1467 vcpu backend 解耦)均为本 PR 的前置工作,本 PR 在此基础之上继续推进架构解耦方向。
代码质量
- 所有
VmArchVcpuOps实现者(AArch64、x86_64 VMX/SVM/no-backend、riscv64、loongarch64)均已添加type Exit声明,无遗漏。 - AArch64
ExternalInterrupt处理从原来的 unbind 后执行改为在handle_vcpu_exit内内联执行(Yield返回后再 unbind),由于gic::handle_irq不依赖 vCPU 绑定状态,行为等价。 - unhandled exit 从旧代码的
warn!+ continue 改为ax_err!(Unsupported, ...)返回错误,行为更严格但正确——未预期的 exit 不应被静默忽略。 handle_halt从fn(&VmRuntimeHandle) -> bool简化为fn() -> VcpuRunAction,x86_64 从true(continue)等价改为VcpuRunAction::Yield,默认实现从false(wait)改为VcpuRunAction::Wait,语义完全一致。width_mask/sign_extend_value从vm.rs私有函数改为pub(crate)供arch/mod.rs使用,访问控制合理。- 编译期测试覆盖:
axvm-types新增MockExit验证VmArchVcpuOps::Exit关联类型可用;AArch64 模块新增assert_arm_exit_type::<AxvmArmVcpu>()锁定Exit = ArmVmExit。
结论
无阻塞性问题。架构解耦方向清晰,过渡方案稳妥,所有本地验证通过。建议合入。
APPROVE
Powered by deepseek-v4-pro
There was a problem hiding this comment.
审查总结
改动概述
PR 分两步将 axvm 的 vCPU exit 处理完全收敛到各架构适配器内部:
Commit 1 (7d4575a): 为 VmArchVcpuOps 增加关联类型 Exit,将 run() 改为返回架构本地 exit;新增 handle_vcpu_exit_bound/finish_deferred_run_work 两个 ArchOps 方法;AArch64 直接 match ArmVmExit 消除 arm_exit_to_ax 中间层;x86/RISC-V/LoongArch 通过 handle_transitional_vm_exit 处理 legacy VmExit。
Commit 2 (398319ba): 将 run_vcpu() 从 vm.rs 上提到 ArchOps::run_vcpu() 默认实现骨架,统一处理 bind/unbind、pending interrupt 注入、handle_vcpu_exit_bound re-enter 循环、BoundVcpuExit::Defer → finish_deferred_run_work 的 unbind 后执行链;LoongArch PCH-PIC assert/drain 逻辑从 vm.rs 移入 arch/loongarch64;新增 arch_boundary_contract.rs 编译期回归测试。
设计评价
架构解耦方向完全正确:
- 通用层 (
vm.rs/runtime/vcpus.rs) 不再 importCurrentArch、ArchOps、VcpuRunAction或任何架构 exit 细节,只消费Yield/Wait/Stop三种调度动作。 - 架构模块通过
BoundVcpuExit::Complete/Defer/Continue自主决定 exit 处理节奏,非 AArch64 后端保留 deprecatedhandle_transitional_vm_exit过渡路径。 VcpuRunAction从原先 5 个变体精简为 3 个(Yield/Wait/Stop),HostInterrupt和Continue不再泄漏到 runtime 层。BoundVcpuExit<D>泛型 deferred work 设计干净,AArch64 用Aarch64DeferredRunWork::ExternalInterrupt,legacy 后端用LegacyDeferredRunWork,互不干扰。
验证结果
本地全部通过:
cargo fmt --check✓cargo clippy -p axvm-types --all-features -- -D warnings✓cargo clippy -p axvm -- -D warnings✓cargo test -p axvm-types✓ (2 tests)cargo test -p axvm✓ (90 unit tests + 2 arch_boundary_contract tests)cargo check -p axvm --target aarch64-unknown-none-softfloat✓cargo check -p axvm --target x86_64-unknown-none✓
CI (run 28855505135, head 398319ba):
Check formatting / run_host✓Run spin-lint / run_container✓Run sync-lint / run_container✓Test axvisor riscv64 qemu / run_host✓Test axvisor loongarch64 qemu / run_container✓Test axvisor aarch64 qemu / run_container按 path filter 被 skipped(此 PR 不改 aarch64 以外的 axvisor 测试路径,预期行为)- 所有 Starry/ArceOS/board test jobs 按 path filter 正确 skipped
- 无任何 failed/cancelled job
重复/重叠分析
- open PR 搜索:仅本 PR #1528 涉及 axvm vCPU exit 重构;#1322(axdevice 统一设备注册表)是完全不同的子系统,无重叠。
- base 分支检查:
origin/dev上最近的 #1477(generic NPT)、#1471(axvisor arch 解耦)、#1467(vcpu backend 解耦)均为本 PR 的前置解耦工作,本 PR 在此基础上继续推进,方向一致。
前次审查
mai-team-app[bot] 已在 commit 7d4575a 提交 APPROVE。该审查覆盖了 commit 1 的核心设计(Exit 关联类型、arch-local handler、transitional handler),结论仍然有效。Commit 2 在此基础上进一步完成 run_vcpu() 上提和 boundary contract test,属于同一重构方向的收尾工作。
代码质量要点
arch_boundary_contract.rs通过include_str!+contains断言确保vm.rs和runtime/vcpus.rs不再包含架构 exit 细节,是低开销的编译期回归测试。handle_vcpu_exit_bound中 AArch64ExternalInterrupt通过BoundVcpuExit::Defer+finish_deferred_run_work在 unbind 后执行,与旧行为等价(gic::handle_irq不依赖绑定状态)。BoundVcpuExit::Continue在run_vcpu()的unreachable!()断言正确——loop 内不会将Continue返回给调用者。- LoongArch
external_irq_vector/drain_pch_pic_events从vm.rs移入arch/loongarch64,函数签名改为接收&AxVMRef并通过vm.get_devices()访问设备,解耦干净。 width_mask/sign_extend_value从vm.rs私有函数变为pub(crate),被arch/mod.rs的handle_mmio_read复用,访问控制合理。
结论
无阻塞性问题。架构解耦方向清晰,过渡方案稳妥,本地和 CI 验证全部通过。arch_boundary_contract 测试保证了重构后的边界不会退化。
APPROVE
Powered by deepseek-v4-pro
问题
axvm运行层原先统一消费axvm_types::VmExit,导致 VM/vCPU 通用状态机、runtime 调度循环和各架构 exit 语义耦合在一起。AArch64 已经有自己的ArmVmExit,但进入 AxVM 后仍需要转换成统一VmExit;同时旧的通用层还会理解Continue、host IRQ 等 exit 细节,边界仍然偏低。改动
VmArchVcpuOps增加关联类型Exit,将run()改为返回架构本地 exit 类型。ArchOps::run_vcpu()默认骨架:统一处理 bind/unbind、current-vCPU scope、pending interrupt 注入、重复 re-enter、post-unbind deferred work。VcpuRunAction收敛为 runtime 调度语义:Yield、Wait、Stop(StopReason);新增BoundVcpuExit<D>表达 bound exit handling 的Continue、Complete和Defer。VmExit/HostInterrupt/Continue的处理移入 arch cfg;runtime 只调用CurrentArch::run_vcpu()并消费调度动作。ArmVmExit,外部中断类工作通过Aarch64DeferredRunWork在unbind()后完成。VmExit,但统一走 arch-local transitional handler,并用LegacyDeferredRunWork延后处理 host IRQ、timer、EOI、idle 等需要 host-side side effect 的事件。vm.rs中的 arch-specific 操作:AxVM::handle_mmio_write()只做设备写和 fw_cfg DMA;LoongArch PCH-PIC assert/drain 逻辑移回arch/loongarch64;vm.rs不再 import/useCurrentArch、ArchOps或VcpuRunAction。vm.rs/runtime/vcpus.rs不再泄漏架构 exit 细节。axvm_types::VmExit作为兼容/过渡 normalized event,并在文档中说明不再是所有架构 raw exit 的唯一接口。设计说明
通用层只保留 VM/vCPU 生命周期骨架和可复用的小粒度 helper,不解释 MPIDR、hart、APIC、IOCSR 等架构语义。架构模块先把本地 exit 转换成这些 helper 需要的规范化输入,再决定继续运行、yield、wait、停止 VM,或把需要 unbind 后执行的工作放进 deferred work。
这次为了降低风险,非 AArch64 后端没有同步拆分底层 raw exit enum,而是先把 legacy
VmExit的消费边界搬进各自 arch cfg 模块。验证
cargo fmt --checkcargo test -p axvm --test arch_boundary_contractcargo test -p axvm-typescargo xtask clippy --package axvmcargo xtask clippy --package arm_vcpucargo check -p axvm --target aarch64-unknown-none-softfloatcargo check -p axvm --target x86_64-unknown-nonecargo check -p axvm --target riscv64gc-unknown-none-elfcargo check -p axvm --target loongarch64-unknown-none-softfloatcargo xtask axvisor test qemu --arch riscv64cargo xtask axvisor test qemu --arch aarch64 --test-group normal --test-case smoke