@@ -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 :: * , * } ;
4549use utils:: eventfd:: EventFd ;
4650use utils:: signal:: { register_signal_handler, sigrtmin, Killable } ;
4751use utils:: sm:: StateMachine ;
4852use 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
377388impl 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