Skip to content

Commit e6800b3

Browse files
committed
vmm/linux: Use guest_memfd if required
guest_memfd is required by SEV-SNP guests, and will also be used for other TEE architectures such as TDX and CCA. Probe if guest_memfd will be used on the system (non-TEE workloads do not require guest_memfd), and create/map them if so. Signed-off-by: Tyler Fanelli <[email protected]>
1 parent 4dd2348 commit e6800b3

File tree

1 file changed

+75
-11
lines changed

1 file changed

+75
-11
lines changed

src/vmm/src/linux/vstate.rs

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,18 @@ use kvm_bindings::{
4040
KVM_CLOCK_TSC_STABLE, KVM_IRQCHIP_IOAPIC, KVM_IRQCHIP_PIC_MASTER, KVM_IRQCHIP_PIC_SLAVE,
4141
KVM_MAX_CPUID_ENTRIES,
4242
};
43-
use kvm_bindings::{kvm_userspace_memory_region, KVM_API_VERSION};
44-
use kvm_ioctls::*;
43+
use kvm_bindings::{
44+
kvm_create_guest_memfd, kvm_memory_attributes, kvm_userspace_memory_region,
45+
kvm_userspace_memory_region2, KVM_API_VERSION, KVM_MEMORY_ATTRIBUTE_PRIVATE,
46+
KVM_MEM_GUEST_MEMFD,
47+
};
48+
use kvm_ioctls::{Cap::*, *};
4549
use utils::eventfd::EventFd;
4650
use utils::signal::{register_signal_handler, sigrtmin, Killable};
4751
use utils::sm::StateMachine;
4852
use vm_memory::{
4953
Address, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap, GuestMemoryRegion,
54+
GuestRegionMmap,
5055
};
5156

5257
#[cfg(feature = "amd-sev")]
@@ -61,6 +66,8 @@ pub enum Error {
6166
#[cfg(target_arch = "x86_64")]
6267
/// A call to cpuid instruction failed.
6368
CpuId(cpuid::Error),
69+
/// Unable to create a KVM guest_memfd.
70+
CreateGuestMemfd(kvm_ioctls::Error),
6471
#[cfg(target_arch = "x86_64")]
6572
/// Error configuring the floating point related registers
6673
FPUConfiguration(arch::x86_64::regs::Error),
@@ -97,6 +104,8 @@ pub enum Error {
97104
#[cfg(target_arch = "x86_64")]
98105
/// Error configuring the general purpose registers
99106
REGSConfiguration(arch::x86_64::regs::Error),
107+
/// Cannot set memory region attributes.
108+
SetMemoryAttributes(kvm_ioctls::Error),
100109
/// Cannot set the memory regions.
101110
SetUserMemoryRegion(kvm_ioctls::Error),
102111
/// Error creating memory map for SHM region.
@@ -226,6 +235,7 @@ impl Display for Error {
226235
match self {
227236
#[cfg(target_arch = "x86_64")]
228237
CpuId(e) => write!(f, "Cpuid error: {e:?}"),
238+
CreateGuestMemfd(e) => write!(f, "Unable to create KVM guest_memfd: {e:?}"),
229239
GuestMemoryMmap(e) => write!(f, "Guest memory error: {e:?}"),
230240
#[cfg(target_arch = "x86_64")]
231241
GuestMSRs(e) => write!(f, "Retrieving supported guest MSRs fails: {e:?}"),
@@ -250,6 +260,7 @@ impl Display for Error {
250260
f,
251261
"Cannot set the local interruption due to bad configuration: {e:?}"
252262
),
263+
SetMemoryAttributes(e) => write!(f, "Cannot set memory region attributes: {e}"),
253264
SetUserMemoryRegion(e) => write!(f, "Cannot set the memory regions: {e}"),
254265
ShmMmap(e) => write!(f, "Error creating memory map for SHM region: {e}"),
255266
#[cfg(feature = "tee")]
@@ -376,7 +387,6 @@ pub struct KvmContext {
376387

377388
impl KvmContext {
378389
pub fn new() -> Result<Self> {
379-
use kvm_ioctls::Cap::*;
380390
let kvm = Kvm::new().expect("Error creating the Kvm object");
381391

382392
// Check that KVM has the correct version.
@@ -508,31 +518,85 @@ impl Vm {
508518
if guest_mem.num_regions() > kvm_max_memslots {
509519
return Err(Error::NotEnoughMemorySlots);
510520
}
521+
511522
for region in guest_mem.iter() {
512-
// It's safe to unwrap because the guest address is valid.
513-
let host_addr = guest_mem.get_host_address(region.start_addr()).unwrap();
514-
debug!("Guest memory starts at {:x?}", host_addr);
523+
self.memory_region_set(guest_mem, region)?;
524+
}
525+
526+
#[cfg(target_arch = "x86_64")]
527+
self.fd
528+
.set_tss_address(arch::x86_64::layout::KVM_TSS_ADDRESS as usize)
529+
.map_err(Error::VmSetup)?;
530+
531+
Ok(())
532+
}
533+
534+
fn memory_region_set(
535+
&mut self,
536+
guest_mem: &GuestMemoryMmap,
537+
region: &GuestRegionMmap,
538+
) -> Result<()> {
539+
let host_addr = guest_mem.get_host_address(region.start_addr()).unwrap();
540+
if !self.fd.check_extension(GuestMemfd) {
515541
let memory_region = kvm_userspace_memory_region {
516542
slot: self.next_mem_slot,
517543
guest_phys_addr: region.start_addr().raw_value(),
518544
memory_size: region.len(),
519545
userspace_addr: host_addr as u64,
520546
flags: 0,
521547
};
548+
522549
// Safe because we mapped the memory region, we made sure that the regions
523550
// are not overlapping.
524551
unsafe {
525552
self.fd
526553
.set_user_memory_region(memory_region)
527554
.map_err(Error::SetUserMemoryRegion)?;
528555
};
529-
self.next_mem_slot += 1;
556+
} else {
557+
// Create a guest_memfd and set the region.
558+
let guest_memfd = self
559+
.fd
560+
.create_guest_memfd(kvm_create_guest_memfd {
561+
size: region.size() as u64,
562+
flags: 0,
563+
reserved: [0; 6],
564+
})
565+
.map_err(Error::CreateGuestMemfd)?;
566+
567+
let memory_region = kvm_userspace_memory_region2 {
568+
slot: self.next_mem_slot,
569+
flags: KVM_MEM_GUEST_MEMFD,
570+
guest_phys_addr: region.start_addr().raw_value(),
571+
memory_size: region.len(),
572+
userspace_addr: host_addr as u64,
573+
guest_memfd_offset: 0,
574+
guest_memfd: guest_memfd as u32,
575+
pad1: 0,
576+
pad2: [0; 14],
577+
};
578+
579+
// Safe because we mapped the memory region, we made sure that the regions
580+
// are not overlapping.
581+
unsafe {
582+
self.fd
583+
.set_user_memory_region2(memory_region)
584+
.map_err(Error::SetUserMemoryRegion)?;
585+
};
586+
587+
let attr = kvm_memory_attributes {
588+
address: region.start_addr().raw_value(),
589+
size: region.len(),
590+
attributes: KVM_MEMORY_ATTRIBUTE_PRIVATE as u64,
591+
flags: 0,
592+
};
593+
594+
self.fd
595+
.set_memory_attributes(attr)
596+
.map_err(Error::SetMemoryAttributes)?;
530597
}
531598

532-
#[cfg(target_arch = "x86_64")]
533-
self.fd
534-
.set_tss_address(arch::x86_64::layout::KVM_TSS_ADDRESS as usize)
535-
.map_err(Error::VmSetup)?;
599+
self.next_mem_slot += 1;
536600

537601
Ok(())
538602
}

0 commit comments

Comments
 (0)