1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
//! Model-specific register vmexit controller.
//!
//! x86 processors include a collection of specialized registers that permit the customization of CPU capabilities.
//! Each register possesses a 64-bit space, and accessing these registers necessitates using `rdmsr` (read) or `wrmsr` (write) instructions.
//!
//! The `rdmsr` instruction reads a register that is determined by the index value provided in the ECX register.
//! The retrieved MSR value is stored in the EDX and EAX registers, with the high-order 32 bits of the MSR value placed in the EDX register,
//! and the low-order 32 bits placed in the EAX register. In 64-bit architectures, the high-order 32 bits of both the RDX and RAX registers are set to 0.
//!
//! The `wrmsr` instruction writes a value to a register specified in the ECX register as an index.
//! The value written to the MSR is obtained from the EDX and EAX registers.
//! Specifically, the value in EDX is written to MSR\[63:32\] (high-order 32bits), and the value in EAX is written to MSR\[31:0\] (low-order 32bits).
//!
//! When managing virtual machines, the default behavior is for the host to intercept `rdmsr`/`wrmsr` instructions from the guest.
//! Therefore, the host needs to emulate these MSR access requests.
//!
//! ## Tasks
//! In this part, you requires to write a manager to maintain the msr. When configuring the VCpu, the msr handlers are registered via [`Controller::insert`].
//! After that, when the guest operating system is trapped back to the VMM by executing either `rdmsr` or `wrmsr`, the control passed to the
//! [`Controller::handle`]. In the function, the handler finds the corresponding msr handlers, runs the handler and reflect the result into the VCpu state.
//! Again, you **MUST** forward the vCPU instruction pointer (rip) to prevent it from executing the same instructions infinitely.
use alloc::{
boxed::Box,
collections::{btree_map::Entry, BTreeMap},
};
use kev::{
vcpu::{GenericVCpuState, VmexitResult},
vmcs::{BasicExitReason, ExitReason},
vmexits::VmexitController,
Probe, VmError,
};
/// Trait that represent handlers for MSR registers.
pub trait Msr
where
Self: Send + Sync,
{
/// Handler on wrmsr.
fn rdmsr(
&self,
index: u32,
p: &dyn Probe,
generic_vcpu_state: &mut GenericVCpuState,
) -> Result<u64, VmError>;
/// Handler on wrmsr.
fn wrmsr(
&mut self,
index: u32,
value: u64,
p: &dyn Probe,
generic_vcpu_state: &mut GenericVCpuState,
) -> Result<(), VmError>;
}
/// Msr vmexit controller.
pub struct Controller {
msrs: BTreeMap<u32, Box<dyn Msr>>,
}
impl Controller {
/// Create a new msr controller.
pub fn new() -> Self {
Self {
msrs: BTreeMap::new(),
}
}
/// Insert msr handler to the index.
///
/// Return false if msr handler for index is exists.
/// Otherwise, return true.
pub fn insert(&mut self, index: u32, msr: impl Msr + 'static) -> bool {
todo!()
}
}
impl VmexitController for Controller {
fn handle<P: kev::Probe>(
&mut self,
reason: ExitReason,
p: &mut P,
generic_vcpu_state: &mut GenericVCpuState,
) -> Result<VmexitResult, kev::VmError> {
match reason.get_basic_reason() {
BasicExitReason::Rdmsr => {
todo!()
}
BasicExitReason::Wrmsr => {
todo!()
}
_ => Err(kev::VmError::HandleVmexitFailed(reason)),
}
}
}