From 702d17fe9dd1e6aa285deb06da47be138522a94e Mon Sep 17 00:00:00 2001 From: Matias Ezequiel Vara Larsen Date: Mon, 29 Jul 2024 11:41:26 -0400 Subject: [PATCH] Enable creating guest memory regions with create_guest_memfd() and set_user_memory_region2() This is a WIP commit. Signed-off-by: Matias Ezequiel Vara Larsen --- src/vmm/src/builder.rs | 4 +- src/vmm/src/linux/vstate.rs | 81 ++++++++++++++++++++++++++++--------- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index 1f5d993e..627d7134 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -819,7 +819,7 @@ pub(crate) fn setup_vm( let mut vm = Vm::new(kvm.fd()) .map_err(Error::Vm) .map_err(StartMicrovmError::Internal)?; - vm.memory_init(guest_memory, kvm.max_memslots()) + vm.memory_init(guest_memory, kvm.max_memslots(), false) .map_err(Error::Vm) .map_err(StartMicrovmError::Internal)?; Ok(vm) @@ -833,7 +833,7 @@ pub(crate) fn setup_vm( let mut vm = Vm::new(kvm.fd(), tee_config) .map_err(Error::Vm) .map_err(StartMicrovmError::Internal)?; - vm.memory_init(guest_memory, kvm.max_memslots()) + vm.memory_init(guest_memory, kvm.max_memslots(), false) .map_err(Error::Vm) .map_err(StartMicrovmError::Internal)?; Ok(vm) diff --git a/src/vmm/src/linux/vstate.rs b/src/vmm/src/linux/vstate.rs index 8a64740f..439dd203 100644 --- a/src/vmm/src/linux/vstate.rs +++ b/src/vmm/src/linux/vstate.rs @@ -10,6 +10,7 @@ use libc::{c_int, c_void, siginfo_t}; use std::cell::Cell; use std::fmt::{Display, Formatter}; use std::io; +use std::os::fd::RawFd; #[cfg(feature = "tee")] use std::os::unix::io::RawFd; @@ -46,7 +47,10 @@ use kvm_bindings::{ Msrs, KVM_CLOCK_TSC_STABLE, KVM_IRQCHIP_IOAPIC, KVM_IRQCHIP_PIC_MASTER, KVM_IRQCHIP_PIC_SLAVE, KVM_MAX_CPUID_ENTRIES, KVM_PIT_SPEAKER_DUMMY, }; -use kvm_bindings::{kvm_userspace_memory_region, KVM_API_VERSION}; +use kvm_bindings::{ + kvm_create_guest_memfd, kvm_userspace_memory_region, kvm_userspace_memory_region2, + KVM_API_VERSION, KVM_MEM_GUEST_MEMFD, +}; use kvm_ioctls::*; use utils::eventfd::EventFd; use utils::signal::{register_signal_handler, sigrtmin, Killable}; @@ -111,6 +115,10 @@ pub enum Error { SetupGIC(arch::aarch64::gic::Error), /// Cannot set the memory regions. SetUserMemoryRegion(kvm_ioctls::Error), + /// Cannot set the memory regions. + SetUserMemoryRegion2(kvm_ioctls::Error), + // Cannot create guest memfd. + CreateGuestMemfd(kvm_ioctls::Error), #[cfg(feature = "amd-sev")] /// Error initializing the Secure Virtualization Backend (SEV). SevSecVirtInit(SevError), @@ -270,6 +278,8 @@ impl Display for Error { "Cannot set the local interruption due to bad configuration: {e:?}" ), SetUserMemoryRegion(e) => write!(f, "Cannot set the memory regions: {e}"), + SetUserMemoryRegion2(e) => write!(f, "Cannot set the memory regions: {e}"), + CreateGuestMemfd(e) => write!(f, "Cannot create guest memfd: {e}"), #[cfg(feature = "tee")] SevSecVirtInit(e) => { write!( @@ -549,6 +559,7 @@ impl Vm { &mut self, guest_mem: &GuestMemoryMmap, kvm_max_memslots: usize, + require_guest_memfd: bool, ) -> Result<()> { if guest_mem.num_regions() > kvm_max_memslots { return Err(Error::NotEnoughMemorySlots); @@ -557,19 +568,53 @@ impl Vm { // It's safe to unwrap because the guest address is valid. let host_addr = guest_mem.get_host_address(region.start_addr()).unwrap(); info!("Guest memory starts at {:x?}", host_addr); - let memory_region = kvm_userspace_memory_region { - slot: index as u32, - guest_phys_addr: region.start_addr().raw_value(), - memory_size: region.len(), - userspace_addr: host_addr as u64, - flags: 0, - }; - // Safe because we mapped the memory region, we made sure that the regions - // are not overlapping. - unsafe { - self.fd - .set_user_memory_region(memory_region) - .map_err(Error::SetUserMemoryRegion)?; + + if require_guest_memfd { + let gmem = kvm_create_guest_memfd { + size: region.len(), + flags: 0, + reserved: [0; 6], + }; + + let id: RawFd = self + .fd + .create_guest_memfd(gmem) + .map_err(Error::CreateGuestMemfd)?; + + let memory_region = kvm_userspace_memory_region2 { + slot: index as u32, + flags: KVM_MEM_GUEST_MEMFD, + guest_phys_addr: region.start_addr().raw_value(), + memory_size: region.len(), + userspace_addr: host_addr as u64, + guest_memfd_offset: 0, + guest_memfd: id as u32, + pad1: 0, + pad2: [0; 14], + }; + + // Safe because we mapped the memory region, we made sure that the regions + // are not overlapping. + unsafe { + self.fd + .set_user_memory_region2(memory_region) + .map_err(Error::SetUserMemoryRegion2)?; + }; + } else { + let memory_region = kvm_userspace_memory_region { + slot: index as u32, + guest_phys_addr: region.start_addr().raw_value(), + memory_size: region.len(), + userspace_addr: host_addr as u64, + flags: 0, + }; + // Safe because we mapped the memory region, we made sure that the regions + // are not overlapping. + unsafe { + self.fd + .set_user_memory_region(memory_region) + .map_err(Error::SetUserMemoryRegion)?; + }; }; } @@ -1505,7 +1550,7 @@ mod tests { let kvm = KvmContext::new().unwrap(); let gm = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), mem_size)]).unwrap(); let mut vm = Vm::new(kvm.fd()).expect("Cannot create new vm"); - assert!(vm.memory_init(&gm, kvm.max_memslots()).is_ok()); + assert!(vm.memory_init(&gm, kvm.max_memslots(), false).is_ok()); let exit_evt = EventFd::new(utils::eventfd::EFD_NONBLOCK).unwrap(); @@ -1560,7 +1605,7 @@ mod tests { // Create valid memory region and test that the initialization is successful. let gm = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x1000)]).unwrap(); - assert!(vm.memory_init(&gm, kvm_context.max_memslots()).is_ok()); + assert!(vm.memory_init(&gm, kvm_context.max_memslots(), false).is_ok()); // Set the maximum number of memory slots to 1 in KvmContext to check the error // path of memory_init. Create 2 non-overlapping memory slots. @@ -1570,7 +1615,7 @@ mod tests { (GuestAddress(0x1001), 0x2000), ]) .unwrap(); - assert!(vm.memory_init(&gm, kvm_context.max_memslots()).is_err()); + assert!(vm.memory_init(&gm, kvm_context.max_memslots(), false).is_err()); } #[cfg(target_arch = "x86_64")] @@ -1651,7 +1696,7 @@ mod tests { let kvm = KvmContext::new().unwrap(); let gm = GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap(); let mut vm = Vm::new(kvm.fd()).expect("new vm failed"); - assert!(vm.memory_init(&gm, kvm.max_memslots()).is_ok()); + assert!(vm.memory_init(&gm, kvm.max_memslots(), false).is_ok()); // Try it for when vcpu id is 0. let mut vcpu = Vcpu::new_aarch64(