diff --git a/devices/src/acpi.rs b/devices/src/acpi.rs index 188812259..c66279526 100644 --- a/devices/src/acpi.rs +++ b/devices/src/acpi.rs @@ -5,6 +5,7 @@ use acpi_tables::{aml, aml::Aml}; use std::sync::Arc; +use std::time::Instant; use vm_device::interrupt::InterruptSourceGroup; use vmm_sys_util::eventfd::EventFd; use BusDevice; @@ -149,3 +150,39 @@ impl Aml for AcpiGEDDevice { .to_aml_bytes() } } + +pub struct AcpiPMTimerDevice { + start: Instant, +} + +impl AcpiPMTimerDevice { + pub fn new() -> Self { + Self { + start: Instant::now(), + } + } +} + +impl Default for AcpiPMTimerDevice { + fn default() -> Self { + Self::new() + } +} + +impl BusDevice for AcpiPMTimerDevice { + fn read(&mut self, _base: u64, _offset: u64, data: &mut [u8]) { + let now = Instant::now(); + let since = now.duration_since(self.start); + let nanos = since.as_nanos(); + + const PM_TIMER_FREQUENCY_HZ: u128 = 3_579_545; + const NANOS_PER_SECOND: u128 = 1_000_000_000; + + let counter = (nanos * PM_TIMER_FREQUENCY_HZ) / NANOS_PER_SECOND; + let counter: u32 = (counter & 0xffff_ffff) as u32; + + data.copy_from_slice(&counter.to_le_bytes()); + } + + fn write(&mut self, _base: u64, _offset: u64, _data: &[u8]) {} +} diff --git a/devices/src/lib.rs b/devices/src/lib.rs index 329eaff70..4677146b2 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -39,7 +39,7 @@ pub mod ioapic; pub mod legacy; #[cfg(feature = "acpi")] -pub use self::acpi::{AcpiGEDDevice, AcpiShutdownDevice}; +pub use self::acpi::{AcpiGEDDevice, AcpiPMTimerDevice, AcpiShutdownDevice}; pub use self::bus::{Bus, BusDevice, Error as BusError}; pub type DeviceEventT = u16; diff --git a/vmm/src/acpi.rs b/vmm/src/acpi.rs index 2d3145e8f..7e831b619 100644 --- a/vmm/src/acpi.rs +++ b/vmm/src/acpi.rs @@ -64,8 +64,11 @@ pub fn create_acpi_tables( // Revision 6 of the ACPI FADT table is 276 bytes long let mut facp = SDT::new(*b"FACP", 276, 6, *b"CLOUDH", *b"CHFACP ", 1); - // HW_REDUCED_ACPI and RESET_REG_SUP - let fadt_flags: u32 = 1 << 20 | 1 << 10; + // PM_TMR_BLK I/O port + facp.write(76, 0xb008); + + // HW_REDUCED_ACPI, RESET_REG_SUP, TMR_VAL_EXT + let fadt_flags: u32 = 1 << 20 | 1 << 10 | 1 << 8; facp.write(112, fadt_flags); // RESET_REG @@ -76,6 +79,9 @@ pub fn create_acpi_tables( facp.write(131, 3u8); // FADT minor version facp.write(140, dsdt_offset.0); // X_DSDT + // X_PM_TMR_BLK + facp.write(208, GenericAddress::io_port_address(0xb008)); + // SLEEP_CONTROL_REG facp.write(244, GenericAddress::io_port_address(0x3c0)); // SLEEP_STATUS_REG diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 93117a8d9..bc79791f5 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -1224,6 +1224,24 @@ impl DeviceManager { .io_bus .insert(ged_device.clone(), 0xb000, 0x1) .map_err(DeviceManagerError::BusError)?; + + let pm_timer_device = Arc::new(Mutex::new(devices::AcpiPMTimerDevice::new())); + + self.bus_devices + .push(Arc::clone(&pm_timer_device) as Arc>); + + self.address_manager + .allocator + .lock() + .unwrap() + .allocate_io_addresses(Some(GuestAddress(0xb008)), 0x4, None) + .ok_or(DeviceManagerError::AllocateIOPort)?; + + self.address_manager + .io_bus + .insert(pm_timer_device, 0xb008, 0x4) + .map_err(DeviceManagerError::BusError)?; + Ok(Some(ged_device)) }