From e0d3efec6e61df710ee69bba317b5d032e2af82d Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 29 Mar 2022 12:40:34 +0100 Subject: [PATCH] devices: cmos: Implement CMOS based reset If EFI reset fails on the Linux kernel then it will fallthrough to CMOS reset. Implement this as one of our reset solutions. Fixes: #3912 Signed-off-by: Rob Bradford --- devices/src/legacy/cmos.rs | 21 +++++++++++++++++---- vmm/src/device_manager.rs | 5 ++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/devices/src/legacy/cmos.rs b/devices/src/legacy/cmos.rs index 3d07eb84c..4ccb396d6 100644 --- a/devices/src/legacy/cmos.rs +++ b/devices/src/legacy/cmos.rs @@ -7,6 +7,7 @@ use std::cmp::min; use std::mem; use std::sync::{Arc, Barrier}; use vm_device::BusDevice; +use vmm_sys_util::eventfd::EventFd; // https://github.com/rust-lang/libc/issues/1848 #[cfg_attr(target_env = "musl", allow(deprecated))] @@ -21,13 +22,14 @@ const DATA_LEN: usize = 128; pub struct Cmos { index: u8, data: [u8; DATA_LEN], + reset_evt: EventFd, } impl Cmos { /// Constructs a CMOS/RTC device with initial data. /// `mem_below_4g` is the size of memory in bytes below the 32-bit gap. /// `mem_above_4g` is the size of memory in bytes above the 32-bit gap. - pub fn new(mem_below_4g: u64, mem_above_4g: u64) -> Cmos { + pub fn new(mem_below_4g: u64, mem_above_4g: u64, reset_evt: EventFd) -> Cmos { let mut data = [0u8; DATA_LEN]; // Extended memory from 16 MB to 4 GB in units of 64 KB @@ -44,7 +46,11 @@ impl Cmos { data[0x5c] = (high_mem >> 8) as u8; data[0x5d] = (high_mem >> 16) as u8; - Cmos { index: 0, data } + Cmos { + index: 0, + data, + reset_evt, + } } } @@ -56,8 +62,15 @@ impl BusDevice for Cmos { } match offset { - INDEX_OFFSET => self.index = data[0] & INDEX_MASK, - DATA_OFFSET => self.data[self.index as usize] = data[0], + INDEX_OFFSET => self.index = data[0], + DATA_OFFSET => { + if self.index == 0x8f && data[0] == 0 { + info!("CMOS reset"); + self.reset_evt.write(1).unwrap(); + } else { + self.data[(self.index & INDEX_MASK) as usize] = data[0] + } + } o => warn!("bad write offset on CMOS device: {}", o), }; None diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 473924152..62c5f58f1 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -1459,7 +1459,9 @@ impl DeviceManager { #[cfg(target_arch = "x86_64")] fn add_legacy_devices(&mut self, reset_evt: EventFd) -> DeviceManagerResult<()> { // Add a shutdown device (i8042) - let i8042 = Arc::new(Mutex::new(devices::legacy::I8042Device::new(reset_evt))); + let i8042 = Arc::new(Mutex::new(devices::legacy::I8042Device::new( + reset_evt.try_clone().unwrap(), + ))); self.bus_devices .push(Arc::clone(&i8042) as Arc>); @@ -1486,6 +1488,7 @@ impl DeviceManager { let cmos = Arc::new(Mutex::new(devices::legacy::Cmos::new( mem_below_4g, mem_above_4g, + reset_evt, ))); self.bus_devices