use std::time::Instant;
use log::error;
use address_space::GuestAddress;
use util::{
num_ops::{read_data_u16, write_data_u16},
time::NANOSECONDS_PER_SECOND,
};
const PM_TIMER_FREQUENCY: u128 = 3_579_545;
const ACPI_BITMASK_SLEEP_ENABLE: u16 = 0x2000;
#[allow(clippy::upper_case_acronyms)]
pub struct AcpiPMTimer {
start: Instant,
}
impl Default for AcpiPMTimer {
fn default() -> Self {
Self::new()
}
}
impl AcpiPMTimer {
pub fn new() -> AcpiPMTimer {
AcpiPMTimer {
start: Instant::now(),
}
}
pub fn read(&mut self, data: &mut [u8], _base: GuestAddress, _offset: u64) -> bool {
if data.len() != 4 {
error!(
"PM Timer read: invalid data length {}, required length is 4",
data.len()
);
}
let now = Instant::now();
let time_nanos = now.duration_since(self.start).as_nanos();
let counter: u128 = (time_nanos * PM_TIMER_FREQUENCY) / u128::from(NANOSECONDS_PER_SECOND);
data.copy_from_slice(&((counter & 0xFFFF_FFFF) as u32).to_le_bytes());
true
}
}
#[derive(Default)]
pub struct AcpiPmEvent {
status: u16,
enable: u16,
}
impl AcpiPmEvent {
pub fn new() -> AcpiPmEvent {
AcpiPmEvent {
status: 0,
enable: 0,
}
}
pub fn read(&mut self, data: &mut [u8], _base: GuestAddress, offset: u64) -> bool {
match offset {
0 => write_data_u16(data, self.status),
2 => write_data_u16(data, self.enable),
_ => {
error!("Invalid offset");
false
}
}
}
pub fn write(&mut self, data: &[u8], _base: GuestAddress, offset: u64) -> bool {
match offset {
0 => {
let mut value = 0;
if !read_data_u16(data, &mut value) {
return false;
}
self.status &= !value;
}
2 => {
let mut value = 0;
if !read_data_u16(data, &mut value) {
return false;
}
self.enable = value;
}
_ => {
error!("Invalid offset");
return false;
}
}
true
}
}
#[derive(Default)]
pub struct AcpiPmCtrl {
control: u16,
}
impl AcpiPmCtrl {
pub fn new() -> AcpiPmCtrl {
AcpiPmCtrl { control: 0 }
}
pub fn read(&mut self, data: &mut [u8], _base: GuestAddress, _offset: u64) -> bool {
write_data_u16(data, self.control)
}
pub fn write(&mut self, data: &[u8], _base: GuestAddress, _offset: u64) -> bool {
let mut value = 0;
if !read_data_u16(data, &mut value) {
return false;
}
self.control = value & !ACPI_BITMASK_SLEEP_ENABLE;
value & ACPI_BITMASK_SLEEP_ENABLE != 0
}
}