use super::{
super::{Backend, bitmaps, memory::ControlRegion},
Vmcb, VmcbImage,
};
use crate::{
PhysAddr,
virtualization::{ControlMemory, VirtualizationError},
};
pub struct SvmControlMemory<M: ControlMemory> {
pub guest: M,
pub host: M,
pub io_permissions: M,
pub msr_permissions: M,
}
pub struct SvmControls<M: ControlMemory> {
guest: Vmcb<M>,
host: Vmcb<M>,
io: ControlRegion<M>,
msr: ControlRegion<M>,
}
impl<M: ControlMemory> SvmControls<M> {
pub fn new(memory: SvmControlMemory<M>) -> Result<Self, VirtualizationError> {
let guest = Vmcb::new(memory.guest)?;
let host = Vmcb::new(memory.host)?;
let mut io = ControlRegion::new(memory.io_permissions, 3 * 4096, 4096)?;
let mut msr = ControlRegion::new(memory.msr_permissions, 2 * 4096, 4096)?;
io.fill(0xff);
msr.fill(0xff);
Ok(Self {
guest,
host,
io,
msr,
})
}
pub fn reset_guest_image(&mut self) {
self.guest.reset();
}
pub fn guest_address(&self) -> PhysAddr {
self.guest.physical_address()
}
pub fn host_address(&self) -> PhysAddr {
self.host.physical_address()
}
pub fn image(&self) -> &VmcbImage {
self.guest.image()
}
pub fn image_mut(&mut self) -> &mut VmcbImage {
self.guest.image_mut()
}
pub fn io_address(&self) -> PhysAddr {
self.io.physical_address()
}
pub fn msr_address(&self) -> PhysAddr {
self.msr.physical_address()
}
pub fn intercept_all_msrs(&mut self, intercept: bool) {
self.msr.fill(if intercept { 0xff } else { 0 });
}
pub fn set_io_intercept(&mut self, port: u16, intercept: bool) {
self.io.set_bit(usize::from(port), intercept);
}
pub fn set_io_range(
&mut self,
first: u16,
count: u32,
intercept: bool,
) -> Result<(), VirtualizationError> {
for port in bitmaps::port_range(first, count)? {
self.set_io_intercept(port as u16, intercept);
}
Ok(())
}
pub fn set_msr_read_intercept(
&mut self,
msr: u32,
intercept: bool,
) -> Result<(), VirtualizationError> {
bitmaps::set_msr(&mut self.msr, Backend::Svm, msr, false, intercept)
}
pub fn set_msr_write_intercept(
&mut self,
msr: u32,
intercept: bool,
) -> Result<(), VirtualizationError> {
bitmaps::set_msr(&mut self.msr, Backend::Svm, msr, true, intercept)
}
}