@@ -38,6 +38,7 @@ use crate::cpu_config::templates::{
38
38
CpuConfiguration , CustomCpuTemplate , GetCpuTemplate , GetCpuTemplateError , GuestConfigError ,
39
39
KvmCapability ,
40
40
} ;
41
+ use crate :: cpu_config:: x86_64:: cpuid:: { self , Cpuid } ;
41
42
#[ cfg( target_arch = "x86_64" ) ]
42
43
use crate :: device_manager:: acpi:: ACPIDeviceManager ;
43
44
#[ cfg( target_arch = "x86_64" ) ]
@@ -86,6 +87,9 @@ pub enum StartMicrovmError {
86
87
/// Unable to attach the VMGenID device: {0}
87
88
#[ cfg( target_arch = "x86_64" ) ]
88
89
AttachVmgenidDevice ( kvm_ioctls:: Error ) ,
90
+ /// Unable to attach the CpuContainer device: {0}
91
+ #[ cfg( target_arch = "x86_64" ) ]
92
+ AttachCpuContainerDevice ( kvm_ioctls:: Error ) ,
89
93
/// System configuration error: {0}
90
94
ConfigureSystem ( crate :: arch:: ConfigurationError ) ,
91
95
/// Failed to create guest config: {0}
@@ -185,18 +189,32 @@ fn create_vmm_and_vcpus(
185
189
// Instantiate the MMIO device manager.
186
190
let mut mmio_device_manager = MMIODeviceManager :: new ( ) ;
187
191
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) ?;
190
198
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
+ }
194
211
}
195
212
196
213
// Instantiate ACPI device manager.
197
214
#[ cfg( target_arch = "x86_64" ) ]
198
215
let acpi_device_manager = {
199
216
let cpu_container = Arc :: new ( Mutex :: new ( CpuContainer :: new (
217
+ vm. fd ( ) ,
200
218
& mut resource_allocator,
201
219
vcpu_count,
202
220
) ?) ) ;
@@ -207,7 +225,6 @@ fn create_vmm_and_vcpus(
207
225
// while on aarch64 we need to do it the other way around.
208
226
#[ cfg( target_arch = "x86_64" ) ]
209
227
let ( vcpus, pio_device_manager) = {
210
- setup_interrupt_controller ( & mut vm) ?;
211
228
let vcpus = create_vcpus ( & vm, vcpu_count, & vcpus_exit_evt) . map_err ( Internal ) ?;
212
229
213
230
// Make stdout non blocking.
@@ -281,7 +298,7 @@ pub fn build_microvm_for_boot(
281
298
use self :: StartMicrovmError :: * ;
282
299
283
300
// Timestamp for measuring microVM boot duration.
284
- let request_ts = TimestampUs :: default ( ) ;
301
+ // let request_ts = TimestampUs::default();
285
302
286
303
let boot_config = vm_resources
287
304
. boot_source_builder ( )
@@ -342,13 +359,6 @@ pub fn build_microvm_for_boot(
342
359
vm_resources. boot_timer ,
343
360
) ?;
344
361
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
-
352
362
#[ cfg( target_arch = "x86_64" ) ]
353
363
attach_cpu_container_device ( & mut vmm) ?;
354
364
@@ -570,14 +580,20 @@ pub fn build_microvm_from_snapshot(
570
580
571
581
#[ cfg( target_arch = "x86_64" ) ]
572
582
{
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
+ } ;
578
593
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
+ }
581
597
582
598
// Inject the notification to VMGenID that we have resumed from a snapshot.
583
599
// 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>(
930
946
. map ( |_| ( ) )
931
947
}
932
948
949
+ // Temporarily test only. (waiting for decision on CpuContainer being an option or not)
950
+ #[ cfg( target_arch = "x86_64" ) ]
933
951
pub ( crate ) fn attach_boot_timer_device (
934
952
vmm : & mut Vmm ,
935
953
request_ts : TimestampUs ,
@@ -1051,6 +1069,20 @@ fn attach_balloon_device(
1051
1069
attach_virtio_device ( event_manager, vmm, id, balloon. clone ( ) , cmdline, false )
1052
1070
}
1053
1071
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
+
1054
1086
// Adds `O_NONBLOCK` to the stdout flags.
1055
1087
pub ( crate ) fn set_stdout_nonblocking ( ) {
1056
1088
// SAFETY: Call is safe since parameters are valid.
@@ -1161,6 +1193,9 @@ pub mod tests {
1161
1193
#[ cfg( target_arch = "aarch64" ) ]
1162
1194
let resource_allocator = ResourceAllocator :: new ( ) . unwrap ( ) ;
1163
1195
1196
+ #[ cfg( target_arch = "x86_64" ) ]
1197
+ let mut mmio_device_manager = MMIODeviceManager :: new ( ) ;
1198
+ #[ cfg( target_arch = "aarch64" ) ]
1164
1199
let mmio_device_manager = MMIODeviceManager :: new ( ) ;
1165
1200
1166
1201
#[ cfg( target_arch = "x86_64" ) ]
@@ -1169,11 +1204,11 @@ pub mod tests {
1169
1204
#[ cfg( target_arch = "x86_64" ) ]
1170
1205
let acpi_device_manager = {
1171
1206
let cpu_container = Arc :: new ( Mutex :: new (
1172
- CpuContainer :: new ( & mut resource_allocator, 1 )
1207
+ CpuContainer :: new ( vm . fd ( ) , & mut resource_allocator, 1 )
1173
1208
. map_err ( StartMicrovmError :: CreateCpuContainer )
1174
1209
. unwrap ( ) ,
1175
1210
) ) ;
1176
- ACPIDeviceManager :: new ( cpu_container)
1211
+ ACPIDeviceManager :: new ( cpu_container. clone ( ) )
1177
1212
} ;
1178
1213
1179
1214
#[ cfg( target_arch = "x86_64" ) ]
@@ -1199,6 +1234,15 @@ pub mod tests {
1199
1234
setup_interrupt_controller ( & mut vm, 1 ) . unwrap ( ) ;
1200
1235
}
1201
1236
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
+
1202
1246
Vmm {
1203
1247
events_observer : Some ( std:: io:: stdin ( ) ) ,
1204
1248
instance_info : InstanceInfo :: default ( ) ,
0 commit comments