use core::marker::PhantomData;
use crate::virtualization::VirtualizationError;
#[derive(Debug)]
struct HostState {
vector: usize,
guest_vector: usize,
status: usize,
}
#[derive(Debug, Default)]
pub struct PerCpu {
host: Option<HostState>,
local: PhantomData<*mut ()>,
}
impl PerCpu {
pub const fn new() -> Self {
Self {
host: None,
local: PhantomData,
}
}
pub fn is_enabled(&self) -> bool {
self.host.is_some()
}
pub unsafe fn enable(&mut self) -> Result<(), VirtualizationError> {
if self.host.is_some() {
return Err(VirtualizationError::AlreadyEnabled);
}
if !crate::capability::has_hypervisor_extension() {
return Err(VirtualizationError::Unavailable);
}
let vector;
let guest_vector;
let status;
unsafe {
core::arch::asm!("csrrd {}, 0xc", out(reg) vector, options(nostack));
core::arch::asm!("gcsrrd {}, 0xc", out(reg) guest_vector, options(nostack));
core::arch::asm!("csrrd {}, 0x50", out(reg) status, options(nostack));
}
self.host = Some(HostState {
vector,
guest_vector,
status,
});
Ok(())
}
pub unsafe fn disable(&mut self) -> Result<(), VirtualizationError> {
let host = self.host.take().ok_or(VirtualizationError::NotEnabled)?;
unsafe {
core::arch::asm!("gcsrwr {}, 0xc", inout(reg) host.guest_vector => _, options(nostack));
core::arch::asm!("csrwr {}, 0x50", inout(reg) host.status => _, options(nostack));
core::arch::asm!("csrwr {}, 0xc", inout(reg) host.vector => _, options(nostack));
}
Ok(())
}
}