Skip to content

Commit a8dfc32

Browse files
committed
MMIO Portion of hotplugging
Implement MMIO for the CpuContainer. This allows the AML methods to read from and write to the defined AML fields. Signed-off-by: James Curtis <[email protected]>
1 parent 900b276 commit a8dfc32

File tree

7 files changed

+223
-40
lines changed

7 files changed

+223
-40
lines changed

src/vmm/src/arch/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ pub enum DeviceType {
4141
Rtc,
4242
/// Device Type: BootTimer.
4343
BootTimer,
44+
/// Device Type: CpuContainer
45+
#[cfg(target_arch = "x86_64")]
46+
CpuContainer,
4447
}
4548

4649
/// Type for passing information about the initrd in the guest memory.

src/vmm/src/builder.rs

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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")]
4243
use 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")]
933951
pub(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.
10551087
pub(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(),

src/vmm/src/device_manager/mmio.rs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use super::resources::ResourceAllocator;
2424
use crate::arch::aarch64::DeviceInfoForFDT;
2525
use crate::arch::DeviceType;
2626
use crate::arch::DeviceType::Virtio;
27+
#[cfg(target_arch = "x86_64")]
28+
use crate::devices::acpi::cpu_container::CpuContainer;
2729
#[cfg(target_arch = "aarch64")]
2830
use crate::devices::legacy::{RTCDevice, SerialDevice};
2931
use crate::devices::pseudo::BootTimer;
@@ -319,7 +321,7 @@ impl MMIODeviceManager {
319321
self.register_mmio_device(
320322
identifier,
321323
device_info,
322-
Arc::new(Mutex::new(BusDevice::RTCDevice(rtc))),
324+
BusDevice::RTCDevice(Arc::new(Mutex::new(rtc))),
323325
)
324326
}
325327

@@ -340,6 +342,52 @@ impl MMIODeviceManager {
340342
)
341343
}
342344

345+
#[cfg(target_arch = "x86_64")]
346+
pub fn register_mmio_cpu_container(
347+
&mut self,
348+
vm: &VmFd,
349+
device: Arc<Mutex<CpuContainer>>,
350+
device_info: &MMIODeviceInfo,
351+
) -> Result<(), MmioError> {
352+
let identifier = (
353+
DeviceType::CpuContainer,
354+
DeviceType::CpuContainer.to_string(),
355+
);
356+
{
357+
let container = device.lock().expect("Poisoned lock");
358+
vm.register_irqfd(&container.mmio_interrupt_evt, device_info.irqs[0])
359+
.map_err(MmioError::RegisterIrqFd)?;
360+
}
361+
362+
self.register_mmio_device(
363+
identifier,
364+
device_info.clone(),
365+
BusDevice::CpuContainer(device),
366+
)?;
367+
Ok(())
368+
}
369+
370+
#[cfg(target_arch = "x86_64")]
371+
pub fn register_mmio_cpu_container_for_boot(
372+
&mut self,
373+
vm: &VmFd,
374+
resource_allocator: &mut ResourceAllocator,
375+
device: Arc<Mutex<CpuContainer>>,
376+
) -> Result<(), MmioError> {
377+
let device_info = {
378+
let locked_container = device.lock().expect("Poisoned lock");
379+
let irqs = resource_allocator.allocate_gsi(1)?;
380+
MMIODeviceInfo {
381+
addr: locked_container.mmio_address.0,
382+
len: MMIO_LEN,
383+
irqs,
384+
}
385+
};
386+
387+
self.register_mmio_cpu_container(vm, device, &device_info)?;
388+
Ok(())
389+
}
390+
343391
/// Gets the information of the devices registered up to some point in time.
344392
pub fn get_device_info(&self) -> &HashMap<(DeviceType, String), MMIODeviceInfo> {
345393
&self.id_to_dev_info
@@ -832,4 +880,24 @@ mod tests {
832880
.allocate_mmio_resources(&mut resource_allocator, 0)
833881
.unwrap();
834882
}
883+
884+
#[test]
885+
#[cfg(target_arch = "x86_64")]
886+
fn test_register_cpu_container() {
887+
let mut device_manager = MMIODeviceManager::new();
888+
let mut resource_allocator = ResourceAllocator::new().unwrap();
889+
let mut vm = Vm::new(vec![]).unwrap();
890+
builder::setup_interrupt_controller(&mut vm).unwrap();
891+
let cpu_container = Arc::new(Mutex::new(
892+
CpuContainer::new(vm.fd(), &mut resource_allocator, 1).unwrap(),
893+
));
894+
895+
device_manager
896+
.register_mmio_cpu_container_for_boot(vm.fd(), &mut resource_allocator, cpu_container)
897+
.unwrap();
898+
899+
device_manager
900+
.get_device(DeviceType::CpuContainer, "CpuContainer")
901+
.unwrap();
902+
}
835903
}

0 commit comments

Comments
 (0)