@@ -15,6 +15,8 @@ use linux_loader::cmdline::Cmdline as LoaderKernelCmdline;
15
15
use userfaultfd:: Uffd ;
16
16
use utils:: time:: TimestampUs ;
17
17
#[ cfg( target_arch = "aarch64" ) ]
18
+ use vm_memory:: GuestAddress ;
19
+ #[ cfg( target_arch = "aarch64" ) ]
18
20
use vm_superio:: Rtc ;
19
21
use vm_superio:: Serial ;
20
22
use vmm_sys_util:: eventfd:: EventFd ;
@@ -82,6 +84,9 @@ pub enum StartMicrovmError {
82
84
CreateLegacyDevice ( device_manager:: legacy:: LegacyDeviceError ) ,
83
85
/// Error creating VMGenID device: {0}
84
86
CreateVMGenID ( VmGenIdError ) ,
87
+ /// Error enabling pvtime on vcpu: {0}
88
+ #[ cfg( target_arch = "aarch64" ) ]
89
+ EnablePVTime ( crate :: arch:: VcpuArchError ) ,
85
90
/// Invalid Memory Configuration: {0}
86
91
GuestMemory ( crate :: vstate:: memory:: MemoryError ) ,
87
92
/// Error with initrd initialization: {0}.
@@ -289,6 +294,13 @@ pub fn build_microvm_for_boot(
289
294
290
295
attach_vmgenid_device ( & mut vmm) ?;
291
296
297
+ #[ cfg( target_arch = "aarch64" ) ]
298
+ if vcpus[ 0 ] . kvm_vcpu . supports_pvtime ( ) {
299
+ setup_pvtime ( & mut vmm, & mut vcpus) ?;
300
+ } else {
301
+ log:: warn!( "Vcpus do not support pvtime, steal time will not be reported to guest" ) ;
302
+ }
303
+
292
304
configure_system_for_boot (
293
305
& mut vmm,
294
306
vcpus. as_mut ( ) ,
@@ -449,6 +461,16 @@ pub fn build_microvm_from_snapshot(
449
461
}
450
462
}
451
463
464
+ // Restore allocator state
465
+ #[ cfg( target_arch = "aarch64" ) ]
466
+ if let Some ( pvtime_ipa) = vcpus[ 0 ] . kvm_vcpu . pvtime_ipa {
467
+ allocate_pvtime_region (
468
+ & mut vmm,
469
+ vcpus. len ( ) ,
470
+ vm_allocator:: AllocPolicy :: ExactMatch ( pvtime_ipa. 0 ) ,
471
+ ) ?;
472
+ }
473
+
452
474
// Restore vcpus kvm state.
453
475
for ( vcpu, state) in vcpus. iter_mut ( ) . zip ( microvm_state. vcpu_states . iter ( ) ) {
454
476
vcpu. kvm_vcpu
@@ -552,6 +574,44 @@ pub fn setup_serial_device(
552
574
Ok ( serial)
553
575
}
554
576
577
+ /// 64 bytes due to alignment requirement in 3.1 of https://www.kernel.org/doc/html/v5.8/virt/kvm/devices/vcpu.html#attribute-kvm-arm-vcpu-pvtime-ipa
578
+ #[ cfg( target_arch = "aarch64" ) ]
579
+ const STEALTIME_STRUCT_MEM_SIZE : u64 = 64 ;
580
+
581
+ /// Helper method to allocate steal time region
582
+ #[ cfg( target_arch = "aarch64" ) ]
583
+ fn allocate_pvtime_region (
584
+ vmm : & mut Vmm ,
585
+ vcpu_count : usize ,
586
+ policy : vm_allocator:: AllocPolicy ,
587
+ ) -> Result < GuestAddress , StartMicrovmError > {
588
+ let size = STEALTIME_STRUCT_MEM_SIZE * vcpu_count as u64 ;
589
+ let addr = vmm
590
+ . resource_allocator
591
+ . allocate_system_memory ( size, STEALTIME_STRUCT_MEM_SIZE , policy)
592
+ . map_err ( StartMicrovmError :: AllocateResources ) ?;
593
+ Ok ( GuestAddress ( addr) )
594
+ }
595
+
596
+ /// Sets up pvtime for all vcpus
597
+ #[ cfg( target_arch = "aarch64" ) ]
598
+ fn setup_pvtime ( vmm : & mut Vmm , vcpus : & mut [ Vcpu ] ) -> Result < ( ) , StartMicrovmError > {
599
+ // Alloc sys mem for steal time region
600
+ let pvtime_mem: GuestAddress =
601
+ allocate_pvtime_region ( vmm, vcpus. len ( ) , vm_allocator:: AllocPolicy :: LastMatch ) ?;
602
+
603
+ // Register all vcpus with pvtime device
604
+ for ( i, vcpu) in vcpus. iter_mut ( ) . enumerate ( ) {
605
+ vcpu. kvm_vcpu
606
+ . enable_pvtime ( GuestAddress (
607
+ pvtime_mem. 0 + i as u64 * STEALTIME_STRUCT_MEM_SIZE ,
608
+ ) )
609
+ . map_err ( StartMicrovmError :: EnablePVTime ) ?;
610
+ }
611
+
612
+ Ok ( ( ) )
613
+ }
614
+
555
615
#[ cfg( target_arch = "aarch64" ) ]
556
616
fn attach_legacy_devices_aarch64 (
557
617
event_manager : & mut EventManager ,
0 commit comments