@@ -40,13 +40,18 @@ use kvm_bindings::{
40
40
KVM_CLOCK_TSC_STABLE , KVM_IRQCHIP_IOAPIC , KVM_IRQCHIP_PIC_MASTER , KVM_IRQCHIP_PIC_SLAVE ,
41
41
KVM_MAX_CPUID_ENTRIES ,
42
42
} ;
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 :: * , * } ;
45
49
use utils:: eventfd:: EventFd ;
46
50
use utils:: signal:: { register_signal_handler, sigrtmin, Killable } ;
47
51
use utils:: sm:: StateMachine ;
48
52
use vm_memory:: {
49
53
Address , GuestAddress , GuestMemory , GuestMemoryError , GuestMemoryMmap , GuestMemoryRegion ,
54
+ GuestRegionMmap ,
50
55
} ;
51
56
52
57
#[ cfg( feature = "amd-sev" ) ]
@@ -61,6 +66,8 @@ pub enum Error {
61
66
#[ cfg( target_arch = "x86_64" ) ]
62
67
/// A call to cpuid instruction failed.
63
68
CpuId ( cpuid:: Error ) ,
69
+ /// Unable to create a KVM guest_memfd.
70
+ CreateGuestMemfd ( kvm_ioctls:: Error ) ,
64
71
#[ cfg( target_arch = "x86_64" ) ]
65
72
/// Error configuring the floating point related registers
66
73
FPUConfiguration ( arch:: x86_64:: regs:: Error ) ,
@@ -97,6 +104,8 @@ pub enum Error {
97
104
#[ cfg( target_arch = "x86_64" ) ]
98
105
/// Error configuring the general purpose registers
99
106
REGSConfiguration ( arch:: x86_64:: regs:: Error ) ,
107
+ /// Cannot set memory region attributes.
108
+ SetMemoryAttributes ( kvm_ioctls:: Error ) ,
100
109
/// Cannot set the memory regions.
101
110
SetUserMemoryRegion ( kvm_ioctls:: Error ) ,
102
111
/// Error creating memory map for SHM region.
@@ -226,6 +235,7 @@ impl Display for Error {
226
235
match self {
227
236
#[ cfg( target_arch = "x86_64" ) ]
228
237
CpuId ( e) => write ! ( f, "Cpuid error: {e:?}" ) ,
238
+ CreateGuestMemfd ( e) => write ! ( f, "Unable to create KVM guest_memfd: {e:?}" ) ,
229
239
GuestMemoryMmap ( e) => write ! ( f, "Guest memory error: {e:?}" ) ,
230
240
#[ cfg( target_arch = "x86_64" ) ]
231
241
GuestMSRs ( e) => write ! ( f, "Retrieving supported guest MSRs fails: {e:?}" ) ,
@@ -250,6 +260,7 @@ impl Display for Error {
250
260
f,
251
261
"Cannot set the local interruption due to bad configuration: {e:?}"
252
262
) ,
263
+ SetMemoryAttributes ( e) => write ! ( f, "Cannot set memory region attributes: {e}" ) ,
253
264
SetUserMemoryRegion ( e) => write ! ( f, "Cannot set the memory regions: {e}" ) ,
254
265
ShmMmap ( e) => write ! ( f, "Error creating memory map for SHM region: {e}" ) ,
255
266
#[ cfg( feature = "tee" ) ]
@@ -376,7 +387,6 @@ pub struct KvmContext {
376
387
377
388
impl KvmContext {
378
389
pub fn new ( ) -> Result < Self > {
379
- use kvm_ioctls:: Cap :: * ;
380
390
let kvm = Kvm :: new ( ) . expect ( "Error creating the Kvm object" ) ;
381
391
382
392
// Check that KVM has the correct version.
@@ -508,31 +518,85 @@ impl Vm {
508
518
if guest_mem. num_regions ( ) > kvm_max_memslots {
509
519
return Err ( Error :: NotEnoughMemorySlots ) ;
510
520
}
521
+
511
522
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 ) {
515
541
let memory_region = kvm_userspace_memory_region {
516
542
slot : self . next_mem_slot ,
517
543
guest_phys_addr : region. start_addr ( ) . raw_value ( ) ,
518
544
memory_size : region. len ( ) ,
519
545
userspace_addr : host_addr as u64 ,
520
546
flags : 0 ,
521
547
} ;
548
+
522
549
// Safe because we mapped the memory region, we made sure that the regions
523
550
// are not overlapping.
524
551
unsafe {
525
552
self . fd
526
553
. set_user_memory_region ( memory_region)
527
554
. map_err ( Error :: SetUserMemoryRegion ) ?;
528
555
} ;
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 ) ?;
530
597
}
531
598
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 ;
536
600
537
601
Ok ( ( ) )
538
602
}
0 commit comments