diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index be98862b..ccc360c8 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -15,7 +15,7 @@ use x86_64::structures::paging::{ PageTable, PageTableIndex, }; -use crate::{consts::PML4_OFFSET, mem::MmapMemory, paging::PagetableError}; +use crate::{mem::MmapMemory, paging::PagetableError}; pub const RAM_START: GuestPhysAddr = GuestPhysAddr::new(0x00); @@ -111,6 +111,7 @@ pub fn get_cpu_frequency_from_os() -> std::result::Result Result { /// Number of Offset bits of a virtual address for a 4 KiB page, which are shifted away to get its Page Frame Number (PFN). pub const PAGE_BITS: u64 = 12; @@ -118,13 +119,8 @@ pub fn virt_to_phys( /// Number of bits of the index in each table (PML4, PDPT, PDT, PGT). pub const PAGE_MAP_BITS: usize = 9; - let guest_address = (*crate::vm::GUEST_ADDRESS.get().unwrap()).as_u64(); - let mut page_table = unsafe { - (mem.host_address(GuestPhysAddr::new(guest_address + PML4_OFFSET)) - .unwrap() as *mut PageTable) - .as_mut() - } - .unwrap(); + let mut page_table = + unsafe { (mem.host_address(pml4).unwrap() as *mut PageTable).as_mut() }.unwrap(); let mut page_bits = 39; let mut entry = PageTableEntry::new(); @@ -252,9 +248,7 @@ mod tests { .is_test(true) .try_init(); - use crate::vm::GUEST_ADDRESS; let guest_address = GuestPhysAddr::new(0x11111000); - let _ = *GUEST_ADDRESS.get_or_init(|| guest_address); let mem = MmapMemory::new(0, MIN_PHYSMEM_SIZE * 2, guest_address, true, true); println!("mmap memory created {mem:x?}"); @@ -267,12 +261,12 @@ mod tests { // Get the address of the first entry in PML4 (the address of the PML4 itself) let virt_addr = GuestVirtAddr::new(0xFFFFFFFFFFFFF000); - let p_addr = virt_to_phys(virt_addr, &mem).unwrap(); + let p_addr = virt_to_phys(virt_addr, &mem, guest_address + PML4_OFFSET).unwrap(); assert_eq!(p_addr, guest_address + PML4_OFFSET); // The last entry on the PML4 is the address of the PML4 with flags let virt_addr = GuestVirtAddr::new(0xFFFFFFFFFFFFF000 | (4096 - 8)); - let p_addr = virt_to_phys(virt_addr, &mem).unwrap(); + let p_addr = virt_to_phys(virt_addr, &mem, guest_address + PML4_OFFSET).unwrap(); assert_eq!( mem.read::(p_addr).unwrap(), (guest_address + PML4_OFFSET).as_u64() @@ -281,7 +275,7 @@ mod tests { // the first entry on the 3rd level entry in the pagetables is the address of the boot pdpte let virt_addr = GuestVirtAddr::new(0xFFFFFFFFFFE00000); - let p_addr = virt_to_phys(virt_addr, &mem).unwrap(); + let p_addr = virt_to_phys(virt_addr, &mem, guest_address + PML4_OFFSET).unwrap(); assert!(p_addr.as_u64() - guest_address.as_u64() >= PAGETABLES_OFFSET); assert!(p_addr.as_u64() - guest_address.as_u64() <= PAGETABLES_END); @@ -289,7 +283,7 @@ mod tests { let idx2 = GuestVirtAddr::new(guest_address.as_u64()).p2_index(); let virt_addr = GuestVirtAddr::new(0xFFFFFFFFC0000000) + u64::from(idx2) * size_of::() as u64; - let p_addr = virt_to_phys(virt_addr, &mem).unwrap(); + let p_addr = virt_to_phys(virt_addr, &mem, guest_address + PML4_OFFSET).unwrap(); assert!(p_addr.as_u64() - guest_address.as_u64() >= PAGETABLES_OFFSET); assert!(p_addr.as_u64() - guest_address.as_u64() <= PAGETABLES_END); // That address points to a huge page diff --git a/src/hypercall.rs b/src/hypercall.rs index f5237e49..0dd4361e 100644 --- a/src/hypercall.rs +++ b/src/hypercall.rs @@ -146,11 +146,11 @@ pub fn close(sysclose: &mut CloseParams) { } /// Handles an read syscall on the host. -pub fn read(mem: &MmapMemory, sysread: &mut ReadParams) { +pub fn read(mem: &MmapMemory, sysread: &mut ReadParams, root_pt: GuestPhysAddr) { unsafe { let bytes_read = libc::read( sysread.fd, - mem.host_address(virt_to_phys(sysread.buf, mem).unwrap()) + mem.host_address(virt_to_phys(sysread.buf, mem, root_pt).unwrap()) .unwrap() as *mut libc::c_void, sysread.len, ); @@ -166,11 +166,12 @@ pub fn read(mem: &MmapMemory, sysread: &mut ReadParams) { pub fn write( parent_vm: &UhyveVm, syswrite: &WriteParams, + root_pt: GuestPhysAddr, ) -> io::Result<()> { let mut bytes_written: usize = 0; while bytes_written != syswrite.len { let guest_phys_addr = - virt_to_phys(syswrite.buf + bytes_written as u64, &parent_vm.mem).unwrap(); + virt_to_phys(syswrite.buf + bytes_written as u64, &parent_vm.mem, root_pt).unwrap(); if syswrite.fd == 1 { // fd 0 is stdout diff --git a/src/linux/gdb/breakpoints.rs b/src/linux/gdb/breakpoints.rs index 1d84f999..b4b530f8 100644 --- a/src/linux/gdb/breakpoints.rs +++ b/src/linux/gdb/breakpoints.rs @@ -52,7 +52,12 @@ impl target::ext::breakpoints::SwBreakpoint for GdbUhyve { // Safety: mem is not altered during the lifetime of `instructions` let instructions = unsafe { self.vm.mem.slice_at_mut( - virt_to_phys(GuestVirtAddr::new(addr), &self.vm.mem).map_err(|_err| ())?, + virt_to_phys( + GuestVirtAddr::new(addr), + &self.vm.mem, + self.vcpu.get_root_pagetable(), + ) + .map_err(|_err| ())?, kind, ) } @@ -72,7 +77,12 @@ impl target::ext::breakpoints::SwBreakpoint for GdbUhyve { // Safety: mem is not altered during the lifetime of `instructions` let instructions = unsafe { self.vm.mem.slice_at_mut( - virt_to_phys(GuestVirtAddr::new(addr), &self.vm.mem).map_err(|_err| ())?, + virt_to_phys( + GuestVirtAddr::new(addr), + &self.vm.mem, + self.vcpu.get_root_pagetable(), + ) + .map_err(|_err| ())?, kind, ) } diff --git a/src/linux/gdb/mod.rs b/src/linux/gdb/mod.rs index 52e34be3..b1c0db11 100644 --- a/src/linux/gdb/mod.rs +++ b/src/linux/gdb/mod.rs @@ -133,7 +133,8 @@ impl SingleThreadBase for GdbUhyve { // Safety: mem is copied to data before mem can be modified. let src = unsafe { self.vm.mem.slice_at( - virt_to_phys(guest_addr, &self.vm.mem).map_err(|_err| ())?, + virt_to_phys(guest_addr, &self.vm.mem, self.vcpu.get_root_pagetable()) + .map_err(|_err| ())?, data.len(), ) } @@ -146,7 +147,12 @@ impl SingleThreadBase for GdbUhyve { // Safety: self.vm.mem is not altered during the lifetime of mem. let mem = unsafe { self.vm.mem.slice_at_mut( - virt_to_phys(GuestVirtAddr::new(start_addr), &self.vm.mem).map_err(|_err| ())?, + virt_to_phys( + GuestVirtAddr::new(start_addr), + &self.vm.mem, + self.vcpu.get_root_pagetable(), + ) + .map_err(|_err| ())?, data.len(), ) } diff --git a/src/linux/x86_64/kvm_cpu.rs b/src/linux/x86_64/kvm_cpu.rs index b58f8850..03c04946 100644 --- a/src/linux/x86_64/kvm_cpu.rs +++ b/src/linux/x86_64/kvm_cpu.rs @@ -85,7 +85,7 @@ impl VirtualizationBackend for KvmVm { slot: 1, flags: mem.flags, memory_size: (mem.memory_size - KVM_32BIT_GAP_START - KVM_32BIT_GAP_SIZE) as u64, - guest_phys_addr: (*crate::vm::GUEST_ADDRESS.get().unwrap()).as_u64() + guest_phys_addr: mem.guest_address.as_u64() + (KVM_32BIT_GAP_START + KVM_32BIT_GAP_SIZE) as u64, userspace_addr: (mem.host_address as usize + KVM_32BIT_GAP_START @@ -340,6 +340,10 @@ impl KvmCpu { &mut self.vcpu } + pub fn get_root_pagetable(&self) -> GuestPhysAddr { + GuestPhysAddr::new(self.vcpu.get_sregs().unwrap().cr3) + } + fn init( &mut self, entry_point: GuestPhysAddr, @@ -462,13 +466,17 @@ impl VirtualCPU for KvmCpu { sysopen, &mut self.parent_vm.file_mapping.lock().unwrap(), ), - Hypercall::FileRead(sysread) => { - hypercall::read(&self.parent_vm.mem, sysread) - } - Hypercall::FileWrite(syswrite) => { - hypercall::write(&self.parent_vm, syswrite) - .map_err(|_e| HypervisorError::new(libc::EFAULT))? - } + Hypercall::FileRead(sysread) => hypercall::read( + &self.parent_vm.mem, + sysread, + self.get_root_pagetable(), + ), + Hypercall::FileWrite(syswrite) => hypercall::write( + &self.parent_vm, + syswrite, + self.get_root_pagetable(), + ) + .map_err(|_e| HypervisorError::new(libc::EFAULT))?, Hypercall::FileUnlink(sysunlink) => hypercall::unlink( &self.parent_vm.mem, sysunlink, diff --git a/src/vm.rs b/src/vm.rs index 853aca28..0878187f 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -5,7 +5,7 @@ use std::{ num::NonZeroU32, path::PathBuf, ptr, str, - sync::{Arc, Mutex, OnceLock}, + sync::{Arc, Mutex}, time::SystemTime, }; @@ -36,8 +36,6 @@ use crate::{ pub type HypervisorResult = Result; -pub static GUEST_ADDRESS: OnceLock = OnceLock::new(); - #[derive(Error, Debug)] pub enum LoadKernelError { #[error(transparent)] @@ -192,7 +190,6 @@ impl UhyveVm { dbg!(GuestPhysAddr::new(offset)); dbg!(guest_address); - let _ = *GUEST_ADDRESS.get_or_init(|| guest_address); #[cfg(target_os = "linux")] #[cfg(target_arch = "x86_64")]