From a4dd345597a35ccd48ae26dad26aaf1cf67396cc Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 01:07:28 +0000 Subject: [PATCH 01/12] feat: add device_manager Add single entity to controll all devices in the vmm. There are currently 2 types of devices in Firecraker: mmio and pio devices. Each type is managed by it's own device manager. This works fine in current setup. But with prospect of adding ACPI there will be 3 types of devices and all interactions with them will become more entangled than they are right now. To prevent this from happening single device manager will controll all devices and have all device specific logic inside of it. Signed-off-by: Egor Lazarchuk --- src/vmm/src/builder.rs | 94 +++++++++++++++++---------- src/vmm/src/device_manager/mod.rs | 11 ++++ src/vmm/src/device_manager/persist.rs | 8 ++- src/vmm/src/lib.rs | 41 +++++++----- src/vmm/src/persist.rs | 2 +- 5 files changed, 100 insertions(+), 56 deletions(-) diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index b6b3fad97e8..6d35f72cbbc 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -38,6 +38,7 @@ use crate::cpu_config::templates::{ use crate::device_manager::legacy::PortIODeviceManager; use crate::device_manager::mmio::MMIODeviceManager; use crate::device_manager::persist::MMIODevManagerConstructorArgs; +use crate::device_manager::DeviceManager; use crate::devices::legacy::serial::SerialOut; #[cfg(target_arch = "aarch64")] use crate::devices::legacy::RTCDevice; @@ -147,16 +148,6 @@ fn create_vmm_and_vcpus( .map_err(VmmError::EventFd) .map_err(Internal)?; - // Instantiate the MMIO device manager. - // 'mmio_base' address has to be an address which is protected by the kernel - // and is architectural specific. - let mmio_device_manager = MMIODeviceManager::new( - crate::arch::MMIO_MEM_START, - crate::arch::MMIO_MEM_SIZE, - (crate::arch::IRQ_BASE, crate::arch::IRQ_MAX), - ) - .map_err(StartMicrovmError::RegisterMmioDevice)?; - // For x86_64 we need to create the interrupt controller before calling `KVM_CREATE_VCPUS` // while on aarch64 we need to do it the other way around. #[cfg(target_arch = "x86_64")] @@ -199,6 +190,17 @@ fn create_vmm_and_vcpus( vcpus }; + let device_manager = DeviceManager { + mmio_devices: MMIODeviceManager::new( + crate::arch::MMIO_MEM_START, + crate::arch::MMIO_MEM_SIZE, + (crate::arch::IRQ_BASE, crate::arch::IRQ_MAX), + ) + .map_err(StartMicrovmError::RegisterMmioDevice)?, + #[cfg(target_arch = "x86_64")] + pio_diveces: pio_device_manager, + }; + let vmm = Vmm { events_observer: Some(std::io::stdin()), instance_info: instance_info.clone(), @@ -208,9 +210,7 @@ fn create_vmm_and_vcpus( uffd, vcpus_handles: Vec::new(), vcpus_exit_evt, - mmio_device_manager, - #[cfg(target_arch = "x86_64")] - pio_device_manager, + device_manager, }; Ok((vmm, vcpus)) @@ -501,7 +501,7 @@ pub fn build_microvm_from_snapshot( instance_id: &instance_info.id, }; - vmm.mmio_device_manager = + vmm.device_manager.mmio_devices = MMIODeviceManager::restore(mmio_ctor_args, µvm_state.device_states) .map_err(MicrovmStateError::RestoreDevices)?; vmm.emulate_serial_init()?; @@ -680,10 +680,12 @@ fn attach_legacy_devices_aarch64( // Make stdout non-blocking. set_stdout_nonblocking(); let serial = setup_serial_device(event_manager, std::io::stdin(), std::io::stdout())?; - vmm.mmio_device_manager + vmm.device_manager + .mmio_devices .register_mmio_serial(vmm.vm.fd(), serial, None) .map_err(VmmError::RegisterMMIODevice)?; - vmm.mmio_device_manager + vmm.device_manager + .mmio_devices .add_mmio_serial_to_cmdline(cmdline) .map_err(VmmError::RegisterMMIODevice)?; } @@ -691,7 +693,8 @@ fn attach_legacy_devices_aarch64( let rtc = RTCDevice(Rtc::with_events( &crate::devices::legacy::rtc_pl031::METRICS, )); - vmm.mmio_device_manager + vmm.device_manager + .mmio_devices .register_mmio_rtc(rtc, None) .map_err(VmmError::RegisterMMIODevice) } @@ -802,7 +805,7 @@ pub fn configure_system_for_boot( &vmm.guest_memory, cmdline, vcpu_mpidr, - vmm.mmio_device_manager.get_device_info(), + vmm.device_manager.mmio_devices.get_device_info(), vmm.vm.get_irqchip(), initrd, ) @@ -826,7 +829,8 @@ fn attach_virtio_device( // The device mutex mustn't be locked here otherwise it will deadlock. let device = MmioTransport::new(vmm.guest_memory().clone(), device, is_vhost_user); - vmm.mmio_device_manager + vmm.device_manager + .mmio_devices .register_mmio_virtio_for_boot(vmm.vm.fd(), id, device, cmdline) .map_err(RegisterMmioDevice) .map(|_| ()) @@ -840,7 +844,8 @@ pub(crate) fn attach_boot_timer_device( let boot_timer = crate::devices::pseudo::BootTimer::new(request_ts); - vmm.mmio_device_manager + vmm.device_manager + .mmio_devices .register_mmio_boot_timer(boot_timer) .map_err(RegisterMmioDevice)?; @@ -1078,6 +1083,12 @@ pub mod tests { setup_interrupt_controller(&mut vm, 1).unwrap(); } + let device_manager = DeviceManager { + mmio_devices: default_mmio_device_manager(), + #[cfg(target_arch = "x86_64")] + pio_diveces: pio_device_manager, + }; + Vmm { events_observer: Some(std::io::stdin()), instance_info: InstanceInfo::default(), @@ -1087,9 +1098,7 @@ pub mod tests { uffd: None, vcpus_handles: Vec::new(), vcpus_exit_evt, - mmio_device_manager, - #[cfg(target_arch = "x86_64")] - pio_device_manager, + device_manager, } } @@ -1185,7 +1194,8 @@ pub mod tests { attach_unixsock_vsock_device(vmm, cmdline, &vsock, event_manager).unwrap(); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_VSOCK), &vsock_dev_id) .is_some()); } @@ -1202,7 +1212,8 @@ pub mod tests { attach_entropy_device(vmm, cmdline, &entropy, event_manager).unwrap(); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_RNG), ENTROPY_DEV_ID) .is_some()); } @@ -1220,7 +1231,8 @@ pub mod tests { attach_balloon_device(vmm, cmdline, balloon, event_manager).unwrap(); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_BALLOON), BALLOON_DEV_ID) .is_some()); } @@ -1348,7 +1360,8 @@ pub mod tests { insert_block_devices(&mut vmm, &mut cmdline, &mut event_manager, block_configs); assert!(cmdline_contains(&cmdline, "root=/dev/vda ro")); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_BLOCK), drive_id.as_str()) .is_some()); } @@ -1368,7 +1381,8 @@ pub mod tests { insert_block_devices(&mut vmm, &mut cmdline, &mut event_manager, block_configs); assert!(cmdline_contains(&cmdline, "root=PARTUUID=0eaa91a0-01 rw")); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_BLOCK), drive_id.as_str()) .is_some()); } @@ -1389,7 +1403,8 @@ pub mod tests { assert!(!cmdline_contains(&cmdline, "root=PARTUUID=")); assert!(!cmdline_contains(&cmdline, "root=/dev/vda")); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_BLOCK), drive_id.as_str()) .is_some()); } @@ -1425,15 +1440,18 @@ pub mod tests { assert!(cmdline_contains(&cmdline, "root=PARTUUID=0eaa91a0-01 rw")); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_BLOCK), "root") .is_some()); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_BLOCK), "secondary") .is_some()); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_BLOCK), "third") .is_some()); @@ -1461,7 +1479,8 @@ pub mod tests { insert_block_devices(&mut vmm, &mut cmdline, &mut event_manager, block_configs); assert!(cmdline_contains(&cmdline, "root=/dev/vda rw")); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_BLOCK), drive_id.as_str()) .is_some()); } @@ -1481,7 +1500,8 @@ pub mod tests { insert_block_devices(&mut vmm, &mut cmdline, &mut event_manager, block_configs); assert!(cmdline_contains(&cmdline, "root=PARTUUID=0eaa91a0-01 ro")); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_BLOCK), drive_id.as_str()) .is_some()); } @@ -1501,7 +1521,8 @@ pub mod tests { insert_block_devices(&mut vmm, &mut cmdline, &mut event_manager, block_configs); assert!(cmdline_contains(&cmdline, "root=/dev/vda rw")); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::Virtio(TYPE_BLOCK), drive_id.as_str()) .is_some()); } @@ -1515,7 +1536,8 @@ pub mod tests { let res = attach_boot_timer_device(&mut vmm, request_ts); res.unwrap(); assert!(vmm - .mmio_device_manager + .device_manager + .mmio_devices .get_device(DeviceType::BootTimer, &DeviceType::BootTimer.to_string()) .is_some()); } diff --git a/src/vmm/src/device_manager/mod.rs b/src/vmm/src/device_manager/mod.rs index b55c5154276..fea1e869edb 100644 --- a/src/vmm/src/device_manager/mod.rs +++ b/src/vmm/src/device_manager/mod.rs @@ -5,9 +5,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the THIRD-PARTY file. +#[cfg(target_arch = "x86_64")] +use self::legacy::PortIODeviceManager; +use self::mmio::MMIODeviceManager; + /// Legacy Device Manager. pub mod legacy; /// Memory Mapped I/O Manager. pub mod mmio; /// Device managers (de)serialization support. pub mod persist; + +#[derive(Debug)] +pub struct DeviceManager { + pub mmio_devices: MMIODeviceManager, + #[cfg(target_arch = "x86_64")] + pub pio_diveces: PortIODeviceManager, +} diff --git a/src/vmm/src/device_manager/persist.rs b/src/vmm/src/device_manager/persist.rs index 094c4bf14a8..96b02283820 100644 --- a/src/vmm/src/device_manager/persist.rs +++ b/src/vmm/src/device_manager/persist.rs @@ -740,10 +740,14 @@ mod tests { let entropy_config = EntropyDeviceConfig::default(); insert_entropy_device(&mut vmm, &mut cmdline, &mut event_manager, entropy_config); - Snapshot::serialize(&mut buf.as_mut_slice(), &vmm.mmio_device_manager.save()).unwrap(); + Snapshot::serialize( + &mut buf.as_mut_slice(), + &vmm.device_manager.mmio_devices.save(), + ) + .unwrap(); // We only want to keep the device map from the original MmioDeviceManager. - vmm.mmio_device_manager.soft_clone() + vmm.device_manager.mmio_devices.soft_clone() }; tmp_sock_file.remove().unwrap(); diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index 83d1607e1c6..cdb82e83fc2 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -113,6 +113,7 @@ use std::sync::mpsc::RecvTimeoutError; use std::sync::{Arc, Barrier, Mutex}; use std::time::Duration; +use device_manager::DeviceManager; use event_manager::{EventManager as BaseEventManager, EventOps, Events, MutEventSubscriber}; use seccompiler::BpfProgram; use userfaultfd::Uffd; @@ -124,9 +125,6 @@ use vstate::vcpu::{self, KvmVcpuConfigureError, StartThreadedError, VcpuSendEven use crate::arch::DeviceType; use crate::cpu_config::templates::CpuConfiguration; -#[cfg(target_arch = "x86_64")] -use crate::device_manager::legacy::PortIODeviceManager; -use crate::device_manager::mmio::MMIODeviceManager; use crate::devices::legacy::{IER_RDA_BIT, IER_RDA_OFFSET}; use crate::devices::virtio::balloon::{ Balloon, BalloonConfig, BalloonError, BalloonStats, BALLOON_DEV_ID, @@ -307,10 +305,11 @@ pub struct Vmm { // Used by Vcpus and devices to initiate teardown; Vmm should never write here. vcpus_exit_evt: EventFd, + device_manager: DeviceManager, // Guest VM devices. - mmio_device_manager: MMIODeviceManager, - #[cfg(target_arch = "x86_64")] - pio_device_manager: PortIODeviceManager, + // device_manager.mmio_devices: MMIODeviceManager, + // #[cfg(target_arch = "x86_64")] + // pio_device_manager: PortIODeviceManager, } impl Vmm { @@ -335,7 +334,9 @@ impl Vmm { device_type: DeviceType, device_id: &str, ) -> Option<&Mutex> { - self.mmio_device_manager.get_device(device_type, device_id) + self.device_manager + .mmio_devices + .get_device(device_type, device_id) } /// Starts the microVM vcpus. @@ -372,10 +373,10 @@ impl Vmm { self.vcpus_handles.reserve(vcpu_count); for mut vcpu in vcpus.drain(..) { - vcpu.set_mmio_bus(self.mmio_device_manager.bus.clone()); + vcpu.set_mmio_bus(self.device_manager.mmio_devices.bus.clone()); #[cfg(target_arch = "x86_64")] vcpu.kvm_vcpu - .set_pio_bus(self.pio_device_manager.io_bus.clone()); + .set_pio_bus(self.device_manager.pio_diveces.io_bus.clone()); self.vcpus_handles .push(vcpu.start_threaded(vcpu_seccomp_filter.clone(), barrier.clone())?); @@ -389,7 +390,7 @@ impl Vmm { /// Sends a resume command to the vCPUs. pub fn resume_vm(&mut self) -> Result<(), VmmError> { - self.mmio_device_manager.kick_devices(); + self.device_manager.mmio_devices.kick_devices(); // Send the events. self.vcpus_handles @@ -469,7 +470,8 @@ impl Vmm { #[cfg(target_arch = "x86_64")] { let mut guard = self - .pio_device_manager + .device_manager + .pio_diveces .stdio_serial .lock() .expect("Poisoned lock"); @@ -486,7 +488,8 @@ impl Vmm { /// Injects CTRL+ALT+DEL keystroke combo in the i8042 device. #[cfg(target_arch = "x86_64")] pub fn send_ctrl_alt_del(&mut self) -> Result<(), VmmError> { - self.pio_device_manager + self.device_manager + .pio_diveces .i8042 .lock() .expect("i8042 lock was poisoned") @@ -512,7 +515,7 @@ impl Vmm { self.vm.save_state(&mpidrs).map_err(SaveVmState)? } }; - let device_states = self.mmio_device_manager.save(); + let device_states = self.device_manager.mmio_devices.save(); let memory_state = self.guest_memory().describe(); @@ -618,7 +621,8 @@ impl Vmm { drive_id: &str, path_on_host: String, ) -> Result<(), VmmError> { - self.mmio_device_manager + self.device_manager + .mmio_devices .with_virtio_device_with_id(TYPE_BLOCK, drive_id, |block: &mut Block| { block .update_disk_image(path_on_host) @@ -634,7 +638,8 @@ impl Vmm { rl_bytes: BucketUpdate, rl_ops: BucketUpdate, ) -> Result<(), VmmError> { - self.mmio_device_manager + self.device_manager + .mmio_devices .with_virtio_device_with_id(TYPE_BLOCK, drive_id, |block: &mut Block| { block .update_rate_limiter(rl_bytes, rl_ops) @@ -645,7 +650,8 @@ impl Vmm { /// Updates the rate limiter parameters for block device with `drive_id` id. pub fn update_vhost_user_block_config(&mut self, drive_id: &str) -> Result<(), VmmError> { - self.mmio_device_manager + self.device_manager + .mmio_devices .with_virtio_device_with_id(TYPE_BLOCK, drive_id, |block: &mut Block| { block.update_config().map_err(|err| err.to_string()) }) @@ -661,7 +667,8 @@ impl Vmm { tx_bytes: BucketUpdate, tx_ops: BucketUpdate, ) -> Result<(), VmmError> { - self.mmio_device_manager + self.device_manager + .mmio_devices .with_virtio_device_with_id(TYPE_NET, net_id, |net: &mut Net| { net.patch_rate_limiters(rx_bytes, rx_ops, tx_bytes, tx_ops); Ok(()) diff --git a/src/vmm/src/persist.rs b/src/vmm/src/persist.rs index e1290ca8492..aa2103a0b56 100644 --- a/src/vmm/src/persist.rs +++ b/src/vmm/src/persist.rs @@ -684,7 +684,7 @@ mod tests { #[test] fn test_microvm_state_snapshot() { let vmm = default_vmm_with_devices(); - let states = vmm.mmio_device_manager.save(); + let states = vmm.device_manager.mmio_devices.save(); // Only checking that all devices are saved, actual device state // is tested by that device's tests. From 250d37133ab0b41d5d3738337591df4be899a6e2 Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 12:09:04 +0000 Subject: [PATCH 02/12] refactor(mmio): move KVM device registration to MMIODeviceInfo Now registration of KVM resources is not attached to the mmio_device_manager and can be performed outside of it. Signed-off-by: Egor Lazarchuk --- src/vmm/src/device_manager/mmio.rs | 38 ++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/vmm/src/device_manager/mmio.rs b/src/vmm/src/device_manager/mmio.rs index d0f10011bf7..91814d344ec 100644 --- a/src/vmm/src/device_manager/mmio.rs +++ b/src/vmm/src/device_manager/mmio.rs @@ -74,6 +74,26 @@ pub struct MMIODeviceInfo { pub irqs: Vec, } +impl MMIODeviceInfo { + pub fn register_kvm_device( + &self, + vm: &VmFd, + mmio_device: &MmioTransport, + ) -> Result<(), MmioError> { + let locked_device = mmio_device.locked_device(); + for (i, queue_evt) in locked_device.queue_events().iter().enumerate() { + let io_addr = IoEventAddress::Mmio( + self.addr + u64::from(crate::devices::virtio::NOTIFY_REG_OFFSET), + ); + vm.register_ioevent(queue_evt, &io_addr, u32::try_from(i).unwrap()) + .map_err(MmioError::RegisterIoEvent)?; + } + vm.register_irqfd(locked_device.interrupt_evt(), self.irqs[0]) + .map_err(MmioError::RegisterIrqFd)?; + Ok(()) + } +} + /// Manages the complexities of registering a MMIO device. #[derive(Debug)] pub struct MMIODeviceManager { @@ -144,20 +164,12 @@ impl MMIODeviceManager { if device_info.irqs.len() != 1 { return Err(MmioError::InvalidIrqConfig); } - let identifier; - { + let identifier = { let locked_device = mmio_device.locked_device(); - identifier = (DeviceType::Virtio(locked_device.device_type()), device_id); - for (i, queue_evt) in locked_device.queue_events().iter().enumerate() { - let io_addr = IoEventAddress::Mmio( - device_info.addr + u64::from(crate::devices::virtio::NOTIFY_REG_OFFSET), - ); - vm.register_ioevent(queue_evt, &io_addr, u32::try_from(i).unwrap()) - .map_err(MmioError::RegisterIoEvent)?; - } - vm.register_irqfd(locked_device.interrupt_evt(), device_info.irqs[0]) - .map_err(MmioError::RegisterIrqFd)?; - } + (DeviceType::Virtio(locked_device.device_type()), device_id) + }; + + device_info.register_kvm_device(vm, &mmio_device)?; self.register_mmio_device( identifier, From f0d06c7ae57c3e9ae4aa893739ea2b7b8b4f629b Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 12:23:01 +0000 Subject: [PATCH 03/12] refactor(mmio): move cmd line update out of mmio_device_manager Update of cmd line with virtio devices does not need to access to the mmio_device_manager and can be done outside of it. Signed-off-by: Egor Lazarchuk --- src/vmm/src/builder.rs | 31 +++++++++---- src/vmm/src/device_manager/mmio.rs | 74 ++++++------------------------ 2 files changed, 36 insertions(+), 69 deletions(-) diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index 6d35f72cbbc..bf380a7e18c 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -680,14 +680,14 @@ fn attach_legacy_devices_aarch64( // Make stdout non-blocking. set_stdout_nonblocking(); let serial = setup_serial_device(event_manager, std::io::stdin(), std::io::stdout())?; - vmm.device_manager + let device_info = vmm + .device_manager .mmio_devices .register_mmio_serial(vmm.vm.fd(), serial, None) .map_err(VmmError::RegisterMMIODevice)?; - vmm.device_manager - .mmio_devices - .add_mmio_serial_to_cmdline(cmdline) - .map_err(VmmError::RegisterMMIODevice)?; + cmdline + .insert("earlycon", &format!("uart,mmio,0x{:08x}", device_info.addr)) + .expect("All args are valid"); } let rtc = RTCDevice(Rtc::with_events( @@ -820,7 +820,7 @@ fn attach_virtio_device( vmm: &mut Vmm, id: String, device: Arc>, - cmdline: &mut LoaderKernelCmdline, + _cmdline: &mut LoaderKernelCmdline, is_vhost_user: bool, ) -> Result<(), StartMicrovmError> { use self::StartMicrovmError::*; @@ -829,11 +829,22 @@ fn attach_virtio_device( // The device mutex mustn't be locked here otherwise it will deadlock. let device = MmioTransport::new(vmm.guest_memory().clone(), device, is_vhost_user); - vmm.device_manager + let _device_info = vmm + .device_manager .mmio_devices - .register_mmio_virtio_for_boot(vmm.vm.fd(), id, device, cmdline) - .map_err(RegisterMmioDevice) - .map(|_| ()) + .add_device(vmm.vm.fd(), id, device) + .map_err(RegisterMmioDevice)?; + + #[cfg(target_arch = "x86_64")] + _cmdline + .add_virtio_mmio_device( + _device_info.len, + GuestAddress(_device_info.addr), + _device_info.irqs[0], + None, + ) + .expect("MMIO device len is 0x1000"); + Ok(()) } pub(crate) fn attach_boot_timer_device( diff --git a/src/vmm/src/device_manager/mmio.rs b/src/vmm/src/device_manager/mmio.rs index 91814d344ec..9f52eb6661c 100644 --- a/src/vmm/src/device_manager/mmio.rs +++ b/src/vmm/src/device_manager/mmio.rs @@ -10,7 +10,6 @@ use std::fmt::Debug; use std::sync::{Arc, Mutex}; use kvm_ioctls::{IoEventAddress, VmFd}; -use linux_loader::cmdline as kernel_cmdline; use log::info; use serde::{Deserialize, Serialize}; use vm_allocator::{AddressAllocator, AllocPolicy, IdAllocator}; @@ -31,8 +30,6 @@ use crate::devices::virtio::rng::Entropy; use crate::devices::virtio::vsock::TYPE_VSOCK; use crate::devices::virtio::{TYPE_BALLOON, TYPE_BLOCK, TYPE_NET, TYPE_RNG}; use crate::devices::BusDevice; -#[cfg(target_arch = "x86_64")] -use crate::vstate::memory::GuestAddress; /// Errors for MMIO device manager. #[derive(Debug, thiserror::Error, displaydoc::Display)] @@ -41,8 +38,6 @@ pub enum MmioError { Allocator(vm_allocator::Error), /// Failed to insert device on the bus: {0} BusInsert(crate::devices::BusError), - /// Failed to allocate requested resourc: {0} - Cmdline(linux_loader::cmdline::Error), /// Failed to find the device on the bus. DeviceNotFound, /// Invalid device type found on the MMIO bus. @@ -151,6 +146,18 @@ impl MMIODeviceManager { Ok(()) } + /// Add new virtio-over-MMIO device. + pub fn add_device( + &mut self, + vm: &VmFd, + device_id: String, + mmio_device: MmioTransport, + ) -> Result { + let device_info = self.allocate_mmio_resources(1)?; + self.register_mmio_virtio(vm, device_id, mmio_device, &device_info)?; + Ok(device_info) + } + /// Register a virtio-over-MMIO device to be used via MMIO transport at a specific slot. pub fn register_mmio_virtio( &mut self, @@ -178,43 +185,6 @@ impl MMIODeviceManager { ) } - /// Append a registered virtio-over-MMIO device to the kernel cmdline. - #[cfg(target_arch = "x86_64")] - pub fn add_virtio_device_to_cmdline( - cmdline: &mut kernel_cmdline::Cmdline, - device_info: &MMIODeviceInfo, - ) -> Result<(), MmioError> { - // as per doc, [virtio_mmio.]device=@: needs to be appended - // to kernel commandline for virtio mmio devices to get recognized - // the size parameter has to be transformed to KiB, so dividing hexadecimal value in - // bytes to 1024; further, the '{}' formatting rust construct will automatically - // transform it to decimal - cmdline - .add_virtio_mmio_device( - device_info.len, - GuestAddress(device_info.addr), - device_info.irqs[0], - None, - ) - .map_err(MmioError::Cmdline) - } - - /// Allocate slot and register an already created virtio-over-MMIO device. Also Adds the device - /// to the boot cmdline. - pub fn register_mmio_virtio_for_boot( - &mut self, - vm: &VmFd, - device_id: String, - mmio_device: MmioTransport, - _cmdline: &mut kernel_cmdline::Cmdline, - ) -> Result { - let device_info = self.allocate_mmio_resources(1)?; - self.register_mmio_virtio(vm, device_id, mmio_device, &device_info)?; - #[cfg(target_arch = "x86_64")] - Self::add_virtio_device_to_cmdline(_cmdline, &device_info)?; - Ok(device_info) - } - #[cfg(target_arch = "aarch64")] /// Register an early console at the specified MMIO configuration if given as parameter, /// otherwise allocate a new MMIO resources for it. @@ -223,7 +193,7 @@ impl MMIODeviceManager { vm: &VmFd, serial: Arc>, device_info_opt: Option, - ) -> Result<(), MmioError> { + ) -> Result { // Create a new MMIODeviceInfo object on boot path or unwrap the // existing object on restore path. let device_info = if let Some(device_info) = device_info_opt { @@ -246,22 +216,8 @@ impl MMIODeviceManager { let identifier = (DeviceType::Serial, DeviceType::Serial.to_string()); // Register the newly created Serial object. - self.register_mmio_device(identifier, device_info, serial) - } - - #[cfg(target_arch = "aarch64")] - /// Append the registered early console to the kernel cmdline. - pub fn add_mmio_serial_to_cmdline( - &self, - cmdline: &mut kernel_cmdline::Cmdline, - ) -> Result<(), MmioError> { - let device_info = self - .id_to_dev_info - .get(&(DeviceType::Serial, DeviceType::Serial.to_string())) - .ok_or(MmioError::DeviceNotFound)?; - cmdline - .insert("earlycon", &format!("uart,mmio,0x{:08x}", device_info.addr)) - .map_err(MmioError::Cmdline) + self.register_mmio_device(identifier, device_info.clone(), serial)?; + Ok(device_info) } #[cfg(target_arch = "aarch64")] From 069e62aeec2083c12627c676241c85bf446802bb Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 13:44:12 +0000 Subject: [PATCH 04/12] refactor(mmio): explicit bus device addition MMIODeviceManager was aware of different types of devices like Rtc or BootTimer. Because of this MMIODeviceManager had specialized methods to deal with such devices. This commit tries to generalize addition of such devices, so MMIODeviceManager will not differentiate between them. Signed-off-by: Egor Lazarchuk --- src/vmm/src/builder.rs | 21 ++++--- src/vmm/src/device_manager/mmio.rs | 87 +++++++++------------------ src/vmm/src/device_manager/persist.rs | 9 ++- 3 files changed, 47 insertions(+), 70 deletions(-) diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index bf380a7e18c..afef4d7e102 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -27,7 +27,7 @@ use vm_memory::ReadVolatile; use vm_superio::Rtc; use vm_superio::Serial; -use crate::arch::InitrdConfig; +use crate::arch::{DeviceType, InitrdConfig}; #[cfg(target_arch = "aarch64")] use crate::construct_kvm_mpidrs; use crate::cpu_config::templates::{ @@ -43,6 +43,7 @@ use crate::devices::legacy::serial::SerialOut; #[cfg(target_arch = "aarch64")] use crate::devices::legacy::RTCDevice; use crate::devices::legacy::{EventFdTrigger, SerialEventsWrapper, SerialWrapper}; +use crate::devices::pseudo::BootTimer; use crate::devices::virtio::balloon::Balloon; use crate::devices::virtio::block::device::Block; use crate::devices::virtio::device::VirtioDevice; @@ -690,12 +691,13 @@ fn attach_legacy_devices_aarch64( .expect("All args are valid"); } - let rtc = RTCDevice(Rtc::with_events( - &crate::devices::legacy::rtc_pl031::METRICS, - )); + let identifier = (DeviceType::Rtc, DeviceType::Rtc.to_string()); + let rtc = Arc::new(Mutex::new(BusDevice::RTCDevice(RTCDevice( + Rtc::with_events(&crate::devices::legacy::rtc_pl031::METRICS), + )))); vmm.device_manager .mmio_devices - .register_mmio_rtc(rtc, None) + .add_bus_device(identifier, rtc) .map_err(VmmError::RegisterMMIODevice) } @@ -853,14 +855,13 @@ pub(crate) fn attach_boot_timer_device( ) -> Result<(), StartMicrovmError> { use self::StartMicrovmError::*; - let boot_timer = crate::devices::pseudo::BootTimer::new(request_ts); + let identifier = (DeviceType::BootTimer, DeviceType::BootTimer.to_string()); + let boot_timer = Arc::new(Mutex::new(BusDevice::BootTimer(BootTimer::new(request_ts)))); vmm.device_manager .mmio_devices - .register_mmio_boot_timer(boot_timer) - .map_err(RegisterMmioDevice)?; - - Ok(()) + .add_bus_device(identifier, boot_timer) + .map_err(RegisterMmioDevice) } fn attach_entropy_device( diff --git a/src/vmm/src/device_manager/mmio.rs b/src/vmm/src/device_manager/mmio.rs index 9f52eb6661c..9213176ec1d 100644 --- a/src/vmm/src/device_manager/mmio.rs +++ b/src/vmm/src/device_manager/mmio.rs @@ -18,9 +18,6 @@ use vm_allocator::{AddressAllocator, AllocPolicy, IdAllocator}; use crate::arch::aarch64::DeviceInfoForFDT; use crate::arch::DeviceType; use crate::arch::DeviceType::Virtio; -#[cfg(target_arch = "aarch64")] -use crate::devices::legacy::RTCDevice; -use crate::devices::pseudo::BootTimer; use crate::devices::virtio::balloon::Balloon; use crate::devices::virtio::block::device::Block; use crate::devices::virtio::device::VirtioDevice; @@ -132,20 +129,6 @@ impl MMIODeviceManager { Ok(device_info) } - /// Register a device at some MMIO address. - fn register_mmio_device( - &mut self, - identifier: (DeviceType, String), - device_info: MMIODeviceInfo, - device: Arc>, - ) -> Result<(), MmioError> { - self.bus - .insert(device, device_info.addr, device_info.len) - .map_err(MmioError::BusInsert)?; - self.id_to_dev_info.insert(identifier, device_info); - Ok(()) - } - /// Add new virtio-over-MMIO device. pub fn add_device( &mut self, @@ -158,6 +141,31 @@ impl MMIODeviceManager { Ok(device_info) } + /// Add new MMIO device to the MMIO bus. + pub fn add_bus_device( + &mut self, + identifier: (DeviceType, String), + device: Arc>, + ) -> Result<(), MmioError> { + let device_info = self.allocate_mmio_resources(1)?; + self.add_bus_device_with_info(identifier, device, device_info) + } + + /// Add new MMIO device to the MMIO bus with specified + /// device info. + pub fn add_bus_device_with_info( + &mut self, + identifier: (DeviceType, String), + device: Arc>, + device_info: MMIODeviceInfo, + ) -> Result<(), MmioError> { + self.bus + .insert(device, device_info.addr, device_info.len) + .map_err(MmioError::BusInsert)?; + self.id_to_dev_info.insert(identifier, device_info); + Ok(()) + } + /// Register a virtio-over-MMIO device to be used via MMIO transport at a specific slot. pub fn register_mmio_virtio( &mut self, @@ -178,10 +186,10 @@ impl MMIODeviceManager { device_info.register_kvm_device(vm, &mmio_device)?; - self.register_mmio_device( + self.add_bus_device_with_info( identifier, - device_info.clone(), Arc::new(Mutex::new(BusDevice::MmioTransport(mmio_device))), + device_info.clone(), ) } @@ -216,49 +224,10 @@ impl MMIODeviceManager { let identifier = (DeviceType::Serial, DeviceType::Serial.to_string()); // Register the newly created Serial object. - self.register_mmio_device(identifier, device_info.clone(), serial)?; + self.add_bus_device_with_info(identifier, serial, device_info.clone())?; Ok(device_info) } - #[cfg(target_arch = "aarch64")] - /// Create and register a MMIO RTC device at the specified MMIO configuration if - /// given as parameter, otherwise allocate a new MMIO resources for it. - pub fn register_mmio_rtc( - &mut self, - rtc: RTCDevice, - device_info_opt: Option, - ) -> Result<(), MmioError> { - // Create a new MMIODeviceInfo object on boot path or unwrap the - // existing object on restore path. - let device_info = if let Some(device_info) = device_info_opt { - device_info - } else { - self.allocate_mmio_resources(1)? - }; - - // Create a new identifier for the RTC device. - let identifier = (DeviceType::Rtc, DeviceType::Rtc.to_string()); - // Attach the newly created RTC device. - self.register_mmio_device( - identifier, - device_info, - Arc::new(Mutex::new(BusDevice::RTCDevice(rtc))), - ) - } - - /// Register a boot timer device. - pub fn register_mmio_boot_timer(&mut self, device: BootTimer) -> Result<(), MmioError> { - // Attach a new boot timer device. - let device_info = self.allocate_mmio_resources(0)?; - - let identifier = (DeviceType::BootTimer, DeviceType::BootTimer.to_string()); - self.register_mmio_device( - identifier, - device_info, - Arc::new(Mutex::new(BusDevice::BootTimer(device))), - ) - } - /// Gets the information of the devices registered up to some point in time. pub fn get_device_info(&self) -> &HashMap<(DeviceType, String), MMIODeviceInfo> { &self.id_to_dev_info diff --git a/src/vmm/src/device_manager/persist.rs b/src/vmm/src/device_manager/persist.rs index 96b02283820..5430a53fd75 100644 --- a/src/vmm/src/device_manager/persist.rs +++ b/src/vmm/src/device_manager/persist.rs @@ -38,6 +38,8 @@ use crate::devices::virtio::vsock::{ Vsock, VsockError, VsockUnixBackend, VsockUnixBackendError, TYPE_VSOCK, }; use crate::devices::virtio::{TYPE_BALLOON, TYPE_BLOCK, TYPE_NET, TYPE_RNG}; +#[cfg(target_arch = "aarch64")] +use crate::devices::BusDevice; use crate::mmds::data_store::MmdsVersion; use crate::resources::{ResourcesError, VmResources}; use crate::snapshot::Persist; @@ -407,7 +409,12 @@ impl<'a> Persist<'a> for MMIODeviceManager { .map_err(|e| { DevicePersistError::DeviceManager(super::mmio::MmioError::Allocator(e)) })?; - dev_manager.register_mmio_rtc(rtc, Some(state.device_info.clone()))?; + let identifier = (DeviceType::Rtc, DeviceType::Rtc.to_string()); + dev_manager.add_bus_device_with_info( + identifier, + Arc::new(Mutex::new(BusDevice::RTCDevice(rtc))), + state.device_info.clone(), + )?; } } } From a507c2258cd14207bd0985f9a10debadcd5bea62 Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 14:23:38 +0000 Subject: [PATCH 05/12] refactor(serial): remove generic from SerialDevice SerialDevice is always used with stdin as an input source. Setting generic parameter of SerialDevice to always be Stdin removes duplication of it's definitions all over codebase. Also it allows to make a simple `new` method to create SerialDevice instead of specifying each field separately. Signed-off-by: Egor Lazarchuk --- src/vmm/src/builder.rs | 27 +++++---------------------- src/vmm/src/device_manager/persist.rs | 7 ++----- src/vmm/src/devices/bus.rs | 6 +++--- src/vmm/src/devices/legacy/serial.rs | 26 +++++++++++++++++++++++--- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index afef4d7e102..71db070fa5b 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -10,7 +10,6 @@ use std::io::{self, Seek, SeekFrom}; use std::sync::{Arc, Mutex}; use event_manager::{MutEventSubscriber, SubscriberOps}; -use libc::EFD_NONBLOCK; use linux_loader::cmdline::Cmdline as LoaderKernelCmdline; #[cfg(target_arch = "x86_64")] use linux_loader::loader::elf::Elf as Loader; @@ -25,7 +24,6 @@ use utils::u64_to_usize; use vm_memory::ReadVolatile; #[cfg(target_arch = "aarch64")] use vm_superio::Rtc; -use vm_superio::Serial; use crate::arch::{DeviceType, InitrdConfig}; #[cfg(target_arch = "aarch64")] @@ -39,10 +37,9 @@ use crate::device_manager::legacy::PortIODeviceManager; use crate::device_manager::mmio::MMIODeviceManager; use crate::device_manager::persist::MMIODevManagerConstructorArgs; use crate::device_manager::DeviceManager; -use crate::devices::legacy::serial::SerialOut; #[cfg(target_arch = "aarch64")] use crate::devices::legacy::RTCDevice; -use crate::devices::legacy::{EventFdTrigger, SerialEventsWrapper, SerialWrapper}; +use crate::devices::legacy::SerialDevice; use crate::devices::pseudo::BootTimer; use crate::devices::virtio::balloon::Balloon; use crate::devices::virtio::block::device::Block; @@ -160,8 +157,7 @@ fn create_vmm_and_vcpus( set_stdout_nonblocking(); // Serial device setup. - let serial_device = - setup_serial_device(event_manager, std::io::stdin(), io::stdout()).map_err(Internal)?; + let serial_device = setup_serial_device(event_manager).map_err(Internal)?; // x86_64 uses the i8042 reset event as the Vmm exit event. let reset_evt = vcpus_exit_evt @@ -643,22 +639,9 @@ pub fn setup_interrupt_controller(vm: &mut Vm, vcpu_count: u8) -> Result<(), Sta /// Sets up the serial device. pub fn setup_serial_device( event_manager: &mut EventManager, - input: std::io::Stdin, - out: std::io::Stdout, ) -> Result>, VmmError> { - let interrupt_evt = EventFdTrigger::new(EventFd::new(EFD_NONBLOCK).map_err(VmmError::EventFd)?); - let kick_stdin_read_evt = - EventFdTrigger::new(EventFd::new(EFD_NONBLOCK).map_err(VmmError::EventFd)?); - let serial = Arc::new(Mutex::new(BusDevice::Serial(SerialWrapper { - serial: Serial::with_events( - interrupt_evt, - SerialEventsWrapper { - buffer_ready_event_fd: Some(kick_stdin_read_evt), - }, - SerialOut::Stdout(out), - ), - input: Some(input), - }))); + let serial = SerialDevice::new().map_err(VmmError::EventFd)?; + let serial = Arc::new(Mutex::new(BusDevice::Serial(serial))); event_manager.add_subscriber(serial.clone()); Ok(serial) } @@ -680,7 +663,7 @@ fn attach_legacy_devices_aarch64( if cmdline_contains_console { // Make stdout non-blocking. set_stdout_nonblocking(); - let serial = setup_serial_device(event_manager, std::io::stdin(), std::io::stdout())?; + let serial = setup_serial_device(event_manager)?; let device_info = vmm .device_manager .mmio_devices diff --git a/src/vmm/src/device_manager/persist.rs b/src/vmm/src/device_manager/persist.rs index 5430a53fd75..b568f468d46 100644 --- a/src/vmm/src/device_manager/persist.rs +++ b/src/vmm/src/device_manager/persist.rs @@ -372,11 +372,8 @@ impl<'a> Persist<'a> for MMIODeviceManager { { for state in &state.legacy_devices { if state.type_ == DeviceType::Serial { - let serial = crate::builder::setup_serial_device( - constructor_args.event_manager, - std::io::stdin(), - std::io::stdout(), - )?; + let serial = + crate::builder::setup_serial_device(constructor_args.event_manager)?; dev_manager .address_allocator diff --git a/src/vmm/src/devices/bus.rs b/src/vmm/src/devices/bus.rs index 2b016d73083..d8e1fb79e14 100644 --- a/src/vmm/src/devices/bus.rs +++ b/src/vmm/src/devices/bus.rs @@ -65,7 +65,7 @@ pub enum BusDevice { RTCDevice(RTCDevice), BootTimer(BootTimer), MmioTransport(MmioTransport), - Serial(SerialDevice), + Serial(SerialDevice), #[cfg(test)] Dummy(DummyDevice), #[cfg(test)] @@ -127,7 +127,7 @@ impl BusDevice { _ => None, } } - pub fn serial_ref(&self) -> Option<&SerialDevice> { + pub fn serial_ref(&self) -> Option<&SerialDevice> { match self { Self::Serial(x) => Some(x), _ => None, @@ -159,7 +159,7 @@ impl BusDevice { _ => None, } } - pub fn serial_mut(&mut self) -> Option<&mut SerialDevice> { + pub fn serial_mut(&mut self) -> Option<&mut SerialDevice> { match self { Self::Serial(x) => Some(x), _ => None, diff --git a/src/vmm/src/devices/legacy/serial.rs b/src/vmm/src/devices/legacy/serial.rs index a348291fcea..d655572c257 100644 --- a/src/vmm/src/devices/legacy/serial.rs +++ b/src/vmm/src/devices/legacy/serial.rs @@ -7,14 +7,15 @@ //! Implements a wrapper over an UART serial device. use std::fmt::Debug; -use std::io; -use std::io::{Read, Write}; +use std::io::{self, Read, Stdin, Write}; use std::os::unix::io::{AsRawFd, RawFd}; use event_manager::{EventOps, Events, MutEventSubscriber}; +use libc::EFD_NONBLOCK; use log::{error, warn}; use serde::Serialize; use utils::epoll::EventSet; +use utils::eventfd::EventFd; use vm_superio::serial::{Error as SerialError, SerialEvents}; use vm_superio::{Serial, Trigger}; @@ -220,7 +221,26 @@ impl SerialWrapper = SerialWrapper; +pub type SerialDevice = SerialWrapper; + +impl SerialDevice { + pub fn new() -> Result { + let stdin = std::io::stdin(); + let stdout = io::stdout(); + let interrupt_evt = EventFdTrigger::new(EventFd::new(EFD_NONBLOCK)?); + let buffer_ready_event_fd = EventFdTrigger::new(EventFd::new(EFD_NONBLOCK)?); + Ok(SerialDevice { + serial: Serial::with_events( + interrupt_evt, + SerialEventsWrapper { + buffer_ready_event_fd: Some(buffer_ready_event_fd), + }, + SerialOut::Stdout(stdout), + ), + input: Some(stdin), + }) + } +} impl MutEventSubscriber for SerialWrapper From e08ef27c4294a81c880f2a329ec505bcfbfb32e9 Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 14:35:50 +0000 Subject: [PATCH 06/12] refactor(mmio): move irqfd registration to MMIODeviceInfo MMIODeviceInfo now handles registration of irqfd. This registration can happen outside of MMIODeviceManager in the future. Signed-off-by: Egor Lazarchuk --- src/vmm/src/device_manager/mmio.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/vmm/src/device_manager/mmio.rs b/src/vmm/src/device_manager/mmio.rs index 9213176ec1d..0581ab63fd7 100644 --- a/src/vmm/src/device_manager/mmio.rs +++ b/src/vmm/src/device_manager/mmio.rs @@ -12,6 +12,7 @@ use std::sync::{Arc, Mutex}; use kvm_ioctls::{IoEventAddress, VmFd}; use log::info; use serde::{Deserialize, Serialize}; +use utils::eventfd::EventFd; use vm_allocator::{AddressAllocator, AllocPolicy, IdAllocator}; #[cfg(target_arch = "aarch64")] @@ -84,6 +85,11 @@ impl MMIODeviceInfo { .map_err(MmioError::RegisterIrqFd)?; Ok(()) } + + pub fn register_kvm_irqfd(&self, vm: &VmFd, eventfd: &EventFd) -> Result<(), MmioError> { + vm.register_irqfd(eventfd, self.irqs[0]) + .map_err(MmioError::RegisterIrqFd) + } } /// Manages the complexities of registering a MMIO device. @@ -210,7 +216,8 @@ impl MMIODeviceManager { self.allocate_mmio_resources(1)? }; - vm.register_irqfd( + device_info.register_kvm_irqfd( + vm, serial .lock() .expect("Poisoned lock") @@ -218,9 +225,7 @@ impl MMIODeviceManager { .unwrap() .serial .interrupt_evt(), - device_info.irqs[0], - ) - .map_err(MmioError::RegisterIrqFd)?; + )?; let identifier = (DeviceType::Serial, DeviceType::Serial.to_string()); // Register the newly created Serial object. From d83efb375243f95297c257516a5251c963cc730a Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 15:02:59 +0000 Subject: [PATCH 07/12] refactor(mmio): rename allocate_mmio_resources Rename allocate_mmio_resources into allocate_device_info to better specify the method output. Signed-off-by: Egor Lazarchuk --- src/vmm/src/device_manager/mmio.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/vmm/src/device_manager/mmio.rs b/src/vmm/src/device_manager/mmio.rs index 0581ab63fd7..7c91d1878ad 100644 --- a/src/vmm/src/device_manager/mmio.rs +++ b/src/vmm/src/device_manager/mmio.rs @@ -118,7 +118,7 @@ impl MMIODeviceManager { } /// Allocates resources for a new device to be added. - fn allocate_mmio_resources(&mut self, irq_count: u32) -> Result { + fn allocate_device_info(&mut self, irq_count: u32) -> Result { let irqs = (0..irq_count) .map(|_| self.irq_allocator.allocate_id()) .collect::>() @@ -142,7 +142,7 @@ impl MMIODeviceManager { device_id: String, mmio_device: MmioTransport, ) -> Result { - let device_info = self.allocate_mmio_resources(1)?; + let device_info = self.allocate_device_info(1)?; self.register_mmio_virtio(vm, device_id, mmio_device, &device_info)?; Ok(device_info) } @@ -153,7 +153,7 @@ impl MMIODeviceManager { identifier: (DeviceType, String), device: Arc>, ) -> Result<(), MmioError> { - let device_info = self.allocate_mmio_resources(1)?; + let device_info = self.allocate_device_info(1)?; self.add_bus_device_with_info(identifier, device, device_info) } @@ -213,7 +213,7 @@ impl MMIODeviceManager { let device_info = if let Some(device_info) = device_info_opt { device_info } else { - self.allocate_mmio_resources(1)? + self.allocate_device_info(1)? }; device_info.register_kvm_irqfd( @@ -677,15 +677,15 @@ mod tests { (crate::arch::IRQ_BASE, crate::arch::IRQ_MAX), ) .unwrap(); - let device_info = device_manager.allocate_mmio_resources(0).unwrap(); + let device_info = device_manager.allocate_device_info(0).unwrap(); assert_eq!(device_info.irqs.len(), 0); - let device_info = device_manager.allocate_mmio_resources(1).unwrap(); + let device_info = device_manager.allocate_device_info(1).unwrap(); assert_eq!(device_info.irqs[0], crate::arch::IRQ_BASE); assert_eq!( format!( "{}", device_manager - .allocate_mmio_resources(crate::arch::IRQ_MAX - crate::arch::IRQ_BASE + 1) + .allocate_device_info(crate::arch::IRQ_MAX - crate::arch::IRQ_BASE + 1) .unwrap_err() ), "Failed to allocate requested resource: The requested resource is not available." @@ -697,14 +697,14 @@ mod tests { } let device_info = device_manager - .allocate_mmio_resources(crate::arch::IRQ_MAX - crate::arch::IRQ_BASE - 1) + .allocate_device_info(crate::arch::IRQ_MAX - crate::arch::IRQ_BASE - 1) .unwrap(); assert_eq!(device_info.irqs[16], crate::arch::IRQ_BASE + 16); assert_eq!( - format!("{}", device_manager.allocate_mmio_resources(2).unwrap_err()), + format!("{}", device_manager.allocate_device_info(2).unwrap_err()), "Failed to allocate requested resource: The requested resource is not available." .to_string() ); - device_manager.allocate_mmio_resources(0).unwrap(); + device_manager.allocate_device_info(0).unwrap(); } } From a23efd7626dec6d36cf34efea7855de6d56fd6f7 Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 15:13:00 +0000 Subject: [PATCH 08/12] refactor(mmio): remove serial device specific method Remove special method for serial device from MMIODeviceManager. Now MMIODeviceManager does not have any device specific methods. Signed-off-by: Egor Lazarchuk --- src/vmm/src/builder.rs | 19 ++++++++++++-- src/vmm/src/device_manager/mmio.rs | 36 +-------------------------- src/vmm/src/device_manager/persist.rs | 21 ++++++++++++---- 3 files changed, 34 insertions(+), 42 deletions(-) diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index 71db070fa5b..b72e16574ec 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -663,12 +663,27 @@ fn attach_legacy_devices_aarch64( if cmdline_contains_console { // Make stdout non-blocking. set_stdout_nonblocking(); - let serial = setup_serial_device(event_manager)?; + + let serial = SerialDevice::new().map_err(VmmError::EventFd)?; + let device_info = vmm .device_manager .mmio_devices - .register_mmio_serial(vmm.vm.fd(), serial, None) + .allocate_device_info(1) + .map_err(VmmError::RegisterMMIODevice)?; + device_info + .register_kvm_irqfd(vmm.vm.fd(), serial.serial.interrupt_evt()) + .map_err(VmmError::RegisterMMIODevice)?; + + let serial = Arc::new(Mutex::new(BusDevice::Serial(serial))); + event_manager.add_subscriber(serial.clone()); + + let identifier = (DeviceType::Serial, DeviceType::Serial.to_string()); + vmm.device_manager + .mmio_devices + .add_bus_device_with_info(identifier, serial, device_info.clone()) .map_err(VmmError::RegisterMMIODevice)?; + cmdline .insert("earlycon", &format!("uart,mmio,0x{:08x}", device_info.addr)) .expect("All args are valid"); diff --git a/src/vmm/src/device_manager/mmio.rs b/src/vmm/src/device_manager/mmio.rs index 7c91d1878ad..745ff4e4bb9 100644 --- a/src/vmm/src/device_manager/mmio.rs +++ b/src/vmm/src/device_manager/mmio.rs @@ -118,7 +118,7 @@ impl MMIODeviceManager { } /// Allocates resources for a new device to be added. - fn allocate_device_info(&mut self, irq_count: u32) -> Result { + pub fn allocate_device_info(&mut self, irq_count: u32) -> Result { let irqs = (0..irq_count) .map(|_| self.irq_allocator.allocate_id()) .collect::>() @@ -199,40 +199,6 @@ impl MMIODeviceManager { ) } - #[cfg(target_arch = "aarch64")] - /// Register an early console at the specified MMIO configuration if given as parameter, - /// otherwise allocate a new MMIO resources for it. - pub fn register_mmio_serial( - &mut self, - vm: &VmFd, - serial: Arc>, - device_info_opt: Option, - ) -> Result { - // Create a new MMIODeviceInfo object on boot path or unwrap the - // existing object on restore path. - let device_info = if let Some(device_info) = device_info_opt { - device_info - } else { - self.allocate_device_info(1)? - }; - - device_info.register_kvm_irqfd( - vm, - serial - .lock() - .expect("Poisoned lock") - .serial_ref() - .unwrap() - .serial - .interrupt_evt(), - )?; - - let identifier = (DeviceType::Serial, DeviceType::Serial.to_string()); - // Register the newly created Serial object. - self.add_bus_device_with_info(identifier, serial, device_info.clone())?; - Ok(device_info) - } - /// Gets the information of the devices registered up to some point in time. pub fn get_device_info(&self) -> &HashMap<(DeviceType, String), MMIODeviceInfo> { &self.id_to_dev_info diff --git a/src/vmm/src/device_manager/persist.rs b/src/vmm/src/device_manager/persist.rs index b568f468d46..84ded32d8d5 100644 --- a/src/vmm/src/device_manager/persist.rs +++ b/src/vmm/src/device_manager/persist.rs @@ -15,6 +15,8 @@ use vm_allocator::AllocPolicy; use super::mmio::*; #[cfg(target_arch = "aarch64")] use crate::arch::DeviceType; +#[cfg(target_arch = "aarch64")] +use crate::devices::legacy::SerialDevice; use crate::devices::virtio::balloon::persist::{BalloonConstructorArgs, BalloonState}; use crate::devices::virtio::balloon::{Balloon, BalloonError}; use crate::devices::virtio::block::device::Block; @@ -372,8 +374,7 @@ impl<'a> Persist<'a> for MMIODeviceManager { { for state in &state.legacy_devices { if state.type_ == DeviceType::Serial { - let serial = - crate::builder::setup_serial_device(constructor_args.event_manager)?; + let serial = SerialDevice::new().map_err(crate::VmmError::EventFd)?; dev_manager .address_allocator @@ -386,10 +387,20 @@ impl<'a> Persist<'a> for MMIODeviceManager { DevicePersistError::DeviceManager(super::mmio::MmioError::Allocator(e)) })?; - dev_manager.register_mmio_serial( - vm, + state + .device_info + .register_kvm_irqfd(vm, serial.serial.interrupt_evt())?; + + let serial = Arc::new(Mutex::new(BusDevice::Serial(serial))); + constructor_args + .event_manager + .add_subscriber(serial.clone()); + + let identifier = (DeviceType::Serial, DeviceType::Serial.to_string()); + dev_manager.add_bus_device_with_info( + identifier, serial, - Some(state.device_info.clone()), + state.device_info.clone(), )?; } if state.type_ == DeviceType::Rtc { From 9e6c1b36be1880c1afb8d284bd89e071225a8a8d Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 15:32:29 +0000 Subject: [PATCH 09/12] refactor(builder): remove setup_serial_device method setup_serial_device was only used for x86_64 PortIODeviceManager creation. Moving creation of serial device near creation of PortIODeviceManager removes a need to jump through the code to see how serial device is created. Signed-off-by: Egor Lazarchuk --- src/vmm/src/builder.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index b72e16574ec..32ec063a51f 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -157,7 +157,11 @@ fn create_vmm_and_vcpus( set_stdout_nonblocking(); // Serial device setup. - let serial_device = setup_serial_device(event_manager).map_err(Internal)?; + let serial = SerialDevice::new() + .map_err(VmmError::EventFd) + .map_err(Internal)?; + let serial = Arc::new(Mutex::new(BusDevice::Serial(serial))); + event_manager.add_subscriber(serial.clone()); // x86_64 uses the i8042 reset event as the Vmm exit event. let reset_evt = vcpus_exit_evt @@ -168,7 +172,7 @@ fn create_vmm_and_vcpus( // create pio dev manager with legacy devices let pio_device_manager = { // TODO Remove these unwraps. - let mut pio_dev_mgr = PortIODeviceManager::new(serial_device, reset_evt).unwrap(); + let mut pio_dev_mgr = PortIODeviceManager::new(serial, reset_evt).unwrap(); pio_dev_mgr.register_devices(vm.fd()).unwrap(); pio_dev_mgr }; @@ -636,16 +640,6 @@ pub fn setup_interrupt_controller(vm: &mut Vm, vcpu_count: u8) -> Result<(), Sta .map_err(StartMicrovmError::Internal) } -/// Sets up the serial device. -pub fn setup_serial_device( - event_manager: &mut EventManager, -) -> Result>, VmmError> { - let serial = SerialDevice::new().map_err(VmmError::EventFd)?; - let serial = Arc::new(Mutex::new(BusDevice::Serial(serial))); - event_manager.add_subscriber(serial.clone()); - Ok(serial) -} - #[cfg(target_arch = "aarch64")] fn attach_legacy_devices_aarch64( event_manager: &mut EventManager, From e7a4972c0dace196b51e8c9c9650dbeba4eb4156 Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 15:50:06 +0000 Subject: [PATCH 10/12] refactor(mmio): move MMIODeviceManager into separate module MMIODeviceManager's implementation was spread across 2 modules: mmio.rs and persist.rs. By moving all implementation into mmio module we wil have an easir time when it comes to add more device managers (e.g. ACPI device_manager). Signed-off-by: Egor Lazarchuk --- src/vmm/src/builder.rs | 2 +- .../src/device_manager/{mmio.rs => mmio/mod.rs} | 3 +++ src/vmm/src/device_manager/{ => mmio}/persist.rs | 16 +++++----------- src/vmm/src/device_manager/mod.rs | 2 -- src/vmm/src/persist.rs | 2 +- src/vmm/src/resources.rs | 2 +- 6 files changed, 11 insertions(+), 16 deletions(-) rename src/vmm/src/device_manager/{mmio.rs => mmio/mod.rs} (99%) rename src/vmm/src/device_manager/{ => mmio}/persist.rs (98%) diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index 32ec063a51f..b8695ba3551 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -34,8 +34,8 @@ use crate::cpu_config::templates::{ }; #[cfg(target_arch = "x86_64")] use crate::device_manager::legacy::PortIODeviceManager; +use crate::device_manager::mmio::persist::MMIODevManagerConstructorArgs; use crate::device_manager::mmio::MMIODeviceManager; -use crate::device_manager::persist::MMIODevManagerConstructorArgs; use crate::device_manager::DeviceManager; #[cfg(target_arch = "aarch64")] use crate::devices::legacy::RTCDevice; diff --git a/src/vmm/src/device_manager/mmio.rs b/src/vmm/src/device_manager/mmio/mod.rs similarity index 99% rename from src/vmm/src/device_manager/mmio.rs rename to src/vmm/src/device_manager/mmio/mod.rs index 745ff4e4bb9..b8196bedd46 100644 --- a/src/vmm/src/device_manager/mmio.rs +++ b/src/vmm/src/device_manager/mmio/mod.rs @@ -29,6 +29,9 @@ use crate::devices::virtio::vsock::TYPE_VSOCK; use crate::devices::virtio::{TYPE_BALLOON, TYPE_BLOCK, TYPE_NET, TYPE_RNG}; use crate::devices::BusDevice; +/// Persis logic for MMIODeviceManager. +pub mod persist; + /// Errors for MMIO device manager. #[derive(Debug, thiserror::Error, displaydoc::Display)] pub enum MmioError { diff --git a/src/vmm/src/device_manager/persist.rs b/src/vmm/src/device_manager/mmio/persist.rs similarity index 98% rename from src/vmm/src/device_manager/persist.rs rename to src/vmm/src/device_manager/mmio/persist.rs index 84ded32d8d5..b6ae5b6fe89 100644 --- a/src/vmm/src/device_manager/persist.rs +++ b/src/vmm/src/device_manager/mmio/persist.rs @@ -12,9 +12,9 @@ use log::{error, warn}; use serde::{Deserialize, Serialize}; use vm_allocator::AllocPolicy; -use super::mmio::*; #[cfg(target_arch = "aarch64")] use crate::arch::DeviceType; +use crate::device_manager::mmio::*; #[cfg(target_arch = "aarch64")] use crate::devices::legacy::SerialDevice; use crate::devices::virtio::balloon::persist::{BalloonConstructorArgs, BalloonState}; @@ -57,7 +57,7 @@ pub enum DevicePersistError { /// Block: {0} Block(#[from] BlockError), /// Device manager: {0} - DeviceManager(#[from] super::mmio::MmioError), + DeviceManager(#[from] MmioError), /// Mmio transport MmioTransport, #[cfg(target_arch = "aarch64")] @@ -383,9 +383,7 @@ impl<'a> Persist<'a> for MMIODeviceManager { MMIO_LEN, AllocPolicy::ExactMatch(state.device_info.addr), ) - .map_err(|e| { - DevicePersistError::DeviceManager(super::mmio::MmioError::Allocator(e)) - })?; + .map_err(|e| DevicePersistError::DeviceManager(MmioError::Allocator(e)))?; state .device_info @@ -414,9 +412,7 @@ impl<'a> Persist<'a> for MMIODeviceManager { MMIO_LEN, AllocPolicy::ExactMatch(state.device_info.addr), ) - .map_err(|e| { - DevicePersistError::DeviceManager(super::mmio::MmioError::Allocator(e)) - })?; + .map_err(|e| DevicePersistError::DeviceManager(MmioError::Allocator(e)))?; let identifier = (DeviceType::Rtc, DeviceType::Rtc.to_string()); dev_manager.add_bus_device_with_info( identifier, @@ -460,9 +456,7 @@ impl<'a> Persist<'a> for MMIODeviceManager { MMIO_LEN, AllocPolicy::ExactMatch(device_info.addr), ) - .map_err(|e| { - DevicePersistError::DeviceManager(super::mmio::MmioError::Allocator(e)) - })?; + .map_err(|e| DevicePersistError::DeviceManager(MmioError::Allocator(e)))?; dev_manager.register_mmio_virtio(vm, id.clone(), mmio_transport, device_info)?; diff --git a/src/vmm/src/device_manager/mod.rs b/src/vmm/src/device_manager/mod.rs index fea1e869edb..aba18946a2e 100644 --- a/src/vmm/src/device_manager/mod.rs +++ b/src/vmm/src/device_manager/mod.rs @@ -13,8 +13,6 @@ use self::mmio::MMIODeviceManager; pub mod legacy; /// Memory Mapped I/O Manager. pub mod mmio; -/// Device managers (de)serialization support. -pub mod persist; #[derive(Debug)] pub struct DeviceManager { diff --git a/src/vmm/src/persist.rs b/src/vmm/src/persist.rs index aa2103a0b56..3d71dad9062 100644 --- a/src/vmm/src/persist.rs +++ b/src/vmm/src/persist.rs @@ -26,7 +26,7 @@ use crate::cpu_config::templates::StaticCpuTemplate; use crate::cpu_config::x86_64::cpuid::common::get_vendor_id_from_host; #[cfg(target_arch = "x86_64")] use crate::cpu_config::x86_64::cpuid::CpuidTrait; -use crate::device_manager::persist::{DevicePersistError, DeviceStates}; +use crate::device_manager::mmio::persist::{DevicePersistError, DeviceStates}; use crate::logger::{info, warn}; use crate::resources::VmResources; use crate::snapshot::Snapshot; diff --git a/src/vmm/src/resources.rs b/src/vmm/src/resources.rs index 25e83816236..57940449a74 100644 --- a/src/vmm/src/resources.rs +++ b/src/vmm/src/resources.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; use utils::net::ipv4addr::is_link_local_valid; use crate::cpu_config::templates::CustomCpuTemplate; -use crate::device_manager::persist::SharedDeviceType; +use crate::device_manager::mmio::persist::SharedDeviceType; use crate::logger::{info, log_dev_preview_warning}; use crate::mmds; use crate::mmds::data_store::{Mmds, MmdsVersion}; From c782e0661e4846ce526408c12609b5eebc5a8cfb Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 17:34:34 +0000 Subject: [PATCH 11/12] refactor(device_manager): use DeviceManager to save/restore state Before the inner `MMIODeviceManager` was responsible for state of devices. With this commit it will be easier to save states of other device types (e.g. ACPI devices). Signed-off-by: Egor Lazarchuk --- src/vmm/src/builder.rs | 7 +++---- src/vmm/src/device_manager/mod.rs | 17 +++++++++++++++++ src/vmm/src/lib.rs | 3 +-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index b8695ba3551..b3584f97e0c 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -52,7 +52,6 @@ use crate::devices::BusDevice; use crate::logger::{debug, error}; use crate::persist::{MicrovmState, MicrovmStateError}; use crate::resources::VmResources; -use crate::snapshot::Persist; use crate::vmm_config::boot_source::BootConfig; use crate::vmm_config::instance_info::InstanceInfo; use crate::vmm_config::machine_config::{VmConfig, VmConfigError}; @@ -502,9 +501,9 @@ pub fn build_microvm_from_snapshot( instance_id: &instance_info.id, }; - vmm.device_manager.mmio_devices = - MMIODeviceManager::restore(mmio_ctor_args, µvm_state.device_states) - .map_err(MicrovmStateError::RestoreDevices)?; + vmm.device_manager + .restore(mmio_ctor_args, µvm_state.device_states) + .map_err(MicrovmStateError::RestoreDevices)?; vmm.emulate_serial_init()?; // Move vcpus to their own threads and start their state machine in the 'Paused' state. diff --git a/src/vmm/src/device_manager/mod.rs b/src/vmm/src/device_manager/mod.rs index aba18946a2e..150bd63f745 100644 --- a/src/vmm/src/device_manager/mod.rs +++ b/src/vmm/src/device_manager/mod.rs @@ -7,7 +7,9 @@ #[cfg(target_arch = "x86_64")] use self::legacy::PortIODeviceManager; +use self::mmio::persist::{DevicePersistError, DeviceStates, MMIODevManagerConstructorArgs}; use self::mmio::MMIODeviceManager; +use crate::snapshot::Persist; /// Legacy Device Manager. pub mod legacy; @@ -20,3 +22,18 @@ pub struct DeviceManager { #[cfg(target_arch = "x86_64")] pub pio_diveces: PortIODeviceManager, } + +impl DeviceManager { + pub fn save(&self) -> DeviceStates { + self.mmio_devices.save() + } + + pub fn restore( + &mut self, + constructor_args: MMIODevManagerConstructorArgs, + state: &DeviceStates, + ) -> Result<(), DevicePersistError> { + self.mmio_devices = MMIODeviceManager::restore(constructor_args, state)?; + Ok(()) + } +} diff --git a/src/vmm/src/lib.rs b/src/vmm/src/lib.rs index cdb82e83fc2..deea70eefa6 100644 --- a/src/vmm/src/lib.rs +++ b/src/vmm/src/lib.rs @@ -135,7 +135,6 @@ use crate::devices::virtio::{TYPE_BALLOON, TYPE_BLOCK, TYPE_NET}; use crate::logger::{error, info, warn, MetricsError, METRICS}; use crate::persist::{MicrovmState, MicrovmStateError, VmInfo}; use crate::rate_limiter::BucketUpdate; -use crate::snapshot::Persist; use crate::vmm_config::instance_info::{InstanceInfo, VmState}; use crate::vstate::memory::{ GuestMemory, GuestMemoryExtension, GuestMemoryMmap, GuestMemoryRegion, @@ -515,7 +514,7 @@ impl Vmm { self.vm.save_state(&mpidrs).map_err(SaveVmState)? } }; - let device_states = self.device_manager.mmio_devices.save(); + let device_states = self.device_manager.save(); let memory_state = self.guest_memory().describe(); From 6864abd6913c8d9004f4dcc4e7995b961e9ad5da Mon Sep 17 00:00:00 2001 From: Egor Lazarchuk Date: Sat, 16 Mar 2024 18:12:12 +0000 Subject: [PATCH 12/12] refactor(mmio): replace register_mmio_virtio with add_device_with_info New `add_device_with_info` method plays a bit better with other new `add_*` methods. Signed-off-by: Egor Lazarchuk --- src/vmm/src/device_manager/mmio/mod.rs | 52 ++++++++++------------ src/vmm/src/device_manager/mmio/persist.rs | 8 +++- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/vmm/src/device_manager/mmio/mod.rs b/src/vmm/src/device_manager/mmio/mod.rs index b8196bedd46..2c807e24db0 100644 --- a/src/vmm/src/device_manager/mmio/mod.rs +++ b/src/vmm/src/device_manager/mmio/mod.rs @@ -146,10 +146,33 @@ impl MMIODeviceManager { mmio_device: MmioTransport, ) -> Result { let device_info = self.allocate_device_info(1)?; - self.register_mmio_virtio(vm, device_id, mmio_device, &device_info)?; + self.add_device_with_info(vm, device_id, mmio_device, device_info.clone())?; Ok(device_info) } + /// Add new virtio-over-MMIO device with specified + /// device info. + pub fn add_device_with_info( + &mut self, + vm: &VmFd, + device_id: String, + mmio_device: MmioTransport, + device_info: MMIODeviceInfo, + ) -> Result<(), MmioError> { + let identifier = { + let locked_device = mmio_device.locked_device(); + (DeviceType::Virtio(locked_device.device_type()), device_id) + }; + + device_info.register_kvm_device(vm, &mmio_device)?; + + self.add_bus_device_with_info( + identifier, + Arc::new(Mutex::new(BusDevice::MmioTransport(mmio_device))), + device_info, + ) + } + /// Add new MMIO device to the MMIO bus. pub fn add_bus_device( &mut self, @@ -175,33 +198,6 @@ impl MMIODeviceManager { Ok(()) } - /// Register a virtio-over-MMIO device to be used via MMIO transport at a specific slot. - pub fn register_mmio_virtio( - &mut self, - vm: &VmFd, - device_id: String, - mmio_device: MmioTransport, - device_info: &MMIODeviceInfo, - ) -> Result<(), MmioError> { - // Our virtio devices are currently hardcoded to use a single IRQ. - // Validate that requirement. - if device_info.irqs.len() != 1 { - return Err(MmioError::InvalidIrqConfig); - } - let identifier = { - let locked_device = mmio_device.locked_device(); - (DeviceType::Virtio(locked_device.device_type()), device_id) - }; - - device_info.register_kvm_device(vm, &mmio_device)?; - - self.add_bus_device_with_info( - identifier, - Arc::new(Mutex::new(BusDevice::MmioTransport(mmio_device))), - device_info.clone(), - ) - } - /// Gets the information of the devices registered up to some point in time. pub fn get_device_info(&self) -> &HashMap<(DeviceType, String), MMIODeviceInfo> { &self.id_to_dev_info diff --git a/src/vmm/src/device_manager/mmio/persist.rs b/src/vmm/src/device_manager/mmio/persist.rs index b6ae5b6fe89..8ba7782b4c9 100644 --- a/src/vmm/src/device_manager/mmio/persist.rs +++ b/src/vmm/src/device_manager/mmio/persist.rs @@ -458,8 +458,12 @@ impl<'a> Persist<'a> for MMIODeviceManager { ) .map_err(|e| DevicePersistError::DeviceManager(MmioError::Allocator(e)))?; - dev_manager.register_mmio_virtio(vm, id.clone(), mmio_transport, device_info)?; - + dev_manager.add_device_with_info( + vm, + id.clone(), + mmio_transport, + device_info.clone(), + )?; event_manager.add_subscriber(as_subscriber); Ok(()) };