@@ -21,7 +21,7 @@ use std::sync::Arc;
2121use std:: sync:: Mutex ;
2222use std:: sync:: atomic:: { AtomicBool , AtomicU64 , Ordering } ;
2323
24- use kvm_bindings:: { KVM_MEM_READONLY , kvm_fpu, kvm_regs, kvm_userspace_memory_region} ;
24+ use kvm_bindings:: { kvm_fpu, kvm_regs, kvm_userspace_memory_region} ;
2525use kvm_ioctls:: Cap :: UserMemory ;
2626use kvm_ioctls:: { Kvm , VcpuExit , VcpuFd , VmFd } ;
2727use log:: LevelFilter ;
@@ -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,9 @@ 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 mut kvm_region: kvm_userspace_memory_region = region. clone ( ) . into ( ) ;
323+ kvm_region. slot = i as u32 ;
335324 unsafe { vm_fd. set_user_memory_region ( kvm_region) }
336325 } ) ?;
337326
@@ -378,7 +367,8 @@ impl KVMDriver {
378367 #[ allow( unused_mut) ]
379368 let mut hv = Self {
380369 _kvm : kvm,
381- _vm_fd : vm_fd,
370+ vm_fd,
371+ page_size : 0 ,
382372 vcpu_fd,
383373 entrypoint,
384374 orig_rsp : rsp_gp,
@@ -463,6 +453,8 @@ impl Hypervisor for KVMDriver {
463453 max_guest_log_level : Option < LevelFilter > ,
464454 #[ cfg( gdb) ] dbg_mem_access_fn : DbgMemAccessHandlerWrapper ,
465455 ) -> Result < ( ) > {
456+ self . page_size = page_size as usize ;
457+
466458 let max_guest_log_level: u64 = match max_guest_log_level {
467459 Some ( level) => level as u64 ,
468460 None => self . get_max_log_level ( ) . into ( ) ,
@@ -494,16 +486,40 @@ impl Hypervisor for KVMDriver {
494486 }
495487
496488 #[ 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" ) ;
489+ unsafe fn map_region ( & mut self , region : & MemoryRegion ) -> Result < ( ) > {
490+ if [
491+ region. guest_region . start ,
492+ region. guest_region . end ,
493+ region. host_region . start ,
494+ region. host_region . end ,
495+ ]
496+ . iter ( )
497+ . any ( |x| x % self . page_size != 0 )
498+ {
499+ log_then_return ! (
500+ "region is not page-aligned {:x}, {region:?}" ,
501+ self . page_size
502+ ) ;
503+ }
504+
505+ let mut kvm_region: kvm_userspace_memory_region = region. clone ( ) . into ( ) ;
506+ kvm_region. slot = self . mem_regions . len ( ) as u32 ;
507+ unsafe { self . vm_fd . set_user_memory_region ( kvm_region) } ?;
508+ self . mem_regions . push ( region. to_owned ( ) ) ;
509+ Ok ( ( ) )
499510 }
500511
501512 #[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
502513 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- ) ;
514+ let n_keep = self . mem_regions . len ( ) - n as usize ;
515+ for ( k, region) in self . mem_regions . split_off ( n_keep) . iter ( ) . enumerate ( ) {
516+ let mut kvm_region: kvm_userspace_memory_region = region. clone ( ) . into ( ) ;
517+ kvm_region. slot = ( n_keep + k) as u32 ;
518+ // Setting memory_size to 0 unmaps the slot's region
519+ // From https://docs.kernel.org/virt/kvm/api.html
520+ // > Deleting a slot is done by passing zero for memory_size.
521+ kvm_region. memory_size = 0 ;
522+ unsafe { self . vm_fd . set_user_memory_region ( kvm_region) } ?;
507523 }
508524 Ok ( ( ) )
509525 }
0 commit comments