add VMCS guest state

This commit is contained in:
Masato Imai
2025-04-22 09:55:15 +00:00
parent cc8cd5619e
commit fa0d53cc36
2 changed files with 151 additions and 34 deletions

View File

@@ -9,7 +9,11 @@ use x86::{
use core::arch::naked_asm;
use crate::{info, memory::BootInfoFrameAllocator};
use crate::{
info,
memory::BootInfoFrameAllocator,
vmm::vmcs::{DescriptorType, Granularity, SegmentRights},
};
use super::{
vmcs::{PinBasedVmExecutionControls, Vmcs},
@@ -43,9 +47,11 @@ impl VCpu {
self.reset_vmcs().unwrap();
self.setup_exec_ctrls().unwrap();
self.setup_host_state().unwrap();
self.setup_guest_state().unwrap();
}
pub fn setup_exec_ctrls(&mut self) -> Result<(), VmFail> {
info!("Setting up execution controls");
let basic_msr = unsafe { rdmsr(x86::msr::IA32_VMX_BASIC) };
let mut pin_exec_ctrl = PinBasedVmExecutionControls::read();
@@ -77,6 +83,7 @@ impl VCpu {
}
pub fn setup_host_state(&mut self) -> Result<(), VmFail> {
info!("Setting up host state");
unsafe {
vmwrite(vmcs::host::CR0, cr0().bits() as u64)?;
vmwrite(vmcs::host::CR3, cr3())?;
@@ -126,10 +133,124 @@ impl VCpu {
Ok(())
}
pub fn setup_guest_state(&mut self) -> Result<(), VmFail> {
info!("Setting up guest state");
unsafe {
vmwrite(vmcs::guest::CR0, cr0().bits() as u64)?;
vmwrite(vmcs::guest::CR3, cr3())?;
vmwrite(vmcs::guest::CR4, cr4().bits() as u64)?;
vmwrite(vmcs::guest::CS_BASE, 0)?;
vmwrite(vmcs::guest::SS_BASE, 0)?;
vmwrite(vmcs::guest::DS_BASE, 0)?;
vmwrite(vmcs::guest::ES_BASE, 0)?;
vmwrite(vmcs::guest::FS_BASE, 0)?;
vmwrite(vmcs::guest::GS_BASE, 0)?;
vmwrite(vmcs::guest::TR_BASE, 0)?;
vmwrite(vmcs::guest::GDTR_BASE, 0)?;
vmwrite(vmcs::guest::IDTR_BASE, 0)?;
vmwrite(vmcs::guest::LDTR_BASE, 0xDEAD00)?;
vmwrite(vmcs::guest::CS_LIMIT, u32::MAX as u64)?;
vmwrite(vmcs::guest::SS_LIMIT, u32::MAX as u64)?;
vmwrite(vmcs::guest::DS_LIMIT, u32::MAX as u64)?;
vmwrite(vmcs::guest::ES_LIMIT, u32::MAX as u64)?;
vmwrite(vmcs::guest::FS_LIMIT, u32::MAX as u64)?;
vmwrite(vmcs::guest::GS_LIMIT, u32::MAX as u64)?;
vmwrite(vmcs::guest::TR_LIMIT, u32::MAX as u64)?;
vmwrite(vmcs::guest::GDTR_LIMIT, u32::MAX as u64)?;
vmwrite(vmcs::guest::IDTR_LIMIT, u32::MAX as u64)?;
vmwrite(vmcs::guest::LDTR_LIMIT, u32::MAX as u64)?;
vmwrite(
vmcs::guest::CS_SELECTOR,
x86::segmentation::cs().bits() as u64,
)?;
vmwrite(vmcs::guest::SS_SELECTOR, 0)?;
vmwrite(vmcs::guest::DS_SELECTOR, 0)?;
vmwrite(vmcs::guest::ES_SELECTOR, 0)?;
vmwrite(vmcs::guest::FS_SELECTOR, 0)?;
vmwrite(vmcs::guest::GS_SELECTOR, 0)?;
vmwrite(vmcs::guest::TR_SELECTOR, 0)?;
vmwrite(vmcs::guest::LDTR_SELECTOR, 0)?;
let cs_rights = {
let mut rights = SegmentRights(0);
rights.set_rw(true);
rights.set_dc(false);
rights.set_executable(true);
rights.set_desc_type_raw(DescriptorType::Code as u8);
rights.set_dpl(0);
rights.set_granularity_raw(Granularity::KByte as u8);
rights.set_long(true);
rights.set_db(false);
rights
};
vmwrite(vmcs::guest::CS_ACCESS_RIGHTS, cs_rights.0 as u64)?;
let ds_rights = {
let mut rights = SegmentRights(0);
rights.set_rw(true);
rights.set_dc(false);
rights.set_executable(false);
rights.set_desc_type_raw(DescriptorType::Code as u8);
rights.set_dpl(0);
rights.set_granularity_raw(Granularity::KByte as u8);
rights.set_long(false);
rights.set_db(true);
rights
};
vmwrite(vmcs::guest::DS_ACCESS_RIGHTS, ds_rights.0 as u64)?;
let tr_rights = {
let mut rights = SegmentRights(0);
rights.set_rw(true);
rights.set_dc(false);
rights.set_executable(true);
rights.set_desc_type_raw(DescriptorType::System as u8);
rights.set_dpl(0);
rights.set_granularity_raw(Granularity::Byte as u8);
rights.set_long(false);
rights.set_db(false);
rights
};
vmwrite(vmcs::guest::TR_ACCESS_RIGHTS, tr_rights.0 as u64)?;
let ldtr_rights = {
let mut rights = SegmentRights(0);
rights.set_accessed(false);
rights.set_rw(true);
rights.set_dc(false);
rights.set_executable(false);
rights.set_desc_type_raw(DescriptorType::System as u8);
rights.set_dpl(0);
rights.set_granularity_raw(Granularity::Byte as u8);
rights.set_long(false);
rights.set_db(false);
rights
};
vmwrite(vmcs::guest::LDTR_ACCESS_RIGHTS, ldtr_rights.0 as u64)?;
vmwrite(vmcs::guest::RIP, Self::guest as u64)?;
vmwrite(vmcs::guest::IA32_EFER_FULL, rdmsr(IA32_EFER))?;
vmwrite(vmcs::guest::RFLAGS, 0x2)?;
vmwrite(vmcs::guest::LINK_PTR_FULL, u64::MAX)?;
}
Ok(())
}
pub fn reset_vmcs(&mut self) -> Result<(), VmFail> {
info!("Resetting VMCS");
self.vmcs.reset()
}
#[naked]
unsafe extern "C" fn guest() -> ! {
naked_asm!("hlt");
}
fn vmexit_handler(&mut self) -> ! {
info!("VMExit occurred");

View File

@@ -1,6 +1,6 @@
#![allow(non_camel_case_types)]
use bitfield::BitMut;
use bitfield::{bitfield, BitMut};
use x86::{bits64::vmx, vmx::VmFail};
use x86_64::structures::paging::{FrameAllocator, PhysFrame};
@@ -171,38 +171,6 @@ impl PinBasedVmExecutionControls {
}
}
/*
_reserved1: u2,
interrupt_window: bool,
tsc_offsetting: bool,
_reserved2: u3,
hlt: bool,
_reserved3: u1,
invlpg: bool,
mwait: bool,
rdpmc: bool,
rdtsc: bool,
_reserved4: u2,
cr3load: bool,
cr3store: bool,
activate_teritary_controls: bool,
_reserved: u1,
cr8load: bool,
cr8store: bool,
use_tpr_shadow: bool,
nmi_window: bool,
mov_dr: bool,
unconditional_io: bool,
use_io_bitmap: bool,
_reserved5: u1,
monitor_trap: bool,
use_msr_bitmap: bool,
monitor: bool,
pause: bool,
activate_secondary_controls: bool,
*/
pub struct PrimaryProcessorBasedVmExecutionControls(pub u32);
impl PrimaryProcessorBasedVmExecutionControls {
@@ -222,6 +190,34 @@ impl PrimaryProcessorBasedVmExecutionControls {
}
}
pub enum DescriptorType {
System = 0,
Code = 1,
}
pub enum Granularity {
Byte = 0,
KByte = 1,
}
bitfield! {
pub struct SegmentRights(u32);
impl Debug;
pub accessed, set_accessed: 0;
pub rw, set_rw: 1;
pub dc, set_dc: 2;
pub executable, set_executable: 3;
pub u8, desc_type_raw, set_desc_type_raw: 4, 4;
pub u8, dpl, set_dpl: 6, 5;
pub present, set_present: 7;
pub avl, set_avl: 12;
pub long, set_long: 13;
pub u1, db, set_db: 14;
pub u8, granularity_raw, set_granularity_raw: 15, 15;
pub unusable, set_unusable: 16;
}
pub enum VmcsControl32 {
PIN_BASED_VM_EXECUTION_CONTROLS = 0x00004000,
PRIMARY_PROCESSOR_BASED_VM_EXECUTION_CONTROLS = 0x00004002,