88#[ cfg( target_arch = "x86_64" ) ]
99use std:: fmt;
1010
11- use kvm_bindings:: { KVM_MEM_LOG_DIRTY_PAGES , kvm_userspace_memory_region} ;
12- use kvm_ioctls:: VmFd ;
13- use serde:: { Deserialize , Serialize } ;
14- use vmm_sys_util:: eventfd:: EventFd ;
15-
16- use crate :: arch:: host_page_size;
17- pub use crate :: arch:: { ArchVm as Vm , ArchVmError , VmState } ;
18- use crate :: logger:: info;
19- use crate :: persist:: { CreateSnapshotError , VmInfo } ;
20- use crate :: utils:: u64_to_usize;
21- use crate :: vmm_config:: snapshot:: SnapshotType ;
22- use crate :: vstate:: memory:: {
23- Address , GuestMemory , GuestMemoryExtension , GuestMemoryMmap , GuestMemoryRegion , GuestRegionMmap ,
11+ use kvm_bindings:: {
12+ kvm_clock_data, kvm_irqchip, kvm_pit_config, kvm_pit_state2, kvm_userspace_memory_region,
13+ CpuId , MsrList , KVM_API_VERSION , KVM_CLOCK_TSC_STABLE , KVM_IRQCHIP_IOAPIC ,
14+ KVM_IRQCHIP_PIC_MASTER , KVM_IRQCHIP_PIC_SLAVE , KVM_MAX_CPUID_ENTRIES , KVM_MEM_LOG_DIRTY_PAGES ,
15+ KVM_PIT_SPEAKER_DUMMY ,
2416} ;
25- use kvm_bindings:: { kvm_userspace_memory_region, KVM_API_VERSION , KVM_MEM_LOG_DIRTY_PAGES } ;
2617use kvm_ioctls:: { Kvm , VmFd } ;
2718use serde:: { Deserialize , Serialize } ;
2819
@@ -31,9 +22,16 @@ use crate::arch::aarch64::gic::GICDevice;
3122#[ cfg( target_arch = "aarch64" ) ]
3223use crate :: arch:: aarch64:: gic:: GicState ;
3324use crate :: cpu_config:: templates:: KvmCapability ;
34- # [ cfg ( target_arch = "x86_64" ) ]
35- use crate :: utils:: u64_to_usize;
25+ use crate :: persist :: VmInfo ;
26+ use crate :: utils:: { get_page_size , u64_to_usize} ;
3627use crate :: vstate:: memory:: { Address , GuestMemory , GuestMemoryMmap , GuestMemoryRegion } ;
28+ use crate :: GuestMemoryRegionMapping ;
29+
30+ /// Get the host page size in bytes.
31+ /// This should always succeed on a valid system.
32+ fn host_page_size ( ) -> usize {
33+ get_page_size ( ) . expect ( "Failed to get system page size" )
34+ }
3735
3836/// Errors associated with the wrappers over KVM ioctls.
3937/// Needs `rustfmt::skip` to make multiline comments work
@@ -85,6 +83,8 @@ pub enum VmError {
8583 #[ cfg( target_arch = "aarch64" ) ]
8684 /// Failed to restore the VM's GIC state: {0}
8785 RestoreGic ( crate :: arch:: aarch64:: gic:: GicError ) ,
86+ /// Invalid memory configuration: {0}
87+ InvalidMemoryConfiguration ( String ) ,
8888}
8989
9090/// Error type for [`Vm::restore_state`]
@@ -265,50 +265,35 @@ impl Vm {
265265 pub fn fd ( & self ) -> & VmFd {
266266 & self . fd
267267 }
268- }
269-
270- #[ cfg( target_arch = "aarch64" ) ]
271- impl Vm {
272- const DEFAULT_CAPABILITIES : [ u32 ; 7 ] = [
273- kvm_bindings:: KVM_CAP_IOEVENTFD ,
274- kvm_bindings:: KVM_CAP_IRQFD ,
275- kvm_bindings:: KVM_CAP_USER_MEMORY ,
276- kvm_bindings:: KVM_CAP_ARM_PSCI_0_2 ,
277- kvm_bindings:: KVM_CAP_DEVICE_CTRL ,
278- kvm_bindings:: KVM_CAP_MP_STATE ,
279- kvm_bindings:: KVM_CAP_ONE_REG ,
280- ] ;
281268
282- /// Creates the GIC (Global Interrupt Controller).
283- pub fn setup_irqchip ( & mut self , vcpu_count : u8 ) -> Result < ( ) , VmError > {
284- self . irqchip_handle = Some (
285- crate :: arch:: aarch64:: gic:: create_gic ( & self . fd , vcpu_count. into ( ) , None )
286- . map_err ( VmError :: VmCreateGIC ) ?,
287- ) ;
288- Ok ( ( ) )
289- }
290-
291- /// Gets a reference to the irqchip of the VM.
292- pub fn get_irqchip ( & self ) -> & GICDevice {
293- self . irqchip_handle . as_ref ( ) . expect ( "IRQ chip not set" )
294- }
295-
296- /// Saves and returns the Kvm Vm state.
297- pub fn save_state ( & self , mpidrs : & [ u64 ] ) -> Result < VmState , VmError > {
298- Ok ( VmState {
299- gic : self
300- . get_irqchip ( )
301- . save_device ( mpidrs)
302- . map_err ( VmError :: SaveGic ) ?,
303- kvm_cap_modifiers : self . kvm_cap_modifiers . clone ( ) ,
304- } )
269+ /// Returns the memory mappings for the guest memory.
270+ pub fn guest_memory_mappings (
271+ guest_memory : & GuestMemoryMmap ,
272+ vm_info : & VmInfo ,
273+ ) -> Vec < GuestMemoryRegionMapping > {
274+ let mut offset = 0 ;
275+ let mut mappings = Vec :: new ( ) ;
276+ for mem_region in guest_memory. iter ( ) {
277+ mappings. push ( GuestMemoryRegionMapping {
278+ base_host_virt_addr : mem_region. as_ptr ( ) as u64 ,
279+ size : mem_region. size ( ) ,
280+ offset,
281+ page_size : vm_info. huge_pages . page_size_kib ( ) ,
282+ } ) ;
283+ offset += mem_region. size ( ) as u64 ;
284+ }
285+ mappings
305286 }
306287
307288 /// Gets the memory info (resident and empty pages) for all memory regions.
308289 /// Returns two bitmaps: resident (all resident pages) and empty (zero pages, subset of resident).
309290 /// This checks at the pageSize of each region and requires all regions to have the same page size.
310- pub fn get_memory_info ( & self , vm_info : & VmInfo ) -> Result < ( Vec < u64 > , Vec < u64 > ) , VmError > {
311- let mappings = self . guest_memory_mappings ( vm_info) ;
291+ pub fn get_memory_info (
292+ & self ,
293+ guest_memory : & GuestMemoryMmap ,
294+ vm_info : & VmInfo ,
295+ ) -> Result < ( Vec < u64 > , Vec < u64 > ) , VmError > {
296+ let mappings = Self :: guest_memory_mappings ( guest_memory, vm_info) ;
312297
313298 if mappings. is_empty ( ) {
314299 return Ok ( ( Vec :: new ( ) , Vec :: new ( ) ) ) ;
@@ -338,8 +323,7 @@ impl Vm {
338323
339324 for mapping in & mappings {
340325 // Find the memory region that matches this mapping
341- let mem_region = self
342- . guest_memory ( )
326+ let mem_region = guest_memory
343327 . iter ( )
344328 . find ( |region| region. as_ptr ( ) as u64 == mapping. base_host_virt_addr )
345329 . expect ( "Memory region not found for mapping" ) ;
@@ -410,21 +394,60 @@ impl Vm {
410394
411395 Ok ( ( resident_bitmap, empty_bitmap) )
412396 }
397+ }
398+
399+ #[ cfg( target_arch = "aarch64" ) ]
400+ impl Vm {
401+ const DEFAULT_CAPABILITIES : [ u32 ; 7 ] = [
402+ kvm_bindings:: KVM_CAP_IOEVENTFD ,
403+ kvm_bindings:: KVM_CAP_IRQFD ,
404+ kvm_bindings:: KVM_CAP_USER_MEMORY ,
405+ kvm_bindings:: KVM_CAP_ARM_PSCI_0_2 ,
406+ kvm_bindings:: KVM_CAP_DEVICE_CTRL ,
407+ kvm_bindings:: KVM_CAP_MP_STATE ,
408+ kvm_bindings:: KVM_CAP_ONE_REG ,
409+ ] ;
410+
411+ /// Creates the GIC (Global Interrupt Controller).
412+ pub fn setup_irqchip ( & mut self , vcpu_count : u8 ) -> Result < ( ) , VmError > {
413+ self . irqchip_handle = Some (
414+ crate :: arch:: aarch64:: gic:: create_gic ( & self . fd , vcpu_count. into ( ) , None )
415+ . map_err ( VmError :: VmCreateGIC ) ?,
416+ ) ;
417+ Ok ( ( ) )
418+ }
419+
420+ /// Gets a reference to the irqchip of the VM.
421+ pub fn get_irqchip ( & self ) -> & GICDevice {
422+ self . irqchip_handle . as_ref ( ) . expect ( "IRQ chip not set" )
423+ }
424+
425+ /// Saves and returns the Kvm Vm state.
426+ pub fn save_state ( & self , mpidrs : & [ u64 ] ) -> Result < VmState , VmError > {
427+ Ok ( VmState {
428+ gic : self
429+ . get_irqchip ( )
430+ . save_device ( mpidrs)
431+ . map_err ( VmError :: SaveGic ) ?,
432+ kvm_cap_modifiers : self . kvm_cap_modifiers . clone ( ) ,
433+ } )
434+ }
413435
414436 /// Resets the KVM dirty bitmap for each of the guest's memory regions.
415- pub fn reset_dirty_bitmap ( & self ) {
416- self . guest_memory ( )
417- . iter ( )
418- . zip ( 0u32 ..)
419- . for_each ( |( region, slot) | {
420- let _ = self . fd ( ) . get_dirty_log ( slot, u64_to_usize ( region. len ( ) ) ) ;
421- } ) ;
437+ pub fn reset_dirty_bitmap ( & self , guest_memory : & GuestMemoryMmap ) {
438+ guest_memory. iter ( ) . zip ( 0u32 ..) . for_each ( |( region, slot) | {
439+ let _ = self . fd ( ) . get_dirty_log ( slot, u64_to_usize ( region. len ( ) ) ) ;
440+ } ) ;
422441 }
423442
424443 /// Retrieves the KVM dirty bitmap for each of the guest's memory regions.
425- pub fn get_dirty_bitmap ( & self ) -> Result < DirtyBitmap , vmm_sys_util:: errno:: Error > {
426- let mut bitmap: DirtyBitmap = HashMap :: new ( ) ;
427- self . guest_memory ( )
444+ pub fn get_dirty_bitmap (
445+ & self ,
446+ guest_memory : & GuestMemoryMmap ,
447+ ) -> Result < crate :: DirtyBitmap , vmm_sys_util:: errno:: Error > {
448+ use std:: collections:: HashMap ;
449+ let mut bitmap: crate :: DirtyBitmap = HashMap :: new ( ) ;
450+ guest_memory
428451 . iter ( )
429452 . zip ( 0u32 ..)
430453 . try_for_each ( |( region, slot) | {
0 commit comments