@@ -38,6 +38,7 @@ use crate::cpu_config::templates::{
3838 CpuConfiguration , CustomCpuTemplate , GetCpuTemplate , GetCpuTemplateError , GuestConfigError ,
3939 KvmCapability ,
4040} ;
41+ use crate :: cpu_config:: x86_64:: cpuid:: { self , Cpuid } ;
4142#[ cfg( target_arch = "x86_64" ) ]
4243use crate :: device_manager:: acpi:: ACPIDeviceManager ;
4344#[ cfg( target_arch = "x86_64" ) ]
@@ -86,6 +87,9 @@ pub enum StartMicrovmError {
8687 /// Unable to attach the VMGenID device: {0}
8788 #[ cfg( target_arch = "x86_64" ) ]
8889 AttachVmgenidDevice ( kvm_ioctls:: Error ) ,
90+ /// Unable to attach the CpuContainer device: {0}
91+ #[ cfg( target_arch = "x86_64" ) ]
92+ AttachCpuContainerDevice ( kvm_ioctls:: Error ) ,
8993 /// System configuration error: {0}
9094 ConfigureSystem ( crate :: arch:: ConfigurationError ) ,
9195 /// Failed to create guest config: {0}
@@ -185,18 +189,32 @@ fn create_vmm_and_vcpus(
185189 // Instantiate the MMIO device manager.
186190 let mut mmio_device_manager = MMIODeviceManager :: new ( ) ;
187191
188- if boot_timer_enabled {
189- let boot_timer = crate :: devices:: pseudo:: BootTimer :: new ( TimestampUs :: default ( ) ) ;
192+ #[ cfg( target_arch = "x86_64" ) ]
193+ {
194+ // For x86, we need to create the interrupt controller before calling `KVM_CREATE_VCPUS`,
195+ // but we also need it before the instantiation of the ACPI Device manager,
196+ // this is because the CpuContainer needs to create and register IRQs
197+ setup_interrupt_controller ( & mut vm) ?;
190198
191- mmio_device_manager
192- . register_mmio_boot_timer ( & mut resource_allocator, boot_timer)
193- . map_err ( RegisterMmioDevice ) ?;
199+ // The boot timer device needs to be the first device attached in order
200+ // to maintain the same MMIO address referenced in the documentation
201+ // and tests.
202+ // This has to instantiated here, before the CpuContainer, to ensure that it gets the
203+ // correct address, the first page of MMIO memory.
204+ if boot_timer_enabled {
205+ let boot_timer = crate :: devices:: pseudo:: BootTimer :: new ( TimestampUs :: default ( ) ) ;
206+
207+ mmio_device_manager
208+ . register_mmio_boot_timer ( & mut resource_allocator, boot_timer)
209+ . map_err ( RegisterMmioDevice ) ?;
210+ }
194211 }
195212
196213 // Instantiate ACPI device manager.
197214 #[ cfg( target_arch = "x86_64" ) ]
198215 let acpi_device_manager = {
199216 let cpu_container = Arc :: new ( Mutex :: new ( CpuContainer :: new (
217+ vm. fd ( ) ,
200218 & mut resource_allocator,
201219 vcpu_count,
202220 ) ?) ) ;
@@ -207,7 +225,6 @@ fn create_vmm_and_vcpus(
207225 // while on aarch64 we need to do it the other way around.
208226 #[ cfg( target_arch = "x86_64" ) ]
209227 let ( vcpus, pio_device_manager) = {
210- setup_interrupt_controller ( & mut vm) ?;
211228 let vcpus = create_vcpus ( & vm, vcpu_count, & vcpus_exit_evt) . map_err ( Internal ) ?;
212229
213230 // Make stdout non blocking.
@@ -281,7 +298,7 @@ pub fn build_microvm_for_boot(
281298 use self :: StartMicrovmError :: * ;
282299
283300 // Timestamp for measuring microVM boot duration.
284- let request_ts = TimestampUs :: default ( ) ;
301+ // let request_ts = TimestampUs::default();
285302
286303 let boot_config = vm_resources
287304 . boot_source_builder ( )
@@ -342,13 +359,6 @@ pub fn build_microvm_for_boot(
342359 vm_resources. boot_timer ,
343360 ) ?;
344361
345- // The boot timer device needs to be the first device attached in order
346- // to maintain the same MMIO address referenced in the documentation
347- // and tests.
348- // if vm_resources.boot_timer {
349- // attach_boot_timer_device(&mut vmm, request_ts)?;
350- // }
351-
352362 #[ cfg( target_arch = "x86_64" ) ]
353363 attach_cpu_container_device ( & mut vmm) ?;
354364
@@ -570,14 +580,20 @@ pub fn build_microvm_from_snapshot(
570580
571581 #[ cfg( target_arch = "x86_64" ) ]
572582 {
573- let acpi_ctor_args = ACPIDeviceManagerConstructorArgs {
574- mem : & guest_memory,
575- resource_allocator : & mut vmm. resource_allocator ,
576- vm : vmm. vm . fd ( ) ,
577- } ;
583+ if let Some ( BusDevice :: CpuContainer ( container) ) =
584+ vmm. get_bus_device ( DeviceType :: CpuContainer , "CpuContainer" )
585+ {
586+ let container_ref = container. clone ( ) ;
587+ let acpi_ctor_args = ACPIDeviceManagerConstructorArgs {
588+ mem : & guest_memory,
589+ resource_allocator : & mut vmm. resource_allocator ,
590+ vm : vmm. vm . fd ( ) ,
591+ cpu_container : container_ref,
592+ } ;
578593
579- vmm. acpi_device_manager =
580- ACPIDeviceManager :: restore ( acpi_ctor_args, & microvm_state. acpi_dev_state ) ?;
594+ vmm. acpi_device_manager =
595+ ACPIDeviceManager :: restore ( acpi_ctor_args, & microvm_state. acpi_dev_state ) ?;
596+ }
581597
582598 // Inject the notification to VMGenID that we have resumed from a snapshot.
583599 // This needs to happen before we resume vCPUs, so that we minimize the time between vCPUs
@@ -930,6 +946,8 @@ fn attach_virtio_device<T: 'static + VirtioDevice + MutEventSubscriber + Debug>(
930946 . map ( |_| ( ) )
931947}
932948
949+ // Temporarily test only. (waiting for decision on CpuContainer being an option or not)
950+ #[ cfg( target_arch = "x86_64" ) ]
933951pub ( crate ) fn attach_boot_timer_device (
934952 vmm : & mut Vmm ,
935953 request_ts : TimestampUs ,
@@ -1051,6 +1069,20 @@ fn attach_balloon_device(
10511069 attach_virtio_device ( event_manager, vmm, id, balloon. clone ( ) , cmdline, false )
10521070}
10531071
1072+ #[ cfg( target_arch = "x86_64" ) ]
1073+ fn attach_cpu_container_device ( vmm : & mut Vmm ) -> Result < ( ) , StartMicrovmError > {
1074+ let cpu_container = vmm. acpi_device_manager . cpu_container . clone ( ) ;
1075+ vmm. mmio_device_manager
1076+ . register_mmio_cpu_container_for_boot (
1077+ vmm. vm . fd ( ) ,
1078+ & mut vmm. resource_allocator ,
1079+ cpu_container,
1080+ )
1081+ . map_err ( StartMicrovmError :: RegisterMmioDevice ) ?;
1082+
1083+ Ok ( ( ) )
1084+ }
1085+
10541086// Adds `O_NONBLOCK` to the stdout flags.
10551087pub ( crate ) fn set_stdout_nonblocking ( ) {
10561088 // SAFETY: Call is safe since parameters are valid.
@@ -1161,6 +1193,9 @@ pub mod tests {
11611193 #[ cfg( target_arch = "aarch64" ) ]
11621194 let resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
11631195
1196+ #[ cfg( target_arch = "x86_64" ) ]
1197+ let mut mmio_device_manager = MMIODeviceManager :: new ( ) ;
1198+ #[ cfg( target_arch = "aarch64" ) ]
11641199 let mmio_device_manager = MMIODeviceManager :: new ( ) ;
11651200
11661201 #[ cfg( target_arch = "x86_64" ) ]
@@ -1169,11 +1204,11 @@ pub mod tests {
11691204 #[ cfg( target_arch = "x86_64" ) ]
11701205 let acpi_device_manager = {
11711206 let cpu_container = Arc :: new ( Mutex :: new (
1172- CpuContainer :: new ( & mut resource_allocator, 1 )
1207+ CpuContainer :: new ( vm . fd ( ) , & mut resource_allocator, 1 )
11731208 . map_err ( StartMicrovmError :: CreateCpuContainer )
11741209 . unwrap ( ) ,
11751210 ) ) ;
1176- ACPIDeviceManager :: new ( cpu_container)
1211+ ACPIDeviceManager :: new ( cpu_container. clone ( ) )
11771212 } ;
11781213
11791214 #[ cfg( target_arch = "x86_64" ) ]
@@ -1199,6 +1234,15 @@ pub mod tests {
11991234 setup_interrupt_controller ( & mut vm, 1 ) . unwrap ( ) ;
12001235 }
12011236
1237+ #[ cfg( target_arch = "x86_64" ) ]
1238+ mmio_device_manager
1239+ . register_mmio_cpu_container_for_boot (
1240+ vm. fd ( ) ,
1241+ & mut resource_allocator,
1242+ acpi_device_manager. cpu_container . clone ( ) ,
1243+ )
1244+ . unwrap ( ) ;
1245+
12021246 Vmm {
12031247 events_observer : Some ( std:: io:: stdin ( ) ) ,
12041248 instance_info : InstanceInfo :: default ( ) ,
0 commit comments