use core::marker::PhantomData;
use super::{
super::{
memory::ControlRegion,
percpu::{address_fits, physical_address_bits},
},
VmcbImage,
};
use crate::{
PhysAddr,
virtualization::{ControlMemory, VirtualizationError},
};
pub struct Vmcb<M: ControlMemory> {
region: ControlRegion<M>,
local: PhantomData<*mut ()>,
}
impl<M: ControlMemory> Vmcb<M> {
pub fn new(memory: M) -> Result<Self, VirtualizationError> {
let mut region = ControlRegion::new(memory, size_of::<VmcbImage>(), 4096)?;
if !address_fits(®ion, physical_address_bits()) {
return Err(VirtualizationError::InvalidControlMemory);
}
region.clear();
Ok(Self {
region,
local: PhantomData,
})
}
pub fn physical_address(&self) -> PhysAddr {
self.region.physical_address()
}
pub fn image(&self) -> &VmcbImage {
unsafe { self.region.pointer().cast::<VmcbImage>().as_ref() }
}
pub fn image_mut(&mut self) -> &mut VmcbImage {
unsafe { self.region.pointer().cast::<VmcbImage>().as_mut() }
}
pub unsafe fn save_current_state(&mut self) {
unsafe {
core::arch::asm!(
"vmsave rax",
in("rax") self.physical_address().as_usize(),
options(nostack, preserves_flags),
);
}
}
pub(super) fn reset(&mut self) {
self.region.clear();
}
pub fn into_memory(self) -> M {
self.region.into_memory()
}
}