From 175290ff8b41a6ad27eeb9d5cd523b3668fcf060 Mon Sep 17 00:00:00 2001 From: Jonathan Klimt Date: Thu, 18 Dec 2025 15:36:14 +0100 Subject: [PATCH 1/3] x86_64: Pagetable setup: Relax assertion for mem size --- src/arch/x86_64/paging/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/arch/x86_64/paging/mod.rs b/src/arch/x86_64/paging/mod.rs index e97f2d95..adba9455 100644 --- a/src/arch/x86_64/paging/mod.rs +++ b/src/arch/x86_64/paging/mod.rs @@ -56,7 +56,10 @@ pub fn initialize_pagetables( // TODO: deprecate the legacy_mapping option once hermit pre 0.10.0 isn't a thing anymore. legacy_mapping: bool, ) { - assert!(mem.len() >= MIN_PHYSMEM_SIZE); + assert!( + mem.len() >= PAGETABLES_OFFSET as usize + 2 * PAGE_SIZE, + "Insufficient memory for at least a single three-level pagetable mapping" + ); let mem_addr = std::ptr::addr_of_mut!(mem[0]); let (gdt_entry, pml4); From b7014971df12cc9334e0025b141451370374d80d Mon Sep 17 00:00:00 2001 From: Jonathan Klimt Date: Thu, 6 Jul 2023 16:00:39 +0200 Subject: [PATCH 2/3] Use vm_memory crate for VM memory instead of in-house Co-authored-by: Bader Zaidan --- Cargo.lock | 12 ++ Cargo.toml | 1 + src/arch/aarch64/mod.rs | 2 +- src/arch/x86_64/mod.rs | 4 +- src/arch/x86_64/paging/mod.rs | 2 +- src/linux/x86_64/kvm_cpu.rs | 39 +++--- src/mem.rs | 248 ++++++++++++++++------------------ src/vm.rs | 32 ++--- 8 files changed, 165 insertions(+), 175 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5cce1205..6aa63cff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1785,6 +1785,7 @@ dependencies = [ "uuid", "virtio-bindings", "vm-fdt", + "vm-memory", "vmm-sys-util", "x86_64", "xhypervisor", @@ -1854,6 +1855,17 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e21282841a059bb62627ce8441c491f09603622cd5a21c43bfedc85a2952f23" +[[package]] +name = "vm-memory" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b55e753c7725603745cb32b2287ef7ef3da05c03c7702cda3fa8abe25ae0465" +dependencies = [ + "libc", + "thiserror", + "winapi", +] + [[package]] name = "vmm-sys-util" version = "0.15.0" diff --git a/Cargo.toml b/Cargo.toml index 61ac8cc2..58c0a083 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ time = "0.3" tun-tap = { version = "0.1.3", default-features = false } uhyve-interface = { version = "0.1.4", path = "uhyve-interface", features = ["std"] } virtio-bindings = { version = "0.2", features = ["virtio-v4_14_0"] } +vm-memory = { version = "0.18", features = ["backend-mmap"] } rftrace = { version = "0.3", optional = true } rftrace-frontend = { version = "0.3", optional = true } rand = "0.9" diff --git a/src/arch/aarch64/mod.rs b/src/arch/aarch64/mod.rs index 1095a931..fb659e5d 100644 --- a/src/arch/aarch64/mod.rs +++ b/src/arch/aarch64/mod.rs @@ -137,7 +137,7 @@ fn is_valid_address(virtual_address: GuestVirtAddr) -> bool { } /// Converts a virtual address in the guest to a physical address in the guest -pub fn virt_to_phys( +pub(crate) fn virt_to_phys( addr: GuestVirtAddr, mem: &MmapMemory, pgt: GuestPhysAddr, diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index e28d4555..60f061ab 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -29,7 +29,7 @@ pub(crate) fn generate_address(object_mem_size: usize) -> GuestPhysAddr { } /// Converts a virtual address in the guest to a physical address in the guest -pub fn virt_to_phys( +pub(crate) fn virt_to_phys( addr: GuestVirtAddr, mem: &MmapMemory, pml4: GuestPhysAddr, @@ -95,7 +95,7 @@ mod tests { let guest_address = GuestPhysAddr::new(0x11111000); - let mem = MmapMemory::new(0, MIN_PHYSMEM_SIZE * 2, guest_address, true, true); + let mem = MmapMemory::new(MIN_PHYSMEM_SIZE * 2, guest_address, true, true); println!("mmap memory created {mem:x?}"); init_guest_mem( diff --git a/src/arch/x86_64/paging/mod.rs b/src/arch/x86_64/paging/mod.rs index adba9455..8d71037d 100644 --- a/src/arch/x86_64/paging/mod.rs +++ b/src/arch/x86_64/paging/mod.rs @@ -189,7 +189,7 @@ mod tests { for &guest_address in gaddrs.iter() { println!("\n\n---------------------------------------"); println!("testing guest address {guest_address:?}"); - let mem = MmapMemory::new(0, MIN_PHYSMEM_SIZE * 2, guest_address, true, true); + let mem = MmapMemory::new(MIN_PHYSMEM_SIZE * 2, guest_address, true, true); initialize_pagetables( unsafe { mem.slice_at_mut(guest_address, MIN_PHYSMEM_SIZE * 2) diff --git a/src/linux/x86_64/kvm_cpu.rs b/src/linux/x86_64/kvm_cpu.rs index 8d3d625d..9553aa04 100644 --- a/src/linux/x86_64/kvm_cpu.rs +++ b/src/linux/x86_64/kvm_cpu.rs @@ -75,28 +75,27 @@ impl VirtualizationBackendInternal for KvmVm { ) -> HypervisorResult { let vm = KVM.create_vm().unwrap(); - let sz = std::cmp::min(peripherals.mem.memory_size, KVM_32BIT_GAP_START); + let sz = std::cmp::min(peripherals.mem.size(), KVM_32BIT_GAP_START); let kvm_mem = kvm_userspace_memory_region { slot: 0, - flags: peripherals.mem.flags, + flags: 0, // Can be KVM_MEM_LOG_DIRTY_PAGES and KVM_MEM_READONLY memory_size: sz as u64, - guest_phys_addr: peripherals.mem.guest_address.as_u64(), - userspace_addr: peripherals.mem.host_address as u64, + guest_phys_addr: peripherals.mem.guest_addr().as_u64(), + userspace_addr: peripherals.mem.host_start() as u64, }; unsafe { vm.set_user_memory_region(kvm_mem) }?; - if peripherals.mem.memory_size > KVM_32BIT_GAP_START + KVM_32BIT_GAP_SIZE { + if peripherals.mem.size() > KVM_32BIT_GAP_START + KVM_32BIT_GAP_SIZE { let kvm_mem = kvm_userspace_memory_region { slot: 1, - flags: peripherals.mem.flags, - memory_size: (peripherals.mem.memory_size - - KVM_32BIT_GAP_START - - KVM_32BIT_GAP_SIZE) as u64, - guest_phys_addr: peripherals.mem.guest_address.as_u64() + flags: 0, // Can be KVM_MEM_LOG_DIRTY_PAGES and KVM_MEM_READONLY + memory_size: (peripherals.mem.size() - KVM_32BIT_GAP_START - KVM_32BIT_GAP_SIZE) + as u64, + guest_phys_addr: peripherals.mem.guest_addr().as_u64() + (KVM_32BIT_GAP_START + KVM_32BIT_GAP_SIZE) as u64, - userspace_addr: (peripherals.mem.host_address as usize + userspace_addr: (peripherals.mem.host_start() as usize + KVM_32BIT_GAP_START + KVM_32BIT_GAP_SIZE) as u64, }; @@ -520,15 +519,15 @@ impl VirtualCPU for KvmCpu { Hypercall::SerialWriteBuffer(sysserialwrite) => { // safety: as this buffer is only read and not used afterwards, we don't create multiple aliasing let buf = unsafe { - self - .peripherals - .mem - .slice_at(sysserialwrite.buf, sysserialwrite.len) - .unwrap_or_else(|e| { - panic!( - "Error {e}: Systemcall parameters for SerialWriteBuffer are invalid: {sysserialwrite:?}" - ) - }) + self.peripherals.mem.slice_at( + sysserialwrite.buf, + sysserialwrite.len, + ) + .unwrap_or_else(|e| { + panic!( + "Error {e}: Systemcall parameters for SerialWriteBuffer are invalid: {sysserialwrite:?}" + ) + }) }; self.peripherals diff --git a/src/mem.rs b/src/mem.rs index 41440440..ee175bdd 100644 --- a/src/mem.rs +++ b/src/mem.rs @@ -1,51 +1,53 @@ -use std::{mem::MaybeUninit, ops::Index, os::raw::c_void, ptr::NonNull}; +use std::mem::MaybeUninit; +#[cfg(target_os = "linux")] +use std::{os::raw::c_void, ptr::NonNull}; -use nix::sys::mman::*; +#[cfg(target_os = "linux")] +use nix::sys::mman::{MmapAdvise, madvise}; use thiserror::Error; use uhyve_interface::GuestPhysAddr; +use vm_memory::{ + Address, GuestAddress, GuestMemoryRegion, GuestRegionMmap, MemoryRegionAddress, + mmap::MmapRegionBuilder, +}; #[derive(Error, Debug)] pub enum MemoryError { #[error("Memory bounds exceeded")] BoundsViolation, - #[error("The desired guest location is not part of this memory")] - WrongMemoryError, } /// A general purpose VM memory section that can exploit some Linux Kernel features. +/// Uses `GuestMemoryMmap` under the hood. #[derive(Debug)] -pub struct MmapMemory { - // TODO: make private - pub flags: u32, - pub memory_size: usize, - pub guest_address: GuestPhysAddr, - pub host_address: *mut u8, +pub(crate) struct MmapMemory { + mem: GuestRegionMmap, } - impl MmapMemory { pub fn new( - flags: u32, memory_size: usize, guest_address: GuestPhysAddr, huge_pages: bool, mergeable: bool, - ) -> MmapMemory { - let host_address = unsafe { - mmap_anonymous( - None, - memory_size.try_into().unwrap(), - ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, - MapFlags::MAP_PRIVATE | MapFlags::MAP_NORESERVE, - ) - .expect("mmap failed") - }; + ) -> Self { + let mm_region = MmapRegionBuilder::new_with_bitmap(memory_size, ()) + .with_mmap_prot(libc::PROT_READ | libc::PROT_WRITE) + .with_mmap_flags(libc::MAP_ANONYMOUS | libc::MAP_NORESERVE | libc::MAP_PRIVATE) + .build() + .unwrap(); if mergeable { #[cfg(target_os = "linux")] { debug!("Enable kernel feature to merge same pages"); + unsafe { - madvise(host_address, memory_size, MmapAdvise::MADV_MERGEABLE).unwrap(); + madvise( + NonNull::new(mm_region.as_ptr() as *mut c_void).unwrap(), + memory_size, + MmapAdvise::MADV_MERGEABLE, + ) + .unwrap(); } } #[cfg(not(target_os = "linux"))] @@ -59,7 +61,12 @@ impl MmapMemory { { debug!("Uhyve uses huge pages"); unsafe { - madvise(host_address, memory_size, MmapAdvise::MADV_HUGEPAGE).unwrap(); + madvise( + NonNull::new(mm_region.as_ptr() as *mut c_void).unwrap(), + memory_size, + MmapAdvise::MADV_HUGEPAGE, + ) + .unwrap(); } } #[cfg(not(target_os = "linux"))] @@ -68,20 +75,35 @@ impl MmapMemory { } } - MmapMemory { - flags, - memory_size, - guest_address, - host_address: host_address.as_ptr() as *mut u8, + Self { + mem: GuestRegionMmap::<()>::new(mm_region, GuestAddress(guest_address.as_u64())) + .unwrap(), } } + /// Returns the size of the memory in bytes + pub fn size(&self) -> usize { + self.mem.size() + } + + /// Returns the first valid physical address from the gutest perspective. + pub fn guest_addr(&self) -> GuestPhysAddr { + GuestPhysAddr::new(self.mem.start_addr().0) + } + + /// Returns a pointer to the beginning of the memory on the host. + pub fn host_start(&self) -> *mut u8 { + let start_addr = self.mem.start_addr(); + let region_addr = self.mem.to_region_addr(start_addr).unwrap(); + self.mem.get_host_address(region_addr).unwrap() + } + /// # Safety /// /// This can create multiple aliasing. During the lifetime of the returned slice, the memory must not be altered, dropped or simmilar. #[expect(clippy::mut_from_ref)] pub unsafe fn as_slice_mut(&self) -> &mut [u8] { - unsafe { std::slice::from_raw_parts_mut(self.host_address, self.memory_size) } + unsafe { std::slice::from_raw_parts_mut(self.host_start(), self.size()) } } /// # Safety @@ -90,13 +112,31 @@ impl MmapMemory { #[expect(clippy::mut_from_ref)] pub unsafe fn as_slice_uninit_mut(&self) -> &mut [MaybeUninit] { unsafe { - std::slice::from_raw_parts_mut( - self.host_address as *mut MaybeUninit, - self.memory_size, - ) + std::slice::from_raw_parts_mut(self.host_start() as *mut MaybeUninit, self.size()) } } + /// Converts `addr` to a `MemoryRegionAddress` that is relative to the internally used memory. + fn addr_to_mem_region_addr( + &self, + addr: GuestPhysAddr, + ) -> Result { + Ok(MemoryRegionAddress( + addr.as_u64() + .checked_sub(self.mem.start_addr().0) + .ok_or(MemoryError::BoundsViolation)?, + )) + } + + /// Checks if the range described by `addr` + `len` is part of this memory region + fn check_range(&self, addr: MemoryRegionAddress, len: usize) -> Result { + Ok(self.mem.address_in_range(addr) + && self.mem.address_in_range( + addr.checked_add(if len > 0 { len as u64 - 1 } else { 0 }) + .ok_or(MemoryError::BoundsViolation)?, + )) + } + /// Read a section of the memory. /// /// # Safety @@ -105,10 +145,13 @@ impl MmapMemory { /// the returned slice, the memory must not be altered to prevent undfined /// behaviour. pub unsafe fn slice_at(&self, addr: GuestPhysAddr, len: usize) -> Result<&[u8], MemoryError> { - if addr.as_usize() + len >= self.memory_size + self.guest_address.as_usize() { - Err(MemoryError::BoundsViolation) + let guest_addr = self.addr_to_mem_region_addr(addr)?; + if self.check_range(guest_addr, len)? { + Ok(unsafe { + std::slice::from_raw_parts_mut(self.mem.get_host_address(guest_addr).unwrap(), len) + }) } else { - Ok(unsafe { std::slice::from_raw_parts(self.host_address(addr)?, len) }) + Err(MemoryError::BoundsViolation) } } @@ -125,40 +168,53 @@ impl MmapMemory { addr: GuestPhysAddr, len: usize, ) -> Result<&mut [u8], MemoryError> { - if addr.as_u64() as usize + len > self.memory_size + self.guest_address.as_u64() as usize { - Err(MemoryError::BoundsViolation) + let guest_addr = self.addr_to_mem_region_addr(addr)?; + if self.check_range(guest_addr, len)? { + Ok(unsafe { + std::slice::from_raw_parts_mut(self.mem.get_host_address(guest_addr).unwrap(), len) + }) } else { - Ok(unsafe { std::slice::from_raw_parts_mut(self.host_address(addr)? as *mut u8, len) }) + Err(MemoryError::BoundsViolation) } } /// Returns the host address of the given internal physical address in the /// memory, if the address is valid. pub fn host_address(&self, addr: GuestPhysAddr) -> Result<*const u8, MemoryError> { - if addr < self.guest_address - || addr.as_usize() > self.guest_address.as_usize() + self.memory_size - { - return Err(MemoryError::WrongMemoryError); - } - Ok( - // Safety: - // - The new ptr is checked to be within the mmap'd memory region above - // - to overflow an isize, the guest memory needs to be larger than 2^63 (which is rather unlikely anytime soon). - unsafe { self.host_address.add((addr - self.guest_address) as usize) as usize } - as *const u8, - ) + let ptr = self + .mem + .get_host_address( + self.mem + .to_region_addr(GuestAddress(addr.as_u64())) + .unwrap(), + ) + .unwrap(); + Ok(ptr as *const u8) } /// Read the value in the memory at the given address + #[cfg(test)] pub fn read(&self, addr: GuestPhysAddr) -> Result { Ok(unsafe { self.host_address(addr)?.cast::().read_unaligned() }) } + unsafe fn get_ptr_internal(&self, addr: MemoryRegionAddress) -> Result<*mut u8, MemoryError> { + self.mem + .get_host_address(addr) + .map_err(|_| MemoryError::BoundsViolation) + } + /// # Safety /// /// Get a reference to the type at the given address in the memory. + #[allow(dead_code)] // currently not used on every architecture and OS pub unsafe fn get_ref(&self, addr: GuestPhysAddr) -> Result<&T, MemoryError> { - Ok(unsafe { &*(self.host_address(addr)? as *const T) }) + let guest_addr = self.addr_to_mem_region_addr(addr)?; + if self.check_range(guest_addr, std::mem::size_of::())? { + Ok(unsafe { &*(self.get_ptr_internal(guest_addr)? as *const T) }) + } else { + Err(MemoryError::BoundsViolation) + } } /// # Safety @@ -166,88 +222,14 @@ impl MmapMemory { /// Get a mutable reference to the type at the given address in the memory. #[expect(clippy::mut_from_ref)] pub unsafe fn get_ref_mut(&self, addr: GuestPhysAddr) -> Result<&mut T, MemoryError> { - Ok(unsafe { &mut *(self.host_address(addr)? as *mut T) }) - } -} - -impl Drop for MmapMemory { - fn drop(&mut self) { - if self.memory_size > 0 { - let host_addr = NonNull::new(self.host_address as *mut c_void).unwrap(); - unsafe { - munmap(host_addr, self.memory_size).unwrap(); - } - } - } -} - -impl Index for MmapMemory { - type Output = u8; - - #[inline(always)] - fn index(&self, index: usize) -> &Self::Output { - assert!(index < self.memory_size); - - // Safety: - // - The new ptr is checked to be within the mmap'd memory region above - // - to overflow an isize, the guest memory needs to be larger than 2^63 (which is rather unlikely anytime soon). - unsafe { &*self.host_address.add(index) } - } -} - -/// Wrapper aroud a memory allocation that is aligned to x86 HugePages -/// (`0x20_0000`). Intended for testing purposes only -#[cfg(test)] -#[allow( - dead_code, - reason = "Part of ongoing work-in-progress virtio-net feature" -)] -pub(crate) struct HugePageAlignedMem { - ptr: NonNull, -} -#[cfg(test)] -#[expect( - dead_code, - reason = "Part of ongoing work-in-progress virtio-net feature" -)] -impl HugePageAlignedMem { - pub fn new() -> Self { - use std::alloc::{Layout, alloc_zeroed}; - // TODO: Make this generic to arbitrary alignments. - let layout = Layout::from_size_align(SIZE, 0x20_0000).unwrap(); - let ptr = unsafe { alloc_zeroed(layout) }; - Self { - ptr: NonNull::new(ptr).expect("Allocation failed"), - } - } -} -#[cfg(test)] -impl Drop for HugePageAlignedMem { - fn drop(&mut self) { - use std::alloc::{Layout, dealloc}; - let layout = Layout::from_size_align(SIZE, 0x20_0000).unwrap(); - let ptr = self.ptr.as_ptr(); - unsafe { - dealloc(ptr, layout); + let guest_addr = self.addr_to_mem_region_addr(addr)?; + if self.check_range(guest_addr, std::mem::size_of::())? { + Ok(unsafe { &mut *(self.get_ptr_internal(guest_addr)? as *mut T) }) + } else { + Err(MemoryError::BoundsViolation) } } } -#[cfg(test)] -impl core::ops::Deref for HugePageAlignedMem { - type Target = [u8]; - fn deref(&self) -> &[u8] { - let slice = NonNull::slice_from_raw_parts(self.ptr, SIZE); - unsafe { slice.as_ref() } - } -} - -#[cfg(test)] -impl core::ops::DerefMut for HugePageAlignedMem { - fn deref_mut(&mut self) -> &mut [u8] { - let mut slice = NonNull::slice_from_raw_parts(self.ptr, SIZE); - unsafe { slice.as_mut() } - } -} #[cfg(test)] mod tests { @@ -264,7 +246,7 @@ mod tests { ]; for address in phys_mem_start_addresses { - let mem = MmapMemory::new(0, 40 * PAGE_SIZE, GuestPhysAddr::new(address), true, true); + let mem = MmapMemory::new(40 * PAGE_SIZE, GuestPhysAddr::new(address), true, true); unsafe { mem.as_slice_mut()[0xfe] = 0xaa; mem.as_slice_mut()[0xff] = 0xbb; diff --git a/src/vm.rs b/src/vm.rs index 6b7d2623..68c709df 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -198,10 +198,10 @@ impl UhyveVm { debug!("Kernel gets loaded to {kernel_address:#x}"); #[cfg(target_os = "linux")] - let mut mem = MmapMemory::new(0, memory_size, guest_address, params.thp, params.ksm); + let mut mem = MmapMemory::new(memory_size, guest_address, params.thp, params.ksm); #[cfg(not(target_os = "linux"))] - let mut mem = MmapMemory::new(0, memory_size, guest_address, false, false); + let mut mem = MmapMemory::new(memory_size, guest_address, false, false); // TODO: file_mapping not in kernel_info let file_mapping = Mutex::new(UhyveFileMap::new( @@ -248,7 +248,7 @@ impl UhyveVm { let kernel_info = Arc::new(KernelInfo { entry_point: entry_point.into(), kernel_address, - guest_address: mem.guest_address, + guest_address: mem.guest_addr(), path: kernel_path, params, stack_address, @@ -304,7 +304,7 @@ impl UhyveVm { }; init_guest_mem( unsafe { peripherals.mem.as_slice_mut() }, // slice only lives during this fn call - peripherals.mem.guest_address, + guest_address, kernel_end_address - guest_address, legacy_mapping, ); @@ -476,7 +476,7 @@ fn write_fdt_into_mem( let mut fdt = Fdt::new() .unwrap() - .memory(mem.guest_address..mem.guest_address + mem.memory_size as u64) + .memory(mem.guest_addr()..mem.guest_addr() + mem.size() as u64) .unwrap() .kernel_args(¶ms.kernel_args[..sep]) .app_args(params.kernel_args.get(sep + 1..).unwrap_or_default()); @@ -505,7 +505,7 @@ fn write_fdt_into_mem( debug!("fdt.len() = {}", fdt.len()); assert!(fdt.len() < (BOOT_INFO_OFFSET - FDT_OFFSET) as usize); unsafe { - let fdt_ptr = mem.host_address.add(FDT_OFFSET as usize); + let fdt_ptr = mem.host_start().add(FDT_OFFSET as usize); fdt_ptr.copy_from_nonoverlapping(fdt.as_ptr(), fdt.len()); } } @@ -518,12 +518,12 @@ fn write_boot_info_to_mem( ) { debug!( "Writing BootInfo to {:?}", - mem.guest_address + BOOT_INFO_OFFSET + mem.guest_addr() + BOOT_INFO_OFFSET ); let boot_info = BootInfo { hardware_info: HardwareInfo { - phys_addr_range: mem.guest_address.as_u64() - ..mem.guest_address.as_u64() + mem.memory_size as u64, + phys_addr_range: mem.guest_addr().as_u64() + ..mem.guest_addr().as_u64() + mem.size() as u64, #[cfg_attr( target_arch = "x86_64", expect( @@ -534,11 +534,7 @@ fn write_boot_info_to_mem( serial_port_base: SerialPortBase::new( (uhyve_interface::HypercallAddress::Uart as u16).into(), ), - device_tree: Some( - (mem.guest_address.as_u64() + FDT_OFFSET) - .try_into() - .unwrap(), - ), + device_tree: Some((mem.guest_addr().as_u64() + FDT_OFFSET).try_into().unwrap()), }, load_info, platform_info: PlatformInfo::Uhyve { @@ -549,7 +545,7 @@ fn write_boot_info_to_mem( }, }; unsafe { - let raw_boot_info_ptr = mem.host_address.add(BOOT_INFO_OFFSET as usize) as *mut RawBootInfo; + let raw_boot_info_ptr = mem.host_start().add(BOOT_INFO_OFFSET as usize) as *mut RawBootInfo; *raw_boot_info_ptr = RawBootInfo::from(boot_info); } } @@ -561,9 +557,9 @@ fn load_kernel_to_mem( mem: &mut MmapMemory, relative_offset: u64, ) -> LoadKernelResult<(LoadedKernel, GuestPhysAddr)> { - let kernel_end_address = mem.guest_address + relative_offset + object.mem_size(); + let kernel_end_address = mem.guest_addr() + relative_offset + object.mem_size(); - if kernel_end_address > mem.guest_address + mem.memory_size { + if kernel_end_address > mem.guest_addr() + mem.size() { return Err(LoadKernelError::InsufficientMemory); } @@ -572,7 +568,7 @@ fn load_kernel_to_mem( // Safety: Slice only lives during this fn call, so no aliasing happens &mut unsafe { mem.as_slice_uninit_mut() } [relative_offset as usize..relative_offset as usize + object.mem_size()], - relative_offset + mem.guest_address.as_u64(), + relative_offset + mem.guest_addr().as_u64(), ), kernel_end_address, )) From 712d9cfe48c515d1fad113a62d396eaa62c9f9c0 Mon Sep 17 00:00:00 2001 From: Jonathan Klimt Date: Mon, 26 Jan 2026 11:42:37 +0100 Subject: [PATCH 3/3] mem: added address_range function(s) --- src/mem.rs | 13 ++++++++++++- src/vm.rs | 5 ++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/mem.rs b/src/mem.rs index ee175bdd..6575ba7d 100644 --- a/src/mem.rs +++ b/src/mem.rs @@ -1,4 +1,4 @@ -use std::mem::MaybeUninit; +use std::{mem::MaybeUninit, ops::Range}; #[cfg(target_os = "linux")] use std::{os::raw::c_void, ptr::NonNull}; @@ -229,6 +229,17 @@ impl MmapMemory { Err(MemoryError::BoundsViolation) } } + + /// Produces a (exclusive) range of all valid addresses in this memory. + pub fn address_range(&self) -> Range { + self.guest_addr()..self.guest_addr() + self.size() as u64 + } + + /// Same as [`address_range`] but with `u64` as range type. + // TODO: Eliminate usages in favor of `address_range` + pub fn address_range_u64(&self) -> Range { + self.guest_addr().as_u64()..self.guest_addr().as_u64() + self.size() as u64 + } } #[cfg(test)] diff --git a/src/vm.rs b/src/vm.rs index 68c709df..e4cae274 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -476,7 +476,7 @@ fn write_fdt_into_mem( let mut fdt = Fdt::new() .unwrap() - .memory(mem.guest_addr()..mem.guest_addr() + mem.size() as u64) + .memory(mem.address_range()) .unwrap() .kernel_args(¶ms.kernel_args[..sep]) .app_args(params.kernel_args.get(sep + 1..).unwrap_or_default()); @@ -522,8 +522,7 @@ fn write_boot_info_to_mem( ); let boot_info = BootInfo { hardware_info: HardwareInfo { - phys_addr_range: mem.guest_addr().as_u64() - ..mem.guest_addr().as_u64() + mem.size() as u64, + phys_addr_range: mem.address_range_u64(), #[cfg_attr( target_arch = "x86_64", expect(