use super::{
super::{Backend, bitmaps, memory::ControlRegion},
Vmcs,
fields::{VmcsField, VmcsReadWrite, VmcsValue},
};
use crate::{
PhysAddr,
virtualization::{ControlMemory, VirtualizationError},
};
pub struct VmxControlMemory<M: ControlMemory> {
pub vmcs: M,
pub io_bitmap_a: M,
pub io_bitmap_b: M,
pub msr_bitmap: M,
}
pub struct VmxControls<M: ControlMemory> {
vmcs: Vmcs<M>,
io: [ControlRegion<M>; 2],
msr: ControlRegion<M>,
}
impl<M: ControlMemory> VmxControls<M> {
pub unsafe fn new(memory: VmxControlMemory<M>) -> Result<Self, VirtualizationError> {
let mut io = [
ControlRegion::new(memory.io_bitmap_a, 4096, 4096)?,
ControlRegion::new(memory.io_bitmap_b, 4096, 4096)?,
];
let mut msr = ControlRegion::new(memory.msr_bitmap, 4096, 4096)?;
for region in &mut io {
region.fill(0xff);
}
msr.fill(0xff);
let vmcs = unsafe { Vmcs::new(memory.vmcs)? };
Ok(Self { vmcs, io, msr })
}
pub fn vmcs(&self) -> &Vmcs<M> {
&self.vmcs
}
pub unsafe fn bind(&mut self) -> Result<(), VirtualizationError> {
unsafe { self.vmcs.bind() }
}
pub unsafe fn unbind(&mut self) -> Result<(), VirtualizationError> {
unsafe { self.vmcs.unbind() }
}
pub fn read<T: VmcsValue, A>(&self, field: VmcsField<T, A>) -> Result<T, VirtualizationError> {
self.vmcs.read(field)
}
pub fn write<T: VmcsValue>(
&mut self,
field: VmcsField<T, VmcsReadWrite>,
value: T,
) -> Result<(), VirtualizationError> {
self.vmcs.write(field, value)
}
pub fn io_addresses(&self) -> [PhysAddr; 2] {
[self.io[0].physical_address(), self.io[1].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) {
let port = usize::from(port);
self.io[port / 32768].set_bit(port % 32768, 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::Vmx, msr, false, intercept)
}
pub fn set_msr_write_intercept(
&mut self,
msr: u32,
intercept: bool,
) -> Result<(), VirtualizationError> {
bitmaps::set_msr(&mut self.msr, Backend::Vmx, msr, true, intercept)
}
}
impl<M: ControlMemory> Drop for VmxControls<M> {
fn drop(&mut self) {
if self.vmcs.is_bound() {
for region in &mut self.io {
region.retain_on_failed_retirement();
}
self.msr.retain_on_failed_retirement();
}
}
}