Skip to content

refine: Separate vm-mm as a crate#84

Merged
junyu0312 merged 9 commits intomainfrom
refine
Feb 28, 2026
Merged

refine: Separate vm-mm as a crate#84
junyu0312 merged 9 commits intomainfrom
refine

Conversation

@junyu0312
Copy link
Owner

@junyu0312 junyu0312 commented Feb 28, 2026

Summary by CodeRabbit

  • Refactor
    • Introduces a new dedicated memory-management crate and migrates components to use it; no change to runtime behavior.
  • Public API
    • Standardizes error/result types across crates, adjusts exported modules and type surfaces, and updates VM builder/VM interfaces (including optional debug/stub support).

@coderabbitai
Copy link

coderabbitai bot commented Feb 28, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00b75a1 and d449441.

📒 Files selected for processing (2)
  • crates/vm-machine/src/error.rs
  • crates/vm-machine/src/vm.rs

📝 Walkthrough

Walkthrough

This PR extracts memory-management into a new crate vm-mm, removes vm-core's public mm re-export, updates many imports to vm_mm::*, switches numerous APIs from anyhow::Result to crate Result/Error types, and adds vm-mm to multiple crate manifests.

Changes

Cohort / File(s) Summary
Workspace & Manifests
Cargo.toml, crates/vm-bootloader/Cargo.toml, crates/vm-core/Cargo.toml, crates/vm-device/Cargo.toml, crates/vm-machine/Cargo.toml, crates/vm-virtio/Cargo.toml
Add vm-mm as a workspace member/dependency across multiple manifests.
New crate root & manifest
crates/vm-mm/Cargo.toml, crates/vm-mm/src/lib.rs
Introduce new vm-mm crate and export allocator, error, manager, region modules.
vm-mm module moves & normalization
crates/vm-mm/src/*, crates/vm-mm/src/allocator/*, crates/vm-mm/src/manager.rs, crates/vm-mm/src/region.rs, crates/vm-mm/src/error.rs
Normalize crate-relative paths (move to crate::allocator, crate::error, etc.); remove some pub mod declarations in error.rs; reorganize internal imports.
vm-core public API & errors
crates/vm-core/src/lib.rs, crates/vm-core/src/error.rs, crates/vm-core/src/arch/layout.rs
Remove pub mod mm re-export; add Error variants (MemoryError, LayoutError, Internal) and From<vm_mm::error::Error>; add layout->error conversion.
Virt trait & implementations
crates/vm-core/src/virt.rs, .../virt/hvp.rs, .../virt/hvp/mm.rs, .../virt/kvm.rs, .../virt/kvm/*
Change many signatures from anyhow::Result to crate Result alias; adapt implementations to use crate::error::Error/Result and replace crate-local mm imports with vm_mm types.
KVM/HVP specific changes
crates/vm-core/src/virt/kvm/*, crates/vm-core/src/virt/hvp/*
Introduce vm_mm::manager::MemoryAddressSpace and allocator imports; adjust error construction to Error::Internal and use crate::error::Result.
vm-core vcpu/arch exposure
crates/vm-core/src/vcpu.rs
Remove pub mod arch exposure and related imports.
Bootloader import updates
crates/vm-bootloader/src/... (boot_loader.rs, .../aarch64.rs, .../x86_64.rs, initrd_loader.rs, kernel_loader.rs, kernel_loader/linux/*.rs)
Replace memory-related imports (MemoryContainer, MemoryAddressSpace) to vm_mm::allocator / vm_mm::manager.
Device & virtio import updates
crates/vm-device/src/device/virtio/*, crates/vm-virtio/src/*
Switch memory-related imports from vm_core::mm to vm_mm equivalents.
vm-machine import & API changes
crates/vm-machine/src/device.rs, crates/vm-machine/src/firmware/bios.rs, crates/vm-machine/src/vm.rs, crates/vm-machine/src/error.rs, crates/vm-machine/src/lib.rs
Update memory imports to vm_mm; refactor vm-machine error enum and Result alias; change device module visibility to private and add public error module; update Vm/VmBuilder fields and error propagation to use ?.
Misc internal import adjustments
various crates/* files
Multiple small import/path updates to reference vm_mm or reorganized crate-local modules.

Sequence Diagram(s)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐇 I dug a tunnel, moved modules with care,
vm-mm now hops in its own tidy lair.
Paths swapped and errors gently realigned,
Crates linked together, all neatly combined.
🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: separating vm-mm into a standalone crate, which is the core focus across all file modifications.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refine

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

Copy link

@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.

Caution

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

⚠️ Outside diff range comments (1)
crates/vm-mm/src/manager.rs (1)

75-86: ⚠️ Potential issue | 🔴 Critical

Add bounds validation and use checked arithmetic in copy_from_slice.

The len parameter is independent from buf.len(). If len > buf.len(), the unsafe copy reads past the buffer bounds. Additionally, offset + len as u64 should use checked arithmetic to prevent silent overflow.

Suggested fix
 pub fn copy_from_slice(&mut self, gpa: u64, buf: &[u8], len: usize) -> Result<(), Error> {
     let region = self.try_get_region_by_gpa_mut(gpa)?;
     let hva = region.try_to_hva()?;
     let offset = gpa - region.gpa;

+    if len > buf.len() {
+        return Err(Error::MemoryOverflow);
+    }
+
+    let end = offset
+        .checked_add(len as u64)
+        .ok_or(Error::MemoryOverflow)?;
+    if end > region.len as u64 {
-    if offset + len as u64 > region.len as u64 {
         return Err(Error::MemoryOverflow);
     }

     unsafe {
         hva.add(offset as usize).copy_from(buf.as_ptr(), len);
     }

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

In `@crates/vm-mm/src/manager.rs` around lines 75 - 86, In copy_from_slice,
validate that len does not exceed buf.len() and perform checked arithmetic on
offset + len to avoid overflows: check if len <= buf.len() (or return an
appropriate Error) before the unsafe block, convert len to u64/usize using
try_from/checked conversions, replace the direct offset + len as u64 calculation
with checked_add on offset (or use offset.checked_add(len_u64)) and return
Error::MemoryOverflow on overflow, and only then perform the unsafe copy using
the safely converted usize indices (ref functions/fields: copy_from_slice,
try_get_region_by_gpa_mut, try_to_hva, region.gpa, region.len).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@crates/vm-mm/src/manager.rs`:
- Around line 75-86: In copy_from_slice, validate that len does not exceed
buf.len() and perform checked arithmetic on offset + len to avoid overflows:
check if len <= buf.len() (or return an appropriate Error) before the unsafe
block, convert len to u64/usize using try_from/checked conversions, replace the
direct offset + len as u64 calculation with checked_add on offset (or use
offset.checked_add(len_u64)) and return Error::MemoryOverflow on overflow, and
only then perform the unsafe copy using the safely converted usize indices (ref
functions/fields: copy_from_slice, try_get_region_by_gpa_mut, try_to_hva,
region.gpa, region.len).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ce1a9bf and 42700ec.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (32)
  • Cargo.toml
  • crates/vm-bootloader/Cargo.toml
  • 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/initrd_loader.rs
  • crates/vm-bootloader/src/kernel_loader.rs
  • crates/vm-bootloader/src/kernel_loader/linux/bzimage.rs
  • crates/vm-bootloader/src/kernel_loader/linux/image.rs
  • crates/vm-core/Cargo.toml
  • crates/vm-core/src/lib.rs
  • crates/vm-core/src/virt.rs
  • crates/vm-core/src/virt/hvp.rs
  • crates/vm-core/src/virt/hvp/mm.rs
  • crates/vm-core/src/virt/kvm.rs
  • crates/vm-device/Cargo.toml
  • crates/vm-device/src/device/virtio/virtio_blk.rs
  • crates/vm-device/src/device/virtio/virtio_mmio_kbd.rs
  • crates/vm-machine/Cargo.toml
  • crates/vm-machine/src/device.rs
  • crates/vm-machine/src/firmware/bios.rs
  • crates/vm-machine/src/vm.rs
  • crates/vm-mm/Cargo.toml
  • crates/vm-mm/src/allocator.rs
  • crates/vm-mm/src/allocator/mmap_allocator.rs
  • crates/vm-mm/src/error.rs
  • crates/vm-mm/src/lib.rs
  • crates/vm-mm/src/manager.rs
  • crates/vm-mm/src/region.rs
  • crates/vm-virtio/Cargo.toml
  • crates/vm-virtio/src/virt_queue.rs
  • crates/vm-virtio/src/virt_queue/virtq_desc_table.rs
💤 Files with no reviewable changes (2)
  • crates/vm-core/src/lib.rs
  • crates/vm-mm/src/error.rs

Copy link

@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.

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/arch/x86_64.rs (1)

9-13: ⚠️ Potential issue | 🟠 Major

Avoid panic in arch_post_init; propagate PIT creation failure instead.

Line 12 uses unwrap(), which can crash the VM init path despite returning Result<()>.

Proposed fix
 fn arch_post_init(&mut self) -> Result<()> {
-    {
-        let pit_config = kvm_pit_config::default();
-        self.vm_fd.create_pit2(pit_config).unwrap();
-    }
+    let pit_config = kvm_pit_config::default();
+    self.vm_fd.create_pit2(pit_config)?;
 
     Ok(())
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm-core/src/virt/kvm/arch/x86_64.rs` around lines 9 - 13, The call to
self.vm_fd.create_pit2(pit_config).unwrap() in arch_post_init can panic; change
it to propagate the error instead (use the ? operator or map_err to convert the
kvm error into the function's Result error type) so arch_post_init returns an
Err on PIT creation failure; update the create_pit2 invocation inside
arch_post_init (referencing pit_config, self.vm_fd.create_pit2, and
arch_post_init) to return the error instead of unwrapping.
🧹 Nitpick comments (3)
crates/vm-core/src/virt/kvm.rs (1)

81-90: Potential panic on to_hva().unwrap().

If region.to_hva() returns None, this will panic. Since the allocation happened on line 79, it should generally succeed, but the unwrap() silently assumes success. Consider propagating an error instead for defensive programming.

Suggested improvement
                     self.vm_fd
                         .set_user_memory_region(kvm_userspace_memory_region {
                             slot: slot as u32,
                             flags: 0,
                             guest_phys_addr: region.gpa,
                             memory_size: region.len as u64,
-                            userspace_addr: region.to_hva().unwrap() as u64,
+                            userspace_addr: region
+                                .to_hva()
+                                .ok_or_else(|| Error::Internal("memory region not allocated".to_string()))? as u64,
                         })?;
🤖 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 81 - 90, The call to
region.to_hva().unwrap() in the unsafe block that calls
self.vm_fd.set_user_memory_region can panic if to_hva() returns None; change
this to handle the None case and propagate a proper error instead of unwrapping:
retrieve the HVA via region.to_hva().ok_or_else(|| /* create a suitable error
with context */ )? and pass that value (as u64) to userspace_addr, so
set_user_memory_region returns a Result propagated from the enclosing function
(preserve the unsafe block and kvm_userspace_memory_region construction but
replace the unwrap with an ok_or/ map_err to return an error describing the
missing HVA).
crates/vm-core/src/virt/hvp.rs (2)

45-122: Helper function setup_cpu still uses anyhow::Result.

While setup_cpu is a private helper, it's inconsistent with the migration to crate::error::Result. Since it's only called from within the thread that already uses anyhow::Result, this is functionally fine but creates maintenance overhead if you later want to call it from Result-returning code.

Consider migrating this when addressing the thread error type inconsistency above.

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

In `@crates/vm-core/src/virt/hvp.rs` around lines 45 - 122, The helper function
setup_cpu currently returns anyhow::Result, change its signature to return
crate::error::Result<()> and update any internal ?-propagated calls to be
compatible with crate::error::Error (ensure From<anyhow::Error> or map_err is
used if necessary); update the where clause and all call sites (e.g., where
setup_cpu(...) is invoked) to accept the new Result type and adjust imports to
bring crate::error::Result into scope so compilation and error propagation
remain consistent with the crate-wide error type.

329-382: Mixed error types: spawned thread still uses anyhow::Result.

The outer run method returns crate::error::Result<()>, but the spawned thread closure on line 343 returns anyhow::Result<()>. This inconsistency means:

  1. Errors from the thread are not propagated to the caller
  2. The error handling strategy is inconsistent within the same method

Consider either:

  • Converting the thread's result to crate::error::Error and propagating it
  • Documenting why anyhow is intentionally used here (e.g., thread isolation)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm-core/src/virt/hvp.rs` around lines 329 - 382, The spawned thread
closure currently returns anyhow::Result<()> which breaks consistency with the
outer run signature (crate::error::Result<()>) and prevents thread errors from
propagating; change the closure return type to crate::error::Result<()> (or
convert its anyhow::Error to crate::error::Error at the closure end), collect
each spawn's JoinGuard result from thread::scope and map any thread error (panic
or Err) into crate::error::Error and return it from run; update symbols: the
closure spawned inside run that creates HvpVcpu, calls setup_cpu, vcpu.run, and
handle_vm_exit should return crate::error::Result<()>, and run should
join/inspect each spawn result and propagate the first Err as the run error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@crates/vm-core/src/virt/kvm/arch/x86_64.rs`:
- Around line 9-13: The call to self.vm_fd.create_pit2(pit_config).unwrap() in
arch_post_init can panic; change it to propagate the error instead (use the ?
operator or map_err to convert the kvm error into the function's Result error
type) so arch_post_init returns an Err on PIT creation failure; update the
create_pit2 invocation inside arch_post_init (referencing pit_config,
self.vm_fd.create_pit2, and arch_post_init) to return the error instead of
unwrapping.

---

Nitpick comments:
In `@crates/vm-core/src/virt/hvp.rs`:
- Around line 45-122: The helper function setup_cpu currently returns
anyhow::Result, change its signature to return crate::error::Result<()> and
update any internal ?-propagated calls to be compatible with crate::error::Error
(ensure From<anyhow::Error> or map_err is used if necessary); update the where
clause and all call sites (e.g., where setup_cpu(...) is invoked) to accept the
new Result type and adjust imports to bring crate::error::Result into scope so
compilation and error propagation remain consistent with the crate-wide error
type.
- Around line 329-382: The spawned thread closure currently returns
anyhow::Result<()> which breaks consistency with the outer run signature
(crate::error::Result<()>) and prevents thread errors from propagating; change
the closure return type to crate::error::Result<()> (or convert its
anyhow::Error to crate::error::Error at the closure end), collect each spawn's
JoinGuard result from thread::scope and map any thread error (panic or Err) into
crate::error::Error and return it from run; update symbols: the closure spawned
inside run that creates HvpVcpu, calls setup_cpu, vcpu.run, and handle_vm_exit
should return crate::error::Result<()>, and run should join/inspect each spawn
result and propagate the first Err as the run error.

In `@crates/vm-core/src/virt/kvm.rs`:
- Around line 81-90: The call to region.to_hva().unwrap() in the unsafe block
that calls self.vm_fd.set_user_memory_region can panic if to_hva() returns None;
change this to handle the None case and propagate a proper error instead of
unwrapping: retrieve the HVA via region.to_hva().ok_or_else(|| /* create a
suitable error with context */ )? and pass that value (as u64) to
userspace_addr, so set_user_memory_region returns a Result propagated from the
enclosing function (preserve the unsafe block and kvm_userspace_memory_region
construction but replace the unwrap with an ok_or/ map_err to return an error
describing the missing HVA).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2689292 and 00b75a1.

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

@junyu0312 junyu0312 merged commit a851bae into main Feb 28, 2026
7 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Mar 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