use std::sync::Arc;
use crate::bitflags;
use crate::device::{self, Pause};
use crate::mem::emulated::{Action, Mmio};
use crate::mem::{self, MemRegion};
use crate::pci::cap::PciCapList;
use crate::pci::config::{
BAR_MEM64, BAR_PREFETCHABLE, CommonHeader, DeviceHeader, EmulatedConfig, HeaderType, PciConfig,
};
use crate::pci::{self, Pci, PciBar};
bitflags! {
struct PvPanicByte(u8) {
PANICKED = 1 << 0;
CRASH_LOADED = 1 << 1;
}
}
pub const PVPANIC_VENDOR_ID: u16 = 0x1b36;
pub const PVPANIC_DEVICE_ID: u16 = 0x0011;
const BAR_SIZE: u64 = 0x1000;
#[derive(Debug)]
struct PvPanicBar;
impl Mmio for PvPanicBar {
fn size(&self) -> u64 {
BAR_SIZE
}
fn read(&self, _offset: u64, _size: u8) -> mem::Result<u64> {
Ok(PvPanicByte::all().bits() as u64)
}
fn write(&self, _offset: u64, _size: u8, val: u64) -> mem::Result<Action> {
log::info!("pvpanic: {:x?}", PvPanicByte::from_bits_retain(val as u8));
Ok(Action::Shutdown)
}
}
#[derive(Debug)]
pub struct PvPanic {
pub config: EmulatedConfig,
}
impl PvPanic {
pub fn new() -> Self {
let header = DeviceHeader {
common: CommonHeader {
vendor: PVPANIC_VENDOR_ID,
device: PVPANIC_DEVICE_ID,
revision: 1,
header_type: HeaderType::DEVICE,
class: 0x08,
subclass: 0x80,
..Default::default()
},
bars: [BAR_MEM64 | BAR_PREFETCHABLE, 0, 0, 0, 0, 0],
..Default::default()
};
let bar0 = PciBar::Mem(Arc::new(MemRegion::with_emulated(
Arc::new(PvPanicBar),
mem::MemRegionType::Hidden,
)));
let mut bars = [const { PciBar::Empty }; 6];
bars[0] = bar0;
let config = EmulatedConfig::new_device(header, bars, PciCapList::new());
PvPanic { config }
}
}
impl Default for PvPanic {
fn default() -> Self {
PvPanic::new()
}
}
impl Pause for PvPanic {
fn pause(&self) -> device::Result<()> {
Ok(())
}
fn resume(&self) -> device::Result<()> {
Ok(())
}
}
impl Pci for PvPanic {
fn name(&self) -> &str {
"pvpanic"
}
fn config(&self) -> &dyn PciConfig {
&self.config
}
fn reset(&self) -> pci::Result<()> {
Ok(())
}
}
#[cfg(test)]
#[path = "pvpanic_test.rs"]
mod tests;