Skip to content

Commit 006a6f7

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 32dc871 commit 006a6f7

File tree

1 file changed

+83
-82
lines changed

1 file changed

+83
-82
lines changed

src/vmm/src/linux/vstate.rs

Lines changed: 83 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,17 @@ use kvm_bindings::{
4545
};
4646
#[cfg(feature = "tee")]
4747
use kvm_bindings::{
48-
kvm_create_guest_memfd, kvm_memory_attributes, kvm_userspace_memory_region2, KVM_API_VERSION,
49-
KVM_MEMORY_ATTRIBUTE_PRIVATE, KVM_MEM_GUEST_MEMFD,
48+
kvm_create_guest_memfd, kvm_memory_attributes, kvm_userspace_memory_region,
49+
kvm_userspace_memory_region2, KVM_API_VERSION, KVM_MEMORY_ATTRIBUTE_PRIVATE,
50+
KVM_MEM_GUEST_MEMFD,
5051
};
51-
use kvm_ioctls::*;
52+
use kvm_ioctls::{Cap::*, *};
5253
use utils::eventfd::EventFd;
5354
use utils::signal::{register_signal_handler, sigrtmin, Killable};
5455
use utils::sm::StateMachine;
5556
use vm_memory::{
5657
Address, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap, GuestMemoryRegion,
58+
GuestRegionMmap,
5759
};
5860

5961
#[cfg(feature = "amd-sev")]
@@ -68,6 +70,8 @@ pub enum Error {
6870
#[cfg(target_arch = "x86_64")]
6971
/// A call to cpuid instruction failed.
7072
CpuId(cpuid::Error),
73+
/// Unable to create a KVM guest_memfd.
74+
CreateGuestMemfd(kvm_ioctls::Error),
7175
#[cfg(target_arch = "x86_64")]
7276
/// Error configuring the floating point related registers
7377
FPUConfiguration(arch::x86_64::regs::Error),
@@ -104,16 +108,12 @@ pub enum Error {
104108
#[cfg(target_arch = "x86_64")]
105109
/// Error configuring the general purpose registers
106110
REGSConfiguration(arch::x86_64::regs::Error),
111+
/// Cannot set memory region attributes.
112+
SetMemoryAttributes(kvm_ioctls::Error),
107113
/// Cannot set the memory regions.
108114
SetUserMemoryRegion(kvm_ioctls::Error),
109115
/// Error creating memory map for SHM region.
110116
ShmMmap(io::Error),
111-
#[cfg(feature = "tee")]
112-
/// Cannot set the memory regions.
113-
SetUserMemoryRegion2(kvm_ioctls::Error),
114-
#[cfg(feature = "tee")]
115-
/// Cannot create guest memfd.
116-
CreateGuestMemfd(kvm_ioctls::Error),
117117
#[cfg(feature = "amd-sev")]
118118
/// Error initializing the Secure Virtualization Backend (SNP).
119119
SnpSecVirtInit(SnpError),
@@ -239,6 +239,7 @@ impl Display for Error {
239239
match self {
240240
#[cfg(target_arch = "x86_64")]
241241
CpuId(e) => write!(f, "Cpuid error: {e:?}"),
242+
CreateGuestMemfd(e) => write!(f, "Unable to create KVM guest_memfd: {e:?}"),
242243
GuestMemoryMmap(e) => write!(f, "Guest memory error: {e:?}"),
243244
#[cfg(target_arch = "x86_64")]
244245
GuestMSRs(e) => write!(f, "Retrieving supported guest MSRs fails: {e:?}"),
@@ -263,13 +264,10 @@ impl Display for Error {
263264
f,
264265
"Cannot set the local interruption due to bad configuration: {e:?}"
265266
),
267+
SetMemoryAttributes(e) => write!(f, "Cannot set memory region attributes: {e}"),
266268
SetUserMemoryRegion(e) => write!(f, "Cannot set the memory regions: {e}"),
267269
ShmMmap(e) => write!(f, "Error creating memory map for SHM region: {e}"),
268270
#[cfg(feature = "tee")]
269-
SetUserMemoryRegion2(e) => write!(f, "Cannot set the memory regions: {e}"),
270-
#[cfg(feature = "tee")]
271-
CreateGuestMemfd(e) => write!(f, "Cannot create guest memfd: {e}"),
272-
#[cfg(feature = "tee")]
273271
SnpSecVirtInit(e) => write!(
274272
f,
275273
"Error initializing the Secure Virtualization Backend (SEV): {e:?}"
@@ -393,7 +391,6 @@ pub struct KvmContext {
393391

394392
impl KvmContext {
395393
pub fn new() -> Result<Self> {
396-
use kvm_ioctls::Cap::*;
397394
let kvm = Kvm::new().expect("Error creating the Kvm object");
398395

399396
// Check that KVM has the correct version.
@@ -520,80 +517,14 @@ impl Vm {
520517
pub fn memory_init(
521518
&mut self,
522519
guest_mem: &GuestMemoryMmap,
523-
#[cfg(feature = "tee")] guest_memfd: &mut Vec<RawFd>,
524520
kvm_max_memslots: usize,
525521
) -> Result<()> {
526522
if guest_mem.num_regions() > kvm_max_memslots {
527523
return Err(Error::NotEnoughMemorySlots);
528524
}
529-
for region in guest_mem.iter() {
530-
// It's safe to unwrap because the guest address is valid.
531-
let host_addr = guest_mem.get_host_address(region.start_addr()).unwrap();
532-
info!("Guest memory starts at {:x?}", host_addr);
533525

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

599530
#[cfg(target_arch = "x86_64")]
@@ -604,6 +535,76 @@ impl Vm {
604535
Ok(())
605536
}
606537

538+
fn memory_region_set(
539+
&mut self,
540+
guest_mem: &GuestMemoryMmap,
541+
region: &GuestRegionMmap,
542+
) -> Result<()> {
543+
let host_addr = guest_mem.get_host_address(region.start_addr()).unwrap();
544+
if !self.fd.check_extension(GuestMemfd) {
545+
let memory_region = kvm_userspace_memory_region {
546+
slot: self.next_mem_slot,
547+
guest_phys_addr: region.start_addr().raw_value(),
548+
memory_size: region.len(),
549+
userspace_addr: host_addr as u64,
550+
flags: 0,
551+
};
552+
553+
// Safe because we mapped the memory region, we made sure that the regions
554+
// are not overlapping.
555+
unsafe {
556+
self.fd
557+
.set_user_memory_region(memory_region)
558+
.map_err(Error::SetUserMemoryRegion)?;
559+
};
560+
} else {
561+
// Create a guest_memfd and set the region.
562+
let guest_memfd = self
563+
.fd
564+
.create_guest_memfd(kvm_create_guest_memfd {
565+
size: region.size() as u64,
566+
flags: 0,
567+
reserved: [0; 6],
568+
})
569+
.map_err(Error::CreateGuestMemfd)?;
570+
571+
let memory_region = kvm_userspace_memory_region2 {
572+
slot: self.next_mem_slot,
573+
flags: KVM_MEM_GUEST_MEMFD,
574+
guest_phys_addr: region.start_addr().raw_value(),
575+
memory_size: region.len(),
576+
userspace_addr: host_addr as u64,
577+
guest_memfd_offset: 0,
578+
guest_memfd: guest_memfd as u32,
579+
pad1: 0,
580+
pad2: [0; 14],
581+
};
582+
583+
// Safe because we mapped the memory region, we made sure that the regions
584+
// are not overlapping.
585+
unsafe {
586+
self.fd
587+
.set_user_memory_region2(memory_region)
588+
.map_err(Error::SetUserMemoryRegion)?;
589+
};
590+
591+
let attr = kvm_memory_attributes {
592+
address: region.start_addr().raw_value(),
593+
size: region.len(),
594+
attributes: KVM_MEMORY_ATTRIBUTE_PRIVATE as u64,
595+
flags: 0,
596+
};
597+
598+
self.fd
599+
.set_memory_attributes(attr)
600+
.map_err(Error::SetMemoryAttributes)?;
601+
}
602+
603+
self.next_mem_slot += 1;
604+
605+
Ok(())
606+
}
607+
607608
#[cfg(feature = "amd-sev")]
608609
pub fn snp_secure_virt_prepare(
609610
&self,

0 commit comments

Comments
 (0)