22// SPDX-License-Identifier: Apache-2.0
33
44//! Enables pre-boot setup, instantiation and booting of a Firecracker VMM.
5-
65use std:: fmt:: Debug ;
76use std:: io;
87#[ cfg( feature = "gdb" ) ]
@@ -12,13 +11,15 @@ use std::sync::{Arc, Mutex};
1211use event_manager:: { MutEventSubscriber , SubscriberOps } ;
1312use libc:: EFD_NONBLOCK ;
1413use linux_loader:: cmdline:: Cmdline as LoaderKernelCmdline ;
14+ use log:: { info, warn} ;
1515use userfaultfd:: Uffd ;
1616use utils:: time:: TimestampUs ;
1717#[ cfg( target_arch = "aarch64" ) ]
1818use vm_superio:: Rtc ;
1919use vm_superio:: Serial ;
2020use vmm_sys_util:: eventfd:: EventFd ;
2121
22+ use crate :: arch:: aarch64:: pvtime:: PVTimeError ;
2223use crate :: arch:: { ConfigurationError , configure_system_for_boot, load_kernel} ;
2324#[ cfg( target_arch = "aarch64" ) ]
2425use crate :: construct_kvm_mpidrs;
@@ -69,6 +70,9 @@ pub enum StartMicrovmError {
6970 AttachBlockDevice ( io:: Error ) ,
7071 /// Unable to attach the VMGenID device: {0}
7172 AttachVmgenidDevice ( kvm_ioctls:: Error ) ,
73+ /// PVTime not supported: {0}
74+ #[ cfg( target_arch = "aarch64" ) ]
75+ PVTimeNotSupported ( kvm_ioctls:: Error ) ,
7276 /// System configuration error: {0}
7377 ConfigureSystem ( #[ from] ConfigurationError ) ,
7478 /// Failed to create guest config: {0}
@@ -82,6 +86,8 @@ pub enum StartMicrovmError {
8286 CreateLegacyDevice ( device_manager:: legacy:: LegacyDeviceError ) ,
8387 /// Error creating VMGenID device: {0}
8488 CreateVMGenID ( VmGenIdError ) ,
89+ /// Error creating PVTime device: {0}
90+ CreatePVTime ( PVTimeError ) ,
8591 /// Invalid Memory Configuration: {0}
8692 GuestMemory ( crate :: vstate:: memory:: MemoryError ) ,
8793 /// Error with initrd initialization: {0}.
@@ -289,6 +295,17 @@ pub fn build_microvm_for_boot(
289295
290296 attach_vmgenid_device ( & mut vmm) ?;
291297
298+ // Attempt to setup PVTime, continue if not supported
299+ #[ cfg( target_arch = "aarch64" ) ]
300+ if let Err ( e) = setup_pv_time ( & mut vmm, vcpus. as_mut ( ) ) {
301+ match e {
302+ StartMicrovmError :: PVTimeNotSupported ( e) => {
303+ warn ! ( "PVTime not supported: {}" , e) ;
304+ }
305+ other => return Err ( other) ,
306+ }
307+ }
308+
292309 configure_system_for_boot (
293310 & mut vmm,
294311 vcpus. as_mut ( ) ,
@@ -548,6 +565,49 @@ pub fn setup_serial_device(
548565 Ok ( serial)
549566}
550567
568+ /// Sets up the pvtime device.
569+ #[ cfg( target_arch = "aarch64" ) ]
570+ fn setup_pv_time ( vmm : & mut Vmm , vcpus : & mut Vec < Vcpu > ) -> Result < ( ) , StartMicrovmError > {
571+ // Q: Is this bad practice, using crates in this scope?
572+ use crate :: arch:: aarch64:: pvtime:: PVTime ;
573+
574+ info ! ( "PVTime setup started" ) ;
575+
576+ // Check if pvtime is enabled
577+ let pvtime_device_attr = kvm_bindings:: kvm_device_attr {
578+ group : kvm_bindings:: KVM_ARM_VCPU_PVTIME_CTRL ,
579+ attr : kvm_bindings:: KVM_ARM_VCPU_PVTIME_IPA as u64 ,
580+ addr : 0 ,
581+ flags : 0 ,
582+ } ;
583+
584+ // Use kvm_has_device_attr to check if PVTime is supported
585+ // TODO: Flesh out feature detection. Either throw error and handle, or
586+ // even return silently and just log "no support", or something else.
587+ let vcpu_fd = & vcpus[ 0 ] . kvm_vcpu . fd ;
588+ vcpu_fd
589+ . has_device_attr ( & pvtime_device_attr)
590+ . map_err ( StartMicrovmError :: PVTimeNotSupported ) ?;
591+
592+ info ! ( "PVTime is supported" ) ;
593+
594+ // Create the pvtime device
595+ let pv_time = PVTime :: new ( & mut vmm. resource_allocator , vcpus. len ( ) as u8 )
596+ . map_err ( StartMicrovmError :: CreatePVTime ) ?;
597+
598+ // Register the vcpu with the pvtime device to map its steal time region
599+ for i in 0 ..vcpus. len ( ) {
600+ pv_time
601+ . register_vcpu ( i as u8 , & vcpus[ i] . kvm_vcpu . fd )
602+ . map_err ( StartMicrovmError :: CreatePVTime ) ?; // Change this to its own error
603+ }
604+
605+ // TODO: Store pv_time somewhere (in Vmm ?) for snapshotting later instead of dropping it
606+ info ! ( "PVTime setup completed" ) ;
607+
608+ Ok ( ( ) )
609+ }
610+
551611#[ cfg( target_arch = "aarch64" ) ]
552612fn attach_legacy_devices_aarch64 (
553613 event_manager : & mut EventManager ,
0 commit comments