Skip to content

Commit 8a598ee

Browse files
authored
Merge branch 'main' into update-devctr-v89
2 parents ff9c429 + 86aac24 commit 8a598ee

File tree

9 files changed

+190
-83
lines changed

9 files changed

+190
-83
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ and this project adheres to
3232
HID (Hardware ID) of VMGenID device so that it aligns with the upstream Linux
3333
kernel. This caused the driver not to be bound correctly to the device prior
3434
to Linux kernel 6.10.
35+
- [#5764](https://github.com/firecracker-microvm/firecracker/pull/5764): Fixed a
36+
bug that caused the guest UART driver to get stuck and stop transmitting after
37+
snapshot restore. The bug was triggered by taking a snapshot while a serial
38+
transmission was taking place. On restore the driver would wait for a TX
39+
interrupt that would never arrive and no output would appear in the serial
40+
console.
3541
- [#5780](https://github.com/firecracker-microvm/firecracker/pull/5780): Fixed
3642
missing `/sys/devices/system/cpu/cpu*/cache/*` in aarch64 guests when running
3743
on host kernels >= 6.3 with guest kernels >= 6.1.156.

src/vmm/src/builder.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,6 @@ pub enum BuildMicrovmFromSnapshotError {
411411
VmUpdateConfig(#[from] MachineConfigError),
412412
/// Failed to restore MMIO device: {0}
413413
RestoreMmioDevice(#[from] MicrovmStateError),
414-
/// Failed to emulate MMIO serial: {0}
415-
EmulateSerialInit(#[from] crate::EmulateSerialInitError),
416414
/// Failed to start vCPUs as no vCPU seccomp filter found.
417415
MissingVcpuSeccompFilters,
418416
/// Failed to start vCPUs: {0}

src/vmm/src/device_manager/mod.rs

Lines changed: 43 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@ use pci_mngr::{PciDevices, PciDevicesConstructorArgs, PciManagerError};
2121
use persist::MMIODevManagerConstructorArgs;
2222
use serde::{Deserialize, Serialize};
2323
use utils::time::TimestampUs;
24+
use vm_superio::serial;
2425
use vmm_sys_util::eventfd::EventFd;
2526

2627
use crate::device_manager::acpi::ACPIDeviceError;
2728
#[cfg(target_arch = "x86_64")]
2829
use crate::devices::legacy::I8042Device;
2930
#[cfg(target_arch = "aarch64")]
3031
use crate::devices::legacy::RTCDevice;
32+
use crate::devices::legacy::SerialDevice;
3133
use crate::devices::legacy::serial::SerialOut;
32-
use crate::devices::legacy::{IER_RDA_BIT, IER_RDA_OFFSET, SerialDevice};
3334
use crate::devices::pseudo::BootTimer;
3435
use crate::devices::virtio::ActivateError;
3536
use crate::devices::virtio::balloon::BalloonError;
@@ -47,7 +48,7 @@ use crate::utils::open_file_nonblock;
4748
use crate::vmm_config::mmds::MmdsConfigError;
4849
use crate::vstate::bus::BusError;
4950
use crate::vstate::memory::GuestMemoryMmap;
50-
use crate::{EmulateSerialInitError, EventManager, Vm};
51+
use crate::{EventManager, Vm};
5152

5253
/// ACPI device manager.
5354
pub mod acpi;
@@ -132,6 +133,7 @@ impl DeviceManager {
132133
fn setup_serial_device(
133134
event_manager: &mut EventManager,
134135
output: Option<&PathBuf>,
136+
state: Option<&serial::SerialState>,
135137
) -> Result<Arc<Mutex<SerialDevice>>, std::io::Error> {
136138
let (serial_in, serial_out) = match output {
137139
Some(path) => (None, open_file_nonblock(path).map(SerialOut::File)?),
@@ -142,20 +144,44 @@ impl DeviceManager {
142144
}
143145
};
144146

145-
let serial = Arc::new(Mutex::new(SerialDevice::new(serial_in, serial_out)?));
147+
let serial = Arc::new(Mutex::new(SerialDevice::new(serial_in, serial_out, state)?));
146148
event_manager.add_subscriber(serial.clone());
147149
Ok(serial)
148150
}
149151

152+
fn serial_state(&self) -> Option<persist::SerialState> {
153+
#[cfg(target_arch = "aarch64")]
154+
{
155+
self.mmio_devices.serial.as_ref().map(|device| {
156+
let locked = device.inner.lock().expect("Poisoned lock");
157+
locked.serial.state().into()
158+
})
159+
}
160+
161+
#[cfg(target_arch = "x86_64")]
162+
{
163+
Some(
164+
self.legacy_devices
165+
.stdio_serial
166+
.lock()
167+
.expect("Poisoned lock")
168+
.serial
169+
.state()
170+
.into(),
171+
)
172+
}
173+
}
174+
150175
#[cfg(target_arch = "x86_64")]
151176
fn create_legacy_devices(
152177
event_manager: &mut EventManager,
153178
vcpus_exit_evt: &EventFd,
154179
vm: &Vm,
155180
serial_output: Option<&PathBuf>,
181+
serial_state: Option<&serial::SerialState>,
156182
) -> Result<PortIODeviceManager, DeviceManagerCreateError> {
157183
// Create serial device
158-
let serial = Self::setup_serial_device(event_manager, serial_output)?;
184+
let serial = Self::setup_serial_device(event_manager, serial_output, serial_state)?;
159185
let reset_evt = vcpus_exit_evt
160186
.try_clone()
161187
.map_err(DeviceManagerCreateError::EventFd)?;
@@ -180,7 +206,7 @@ impl DeviceManager {
180206
) -> Result<Self, DeviceManagerCreateError> {
181207
#[cfg(target_arch = "x86_64")]
182208
let legacy_devices =
183-
Self::create_legacy_devices(event_manager, vcpus_exit_evt, vm, serial_output)?;
209+
Self::create_legacy_devices(event_manager, vcpus_exit_evt, vm, serial_output, None)?;
184210

185211
Ok(DeviceManager {
186212
mmio_devices: MMIODeviceManager::new(),
@@ -276,7 +302,7 @@ impl DeviceManager {
276302
.contains("console=");
277303

278304
if cmdline_contains_console {
279-
let serial = Self::setup_serial_device(event_manager, serial_out_path)?;
305+
let serial = Self::setup_serial_device(event_manager, serial_out_path, None)?;
280306
self.mmio_devices.register_mmio_serial(vm, serial, None)?;
281307
self.mmio_devices.add_mmio_serial_to_cmdline(cmdline)?;
282308
}
@@ -419,6 +445,8 @@ pub struct DevicesState {
419445
pub acpi_state: persist::ACPIDeviceManagerState,
420446
/// PCI devices state
421447
pub pci_state: pci_mngr::PciDevicesState,
448+
/// Serial device state
449+
pub serial_state: Option<persist::SerialState>,
422450
}
423451

424452
/// Errors for (de)serialization of the devices.
@@ -466,8 +494,6 @@ pub enum DeviceManagerPersistError {
466494
AcpiRestore(#[from] ACPIDeviceError),
467495
/// Error restoring PCI devices: {0}
468496
PciRestore(DevicePersistError),
469-
/// Error resetting serial console: {0}
470-
SerialRestore(#[from] EmulateSerialInitError),
471497
/// Error inserting device in bus: {0}
472498
Bus(#[from] BusError),
473499
/// Error creating DeviceManager: {0}
@@ -504,6 +530,7 @@ impl<'a> Persist<'a> for DeviceManager {
504530
mmio_state: self.mmio_devices.save(),
505531
acpi_state: self.acpi_devices.save(),
506532
pci_state: self.pci_devices.save(),
533+
serial_state: self.serial_state(),
507534
}
508535
}
509536

@@ -513,11 +540,15 @@ impl<'a> Persist<'a> for DeviceManager {
513540
) -> Result<Self, Self::Error> {
514541
// Setup legacy devices in case of x86
515542
#[cfg(target_arch = "x86_64")]
543+
let serial_state: Option<vm_superio::serial::SerialState> =
544+
state.serial_state.as_ref().map(Into::into);
545+
#[cfg(target_arch = "x86_64")]
516546
let legacy_devices = Self::create_legacy_devices(
517547
constructor_args.event_manager,
518548
constructor_args.vcpus_exit_evt,
519549
constructor_args.vm,
520550
constructor_args.vm_resources.serial_out_path.as_ref(),
551+
serial_state.as_ref(),
521552
)?;
522553

523554
// Restore MMIO devices
@@ -527,6 +558,7 @@ impl<'a> Persist<'a> for DeviceManager {
527558
event_manager: constructor_args.event_manager,
528559
vm_resources: constructor_args.vm_resources,
529560
instance_id: constructor_args.instance_id,
561+
serial_state: state.serial_state.as_ref(),
530562
};
531563
let mmio_devices = MMIODeviceManager::restore(mmio_ctor_args, &state.mmio_state)
532564
.map_err(DeviceManagerPersistError::MmioRestore)?;
@@ -545,59 +577,13 @@ impl<'a> Persist<'a> for DeviceManager {
545577
let pci_devices = PciDevices::restore(pci_ctor_args, &state.pci_state)
546578
.map_err(DeviceManagerPersistError::PciRestore)?;
547579

548-
let device_manager = DeviceManager {
580+
Ok(DeviceManager {
549581
mmio_devices,
550582
#[cfg(target_arch = "x86_64")]
551583
legacy_devices,
552584
acpi_devices,
553585
pci_devices,
554-
};
555-
556-
// Restore serial.
557-
// We need to do that after we restore mmio devices, otherwise it won't succeed in Aarch64
558-
device_manager.emulate_serial_init()?;
559-
560-
Ok(device_manager)
561-
}
562-
}
563-
564-
impl DeviceManager {
565-
/// Sets RDA bit in serial console
566-
pub fn emulate_serial_init(&self) -> Result<(), EmulateSerialInitError> {
567-
// When restoring from a previously saved state, there is no serial
568-
// driver initialization, therefore the RDA (Received Data Available)
569-
// interrupt is not enabled. Because of that, the driver won't get
570-
// notified of any bytes that we send to the guest. The clean solution
571-
// would be to save the whole serial device state when we do the vm
572-
// serialization. For now we set that bit manually
573-
574-
#[cfg(target_arch = "aarch64")]
575-
{
576-
if let Some(device) = &self.mmio_devices.serial {
577-
let mut device_locked = device.inner.lock().expect("Poisoned lock");
578-
579-
device_locked
580-
.serial
581-
.write(IER_RDA_OFFSET, IER_RDA_BIT)
582-
.map_err(|_| EmulateSerialInitError(std::io::Error::last_os_error()))?;
583-
}
584-
Ok(())
585-
}
586-
587-
#[cfg(target_arch = "x86_64")]
588-
{
589-
let mut serial = self
590-
.legacy_devices
591-
.stdio_serial
592-
.lock()
593-
.expect("Poisoned lock");
594-
595-
serial
596-
.serial
597-
.write(IER_RDA_OFFSET, IER_RDA_BIT)
598-
.map_err(|_| EmulateSerialInitError(std::io::Error::last_os_error()))?;
599-
Ok(())
600-
}
586+
})
601587
}
602588
}
603589

@@ -622,7 +608,7 @@ pub(crate) mod tests {
622608
#[cfg(target_arch = "x86_64")]
623609
let legacy_devices = PortIODeviceManager {
624610
stdio_serial: Arc::new(Mutex::new(
625-
SerialDevice::new(None, SerialOut::Sink).unwrap(),
611+
SerialDevice::new(None, SerialOut::Sink, None).unwrap(),
626612
)),
627613
i8042: Arc::new(Mutex::new(
628614
I8042Device::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()).unwrap(),

src/vmm/src/device_manager/persist.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,54 @@ use crate::vmm_config::memory_hotplug::MemoryHotplugConfig;
4545
use crate::vstate::memory::GuestMemoryMmap;
4646
use crate::{EventManager, Vm};
4747

48+
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
49+
pub struct SerialState {
50+
pub baud_divisor_low: u8,
51+
pub baud_divisor_high: u8,
52+
pub interrupt_enable: u8,
53+
pub interrupt_identification: u8,
54+
pub line_control: u8,
55+
pub line_status: u8,
56+
pub modem_control: u8,
57+
pub modem_status: u8,
58+
pub scratch: u8,
59+
pub in_buffer: Vec<u8>,
60+
}
61+
62+
impl From<vm_superio::serial::SerialState> for SerialState {
63+
fn from(s: vm_superio::serial::SerialState) -> Self {
64+
Self {
65+
baud_divisor_low: s.baud_divisor_low,
66+
baud_divisor_high: s.baud_divisor_high,
67+
interrupt_enable: s.interrupt_enable,
68+
interrupt_identification: s.interrupt_identification,
69+
line_control: s.line_control,
70+
line_status: s.line_status,
71+
modem_control: s.modem_control,
72+
modem_status: s.modem_status,
73+
scratch: s.scratch,
74+
in_buffer: s.in_buffer,
75+
}
76+
}
77+
}
78+
79+
impl From<&SerialState> for vm_superio::serial::SerialState {
80+
fn from(s: &SerialState) -> Self {
81+
Self {
82+
baud_divisor_low: s.baud_divisor_low,
83+
baud_divisor_high: s.baud_divisor_high,
84+
interrupt_enable: s.interrupt_enable,
85+
interrupt_identification: s.interrupt_identification,
86+
line_control: s.line_control,
87+
line_status: s.line_status,
88+
modem_control: s.modem_control,
89+
modem_status: s.modem_status,
90+
scratch: s.scratch,
91+
in_buffer: s.in_buffer.clone(),
92+
}
93+
}
94+
}
95+
4896
/// Holds the state of a MMIO VirtIO device
4997
#[derive(Debug, Clone, Serialize, Deserialize)]
5098
pub struct VirtioDeviceState<T> {
@@ -104,6 +152,7 @@ pub struct MMIODevManagerConstructorArgs<'a> {
104152
pub event_manager: &'a mut EventManager,
105153
pub vm_resources: &'a mut VmResources,
106154
pub instance_id: &'a str,
155+
pub serial_state: Option<&'a SerialState>,
107156
}
108157
impl fmt::Debug for MMIODevManagerConstructorArgs<'_> {
109158
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -318,9 +367,12 @@ impl<'a> Persist<'a> for MMIODeviceManager {
318367
{
319368
for state in &state.legacy_devices {
320369
if state.type_ == DeviceType::Serial {
370+
let serial_state: Option<vm_superio::serial::SerialState> =
371+
constructor_args.serial_state.map(Into::into);
321372
let serial = crate::DeviceManager::setup_serial_device(
322373
constructor_args.event_manager,
323374
constructor_args.vm_resources.serial_out_path.as_ref(),
375+
serial_state.as_ref(),
324376
)?;
325377

326378
dev_manager.register_mmio_serial(vm, serial, Some(state.device_info))?;
@@ -719,6 +771,7 @@ mod tests {
719771
event_manager: &mut event_manager,
720772
vm_resources,
721773
instance_id: "microvm-id",
774+
serial_state: None,
722775
};
723776
let _restored_dev_manager =
724777
MMIODeviceManager::restore(restore_args, &device_manager_state.mmio_state).unwrap();

src/vmm/src/devices/legacy/mod.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ use vmm_sys_util::eventfd::EventFd;
2222
pub use self::i8042::{I8042Device, I8042Error as I8042DeviceError};
2323
#[cfg(target_arch = "aarch64")]
2424
pub use self::rtc_pl031::RTCDevice;
25-
pub use self::serial::{
26-
IER_RDA_BIT, IER_RDA_OFFSET, SerialDevice, SerialEventsWrapper, SerialWrapper,
27-
};
25+
pub use self::serial::{SerialDevice, SerialEventsWrapper, SerialWrapper};
2826

2927
/// Wrapper for implementing the trigger functionality for `EventFd`.
3028
///

0 commit comments

Comments
 (0)