add VMCS read write

This commit is contained in:
Masato Imai
2025-04-21 10:22:45 +00:00
parent a3e8288013
commit 9ebd56b32a

View File

@@ -1,8 +1,45 @@
#![allow(non_camel_case_types)]
use bitfield::BitMut;
use x86::{bits64::vmx, vmx::VmFail};
use x86_64::structures::paging::{FrameAllocator, PhysFrame};
use crate::memory::BootInfoFrameAllocator;
macro_rules! vmcs_read {
($field_enum: ident, u64) => {
impl $field_enum {
pub fn read(self) -> x86::vmx::Result<u64> {
unsafe { vmx::vmread(self as u32) }
}
}
};
($field_enum: ident, $ux: ty) => {
impl $field_enum {
pub fn read(self) -> x86::vmx::Result<$ux> {
unsafe { vmx::vmread(self as u32).map(|v| v as $ux) }
}
}
};
}
macro_rules! vmcs_write {
($field_enum: ident, u64) => {
impl $field_enum {
pub fn write(self, value: u64) -> x86::vmx::Result<()> {
unsafe { vmx::vmwrite(self as u32, value) }
}
}
};
($field_enum: ident, $ux: ty) => {
impl $field_enum {
pub fn write(self, value: $ux) -> x86::vmx::Result<()> {
unsafe { vmx::vmwrite(self as u32, value as u64) }
}
}
};
}
pub struct Vmcs {
pub frame: PhysFrame,
}
@@ -66,11 +103,106 @@ impl InstructionError {
}
pub fn read() -> Self {
let err = unsafe { vmx::vmread(0x4400) };
let err = VmcsReadOnlyData32::VM_INSTRUCTION_ERROR.read();
if err.is_err() {
panic!("Failed to read VM instruction error");
}
let err = err.unwrap();
InstructionError(err as u32)
InstructionError(err)
}
}
pub struct PinBasedVmExecutionControls(pub u32);
impl PinBasedVmExecutionControls {
pub fn set_external_interrupt_exiting(&mut self, value: bool) {
self.0.set_bit(0, value);
}
pub fn set_nmi_exiting(&mut self, value: bool) {
self.0.set_bit(3, value);
}
pub fn set_virtual_nmi(&mut self, value: bool) {
self.0.set_bit(5, value);
}
pub fn set_activate_vmx_preemption_timer(&mut self, value: bool) {
self.0.set_bit(6, value);
}
pub fn set_process_posted_interrupts(&mut self, value: bool) {
self.0.set_bit(7, value);
}
pub fn get_external_interrupt_exiting(&self) -> bool {
self.0 & (1 << 0) != 0
}
pub fn get_nmi_exiting(&self) -> bool {
self.0 & (1 << 3) != 0
}
pub fn get_virtual_nmi(&self) -> bool {
self.0 & (1 << 5) != 0
}
pub fn get_activate_vmx_preemption_timer(&self) -> bool {
self.0 & (1 << 6) != 0
}
pub fn get_process_posted_interrupts(&self) -> bool {
self.0 & (1 << 7) != 0
}
pub fn read() -> Self {
let err = VmcsControl32::PIN_BASED_VM_EXECUTION_CONTROLS.read();
if err.is_err() {
panic!("Failed to read Pin Based VM Execution Controls");
}
let err = err.unwrap();
PinBasedVmExecutionControls(err)
}
pub fn write(&self) {
VmcsControl32::PIN_BASED_VM_EXECUTION_CONTROLS
.write(self.0)
.expect("Failed to write Pin Based VM Execution Controls");
}
}
pub enum VmcsControl32 {
PIN_BASED_VM_EXECUTION_CONTROLS = 0x00004000,
PRIMARY_PROCESSOR_BASED_VM_EXECUTION_CONTROLS = 0x00004002,
EXCEPTION_BITMAP = 0x00004004,
PAGE_FAULT_ERROR_CODE_MASK = 0x00004006,
PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008,
CR3_TARGET_COUNT = 0x0000400A,
PRIMARY_VM_EXIT_CONTROLS = 0x0000400C,
VM_EXIT_MSR_STORE_COUNT = 0x0000400E,
VM_EXIT_MSR_LOAD_COUNT = 0x00004010,
VM_ENTRY_CONTROLS = 0x00004012,
VM_ENTRY_MSR_LOAD_COUNT = 0x00004014,
VM_ENTRY_INTERRUPTION_INFORMATION_FIELD = 0x00004016,
VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018,
VM_ENTRY_INSTRUCTION_LENGTH = 0x0000401A,
TPR_THRESHOLD = 0x0000401C,
SECONDARY_PROCESSOR_BASED_VM_EXECUTION_CONTROLS = 0x0000401E,
PLE_GAP = 0x00004020,
PLE_WINDOW = 0x00004022,
INSTRUCTION_TIMEOUT_CONTROL = 0x00004024,
}
vmcs_read!(VmcsControl32, u32);
vmcs_write!(VmcsControl32, u32);
pub enum VmcsReadOnlyData32 {
VM_INSTRUCTION_ERROR = 0x00004400,
VM_EXIT_REASON = 0x00004402,
VM_EXIT_INTERRUPTION_INFORMATION_FIELD = 0x00004404,
VM_EXIT_INTERRUPTION_ERROR_CODE = 0x00004406,
IDT_VECTORING_INFORMATION_FIELD = 0x00004408,
IDT_VECTORING_ERROR_CODE = 0x0000440A,
VM_EXIT_INSTRUCTION_LENGTH = 0x0000440C,
VM_EXIT_INSTRUCTION_INFO = 0x0000440E,
}
vmcs_read!(VmcsReadOnlyData32, u32);