Skip to content

Refactor hvp#113

Merged
junyu0312 merged 3 commits intomainfrom
refactor_hvp
Apr 1, 2026
Merged

Refactor hvp#113
junyu0312 merged 3 commits intomainfrom
refactor_hvp

Conversation

@junyu0312
Copy link
Copy Markdown
Owner

@junyu0312 junyu0312 commented Apr 1, 2026

Summary by CodeRabbit

  • Refactor
    • Boot loader API now takes explicit RAM size and vCPU count and returns the kernel start address.
    • VM initialization captures RAM size and vCPU count and uses the boot loader’s returned start address to begin execution.
    • VM core traits simplified to decouple runtime layout access from VM abstraction.
    • Architecture memory-map values exposed at compile time for consistent placement across components.
    • VM construction now relies on compile-time layout constants instead of querying VM runtime layout.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 1, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bc0ac127-0f45-4483-a751-406581630596

📥 Commits

Reviewing files that changed from the base of the PR and between 5824882 and 3b00e70.

📒 Files selected for processing (6)
  • crates/vm-bootloader/src/boot_loader.rs
  • crates/vm-bootloader/src/boot_loader/arch/aarch64.rs
  • crates/vm-bootloader/src/boot_loader/arch/x86_64.rs
  • crates/vm-bootloader/src/lib.rs
  • crates/vm-cli/src/main.rs
  • crates/vm-machine/src/vm.rs

📝 Walkthrough

Walkthrough

This PR removes runtime layout dependencies from bootloading: BootLoader::load no longer takes a mutable Virt but accepts explicit ram_size and vcpus, and returns a u64 start PC. The Virt trait drops Arch/layout accessors and run now requires start_pc. Changes propagate through bootloaders, virt impls, VM builder, and VM wiring.

Changes

Cohort / File(s) Summary
Bootloader trait & crate root
crates/vm-bootloader/src/boot_loader.rs, crates/vm-bootloader/src/lib.rs
Removed generic V: Virt from BootLoaderBuilder/BootLoader. BootLoader::load now takes ram_size: u64, vcpus: usize, ... and returns Result<u64>. Crate enables #![deny(warnings)] and exposes pub mod boot_loader.
AArch64 bootloader
crates/vm-bootloader/src/boot_loader/arch/aarch64.rs
Replaced layout-driven placements with compile-time constants (RAM_BASE, INITRD_START, DTB_START). Helper methods accept/return loader results; load now takes (ram_size, vcpus, ...) and returns kernel start PC; removed mutated layout uses.
x86_64 bootloader
crates/vm-bootloader/src/boot_loader/arch/x86_64.rs
Removed generics on impls; updated load signature to (ram_size: u64, vcpus: usize, ...) -> Result<u64>. Method bodies remain todo!() but signatures match new trait.
Arch layout constants
crates/vm-core/src/arch/aarch64/layout.rs, crates/vm-core/src/arch/x86_64/layout.rs
Made AArch64 layout constants public (MMIO_START, MMIO_LEN, GIC_*, RAM_BASE, DTB_START, INITRD_START). Added x86_64 pub const placeholders (MMIO_START, MMIO_LEN, RAM_BASE).
Virt trait & implementations
crates/vm-core/src/virt.rs, crates/vm-core/src/virt/hvp.rs, crates/vm-core/src/virt/kvm.rs
Dropped type Arch and layout/vCPU accessor methods from Virt. Renamed init_irqcreate_irq_chip. Changed run to run(&mut self, start_pc: u64, device_vm_exit_handler: ...). Updated Hvp and KVM impls and removed embedded arch/layout state.
VM wiring & builder
crates/vm-machine/src/vm.rs, crates/vm-machine/src/vm_builder.rs
Vm gains crate-visible ram_size and vcpus fields. VM run flow calls boot_loader.load(self.ram_size, self.vcpus, ...), captures returned start_pc, and calls virt.run(start_pc, ...). VmBuilder now uses compile-time arch constants for MMIO/RAM base and calls create_irq_chip.
CLI changes
crates/vm-cli/src/main.rs
Updated generic bound: Loader: BootLoaderBuilder<V>Loader: BootLoaderBuilder to reflect non-generic BootLoaderBuilder trait.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(150,200,255,0.5)
    participant VM as Vm
    end
    rect rgba(200,255,180,0.5)
    participant BL as BootLoader
    end
    rect rgba(255,200,180,0.5)
    participant KL as KernelLoader
    end
    rect rgba(255,220,200,0.5)
    participant VIRT as Virt
    end

    VM->>BL: load(ram_size, vcpus, memory, irq_chip, devices)
    BL->>KL: load_image/initrd/dtb (use RAM_BASE, INITRD_START, DTB_START)
    KL-->>BL: LoadResult(s) (start_pc, initrd bounds, ...)
    BL-->>VM: Result<u64> (start_pc)
    VM->>VIRT: run(start_pc, device_vm_exit_handler)
    VIRT-->>VM: execution (VM run path)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 I nibbled layout vines and set them free,

RAM and DTB now hop where constants be.
Bootloader hums, returns a start PC,
Virt runs forward — swift as carrot glee.
🥕– a rabbit, celebrating code set free

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'Refactor hvp' is vague and does not adequately convey the scope and main objectives of the changes. While the PR does refactor the hvp module, the actual changes are far broader: they introduce a significant architectural refactoring that affects the BootLoader trait, Virt trait, and multiple architecture implementations across the entire codebase. The title only hints at one component rather than capturing the main intent of the refactoring effort. Consider a more descriptive title that captures the core architectural change, such as 'Decouple architecture layout from trait APIs and bootloader' or 'Refactor bootloader and Virt traits to use explicit parameters instead of layout queries'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor_hvp

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/vm-core/src/virt/kvm.rs (1)

64-79: ⚠️ Potential issue | 🔴 Critical

_start_pc parameter is unused because x86_64 bootloader support is incomplete.

The parameter is prefixed with underscore to suppress the unused variable warning. However, this is NOT an intentional design choice—the x86_64 bootloader's load() method (both at the BootLoader trait level and in the KernelLoader) is marked todo!(), meaning the x86_64 implementation is incomplete.

In contrast, the aarch64 implementation properly uses start_pc, passing it to setup_cpu() to set the PC register before execution. The x86_64 side needs to be completed to properly utilize this parameter.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm-core/src/virt/kvm.rs` around lines 64 - 79, The run() method
currently ignores the _start_pc parameter; remove the underscore to make it
start_pc and ensure the x86_64 path sets the guest PC before executing the vCPU
(mirror aarch64 behavior): locate run(), the vcpus collection and the single
vcpu obtained via vcpus.get_mut(0).unwrap(), and call the appropriate CPU setup
on that vcpu (e.g., a setup_cpu or set_guest_rip equivalent) with start_pc
before invoking .run(device_vm_exit_handler); also complete the x86_64
BootLoader::load()/KernelLoader implementation to return or apply the start PC
so run() receives a meaningful value.
🧹 Nitpick comments (5)
crates/vm-bootloader/src/boot_loader/arch/aarch64.rs (5)

241-246: The inner block is unnecessary.

The block containing the kernel_loader and initrd_loader assignments serves no purpose since the variables are declared outside. This appears to be a refactoring artifact.

🧹 Proposed cleanup
     ) -> Result<u64> {
-        let kernel_loader;
-        let initrd_loader;
-        {
-            kernel_loader = self.load_image(ram_size, memory)?;
-            initrd_loader = self.load_initrd(memory)?;
-        }
+        let kernel_loader = self.load_image(ram_size, memory)?;
+        let initrd_loader = self.load_initrd(memory)?;

         {
             let dtb = self.generate_dtb(ram_size, initrd_loader, vcpus, irq_chip, devices)?;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm-bootloader/src/boot_loader/arch/aarch64.rs` around lines 241 - 246,
Remove the redundant inner block around the assignments to kernel_loader and
initrd_loader: instead of declaring kernel_loader and initrd_loader beforehand
and then assigning them inside a separate block, directly assign them by calling
self.load_image(ram_size, memory)? and self.load_initrd(memory)? without the
enclosing braces; update the code around the kernel_loader and initrd_loader
variables (references: kernel_loader, initrd_loader, load_image, load_initrd,
self, ram_size, memory) so the block is eliminated and behavior remains
unchanged.

253-254: Remove commented-out dead code.

These commented lines are refactoring artifacts and should be removed.

🧹 Proposed cleanup
             self.load_dtb(memory, dtb)?;
         }

-        // let layout = virt.get_layout();
-        // layout.validate()?;
-
         Ok(kernel_loader.start_pc)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm-bootloader/src/boot_loader/arch/aarch64.rs` around lines 253 - 254,
Remove the dead commented-out refactoring artifacts in aarch64.rs by deleting
the two commented lines that reference the unused local "layout" and calls "//
let layout = virt.get_layout();" and "// layout.validate()?"; ensure no
remaining commented references to "layout" or "virt.get_layout()" remain in the
function so the codebase contains only active, relevant code.

70-70: Remove commented-out dead code.

This commented line is a leftover from the refactor and should be removed to keep the codebase clean.

🧹 Proposed cleanup
         assert_eq!(result.initrd_start, addr);
-        // layout.set_initrd_len(result.initrd_len)?;

         Ok(Some(result))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm-bootloader/src/boot_loader/arch/aarch64.rs` at line 70, Remove the
dead commented-out line containing the call to
layout.set_initrd_len(result.initrd_len)? in the aarch64 bootloader code; locate
the commented line in the aarch64.rs file (inside the boot_loader::arch module)
and delete that single commented statement so the refactor has no leftover dead
code, then run cargo build/test to verify no unintended changes.

198-204: Use initrd_load_result directly for the conditional to avoid fragile coupling.

The current code checks self.initrd.is_some() but then unwraps initrd_load_result. While these are currently kept in sync by load_initrd, directly checking initrd_load_result would be more robust and self-documenting.

♻️ Proposed refactor
-            if self.initrd.is_some() {
+            if let Some(initrd_result) = initrd_load_result.as_ref() {
                 fdt.property_u64("linux,initrd-start", INITRD_START)?;
                 fdt.property_u64(
                     "linux,initrd-end",
-                    initrd_load_result.as_ref().unwrap().initrd_start
-                        + initrd_load_result.as_ref().unwrap().initrd_len as u64,
+                    initrd_result.initrd_start + initrd_result.initrd_len as u64,
                 )?;
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm-bootloader/src/boot_loader/arch/aarch64.rs` around lines 198 - 204,
The conditional uses self.initrd.is_some() but then unwraps initrd_load_result,
which is fragile; change the check to inspect initrd_load_result (e.g.,
initrd_load_result.is_some()) and then use the bound/as_ref value from
initrd_load_result when calling fdt.property_u64 for "linux,initrd-start" and
"linux,initrd-end"; update the code paths around load_initrd and the
property_u64 calls so they rely on initrd_load_result rather than self.initrd to
avoid coupling.

92-92: Remove commented-out dead code.

Same as above - this is a refactoring artifact that should be cleaned up.

🧹 Proposed cleanup
             .copy_from_slice(dtb_start, &dtb)
             .map_err(|_| Error::LoadDtbFailed("failed to copy".to_string()))?;

-        // layout.set_dtb_len(dtb.len())?;
-
         Ok(())
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm-bootloader/src/boot_loader/arch/aarch64.rs` at line 92, Remove the
commented-out dead code line "layout.set_dtb_len(dtb.len())?;" from the aarch64
boot loader source (it's a refactoring artifact); delete the commented line
entirely (not just uncomment) so there is no leftover dead code or trailing
comment, then run the repo formatter/linter and commit the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/vm-core/src/arch/x86_64/layout.rs`:
- Around line 4-7: The constants MMIO_START, MMIO_LEN, and RAM_BASE in layout.rs
are placeholders set to zero which causes MmioLayout::new(MMIO_START, MMIO_LEN)
-> address_space.try_insert(...).unwrap() to panic with InvalidLen at runtime;
either replace these with correct x86_64 values now (set a non-zero MMIO_LEN and
appropriate MMIO_START/RAM_BASE matching the platform layout used by MmioLayout
and vm_builder) or add a compile-time guard (e.g., a cfg error or compile_error!
when target_arch = "x86_64") so x86_64 builds fail to compile until proper
values are implemented; locate and update the constants MMIO_START, MMIO_LEN,
RAM_BASE in crates/vm-core/src/arch/x86_64/layout.rs and ensure tests or
vm_builder paths that call MmioLayout::new no longer receive a zero length.

In `@crates/vm-machine/src/vm_builder.rs`:
- Around line 3-14: The x86_64 imports (MMIO_LEN, MMIO_START, RAM_BASE) pull in
placeholder zero constants, causing MmioLayout::new(0, 0) to panic; update the
architecture selection so the real x86_64 layout values are used instead of the
zero placeholders: adjust the conditional imports or the code that constructs
MmioLayout (reference: MMIO_LEN, MMIO_START, RAM_BASE and the call to
MmioLayout::new) to use the correct runtime/proper constants for x86_64 (e.g.,
source the real layout values from the proper x86_64 layout module or compute
them before calling MmioLayout::new) so MmioLayout::new is never invoked with
zeros.

---

Outside diff comments:
In `@crates/vm-core/src/virt/kvm.rs`:
- Around line 64-79: The run() method currently ignores the _start_pc parameter;
remove the underscore to make it start_pc and ensure the x86_64 path sets the
guest PC before executing the vCPU (mirror aarch64 behavior): locate run(), the
vcpus collection and the single vcpu obtained via vcpus.get_mut(0).unwrap(), and
call the appropriate CPU setup on that vcpu (e.g., a setup_cpu or set_guest_rip
equivalent) with start_pc before invoking .run(device_vm_exit_handler); also
complete the x86_64 BootLoader::load()/KernelLoader implementation to return or
apply the start PC so run() receives a meaningful value.

---

Nitpick comments:
In `@crates/vm-bootloader/src/boot_loader/arch/aarch64.rs`:
- Around line 241-246: Remove the redundant inner block around the assignments
to kernel_loader and initrd_loader: instead of declaring kernel_loader and
initrd_loader beforehand and then assigning them inside a separate block,
directly assign them by calling self.load_image(ram_size, memory)? and
self.load_initrd(memory)? without the enclosing braces; update the code around
the kernel_loader and initrd_loader variables (references: kernel_loader,
initrd_loader, load_image, load_initrd, self, ram_size, memory) so the block is
eliminated and behavior remains unchanged.
- Around line 253-254: Remove the dead commented-out refactoring artifacts in
aarch64.rs by deleting the two commented lines that reference the unused local
"layout" and calls "// let layout = virt.get_layout();" and "//
layout.validate()?"; ensure no remaining commented references to "layout" or
"virt.get_layout()" remain in the function so the codebase contains only active,
relevant code.
- Line 70: Remove the dead commented-out line containing the call to
layout.set_initrd_len(result.initrd_len)? in the aarch64 bootloader code; locate
the commented line in the aarch64.rs file (inside the boot_loader::arch module)
and delete that single commented statement so the refactor has no leftover dead
code, then run cargo build/test to verify no unintended changes.
- Around line 198-204: The conditional uses self.initrd.is_some() but then
unwraps initrd_load_result, which is fragile; change the check to inspect
initrd_load_result (e.g., initrd_load_result.is_some()) and then use the
bound/as_ref value from initrd_load_result when calling fdt.property_u64 for
"linux,initrd-start" and "linux,initrd-end"; update the code paths around
load_initrd and the property_u64 calls so they rely on initrd_load_result rather
than self.initrd to avoid coupling.
- Line 92: Remove the commented-out dead code line
"layout.set_dtb_len(dtb.len())?;" from the aarch64 boot loader source (it's a
refactoring artifact); delete the commented line entirely (not just uncomment)
so there is no leftover dead code or trailing comment, then run the repo
formatter/linter and commit the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 28f02b7a-06c0-4c67-bac8-6f8969a812b6

📥 Commits

Reviewing files that changed from the base of the PR and between c4c1423 and 5824882.

📒 Files selected for processing (10)
  • crates/vm-bootloader/src/boot_loader.rs
  • crates/vm-bootloader/src/boot_loader/arch/aarch64.rs
  • crates/vm-bootloader/src/boot_loader/arch/x86_64.rs
  • crates/vm-core/src/arch/aarch64/layout.rs
  • crates/vm-core/src/arch/x86_64/layout.rs
  • crates/vm-core/src/virt.rs
  • crates/vm-core/src/virt/hvp.rs
  • crates/vm-core/src/virt/kvm.rs
  • crates/vm-machine/src/vm.rs
  • crates/vm-machine/src/vm_builder.rs

Comment on lines +4 to +7
// TODO
pub const MMIO_START: u64 = 0x0000_0000;
pub const MMIO_LEN: usize = 0x0000_0000;
pub const RAM_BASE: u64 = 0x0000_0000;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Zero-value constants will cause runtime panic on x86_64.

Per crates/vm-core/src/device/mmio/layout.rs:11-24, MmioLayout::new(MMIO_START, MMIO_LEN) calls address_space.try_insert(...).unwrap(). When MMIO_LEN=0, try_insert() returns an InvalidLen error, causing an immediate panic in vm_builder.rs line 82.

These placeholder values break x86_64 builds at runtime. Either implement proper x86_64 layout values now or add a compile-time guard to prevent x86_64 builds until implementation is complete.

Suggested compile-time guard (if deferring implementation)
 // TODO
-pub const MMIO_START: u64 = 0x0000_0000;
-pub const MMIO_LEN: usize = 0x0000_0000;
-pub const RAM_BASE: u64 = 0x0000_0000;
+// x86_64 layout constants - not yet implemented
+// These values will cause a compile error until properly defined
+compile_error!("x86_64 memory layout constants are not yet implemented");
+
+pub const MMIO_START: u64 = 0x0000_0000;
+pub const MMIO_LEN: usize = 0x0000_0000;
+pub const RAM_BASE: u64 = 0x0000_0000;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// TODO
pub const MMIO_START: u64 = 0x0000_0000;
pub const MMIO_LEN: usize = 0x0000_0000;
pub const RAM_BASE: u64 = 0x0000_0000;
// TODO: x86_64 layout constants - not yet implemented
compile_error!("x86_64 memory layout constants are not yet implemented. Please define proper values for MMIO_START, MMIO_LEN, and RAM_BASE before enabling x86_64 builds.");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm-core/src/arch/x86_64/layout.rs` around lines 4 - 7, The constants
MMIO_START, MMIO_LEN, and RAM_BASE in layout.rs are placeholders set to zero
which causes MmioLayout::new(MMIO_START, MMIO_LEN) ->
address_space.try_insert(...).unwrap() to panic with InvalidLen at runtime;
either replace these with correct x86_64 values now (set a non-zero MMIO_LEN and
appropriate MMIO_START/RAM_BASE matching the platform layout used by MmioLayout
and vm_builder) or add a compile-time guard (e.g., a cfg error or compile_error!
when target_arch = "x86_64") so x86_64 builds fail to compile until proper
values are implemented; locate and update the constants MMIO_START, MMIO_LEN,
RAM_BASE in crates/vm-core/src/arch/x86_64/layout.rs and ensure tests or
vm_builder paths that call MmioLayout::new no longer receive a zero length.

Comment on lines +3 to +14
#[cfg(target_arch = "aarch64")]
use vm_core::arch::aarch64::layout::MMIO_LEN;
#[cfg(target_arch = "aarch64")]
use vm_core::arch::aarch64::layout::MMIO_START;
#[cfg(target_arch = "aarch64")]
use vm_core::arch::aarch64::layout::RAM_BASE;
#[cfg(target_arch = "x86_64")]
use vm_core::arch::x86_64::layout::MMIO_LEN;
#[cfg(target_arch = "x86_64")]
use vm_core::arch::x86_64::layout::MMIO_START;
#[cfg(target_arch = "x86_64")]
use vm_core::arch::x86_64::layout::RAM_BASE;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Compile-time architecture selection is clean, but x86_64 imports broken constants.

The conditional import pattern is correct. However, on x86_64, these imports reference the zero-value placeholder constants from x86_64/layout.rs, which will cause a panic at line 82 when MmioLayout::new(0, 0) is called.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm-machine/src/vm_builder.rs` around lines 3 - 14, The x86_64 imports
(MMIO_LEN, MMIO_START, RAM_BASE) pull in placeholder zero constants, causing
MmioLayout::new(0, 0) to panic; update the architecture selection so the real
x86_64 layout values are used instead of the zero placeholders: adjust the
conditional imports or the code that constructs MmioLayout (reference: MMIO_LEN,
MMIO_START, RAM_BASE and the call to MmioLayout::new) to use the correct
runtime/proper constants for x86_64 (e.g., source the real layout values from
the proper x86_64 layout module or compute them before calling MmioLayout::new)
so MmioLayout::new is never invoked with zeros.

@junyu0312 junyu0312 merged commit e962cfe into main Apr 1, 2026
7 checks passed
This was referenced Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant