mirror of
https://github.com/kata-containers/kata-containers.git
synced 2026-07-01 22:50:54 +00:00
Merge pull request #13066 from RainaYL/rainax/guest_memfd_pr
dragonball: Add implementation for KVM-managed guest memfd
This commit is contained in:
@@ -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<T> = std::result::Result<T, AddressManagerError>;
|
||||
@@ -167,6 +185,8 @@ pub struct AddressSpaceMgrBuilder<'a> {
|
||||
dirty_page_logging: bool,
|
||||
vmfd: Option<Arc<VmFd>>,
|
||||
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<VmFd>) -> Option<Arc<VmFd>> {
|
||||
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
|
||||
|
||||
@@ -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<ConfidentialVmType> {
|
||||
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)?;
|
||||
|
||||
@@ -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};
|
||||
@@ -380,6 +381,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<TdvfSection>,
|
||||
|
||||
Reference in New Issue
Block a user