@@ -10,6 +10,7 @@ use libc::{c_int, c_void, siginfo_t};
1010use std:: cell:: Cell ;
1111use std:: fmt:: { Display , Formatter } ;
1212use std:: io;
13+ use std:: os:: fd:: RawFd ;
1314
1415#[ cfg( feature = "tee" ) ]
1516use std:: os:: unix:: io:: RawFd ;
@@ -46,7 +47,10 @@ use kvm_bindings::{
4647 Msrs , KVM_CLOCK_TSC_STABLE , KVM_IRQCHIP_IOAPIC , KVM_IRQCHIP_PIC_MASTER , KVM_IRQCHIP_PIC_SLAVE ,
4748 KVM_MAX_CPUID_ENTRIES , KVM_PIT_SPEAKER_DUMMY ,
4849} ;
49- use kvm_bindings:: { kvm_userspace_memory_region, KVM_API_VERSION } ;
50+ use kvm_bindings:: {
51+ kvm_create_guest_memfd, kvm_userspace_memory_region, kvm_userspace_memory_region2,
52+ KVM_API_VERSION , KVM_MEM_GUEST_MEMFD ,
53+ } ;
5054use kvm_ioctls:: * ;
5155use utils:: eventfd:: EventFd ;
5256use utils:: signal:: { register_signal_handler, sigrtmin, Killable } ;
@@ -111,6 +115,10 @@ pub enum Error {
111115 SetupGIC ( arch:: aarch64:: gic:: Error ) ,
112116 /// Cannot set the memory regions.
113117 SetUserMemoryRegion ( kvm_ioctls:: Error ) ,
118+ /// Cannot set the memory regions.
119+ SetUserMemoryRegion2 ( kvm_ioctls:: Error ) ,
120+ // Cannot create guest memfd.
121+ CreateGuestMemfd ( kvm_ioctls:: Error ) ,
114122 #[ cfg( feature = "amd-sev" ) ]
115123 /// Error initializing the Secure Virtualization Backend (SEV).
116124 SevSecVirtInit ( SevError ) ,
@@ -270,6 +278,8 @@ impl Display for Error {
270278 "Cannot set the local interruption due to bad configuration: {e:?}"
271279 ) ,
272280 SetUserMemoryRegion ( e) => write ! ( f, "Cannot set the memory regions: {e}" ) ,
281+ SetUserMemoryRegion2 ( e) => write ! ( f, "Cannot set the memory regions: {e}" ) ,
282+ CreateGuestMemfd ( e) => write ! ( f, "Cannot create guest memfd: {e}" ) ,
273283 #[ cfg( feature = "tee" ) ]
274284 SevSecVirtInit ( e) => {
275285 write ! (
@@ -549,6 +559,7 @@ impl Vm {
549559 & mut self ,
550560 guest_mem : & GuestMemoryMmap ,
551561 kvm_max_memslots : usize ,
562+ require_guest_memfd : bool ,
552563 ) -> Result < ( ) > {
553564 if guest_mem. num_regions ( ) > kvm_max_memslots {
554565 return Err ( Error :: NotEnoughMemorySlots ) ;
@@ -557,19 +568,53 @@ impl Vm {
557568 // It's safe to unwrap because the guest address is valid.
558569 let host_addr = guest_mem. get_host_address ( region. start_addr ( ) ) . unwrap ( ) ;
559570 info ! ( "Guest memory starts at {:x?}" , host_addr) ;
560- let memory_region = kvm_userspace_memory_region {
561- slot : index as u32 ,
562- guest_phys_addr : region. start_addr ( ) . raw_value ( ) ,
563- memory_size : region. len ( ) ,
564- userspace_addr : host_addr as u64 ,
565- flags : 0 ,
566- } ;
567- // Safe because we mapped the memory region, we made sure that the regions
568- // are not overlapping.
569- unsafe {
570- self . fd
571- . set_user_memory_region ( memory_region)
572- . map_err ( Error :: SetUserMemoryRegion ) ?;
571+
572+ if require_guest_memfd {
573+ let gmem = kvm_create_guest_memfd {
574+ size : region. len ( ) ,
575+ flags : 0 ,
576+ reserved : [ 0 ; 6 ] ,
577+ } ;
578+
579+ let id: RawFd = self
580+ . fd
581+ . create_guest_memfd ( gmem)
582+ . map_err ( Error :: CreateGuestMemfd ) ?;
583+
584+ let memory_region = kvm_userspace_memory_region2 {
585+ slot : index as u32 ,
586+ flags : KVM_MEM_GUEST_MEMFD ,
587+ guest_phys_addr : region. start_addr ( ) . raw_value ( ) ,
588+ memory_size : region. len ( ) ,
589+ userspace_addr : host_addr as u64 ,
590+ guest_memfd_offset : 0 ,
591+ guest_memfd : id as u32 ,
592+ pad1 : 0 ,
593+ pad2 : [ 0 ; 14 ] ,
594+ } ;
595+
596+ // Safe because we mapped the memory region, we made sure that the regions
597+ // are not overlapping.
598+ unsafe {
599+ self . fd
600+ . set_user_memory_region2 ( memory_region)
601+ . map_err ( Error :: SetUserMemoryRegion2 ) ?;
602+ } ;
603+ } else {
604+ let memory_region = kvm_userspace_memory_region {
605+ slot : index as u32 ,
606+ guest_phys_addr : region. start_addr ( ) . raw_value ( ) ,
607+ memory_size : region. len ( ) ,
608+ userspace_addr : host_addr as u64 ,
609+ flags : 0 ,
610+ } ;
611+ // Safe because we mapped the memory region, we made sure that the regions
612+ // are not overlapping.
613+ unsafe {
614+ self . fd
615+ . set_user_memory_region ( memory_region)
616+ . map_err ( Error :: SetUserMemoryRegion ) ?;
617+ } ;
573618 } ;
574619 }
575620
@@ -1505,7 +1550,7 @@ mod tests {
15051550 let kvm = KvmContext :: new ( ) . unwrap ( ) ;
15061551 let gm = GuestMemoryMmap :: from_ranges ( & [ ( GuestAddress ( 0 ) , mem_size) ] ) . unwrap ( ) ;
15071552 let mut vm = Vm :: new ( kvm. fd ( ) ) . expect ( "Cannot create new vm" ) ;
1508- assert ! ( vm. memory_init( & gm, kvm. max_memslots( ) ) . is_ok( ) ) ;
1553+ assert ! ( vm. memory_init( & gm, kvm. max_memslots( ) , false ) . is_ok( ) ) ;
15091554
15101555 let exit_evt = EventFd :: new ( utils:: eventfd:: EFD_NONBLOCK ) . unwrap ( ) ;
15111556
@@ -1560,7 +1605,7 @@ mod tests {
15601605
15611606 // Create valid memory region and test that the initialization is successful.
15621607 let gm = GuestMemoryMmap :: from_ranges ( & [ ( GuestAddress ( 0 ) , 0x1000 ) ] ) . unwrap ( ) ;
1563- assert ! ( vm. memory_init( & gm, kvm_context. max_memslots( ) ) . is_ok( ) ) ;
1608+ assert ! ( vm. memory_init( & gm, kvm_context. max_memslots( ) , false ) . is_ok( ) ) ;
15641609
15651610 // Set the maximum number of memory slots to 1 in KvmContext to check the error
15661611 // path of memory_init. Create 2 non-overlapping memory slots.
@@ -1570,7 +1615,7 @@ mod tests {
15701615 ( GuestAddress ( 0x1001 ) , 0x2000 ) ,
15711616 ] )
15721617 . unwrap ( ) ;
1573- assert ! ( vm. memory_init( & gm, kvm_context. max_memslots( ) ) . is_err( ) ) ;
1618+ assert ! ( vm. memory_init( & gm, kvm_context. max_memslots( ) , false ) . is_err( ) ) ;
15741619 }
15751620
15761621 #[ cfg( target_arch = "x86_64" ) ]
@@ -1651,7 +1696,7 @@ mod tests {
16511696 let kvm = KvmContext :: new ( ) . unwrap ( ) ;
16521697 let gm = GuestMemoryMmap :: from_ranges ( & [ ( GuestAddress ( 0 ) , 0x10000 ) ] ) . unwrap ( ) ;
16531698 let mut vm = Vm :: new ( kvm. fd ( ) ) . expect ( "new vm failed" ) ;
1654- assert ! ( vm. memory_init( & gm, kvm. max_memslots( ) ) . is_ok( ) ) ;
1699+ assert ! ( vm. memory_init( & gm, kvm. max_memslots( ) , false ) . is_ok( ) ) ;
16551700
16561701 // Try it for when vcpu id is 0.
16571702 let mut vcpu = Vcpu :: new_aarch64 (
0 commit comments