@@ -10,6 +10,7 @@ use libc::{c_int, c_void, siginfo_t};
10
10
use std:: cell:: Cell ;
11
11
use std:: fmt:: { Display , Formatter } ;
12
12
use std:: io;
13
+ use std:: os:: fd:: RawFd ;
13
14
14
15
#[ cfg( feature = "tee" ) ]
15
16
use std:: os:: unix:: io:: RawFd ;
@@ -45,7 +46,10 @@ use kvm_bindings::{
45
46
Msrs , KVM_CLOCK_TSC_STABLE , KVM_IRQCHIP_IOAPIC , KVM_IRQCHIP_PIC_MASTER , KVM_IRQCHIP_PIC_SLAVE ,
46
47
KVM_MAX_CPUID_ENTRIES , KVM_PIT_SPEAKER_DUMMY ,
47
48
} ;
48
- use kvm_bindings:: { kvm_userspace_memory_region, KVM_API_VERSION } ;
49
+ use kvm_bindings:: {
50
+ kvm_create_guest_memfd, kvm_userspace_memory_region, kvm_userspace_memory_region2,
51
+ KVM_API_VERSION , KVM_MEM_GUEST_MEMFD ,
52
+ } ;
49
53
use kvm_ioctls:: * ;
50
54
use utils:: eventfd:: EventFd ;
51
55
use utils:: signal:: { register_signal_handler, sigrtmin, Killable } ;
@@ -112,6 +116,10 @@ pub enum Error {
112
116
SetUserMemoryRegion ( kvm_ioctls:: Error ) ,
113
117
/// Error creating memory map for SHM region.
114
118
ShmMmap ( io:: Error ) ,
119
+ /// Cannot set the memory regions.
120
+ SetUserMemoryRegion2 ( kvm_ioctls:: Error ) ,
121
+ /// Cannot create guest memfd.
122
+ CreateGuestMemfd ( kvm_ioctls:: Error ) ,
115
123
#[ cfg( feature = "amd-sev" ) ]
116
124
/// Error initializing the Secure Virtualization Backend (SEV).
117
125
SevSecVirtInit ( SevError ) ,
@@ -272,6 +280,8 @@ impl Display for Error {
272
280
) ,
273
281
SetUserMemoryRegion ( e) => write ! ( f, "Cannot set the memory regions: {e}" ) ,
274
282
ShmMmap ( e) => write ! ( f, "Error creating memory map for SHM region: {e}" ) ,
283
+ SetUserMemoryRegion2 ( e) => write ! ( f, "Cannot set the memory regions: {e}" ) ,
284
+ CreateGuestMemfd ( e) => write ! ( f, "Cannot create guest memfd: {e}" ) ,
275
285
#[ cfg( feature = "tee" ) ]
276
286
SevSecVirtInit ( e) => {
277
287
write ! (
@@ -554,27 +564,62 @@ impl Vm {
554
564
& mut self ,
555
565
guest_mem : & GuestMemoryMmap ,
556
566
kvm_max_memslots : usize ,
567
+ require_guest_memfd : bool ,
557
568
) -> Result < ( ) > {
558
569
if guest_mem. num_regions ( ) > kvm_max_memslots {
559
570
return Err ( Error :: NotEnoughMemorySlots ) ;
560
571
}
561
572
for region in guest_mem. iter ( ) {
562
573
// It's safe to unwrap because the guest address is valid.
563
574
let host_addr = guest_mem. get_host_address ( region. start_addr ( ) ) . unwrap ( ) ;
564
- debug ! ( "Guest memory starts at {:x?}" , host_addr) ;
565
- let memory_region = kvm_userspace_memory_region {
566
- slot : self . next_mem_slot ,
567
- guest_phys_addr : region. start_addr ( ) . raw_value ( ) ,
568
- memory_size : region. len ( ) ,
569
- userspace_addr : host_addr as u64 ,
570
- flags : 0 ,
571
- } ;
572
- // Safe because we mapped the memory region, we made sure that the regions
573
- // are not overlapping.
574
- unsafe {
575
- self . fd
576
- . set_user_memory_region ( memory_region)
577
- . map_err ( Error :: SetUserMemoryRegion ) ?;
575
+ info ! ( "Guest memory starts at {:x?}" , host_addr) ;
576
+
577
+ if require_guest_memfd {
578
+ let gmem = kvm_create_guest_memfd {
579
+ size : region. len ( ) ,
580
+ flags : 0 ,
581
+ reserved : [ 0 ; 6 ] ,
582
+ } ;
583
+
584
+ let id: RawFd = self
585
+ . fd
586
+ . create_guest_memfd ( gmem)
587
+ . map_err ( Error :: CreateGuestMemfd ) ?;
588
+
589
+ let memory_region = kvm_userspace_memory_region2 {
590
+ slot : self . next_mem_slot as u32 ,
591
+ flags : KVM_MEM_GUEST_MEMFD ,
592
+ guest_phys_addr : region. start_addr ( ) . raw_value ( ) ,
593
+ memory_size : region. len ( ) ,
594
+ userspace_addr : host_addr as u64 ,
595
+ guest_memfd_offset : 0 ,
596
+ guest_memfd : id as u32 ,
597
+ pad1 : 0 ,
598
+ pad2 : [ 0 ; 14 ] ,
599
+ } ;
600
+
601
+ // Safe because we mapped the memory region, we made sure that the regions
602
+ // are not overlapping.
603
+ unsafe {
604
+ self . fd
605
+ . set_user_memory_region2 ( memory_region)
606
+ . map_err ( Error :: SetUserMemoryRegion2 ) ?;
607
+ } ;
608
+ } else {
609
+ let memory_region = kvm_userspace_memory_region {
610
+ slot : self . next_mem_slot as u32 ,
611
+ guest_phys_addr : region. start_addr ( ) . raw_value ( ) ,
612
+ memory_size : region. len ( ) ,
613
+ userspace_addr : host_addr as u64 ,
614
+ flags : 0 ,
615
+ } ;
616
+ // Safe because we mapped the memory region, we made sure that the regions
617
+ // are not overlapping.
618
+ unsafe {
619
+ self . fd
620
+ . set_user_memory_region ( memory_region)
621
+ . map_err ( Error :: SetUserMemoryRegion ) ?;
622
+ } ;
578
623
} ;
579
624
self . next_mem_slot += 1 ;
580
625
}
@@ -1510,7 +1555,7 @@ mod tests {
1510
1555
let kvm = KvmContext :: new ( ) . unwrap ( ) ;
1511
1556
let gm = GuestMemoryMmap :: from_ranges ( & [ ( GuestAddress ( 0 ) , mem_size) ] ) . unwrap ( ) ;
1512
1557
let mut vm = Vm :: new ( kvm. fd ( ) ) . expect ( "Cannot create new vm" ) ;
1513
- assert ! ( vm. memory_init( & gm, kvm. max_memslots( ) ) . is_ok( ) ) ;
1558
+ assert ! ( vm. memory_init( & gm, kvm. max_memslots( ) , false ) . is_ok( ) ) ;
1514
1559
1515
1560
let exit_evt = EventFd :: new ( utils:: eventfd:: EFD_NONBLOCK ) . unwrap ( ) ;
1516
1561
@@ -1565,7 +1610,7 @@ mod tests {
1565
1610
1566
1611
// Create valid memory region and test that the initialization is successful.
1567
1612
let gm = GuestMemoryMmap :: from_ranges ( & [ ( GuestAddress ( 0 ) , 0x1000 ) ] ) . unwrap ( ) ;
1568
- assert ! ( vm. memory_init( & gm, kvm_context. max_memslots( ) ) . is_ok( ) ) ;
1613
+ assert ! ( vm. memory_init( & gm, kvm_context. max_memslots( ) , false ) . is_ok( ) ) ;
1569
1614
1570
1615
// Set the maximum number of memory slots to 1 in KvmContext to check the error
1571
1616
// path of memory_init. Create 2 non-overlapping memory slots.
@@ -1575,7 +1620,7 @@ mod tests {
1575
1620
( GuestAddress ( 0x1001 ) , 0x2000 ) ,
1576
1621
] )
1577
1622
. unwrap ( ) ;
1578
- assert ! ( vm. memory_init( & gm, kvm_context. max_memslots( ) ) . is_err( ) ) ;
1623
+ assert ! ( vm. memory_init( & gm, kvm_context. max_memslots( ) , false ) . is_err( ) ) ;
1579
1624
}
1580
1625
1581
1626
#[ cfg( target_arch = "x86_64" ) ]
@@ -1656,7 +1701,7 @@ mod tests {
1656
1701
let kvm = KvmContext :: new ( ) . unwrap ( ) ;
1657
1702
let gm = GuestMemoryMmap :: from_ranges ( & [ ( GuestAddress ( 0 ) , 0x10000 ) ] ) . unwrap ( ) ;
1658
1703
let mut vm = Vm :: new ( kvm. fd ( ) ) . expect ( "new vm failed" ) ;
1659
- assert ! ( vm. memory_init( & gm, kvm. max_memslots( ) ) . is_ok( ) ) ;
1704
+ assert ! ( vm. memory_init( & gm, kvm. max_memslots( ) , false ) . is_ok( ) ) ;
1660
1705
1661
1706
// Try it for when vcpu id is 0.
1662
1707
let mut vcpu = Vcpu :: new_aarch64 (
0 commit comments