Skip to content

Commit 2d119ed

Browse files
committed
vmm/linux: Make guest_memfd optional
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 0f8c912 commit 2d119ed

File tree

1 file changed

+83
-85
lines changed

1 file changed

+83
-85
lines changed

src/vmm/src/linux/vstate.rs

Lines changed: 83 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +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-
#[cfg(feature = "tee")]
4443
use kvm_bindings::{
45-
kvm_create_guest_memfd, kvm_memory_attributes, kvm_userspace_memory_region2, KVM_API_VERSION,
46-
KVM_MEMORY_ATTRIBUTE_PRIVATE, KVM_MEM_GUEST_MEMFD,
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,
4747
};
48-
#[cfg(not(feature = "tee"))]
49-
use kvm_bindings::{kvm_userspace_memory_region, KVM_API_VERSION};
50-
use kvm_ioctls::*;
48+
use kvm_ioctls::{Cap::*, *};
5149
use utils::eventfd::EventFd;
5250
use utils::signal::{register_signal_handler, sigrtmin, Killable};
5351
use utils::sm::StateMachine;
5452
use vm_memory::{
5553
Address, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap, GuestMemoryRegion,
54+
GuestRegionMmap,
5655
};
5756

5857
#[cfg(feature = "amd-sev")]
@@ -67,6 +66,8 @@ pub enum Error {
6766
#[cfg(target_arch = "x86_64")]
6867
/// A call to cpuid instruction failed.
6968
CpuId(cpuid::Error),
69+
/// Unable to create a KVM guest_memfd.
70+
CreateGuestMemfd(kvm_ioctls::Error),
7071
#[cfg(target_arch = "x86_64")]
7172
/// Error configuring the floating point related registers
7273
FPUConfiguration(arch::x86_64::regs::Error),
@@ -103,16 +104,12 @@ pub enum Error {
103104
#[cfg(target_arch = "x86_64")]
104105
/// Error configuring the general purpose registers
105106
REGSConfiguration(arch::x86_64::regs::Error),
107+
/// Cannot set memory region attributes.
108+
SetMemoryAttributes(kvm_ioctls::Error),
106109
/// Cannot set the memory regions.
107110
SetUserMemoryRegion(kvm_ioctls::Error),
108111
/// Error creating memory map for SHM region.
109112
ShmMmap(io::Error),
110-
#[cfg(feature = "tee")]
111-
/// Cannot set the memory regions.
112-
SetUserMemoryRegion2(kvm_ioctls::Error),
113-
#[cfg(feature = "tee")]
114-
/// Cannot create guest memfd.
115-
CreateGuestMemfd(kvm_ioctls::Error),
116113
#[cfg(feature = "amd-sev")]
117114
/// Error initializing the Secure Virtualization Backend (SNP).
118115
SnpSecVirtInit(SnpError),
@@ -238,6 +235,7 @@ impl Display for Error {
238235
match self {
239236
#[cfg(target_arch = "x86_64")]
240237
CpuId(e) => write!(f, "Cpuid error: {e:?}"),
238+
CreateGuestMemfd(e) => write!(f, "Unable to create KVM guest_memfd: {e:?}"),
241239
GuestMemoryMmap(e) => write!(f, "Guest memory error: {e:?}"),
242240
#[cfg(target_arch = "x86_64")]
243241
GuestMSRs(e) => write!(f, "Retrieving supported guest MSRs fails: {e:?}"),
@@ -262,13 +260,10 @@ impl Display for Error {
262260
f,
263261
"Cannot set the local interruption due to bad configuration: {e:?}"
264262
),
263+
SetMemoryAttributes(e) => write!(f, "Cannot set memory region attributes: {e}"),
265264
SetUserMemoryRegion(e) => write!(f, "Cannot set the memory regions: {e}"),
266265
ShmMmap(e) => write!(f, "Error creating memory map for SHM region: {e}"),
267266
#[cfg(feature = "tee")]
268-
SetUserMemoryRegion2(e) => write!(f, "Cannot set the memory regions: {e}"),
269-
#[cfg(feature = "tee")]
270-
CreateGuestMemfd(e) => write!(f, "Cannot create guest memfd: {e}"),
271-
#[cfg(feature = "tee")]
272267
SnpSecVirtInit(e) => write!(
273268
f,
274269
"Error initializing the Secure Virtualization Backend (SEV): {e:?}"
@@ -392,7 +387,6 @@ pub struct KvmContext {
392387

393388
impl KvmContext {
394389
pub fn new() -> Result<Self> {
395-
use kvm_ioctls::Cap::*;
396390
let kvm = Kvm::new().expect("Error creating the Kvm object");
397391

398392
// Check that KVM has the correct version.
@@ -519,80 +513,14 @@ impl Vm {
519513
pub fn memory_init(
520514
&mut self,
521515
guest_mem: &GuestMemoryMmap,
522-
#[cfg(feature = "tee")] guest_memfd: &mut Vec<RawFd>,
523516
kvm_max_memslots: usize,
524517
) -> Result<()> {
525518
if guest_mem.num_regions() > kvm_max_memslots {
526519
return Err(Error::NotEnoughMemorySlots);
527520
}
528-
for region in guest_mem.iter() {
529-
// It's safe to unwrap because the guest address is valid.
530-
let host_addr = guest_mem.get_host_address(region.start_addr()).unwrap();
531-
info!("Guest memory starts at {:x?}", host_addr);
532521

533-
#[cfg(feature = "tee")]
534-
{
535-
let gmem = kvm_create_guest_memfd {
536-
size: region.len(),
537-
flags: 0,
538-
reserved: [0; 6],
539-
};
540-
541-
let id: RawFd = self
542-
.fd
543-
.create_guest_memfd(gmem)
544-
.map_err(Error::CreateGuestMemfd)?;
545-
546-
guest_memfd.push(id);
547-
548-
let memory_region = kvm_userspace_memory_region2 {
549-
slot: self.next_mem_slot as u32,
550-
flags: KVM_MEM_GUEST_MEMFD,
551-
guest_phys_addr: region.start_addr().raw_value(),
552-
memory_size: region.len(),
553-
userspace_addr: host_addr as u64,
554-
guest_memfd_offset: 0,
555-
guest_memfd: id as u32,
556-
pad1: 0,
557-
pad2: [0; 14],
558-
};
559-
560-
// Safe because we mapped the memory region, we made sure that the regions
561-
// are not overlapping.
562-
unsafe {
563-
self.fd
564-
.set_user_memory_region2(memory_region)
565-
.map_err(Error::SetUserMemoryRegion2)?;
566-
};
567-
568-
// set private by default when using guestmemfd
569-
// this imitates QEMU behavior
570-
let attr = kvm_memory_attributes {
571-
address: region.start_addr().raw_value(),
572-
size: region.len(),
573-
attributes: KVM_MEMORY_ATTRIBUTE_PRIVATE as u64,
574-
flags: 0,
575-
};
576-
self.fd.set_memory_attributes(attr).unwrap();
577-
}
578-
#[cfg(not(feature = "tee"))]
579-
{
580-
let memory_region = kvm_userspace_memory_region {
581-
slot: self.next_mem_slot as u32,
582-
guest_phys_addr: region.start_addr().raw_value(),
583-
memory_size: region.len(),
584-
userspace_addr: host_addr as u64,
585-
flags: 0,
586-
};
587-
// Safe because we mapped the memory region, we made sure that the regions
588-
// are not overlapping.
589-
unsafe {
590-
self.fd
591-
.set_user_memory_region(memory_region)
592-
.map_err(Error::SetUserMemoryRegion)?;
593-
};
594-
};
595-
self.next_mem_slot += 1;
522+
for region in guest_mem.iter() {
523+
self.memory_region_set(guest_mem, region)?;
596524
}
597525

598526
#[cfg(target_arch = "x86_64")]
@@ -603,6 +531,76 @@ impl Vm {
603531
Ok(())
604532
}
605533

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) {
541+
let memory_region = kvm_userspace_memory_region {
542+
slot: self.next_mem_slot,
543+
guest_phys_addr: region.start_addr().raw_value(),
544+
memory_size: region.len(),
545+
userspace_addr: host_addr as u64,
546+
flags: 0,
547+
};
548+
549+
// Safe because we mapped the memory region, we made sure that the regions
550+
// are not overlapping.
551+
unsafe {
552+
self.fd
553+
.set_user_memory_region(memory_region)
554+
.map_err(Error::SetUserMemoryRegion)?;
555+
};
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)?;
597+
}
598+
599+
self.next_mem_slot += 1;
600+
601+
Ok(())
602+
}
603+
606604
#[cfg(feature = "amd-sev")]
607605
pub fn snp_secure_virt_prepare(
608606
&self,

0 commit comments

Comments
 (0)