@@ -284,7 +284,8 @@ mod debug {
284
284
/// A Hypervisor driver for KVM on Linux
285
285
pub ( crate ) struct KVMDriver {
286
286
_kvm : Kvm ,
287
- _vm_fd : VmFd ,
287
+ vm_fd : VmFd ,
288
+ page_size : usize ,
288
289
vcpu_fd : VcpuFd ,
289
290
entrypoint : u64 ,
290
291
orig_rsp : GuestPtr ,
@@ -317,21 +318,8 @@ impl KVMDriver {
317
318
318
319
let vm_fd = kvm. create_vm_with_type ( 0 ) ?;
319
320
320
- let perm_flags =
321
- MemoryRegionFlags :: READ | MemoryRegionFlags :: WRITE | MemoryRegionFlags :: EXECUTE ;
322
-
323
321
mem_regions. iter ( ) . enumerate ( ) . try_for_each ( |( i, region) | {
324
- let perm_flags = perm_flags. intersection ( region. flags ) ;
325
- let kvm_region = kvm_userspace_memory_region {
326
- slot : i as u32 ,
327
- guest_phys_addr : region. guest_region . start as u64 ,
328
- memory_size : ( region. guest_region . end - region. guest_region . start ) as u64 ,
329
- userspace_addr : region. host_region . start as u64 ,
330
- flags : match perm_flags {
331
- MemoryRegionFlags :: READ => KVM_MEM_READONLY ,
332
- _ => 0 , // normal, RWX
333
- } ,
334
- } ;
322
+ let kvm_region = mem_region_to_kvm_region ( region, i) ;
335
323
unsafe { vm_fd. set_user_memory_region ( kvm_region) }
336
324
} ) ?;
337
325
@@ -378,7 +366,8 @@ impl KVMDriver {
378
366
#[ allow( unused_mut) ]
379
367
let mut hv = Self {
380
368
_kvm : kvm,
381
- _vm_fd : vm_fd,
369
+ vm_fd,
370
+ page_size : 0 ,
382
371
vcpu_fd,
383
372
entrypoint,
384
373
orig_rsp : rsp_gp,
@@ -463,6 +452,8 @@ impl Hypervisor for KVMDriver {
463
452
max_guest_log_level : Option < LevelFilter > ,
464
453
#[ cfg( gdb) ] dbg_mem_access_fn : DbgMemAccessHandlerWrapper ,
465
454
) -> Result < ( ) > {
455
+ self . page_size = page_size as usize ;
456
+
466
457
let max_guest_log_level: u64 = match max_guest_log_level {
467
458
Some ( level) => level as u64 ,
468
459
None => self . get_max_log_level ( ) . into ( ) ,
@@ -494,16 +485,39 @@ impl Hypervisor for KVMDriver {
494
485
}
495
486
496
487
#[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
497
- unsafe fn map_region ( & mut self , _rgn : & MemoryRegion ) -> Result < ( ) > {
498
- log_then_return ! ( "Mapping host memory into the guest not yet supported on this platform" ) ;
488
+ unsafe fn map_region ( & mut self , region : & MemoryRegion ) -> Result < ( ) > {
489
+ if [
490
+ region. guest_region . start ,
491
+ region. guest_region . end ,
492
+ region. host_region . start ,
493
+ region. host_region . end ,
494
+ ]
495
+ . iter ( )
496
+ . any ( |x| x % self . page_size != 0 )
497
+ {
498
+ log_then_return ! (
499
+ "region is not page-aligned {:x}, {region:?}" ,
500
+ self . page_size
501
+ ) ;
502
+ }
503
+
504
+ let slot = self . mem_regions . len ( ) ;
505
+ let kvm_region = mem_region_to_kvm_region ( region, slot) ;
506
+ unsafe { self . vm_fd . set_user_memory_region ( kvm_region) } ?;
507
+ self . mem_regions . push ( region. to_owned ( ) ) ;
508
+ Ok ( ( ) )
499
509
}
500
510
501
511
#[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
502
512
unsafe fn unmap_regions ( & mut self , n : u64 ) -> Result < ( ) > {
503
- if n > 0 {
504
- log_then_return ! (
505
- "Mapping host memory into the guest not yet supported on this platform"
506
- ) ;
513
+ let n_keep = self . mem_regions . len ( ) - n as usize ;
514
+ for ( k, region) in self . mem_regions . split_off ( n_keep) . iter ( ) . enumerate ( ) {
515
+ let mut kvm_region = mem_region_to_kvm_region ( region, n_keep + k) ;
516
+ // Setting memory_size to 0 unmaps the slot's region
517
+ // From https://docs.kernel.org/virt/kvm/api.html
518
+ // > Deleting a slot is done by passing zero for memory_size.
519
+ kvm_region. memory_size = 0 ;
520
+ unsafe { self . vm_fd . set_user_memory_region ( kvm_region) } ?;
507
521
}
508
522
Ok ( ( ) )
509
523
}
@@ -938,3 +952,21 @@ impl Drop for KVMDriver {
938
952
self . interrupt_handle . dropped . store ( true , Ordering :: Relaxed ) ;
939
953
}
940
954
}
955
+
956
+ fn mem_region_to_kvm_region ( region : & MemoryRegion , slot : usize ) -> kvm_userspace_memory_region {
957
+ let perm_flags =
958
+ MemoryRegionFlags :: READ | MemoryRegionFlags :: WRITE | MemoryRegionFlags :: EXECUTE ;
959
+
960
+ let perm_flags = perm_flags. intersection ( region. flags ) ;
961
+
962
+ kvm_userspace_memory_region {
963
+ slot : slot as u32 ,
964
+ guest_phys_addr : region. guest_region . start as u64 ,
965
+ memory_size : ( region. guest_region . end - region. guest_region . start ) as u64 ,
966
+ userspace_addr : region. host_region . start as u64 ,
967
+ flags : match perm_flags {
968
+ MemoryRegionFlags :: READ => KVM_MEM_READONLY ,
969
+ _ => 0 , // normal, RWX
970
+ } ,
971
+ }
972
+ }
0 commit comments