use super::{VmxControls, VmxEntryContext, fields::*};
use crate::virtualization::{ControlMemory, VirtualizationError};
impl<M: ControlMemory> VmxControls<M> {
pub unsafe fn capture_host(
&mut self,
entry: &VmxEntryContext,
) -> Result<(), VirtualizationError> {
use x86::{
dtables::{self, DescriptorTablePointer},
segmentation,
};
use x86_64::registers::{
control::{Cr0, Cr3, Cr4},
model_specific::Msr,
};
unsafe {
self.write(VmcsHost64::IA32_PAT, Msr::new(0x277).read())?;
self.write(VmcsHost64::IA32_EFER, Msr::new(0xc000_0080).read())?;
self.write(VmcsHostNW::CR0, Cr0::read_raw() as usize)?;
self.write(
VmcsHostNW::CR3,
Cr3::read_raw().0.start_address().as_u64() as usize,
)?;
self.write(VmcsHostNW::CR4, Cr4::read_raw() as usize)?;
self.write(VmcsHost16::ES_SELECTOR, segmentation::es().bits())?;
self.write(VmcsHost16::CS_SELECTOR, segmentation::cs().bits())?;
self.write(VmcsHost16::SS_SELECTOR, segmentation::ss().bits())?;
self.write(VmcsHost16::DS_SELECTOR, segmentation::ds().bits())?;
self.write(VmcsHost16::FS_SELECTOR, segmentation::fs().bits())?;
self.write(VmcsHost16::GS_SELECTOR, segmentation::gs().bits())?;
self.write(VmcsHostNW::FS_BASE, Msr::new(0xc000_0100).read() as usize)?;
self.write(VmcsHostNW::GS_BASE, Msr::new(0xc000_0101).read() as usize)?;
let tr = x86::task::tr();
let mut gdt = DescriptorTablePointer::<u64>::default();
let mut idt = DescriptorTablePointer::<u64>::default();
dtables::sgdt(&mut gdt);
dtables::sidt(&mut idt);
let offset = usize::from(tr.index());
if (offset + 2) * core::mem::size_of::<u64>() > usize::from(gdt.limit) + 1 {
return Err(VirtualizationError::InvalidControlMemory);
}
let low = gdt.base.add(offset).read();
let high = gdt.base.add(offset + 1).read();
let base =
((low >> 16) & 0xffffff) | ((low >> 56) << 24) | ((high & 0xffff_ffff) << 32);
self.write(VmcsHost16::TR_SELECTOR, tr.bits())?;
self.write(VmcsHostNW::TR_BASE, base as usize)?;
self.write(VmcsHostNW::GDTR_BASE, gdt.base as usize)?;
self.write(VmcsHostNW::IDTR_BASE, idt.base as usize)?;
self.write(VmcsHostNW::RIP, VmxEntryContext::exit_address().as_usize())?;
self.write(VmcsHostNW::RSP, entry.host_stack_slot().as_usize())?;
self.write(
VmcsHostNW::IA32_SYSENTER_ESP,
Msr::new(0x175).read() as usize,
)?;
self.write(
VmcsHostNW::IA32_SYSENTER_EIP,
Msr::new(0x176).read() as usize,
)?;
self.write(VmcsHost32::IA32_SYSENTER_CS, Msr::new(0x174).read() as u32)?;
}
Ok(())
}
}