@@ -284,7 +284,8 @@ mod debug {
284284/// A Hypervisor driver for KVM on Linux
285285pub ( crate ) struct KVMDriver {
286286 _kvm : Kvm ,
287- _vm_fd : VmFd ,
287+ vm_fd : VmFd ,
288+ page_size : usize ,
288289 vcpu_fd : VcpuFd ,
289290 entrypoint : u64 ,
290291 orig_rsp : GuestPtr ,
@@ -317,21 +318,8 @@ impl KVMDriver {
317318
318319 let vm_fd = kvm. create_vm_with_type ( 0 ) ?;
319320
320- let perm_flags =
321- MemoryRegionFlags :: READ | MemoryRegionFlags :: WRITE | MemoryRegionFlags :: EXECUTE ;
322-
323321 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) ;
335323 unsafe { vm_fd. set_user_memory_region ( kvm_region) }
336324 } ) ?;
337325
@@ -378,7 +366,8 @@ impl KVMDriver {
378366 #[ allow( unused_mut) ]
379367 let mut hv = Self {
380368 _kvm : kvm,
381- _vm_fd : vm_fd,
369+ vm_fd,
370+ page_size : 0 ,
382371 vcpu_fd,
383372 entrypoint,
384373 orig_rsp : rsp_gp,
@@ -463,6 +452,8 @@ impl Hypervisor for KVMDriver {
463452 max_guest_log_level : Option < LevelFilter > ,
464453 #[ cfg( gdb) ] dbg_mem_access_fn : DbgMemAccessHandlerWrapper ,
465454 ) -> Result < ( ) > {
455+ self . page_size = page_size as usize ;
456+
466457 let max_guest_log_level: u64 = match max_guest_log_level {
467458 Some ( level) => level as u64 ,
468459 None => self . get_max_log_level ( ) . into ( ) ,
@@ -494,16 +485,39 @@ impl Hypervisor for KVMDriver {
494485 }
495486
496487 #[ 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 ( ( ) )
499509 }
500510
501511 #[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
502512 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) } ?;
507521 }
508522 Ok ( ( ) )
509523 }
@@ -938,3 +952,21 @@ impl Drop for KVMDriver {
938952 self . interrupt_handle . dropped . store ( true , Ordering :: Relaxed ) ;
939953 }
940954}
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