diff --git a/src/dragonball/src/address_space_manager.rs b/src/dragonball/src/address_space_manager.rs index 53743368f5..75bb354fb1 100644 --- a/src/dragonball/src/address_space_manager.rs +++ b/src/dragonball/src/address_space_manager.rs @@ -29,7 +29,12 @@ use dbs_address_space::{ use dbs_allocator::Constraint; #[cfg(target_arch = "x86_64")] use dbs_boot::layout::{BIOS_MEM_SIZE, BIOS_MEM_START}; -use kvm_bindings::kvm_userspace_memory_region; +use kvm_bindings::{ + kvm_create_guest_memfd, kvm_userspace_memory_region, kvm_userspace_memory_region2, + KVM_MEM_GUEST_MEMFD, +}; +#[cfg(target_arch = "x86_64")] +use kvm_bindings::{kvm_memory_attributes, KVM_MEMORY_ATTRIBUTE_PRIVATE}; use kvm_ioctls::VmFd; use log::{debug, error, info, warn}; use nix::sys::mman; @@ -153,6 +158,19 @@ pub enum AddressManagerError { /// Failed to create Address Space Region #[error("address manager failed to create Address Space Region {0}")] CreateAddressSpaceRegion(#[source] AddressSpaceError), + + /// Failed to create VM-bound memfd + #[error("address manager failed to create VM-bound memfd: {0}")] + CreateVmboundMemfd(#[source] kvm_ioctls::Error), + + /// Failed to set KVM memory slot with VM-bound memfd + #[error("address manager failed to configure KVM memory slot with VM-bound memfd: {0}")] + KvmSetMemorySlotWithMemfd(#[source] kvm_ioctls::Error), + + #[cfg(target_arch = "x86_64")] + /// Failed to configure KVM memory attributes + #[error("address manager failed to configure KVM memory attributes: {0}")] + KvmSetMemoryAttributes(#[source] kvm_ioctls::Error), } type Result = std::result::Result; @@ -167,6 +185,8 @@ pub struct AddressSpaceMgrBuilder<'a> { dirty_page_logging: bool, vmfd: Option>, use_firmware: bool, + #[cfg(target_arch = "x86_64")] + kvm_mem_attr_private: bool, } impl<'a> AddressSpaceMgrBuilder<'a> { @@ -184,6 +204,8 @@ impl<'a> AddressSpaceMgrBuilder<'a> { dirty_page_logging: false, vmfd: None, use_firmware: false, + #[cfg(target_arch = "x86_64")] + kvm_mem_attr_private: false, }) } @@ -210,6 +232,12 @@ impl<'a> AddressSpaceMgrBuilder<'a> { self.use_firmware = firmware; } + #[cfg(target_arch = "x86_64")] + /// Set KVM memory attribute to private/shared. + pub fn toggle_kvm_mem_attr_private(&mut self, private: bool) { + self.kvm_mem_attr_private = private; + } + /// Set KVM [`VmFd`] handle to configure memory slots. pub fn set_kvm_vm_fd(&mut self, vmfd: Arc) -> Option> { let mut existing_vmfd = None; @@ -431,24 +459,67 @@ impl AddressSpaceMgr { let host_addr = mmap_reg .get_host_address(MemoryRegionAddress(0)) .map_err(|_e| AddressManagerError::InvalidOperation)?; - let flags = 0u32; + let mut flags = 0u32; - let mem_region = kvm_userspace_memory_region { - slot, - guest_phys_addr: reg.start_addr().raw_value(), - memory_size: reg.len(), - userspace_addr: host_addr as u64, - flags, - }; + #[cfg(not(target_arch = "x86_64"))] + let kvm_guest_memfd = false; + #[cfg(target_arch = "x86_64")] + let kvm_guest_memfd = param.kvm_mem_attr_private; - info!( - "VM: guest memory region {:x} starts at {:x?}", - reg.start_addr().raw_value(), - host_addr - ); - // Safe because the guest regions are guaranteed not to overlap. - unsafe { vmfd.set_user_memory_region(mem_region) } - .map_err(AddressManagerError::KvmSetMemorySlot)?; + if !kvm_guest_memfd { + let mem_region = kvm_userspace_memory_region { + slot, + guest_phys_addr: reg.start_addr().raw_value(), + memory_size: reg.len(), + userspace_addr: host_addr as u64, + flags, + }; + + info!( + "VM: guest memory region {:x} starts at {:x?}", + reg.start_addr().raw_value(), + host_addr + ); + // Safe because the guest regions are guaranteed not to overlap. + unsafe { vmfd.set_user_memory_region(mem_region) } + .map_err(AddressManagerError::KvmSetMemorySlot)?; + } else { + let memfd = vmfd + .create_guest_memfd(kvm_create_guest_memfd { + size: reg.len(), + flags: 0, + ..Default::default() + }) + .map_err(AddressManagerError::CreateVmboundMemfd)?; + flags |= KVM_MEM_GUEST_MEMFD; + let guest_phys_addr = reg.start_addr().raw_value(); + let memory_size = reg.len(); + unsafe { + vmfd.set_user_memory_region2(kvm_userspace_memory_region2 { + slot, + flags, + guest_phys_addr, + memory_size, + userspace_addr: host_addr as u64, + guest_memfd_offset: 0, + guest_memfd: memfd as u32, + ..Default::default() + }) + .map_err(AddressManagerError::KvmSetMemorySlotWithMemfd)?; + } + + #[cfg(target_arch = "x86_64")] + if param.kvm_mem_attr_private { + let attributes = KVM_MEMORY_ATTRIBUTE_PRIVATE as u64; + vmfd.set_memory_attributes(kvm_memory_attributes { + address: guest_phys_addr, + size: memory_size, + attributes, + flags: 0, + }) + .map_err(AddressManagerError::KvmSetMemoryAttributes)?; + } + } } self.base_to_slot diff --git a/src/dragonball/src/vm/mod.rs b/src/dragonball/src/vm/mod.rs index 006281c302..b7392d8758 100644 --- a/src/dragonball/src/vm/mod.rs +++ b/src/dragonball/src/vm/mod.rs @@ -34,7 +34,6 @@ use crate::address_space_manager::{ AddressManagerError, AddressSpaceMgr, AddressSpaceMgrBuilder, GuestAddressSpaceImpl, GuestMemoryImpl, }; -#[cfg(target_arch = "x86_64")] use crate::api::v1::ConfidentialVmType; use crate::api::v1::{InstanceInfo, InstanceState}; use crate::device_manager::console_manager::DmesgWriter; @@ -426,6 +425,15 @@ impl Vm { AddressManagerError::GuestMemoryNotInitialized, )) } + + /// Get confidential VM type for micro VM, if any + pub fn confidential_vm_type(&self) -> Option { + self.shared_info + .read() + .unwrap() + .confidential_vm_type + .clone() + } } impl Vm { @@ -616,6 +624,8 @@ impl Vm { .map_err(StartMicroVmError::AddressManagerError)?; address_space_param.set_kvm_vm_fd(self.vm_fd.clone()); address_space_param.toggle_use_firmware(self.firmware_type.is_some()); + #[cfg(target_arch = "x86_64")] + address_space_param.toggle_kvm_mem_attr_private(self.kvm_mem_attr_private()); self.address_space .create_address_space(&self.resource_manager, &numa_regions, address_space_param) .map_err(StartMicroVmError::AddressManagerError)?; diff --git a/src/dragonball/src/vm/x86_64.rs b/src/dragonball/src/vm/x86_64.rs index cd075c047f..03f974a5cd 100644 --- a/src/dragonball/src/vm/x86_64.rs +++ b/src/dragonball/src/vm/x86_64.rs @@ -29,6 +29,7 @@ use slog::info; use vm_memory::{Address, GuestAddress, GuestAddressSpace, GuestMemory}; use crate::address_space_manager::{GuestAddressSpaceImpl, GuestMemoryImpl}; +use crate::api::v1::ConfidentialVmType; use crate::error::{Error, Result, StartMicroVmError}; use crate::event_manager::EventManager; use crate::vm::{Vm, VmError}; @@ -377,6 +378,10 @@ impl Vm { self.shared_info.read().unwrap().split_irqchip() } + pub(crate) fn kvm_mem_attr_private(&self) -> bool { + self.confidential_vm_type() == Some(ConfidentialVmType::TDX) + } + fn load_kernel_with_tdshim( &mut self, sections: &Vec,