use alloc::boxed::Box;
use bit_field::BitField;
use crate::{
contorls::{VmxControl, adjust_vmx_controls}, cputure::{CONTEXT, GuestRegisters}, error::HypervisorError, pagetable::PageTables, share_data::SharedData, vmxerror::ExceptionInterrupt, vt_x::descriptor::DescriptorTables, x86::{controlregs::{self, cr0, cr3, cr4}, dtable, msr::{self, rdmsr}, segmentation::SegmentSelector, task, vmx_consts::{control, host}, vmx_support::{vmclear, vmptrld, vmwrite}}, x86_64::addr::Addrtransfer
};
use crate::x86::vmx_consts::guest;
use crate::x86_64::segmentation_x86_64::SegmentDescriptor;
#[derive(Debug, Clone, Copy)]
#[repr(C, align(4096))]
pub struct __VMCS {
pub revision_id: u32,
pub abort_indicator: u32,
pub reserved: [u8; 0x1000 - size_of::<u32>() * 2],
}
impl __VMCS {
pub fn vmcs_init_cpu<T: Addrtransfer>( index: usize, vmxcs_region: &mut Box<__VMCS, impl core::alloc::Allocator>, trans: &mut T) -> Result<(), HypervisorError> {
vmxcs_region.revision_id =rdmsr(msr::IA32_VMX_BASIC) as u32;
log::debug!("rust: ------------------------------------------------");
vmxcs_region.revision_id.set_bit(31, false);
log::debug!("rust: ------------------------------------------------");
log::debug!("rust: vmxon revision_id {}", vmxcs_region.revision_id);
log::debug!("rust: ------------------------------------------------");
let va = vmxcs_region.as_ref() as *const _ as u64;
log::debug!("rust: cr0 cr4 vmxon executed for cpu core:{}", index);
let phys_addr = trans.va_into_pa(va as u64);
log::debug!("rust: vmcs casted addr for cpu core:{} phys_addr:{:#16x} va:{:#16x}", index, phys_addr, va);
vmclear(phys_addr)?;
vmptrld(phys_addr)?;
Ok(())
}
#[rustfmt::skip]
pub fn setup_guest_registers_state(context: &CONTEXT, guest_descriptor_table: &Box<DescriptorTables, impl core::alloc::Allocator>, guest_registers: &mut GuestRegisters) -> Result<(), crate::error::HypervisorError>{
log::debug!("Setting up Guest Registers State");
vmwrite(guest::CR0, cr0().bits() as u64)?;
vmwrite(guest::CR3, cr3())?;
vmwrite(guest::CR4, cr4().bits() as u64)?;
vmwrite(guest::DR7, context.Dr7)?;
vmwrite(guest::RSP, context.Rsp)?;
vmwrite(guest::RIP, context.Rip)?;
vmwrite(guest::RFLAGS, context.EFlags.into())?;
vmwrite(guest::CS_SELECTOR, context.SegCs.into())?;
vmwrite(guest::SS_SELECTOR, context.SegSs.into())?;
vmwrite(guest::DS_SELECTOR, context.SegDs.into())?;
vmwrite(guest::ES_SELECTOR, context.SegEs.into())?;
vmwrite(guest::FS_SELECTOR, context.SegFs.into())?;
vmwrite(guest::GS_SELECTOR, context.SegGs.into())?;
vmwrite(guest::LDTR_SELECTOR, dtable::ldtr().bits() as u64)?;
vmwrite(guest::TR_SELECTOR, task::tr().bits() as u64)?;
vmwrite(guest::CS_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegCs), &guest_descriptor_table.gdtr).base_address)?;
vmwrite(guest::SS_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegSs), &guest_descriptor_table.gdtr).base_address)?;
vmwrite(guest::DS_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegDs), &guest_descriptor_table.gdtr).base_address)?;
vmwrite(guest::ES_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegEs), &guest_descriptor_table.gdtr).base_address)?;
vmwrite(guest::FS_BASE, msr::rdmsr(msr::IA32_FS_BASE))?;
vmwrite(guest::GS_BASE, msr::rdmsr(msr::IA32_GS_BASE))?;
vmwrite(guest::LDTR_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(dtable::ldtr().bits()), &guest_descriptor_table.gdtr).base_address)?;
vmwrite(guest::TR_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(task::tr().bits()), &guest_descriptor_table.gdtr).base_address)?;
vmwrite(guest::CS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegCs), &guest_descriptor_table.gdtr).segment_limit.into())?;
vmwrite(guest::SS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegSs), &guest_descriptor_table.gdtr).segment_limit.into())?;
vmwrite(guest::DS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegDs), &guest_descriptor_table.gdtr).segment_limit.into())?;
vmwrite(guest::ES_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegEs), &guest_descriptor_table.gdtr).segment_limit.into())?;
vmwrite(guest::FS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegFs), &guest_descriptor_table.gdtr).segment_limit.into())?;
vmwrite(guest::GS_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegGs), &guest_descriptor_table.gdtr).segment_limit.into())?;
vmwrite(guest::LDTR_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(dtable::ldtr().bits()), &guest_descriptor_table.gdtr).segment_limit.into())?;
vmwrite(guest::TR_LIMIT, SegmentDescriptor::from_selector(SegmentSelector::from_raw(task::tr().bits()), &guest_descriptor_table.gdtr).segment_limit.into())?;
vmwrite(guest::CS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegCs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
vmwrite(guest::SS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegSs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
vmwrite(guest::DS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegDs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
vmwrite(guest::ES_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegEs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
vmwrite(guest::FS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegFs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
vmwrite(guest::GS_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(context.SegGs), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
vmwrite(guest::LDTR_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(dtable::ldtr().bits()), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
vmwrite(guest::TR_ACCESS_RIGHTS, SegmentDescriptor::from_selector(SegmentSelector::from_raw(task::tr().bits()), &guest_descriptor_table.gdtr).access_rights.bits().into())?;
vmwrite(guest::GDTR_BASE, guest_descriptor_table.gdtr.base as u64)?;
vmwrite(guest::IDTR_BASE, guest_descriptor_table.idtr.base as u64)?;
vmwrite(guest::GDTR_LIMIT, guest_descriptor_table.gdtr.limit as u64)?;
vmwrite(guest::IDTR_LIMIT, guest_descriptor_table.idtr.limit as u64)?;
vmwrite(guest::IA32_DEBUGCTL_FULL, msr::rdmsr(msr::IA32_DEBUGCTL))?;
vmwrite(guest::IA32_SYSENTER_CS, msr::rdmsr(msr::IA32_SYSENTER_CS))?;
vmwrite(guest::IA32_SYSENTER_ESP, msr::rdmsr(msr::IA32_SYSENTER_ESP))?;
vmwrite(guest::IA32_SYSENTER_EIP, msr::rdmsr(msr::IA32_SYSENTER_EIP))?;
vmwrite(guest::LINK_PTR_FULL, u64::MAX)?;
let xmm_context = unsafe { context.Anonymous.Anonymous };
guest_registers.xmm0 = xmm_context.Xmm0;
guest_registers.xmm1 = xmm_context.Xmm1;
guest_registers.xmm2 = xmm_context.Xmm2;
guest_registers.xmm3 = xmm_context.Xmm3;
guest_registers.xmm4 = xmm_context.Xmm4;
guest_registers.xmm5 = xmm_context.Xmm5;
guest_registers.xmm6 = xmm_context.Xmm6;
guest_registers.xmm7 = xmm_context.Xmm7;
guest_registers.xmm8 = xmm_context.Xmm8;
guest_registers.xmm9 = xmm_context.Xmm9;
guest_registers.xmm10 = xmm_context.Xmm10;
guest_registers.xmm11 = xmm_context.Xmm11;
guest_registers.xmm12 = xmm_context.Xmm12;
guest_registers.xmm13 = xmm_context.Xmm13;
guest_registers.xmm14 = xmm_context.Xmm14;
guest_registers.xmm15 = xmm_context.Xmm15;
guest_registers.rax = context.Rax;
guest_registers.rbx = context.Rbx;
guest_registers.rcx = context.Rcx;
guest_registers.rdx = context.Rdx;
guest_registers.rdi = context.Rdi;
guest_registers.rsi = context.Rsi;
guest_registers.rbp = context.Rbp;
guest_registers.r8 = context.R8;
guest_registers.r9 = context.R9;
guest_registers.r10 = context.R10;
guest_registers.r11 = context.R11;
guest_registers.r12 = context.R12;
guest_registers.r13 = context.R13;
guest_registers.r14 = context.R14;
guest_registers.r15 = context.R15;
log::debug!("Guest Registers State setup successfully!");
Ok(())
}
#[rustfmt::skip]
pub fn setup_host_registers_state<T: Addrtransfer>(context: &CONTEXT, host_descriptor_table: &Box<DescriptorTables, impl core::alloc::Allocator>, host_paging: &Box<PageTables, impl core::alloc::Allocator>, trans: &mut T) -> Result<(), crate::error::HypervisorError> {
log::debug!("Setting up Host Registers State");
vmwrite(host::CR0, controlregs::cr0().bits() as u64)?;
vmwrite(host::CR3, host_paging.get_pml4_pa(trans)?)?;
vmwrite(host::CR4, cr4().bits() as u64)?;
const SELECTOR_MASK: u16 = 0xF8;
vmwrite(host::CS_SELECTOR, (context.SegCs & SELECTOR_MASK) as u64)?;
vmwrite(host::SS_SELECTOR, (context.SegSs & SELECTOR_MASK)as u64)?;
vmwrite(host::DS_SELECTOR, (context.SegDs & SELECTOR_MASK)as u64)?;
vmwrite(host::ES_SELECTOR, (context.SegEs & SELECTOR_MASK)as u64)?;
vmwrite(host::FS_SELECTOR, (context.SegFs & SELECTOR_MASK)as u64)?;
vmwrite(host::GS_SELECTOR, (context.SegGs & SELECTOR_MASK)as u64)?;
vmwrite(host::TR_SELECTOR, (task::tr().bits() & SELECTOR_MASK).into())?;
vmwrite(host::FS_BASE, msr::rdmsr(msr::IA32_FS_BASE))?;
vmwrite(host::GS_BASE, msr::rdmsr(msr::IA32_GS_BASE))?;
vmwrite(host::TR_BASE, SegmentDescriptor::from_selector(SegmentSelector::from_raw(task::tr().bits()), &host_descriptor_table.gdtr).base_address)?;
vmwrite(host::GDTR_BASE, host_descriptor_table.gdtr.base as u64)?;
vmwrite(host::IDTR_BASE, host_descriptor_table.idtr.base as u64)?;
vmwrite(host::IA32_SYSENTER_CS, msr::rdmsr(msr::IA32_SYSENTER_CS))?;
vmwrite(host::IA32_SYSENTER_ESP, msr::rdmsr(msr::IA32_SYSENTER_ESP))?;
vmwrite(host::IA32_SYSENTER_EIP, msr::rdmsr(msr::IA32_SYSENTER_EIP))?;
log::debug!("Host Registers State setup successfully!");
Ok(())
}
#[rustfmt::skip]
pub fn setup_vmcs_control_fields<T: Addrtransfer>(shared_data: &mut SharedData<impl core::alloc::Allocator>, trans: &mut T) -> Result<(), HypervisorError> {
log::debug!("Setting up VMCS Control Fields");
const PRIMARY_CTL: u64 = (control::PrimaryControls::SECONDARY_CONTROLS.bits() | control::PrimaryControls::USE_MSR_BITMAPS.bits()) as u64;
const SECONDARY_CTL: u64 = (control::SecondaryControls::ENABLE_RDTSCP.bits()
| control::SecondaryControls::ENABLE_XSAVES_XRSTORS.bits()
| control::SecondaryControls::ENABLE_INVPCID.bits()
| control::SecondaryControls::ENABLE_VPID.bits()
| control::SecondaryControls::ENABLE_EPT.bits()) as u64;
const ENTRY_CTL: u64 = control::EntryControls::IA32E_MODE_GUEST.bits() as u64;
const EXIT_CTL: u64 = control::ExitControls::HOST_ADDRESS_SPACE_SIZE.bits() as u64;
const PINBASED_CTL: u64 = 0;
vmwrite(control::VMENTRY_CONTROLS, adjust_vmx_controls(VmxControl::VmEntry, ENTRY_CTL))?;
vmwrite(control::VMEXIT_CONTROLS, adjust_vmx_controls(VmxControl::VmExit, EXIT_CTL))?;
vmwrite(control::PRIMARY_PROCBASED_EXEC_CONTROLS, adjust_vmx_controls(VmxControl::ProcessorBased, PRIMARY_CTL ))?;
vmwrite(control::SECONDARY_PROCBASED_EXEC_CONTROLS, adjust_vmx_controls(VmxControl::ProcessorBased2, SECONDARY_CTL))?;
vmwrite(control::PINBASED_EXEC_CONTROLS, adjust_vmx_controls(VmxControl::PinBased, PINBASED_CTL))?;
vmwrite(control::MSR_BITMAPS_ADDR_FULL, trans.va_into_pa(shared_data.msr_bitmap.as_ref() as *const _ as _))?;
vmwrite(control::EXCEPTION_BITMAP, 1u64 << (ExceptionInterrupt::Breakpoint as u32))?;
vmwrite(control::EPTP_FULL, shared_data.primary_eptp)?;
vmwrite(control::VPID, crate::invvpid::VPID_TAG.into())?;
crate::invept::invept_single_context(shared_data.primary_eptp);
crate::invvpid::invvpid_single_context(crate::invvpid::VPID_TAG);
log::debug!("VMCS Control Fields setup successfully!");
Ok(())
}
pub fn get_vmcs_revision_id() -> u32 {
(msr::rdmsr(msr::IA32_VMX_BASIC) as u32) & 0x7FFF_FFFF
}
}