shadow msr
This commit is contained in:
@ -35,6 +35,7 @@ pub fn setup_exec_controls() -> Result<(), &'static str> {
|
||||
vmcs::controls::PrimaryProcessorBasedVmExecutionControls::from(raw_primary_exec_ctrl);
|
||||
primary_exec_ctrl.set_hlt(true);
|
||||
primary_exec_ctrl.set_activate_secondary_controls(true);
|
||||
primary_exec_ctrl.set_use_msr_bitmap(false);
|
||||
|
||||
primary_exec_ctrl.write()?;
|
||||
|
||||
@ -51,9 +52,9 @@ pub fn setup_exec_controls() -> Result<(), &'static str> {
|
||||
|
||||
let mut secondary_exec_ctrl =
|
||||
vmcs::controls::SecondaryProcessorBasedVmExecutionControls::from(raw_secondary_exec_ctrl);
|
||||
secondary_exec_ctrl.set_ept(true); // TODO: true
|
||||
secondary_exec_ctrl.set_unrestricted_guest(true); //TODO: true
|
||||
//secondary_exec_ctrl.set_virtualize_apic_accesses(false); // TODO: true
|
||||
secondary_exec_ctrl.set_ept(true);
|
||||
secondary_exec_ctrl.set_unrestricted_guest(true);
|
||||
//secondary_exec_ctrl.set_virtualize_apic_accesses(false); // TODO: true
|
||||
|
||||
secondary_exec_ctrl.write()?;
|
||||
|
||||
@ -74,8 +75,8 @@ pub fn setup_entry_controls() -> Result<(), &'static str> {
|
||||
|
||||
let mut entry_ctrl = vmcs::controls::EntryControls::from(raw_entry_ctrl);
|
||||
entry_ctrl.set_ia32e_mode_guest(false);
|
||||
/*entry_ctrl.set_load_ia32_efer(true);
|
||||
entry_ctrl.set_load_ia32_pat(true);*/
|
||||
entry_ctrl.set_load_ia32_efer(true);
|
||||
entry_ctrl.set_load_ia32_pat(true);
|
||||
|
||||
entry_ctrl.write()?;
|
||||
|
||||
@ -96,10 +97,10 @@ pub fn setup_exit_controls() -> Result<(), &'static str> {
|
||||
|
||||
let mut exit_ctrl = vmcs::controls::PrimaryExitControls::from(raw_exit_ctrl);
|
||||
exit_ctrl.set_host_addr_space_size(true);
|
||||
/*exit_ctrl.set_save_ia32_efer(true);
|
||||
exit_ctrl.set_save_ia32_pat(true);*/
|
||||
exit_ctrl.set_save_ia32_efer(true);
|
||||
exit_ctrl.set_save_ia32_pat(true);
|
||||
exit_ctrl.set_load_ia32_efer(true);
|
||||
//exit_ctrl.set_load_ia32_pat(true);
|
||||
exit_ctrl.set_load_ia32_pat(true);
|
||||
|
||||
exit_ctrl.write()?;
|
||||
|
||||
|
@ -55,7 +55,7 @@ pub fn handle_cpuid_vmexit(vcpu: &mut IntelVCpu) {
|
||||
},
|
||||
VmxLeaf::EXTENDED_FEATURE => match regs.rcx {
|
||||
0 => {
|
||||
let mut ebx = ExtFeatureEbx0::new()
|
||||
let ebx = ExtFeatureEbx0::new()
|
||||
.with_fsgsbase(false)
|
||||
.with_smep(true)
|
||||
.with_invpcid(false)
|
||||
@ -120,7 +120,6 @@ pub fn handle_cpuid_vmexit(vcpu: &mut IntelVCpu) {
|
||||
.with_sse2(true);
|
||||
|
||||
let mut version_and_feature_info = cpuid!(0x1, 0);
|
||||
let feature = cpuid!(0x0, 0);
|
||||
version_and_feature_info.ecx &= !(1 << 17);
|
||||
|
||||
regs.rax = version_and_feature_info.eax as u64;
|
||||
|
@ -2,6 +2,7 @@ pub mod asm;
|
||||
mod controls;
|
||||
mod cpuid;
|
||||
mod ept;
|
||||
mod msr;
|
||||
mod register;
|
||||
pub mod vcpu;
|
||||
mod vmcs;
|
||||
|
307
nel_os_kernel/src/vmm/x86_64/intel/msr.rs
Normal file
307
nel_os_kernel/src/vmm/x86_64/intel/msr.rs
Normal file
@ -0,0 +1,307 @@
|
||||
use core::u64;
|
||||
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use x86::vmx::vmcs;
|
||||
use x86_64::PhysAddr;
|
||||
|
||||
use crate::info;
|
||||
use crate::vmm::x86_64::common::read_msr;
|
||||
use crate::vmm::x86_64::intel::vcpu::IntelVCpu;
|
||||
use crate::vmm::x86_64::intel::{vmread, vmwrite};
|
||||
|
||||
type MsrIndex = u32;
|
||||
|
||||
const MAX_NUM_ENTS: usize = 512;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(C, packed)]
|
||||
pub struct SavedMsr {
|
||||
pub index: MsrIndex,
|
||||
pub reserved: u32,
|
||||
pub data: u64,
|
||||
}
|
||||
|
||||
impl Default for SavedMsr {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
index: 0,
|
||||
reserved: 0,
|
||||
data: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ShadowMsr {
|
||||
ents: Vec<SavedMsr>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MsrError {
|
||||
TooManyEntries,
|
||||
BitmapAllocationFailed,
|
||||
}
|
||||
|
||||
pub fn register_msrs(vcpu: &mut IntelVCpu) -> Result<(), MsrError> {
|
||||
vcpu.host_msr
|
||||
.set(x86::msr::IA32_TSC_AUX, read_msr(x86::msr::IA32_TSC_AUX))?;
|
||||
vcpu.host_msr
|
||||
.set(x86::msr::IA32_STAR, read_msr(x86::msr::IA32_STAR))
|
||||
.unwrap();
|
||||
vcpu.host_msr
|
||||
.set(x86::msr::IA32_LSTAR, read_msr(x86::msr::IA32_LSTAR))
|
||||
.unwrap();
|
||||
vcpu.host_msr
|
||||
.set(x86::msr::IA32_CSTAR, read_msr(x86::msr::IA32_CSTAR))
|
||||
.unwrap();
|
||||
vcpu.host_msr
|
||||
.set(x86::msr::IA32_FMASK, read_msr(x86::msr::IA32_FMASK))
|
||||
.unwrap();
|
||||
vcpu.host_msr
|
||||
.set(
|
||||
x86::msr::IA32_KERNEL_GSBASE,
|
||||
read_msr(x86::msr::IA32_KERNEL_GSBASE),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
vcpu.guest_msr.set(x86::msr::IA32_TSC_AUX, 0).unwrap();
|
||||
vcpu.guest_msr.set(x86::msr::IA32_STAR, 0).unwrap();
|
||||
vcpu.guest_msr.set(x86::msr::IA32_LSTAR, 0).unwrap();
|
||||
vcpu.guest_msr.set(x86::msr::IA32_CSTAR, 0).unwrap();
|
||||
vcpu.guest_msr.set(x86::msr::IA32_FMASK, 0).unwrap();
|
||||
vcpu.guest_msr.set(x86::msr::IA32_KERNEL_GSBASE, 0).unwrap();
|
||||
vcpu.guest_msr.set(0x1b, 0).unwrap();
|
||||
vcpu.guest_msr.set(0xc0010007, 0).unwrap();
|
||||
vcpu.guest_msr.set(0xc0010117, 0).unwrap();
|
||||
|
||||
vmwrite(
|
||||
vmcs::control::VMEXIT_MSR_LOAD_ADDR_FULL,
|
||||
vcpu.host_msr.phys().as_u64(),
|
||||
)
|
||||
.unwrap();
|
||||
vmwrite(
|
||||
vmcs::control::VMEXIT_MSR_STORE_ADDR_FULL,
|
||||
vcpu.guest_msr.phys().as_u64(),
|
||||
)
|
||||
.unwrap();
|
||||
vmwrite(
|
||||
vmcs::control::VMENTRY_MSR_LOAD_ADDR_FULL,
|
||||
vcpu.guest_msr.phys().as_u64(),
|
||||
)
|
||||
.unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_msrs(vcpu: &mut IntelVCpu) -> Result<(), MsrError> {
|
||||
info!("updating MSRs");
|
||||
let indices_to_update: alloc::vec::Vec<u32> = vcpu
|
||||
.host_msr
|
||||
.saved_ents()
|
||||
.iter()
|
||||
.map(|entry| entry.index)
|
||||
.collect();
|
||||
|
||||
info!("1");
|
||||
|
||||
for index in indices_to_update {
|
||||
info!("{}", index);
|
||||
let value = read_msr(index);
|
||||
vcpu.host_msr.set_by_index(index, value).unwrap();
|
||||
}
|
||||
|
||||
info!("2");
|
||||
vmwrite(
|
||||
vmcs::control::VMEXIT_MSR_LOAD_COUNT,
|
||||
vcpu.host_msr.saved_ents().len() as u64,
|
||||
)
|
||||
.unwrap();
|
||||
info!("3");
|
||||
vmwrite(
|
||||
vmcs::control::VMEXIT_MSR_STORE_COUNT,
|
||||
vcpu.guest_msr.saved_ents().len() as u64,
|
||||
)
|
||||
.unwrap();
|
||||
info!("4");
|
||||
vmwrite(
|
||||
vmcs::control::VMENTRY_MSR_LOAD_COUNT,
|
||||
vcpu.guest_msr.saved_ents().len() as u64,
|
||||
)
|
||||
.unwrap();
|
||||
info!("5");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl ShadowMsr {
|
||||
pub fn new() -> Self {
|
||||
let ents = vec![];
|
||||
|
||||
ShadowMsr { ents }
|
||||
}
|
||||
|
||||
pub fn set(&mut self, index: MsrIndex, data: u64) -> Result<(), MsrError> {
|
||||
self.set_by_index(index, data)
|
||||
}
|
||||
|
||||
pub fn set_by_index(&mut self, index: MsrIndex, data: u64) -> Result<(), MsrError> {
|
||||
if let Some(entry) = self.ents.iter_mut().find(|e| e.index == index) {
|
||||
entry.data = data;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.ents.len() >= MAX_NUM_ENTS {
|
||||
return Err(MsrError::TooManyEntries);
|
||||
}
|
||||
self.ents.push(SavedMsr {
|
||||
index,
|
||||
reserved: 0,
|
||||
data,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn saved_ents(&self) -> &[SavedMsr] {
|
||||
&self.ents
|
||||
}
|
||||
|
||||
pub fn find(&self, index: MsrIndex) -> Option<&SavedMsr> {
|
||||
self.ents.iter().find(|e| e.index == index)
|
||||
}
|
||||
|
||||
pub fn phys(&self) -> PhysAddr {
|
||||
PhysAddr::new(self.ents.as_ptr() as u64)
|
||||
}
|
||||
|
||||
pub fn concat(r1: u64, r2: u64) -> u64 {
|
||||
((r1 & 0xFFFFFFFF) << 32) | (r2 & 0xFFFFFFFF)
|
||||
}
|
||||
|
||||
pub fn set_ret_val(vcpu: &mut IntelVCpu, val: u64) {
|
||||
vcpu.guest_registers.rdx = (val >> 32) as u32 as u64;
|
||||
vcpu.guest_registers.rax = val as u32 as u64;
|
||||
}
|
||||
|
||||
pub fn shadow_read(vcpu: &mut IntelVCpu, msr_kind: MsrIndex) {
|
||||
if let Some(msr) = vcpu.guest_msr.find(msr_kind) {
|
||||
Self::set_ret_val(vcpu, msr.data);
|
||||
} else {
|
||||
panic!("MSR not found");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shadow_write(vcpu: &mut IntelVCpu, msr_kind: MsrIndex) {
|
||||
let regs = &vcpu.guest_registers;
|
||||
if vcpu.guest_msr.find(msr_kind).is_some() {
|
||||
vcpu.guest_msr
|
||||
.set(msr_kind, Self::concat(regs.rdx, regs.rax))
|
||||
.unwrap();
|
||||
} else {
|
||||
panic!("MSR not found: {:#x}", msr_kind);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_read_msr_vmexit(vcpu: &mut IntelVCpu) {
|
||||
let msr_kind = vcpu.guest_registers.rcx as u32;
|
||||
|
||||
match msr_kind {
|
||||
x86::msr::IA32_EFER => {
|
||||
Self::set_ret_val(vcpu, vmread(vmcs::guest::IA32_EFER_FULL).unwrap())
|
||||
}
|
||||
x86::msr::IA32_TIME_STAMP_COUNTER => {
|
||||
Self::set_ret_val(vcpu, unsafe { x86::time::rdtsc() })
|
||||
}
|
||||
x86::msr::IA32_FEATURE_CONTROL => {
|
||||
// Lock bit (0) | Enable VMX inside SMX (1) | Enable VMX outside SMX (2)
|
||||
Self::set_ret_val(vcpu, 0x5)
|
||||
}
|
||||
0x48 => Self::set_ret_val(vcpu, 0), // IA32_SPEC_CTRL
|
||||
0x122 => Self::set_ret_val(vcpu, 0), // IA32_TSX_CTRL
|
||||
0x560 => Self::set_ret_val(vcpu, 0), // IA32_RTIT_OUTPUT_BASE
|
||||
0x561 => Self::set_ret_val(vcpu, 0), // IA32_RTIT_OUTPUT_MASK_PTRS
|
||||
0x570 => Self::set_ret_val(vcpu, 0), // IA32_RTIT_CTL
|
||||
0x571 => Self::set_ret_val(vcpu, 0), // IA32_RTIT_STATUS
|
||||
0x572 => Self::set_ret_val(vcpu, 0), // IA32_CR3_MATCH
|
||||
0x580 => Self::set_ret_val(vcpu, 0), // IA32_ADDR0_START
|
||||
0x581 => Self::set_ret_val(vcpu, 0), // IA32_ADDR0_END
|
||||
0x582 => Self::set_ret_val(vcpu, 0), // IA32_ADDR1_START
|
||||
0x583 => Self::set_ret_val(vcpu, 0), // IA32_ADDR1_END
|
||||
0x584 => Self::set_ret_val(vcpu, 0), // IA32_ADDR2_START
|
||||
0x585 => Self::set_ret_val(vcpu, 0), // IA32_ADDR2_END
|
||||
0x586 => Self::set_ret_val(vcpu, 0), // IA32_ADDR3_START
|
||||
0x587 => Self::set_ret_val(vcpu, 0), // IA32_ADDR3_END
|
||||
x86::msr::IA32_FS_BASE => {
|
||||
Self::set_ret_val(vcpu, vmread(vmcs::guest::FS_BASE).unwrap())
|
||||
}
|
||||
x86::msr::IA32_GS_BASE => {
|
||||
Self::set_ret_val(vcpu, vmread(vmcs::guest::GS_BASE).unwrap())
|
||||
}
|
||||
x86::msr::IA32_KERNEL_GSBASE => Self::shadow_read(vcpu, msr_kind),
|
||||
x86::msr::IA32_STAR => Self::shadow_read(vcpu, msr_kind),
|
||||
x86::msr::IA32_LSTAR => Self::shadow_read(vcpu, msr_kind),
|
||||
x86::msr::IA32_CSTAR => Self::shadow_read(vcpu, msr_kind),
|
||||
x86::msr::IA32_FMASK => Self::shadow_read(vcpu, msr_kind),
|
||||
x86::msr::SYSENTER_CS_MSR => {
|
||||
Self::set_ret_val(vcpu, vmread(vmcs::guest::IA32_SYSENTER_CS).unwrap())
|
||||
}
|
||||
x86::msr::SYSENTER_ESP_MSR => {
|
||||
Self::set_ret_val(vcpu, vmread(vmcs::guest::IA32_SYSENTER_ESP).unwrap())
|
||||
}
|
||||
x86::msr::SYSENTER_EIP_MSR => {
|
||||
Self::set_ret_val(vcpu, vmread(vmcs::guest::IA32_SYSENTER_EIP).unwrap())
|
||||
}
|
||||
0x1b => Self::shadow_read(vcpu, msr_kind),
|
||||
0x8b => Self::set_ret_val(vcpu, 0x8701021),
|
||||
0xc0011029 => Self::set_ret_val(vcpu, 0x3000310e08202),
|
||||
0xc0010000 => Self::set_ret_val(vcpu, 0x130076),
|
||||
0xc0010001 => Self::set_ret_val(vcpu, 0),
|
||||
0xc0010002 => Self::set_ret_val(vcpu, 0),
|
||||
0xc0010003 => Self::set_ret_val(vcpu, 0),
|
||||
0xc0010007 => Self::set_ret_val(vcpu, 0),
|
||||
0xc0010114 => Self::set_ret_val(vcpu, 0),
|
||||
0xc0010117 => Self::set_ret_val(vcpu, 0), // MSR_VM_HSAVE_PA
|
||||
0x277 => Self::set_ret_val(vcpu, 0x0007040600070406),
|
||||
0xc0000103 => Self::shadow_read(vcpu, msr_kind), // TSC_AUX
|
||||
0xd90 => Self::set_ret_val(vcpu, 0), // MSR_C1_PMON_EVNT_SEL0
|
||||
0xe1 => Self::set_ret_val(vcpu, 0), // IA32_UMWAIT_CONTROL
|
||||
0x1c4 => Self::set_ret_val(vcpu, 0), // Unknown MSR
|
||||
0x1c5 => Self::set_ret_val(vcpu, 0), // Unknown MSR
|
||||
_ => {
|
||||
panic!("Unhandled RDMSR: {:#x}", msr_kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_wrmsr_vmexit(vcpu: &mut IntelVCpu) {
|
||||
let regs = &vcpu.guest_registers;
|
||||
let value = Self::concat(regs.rdx, regs.rax);
|
||||
let msr_kind: MsrIndex = regs.rcx as MsrIndex;
|
||||
|
||||
match msr_kind {
|
||||
x86::msr::IA32_STAR => Self::shadow_write(vcpu, msr_kind),
|
||||
x86::msr::IA32_LSTAR => Self::shadow_write(vcpu, msr_kind),
|
||||
x86::msr::IA32_CSTAR => Self::shadow_write(vcpu, msr_kind),
|
||||
x86::msr::IA32_TSC_AUX => Self::shadow_write(vcpu, msr_kind),
|
||||
x86::msr::IA32_FMASK => Self::shadow_write(vcpu, msr_kind),
|
||||
x86::msr::IA32_KERNEL_GSBASE => Self::shadow_write(vcpu, msr_kind),
|
||||
x86::msr::MSR_C5_PMON_BOX_CTRL => Self::shadow_write(vcpu, msr_kind),
|
||||
x86::msr::SYSENTER_CS_MSR => vmwrite(vmcs::guest::IA32_SYSENTER_CS, value).unwrap(),
|
||||
x86::msr::SYSENTER_EIP_MSR => vmwrite(vmcs::guest::IA32_SYSENTER_EIP, value).unwrap(),
|
||||
x86::msr::SYSENTER_ESP_MSR => vmwrite(vmcs::guest::IA32_SYSENTER_ESP, value).unwrap(),
|
||||
x86::msr::IA32_EFER => {
|
||||
info!("Setting IA32_EFER: {:#x}", value);
|
||||
if value == 0xd01 || value == 0x100 {
|
||||
vmwrite(vmcs::guest::IA32_EFER_FULL, value).unwrap()
|
||||
}
|
||||
}
|
||||
x86::msr::IA32_FS_BASE => vmwrite(vmcs::guest::FS_BASE, value).unwrap(),
|
||||
x86::msr::IA32_GS_BASE => vmwrite(vmcs::guest::GS_BASE, value).unwrap(),
|
||||
0x1b => Self::shadow_write(vcpu, msr_kind),
|
||||
0xc0010007 => Self::shadow_write(vcpu, msr_kind),
|
||||
0xc0010117 => Self::shadow_write(vcpu, msr_kind),
|
||||
|
||||
_ => {
|
||||
panic!("Unhandled WRMSR: {:#x}", msr_kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ use crate::{
|
||||
common::{self, read_msr},
|
||||
intel::{
|
||||
controls, cpuid, ept,
|
||||
msr::{self, ShadowMsr},
|
||||
register::GuestRegisters,
|
||||
vmcs::{
|
||||
self,
|
||||
@ -40,6 +41,8 @@ pub struct IntelVCpu {
|
||||
ept: ept::EPT,
|
||||
eptp: ept::EPTP,
|
||||
guest_memory_size: u64,
|
||||
pub host_msr: ShadowMsr,
|
||||
pub guest_msr: ShadowMsr,
|
||||
}
|
||||
|
||||
impl IntelVCpu {
|
||||
@ -74,13 +77,22 @@ impl IntelVCpu {
|
||||
|
||||
match exit_reason {
|
||||
VmxExitReason::HLT => {
|
||||
//info!("VM hlt");
|
||||
info!("VM hlt");
|
||||
self.step_next_inst()?;
|
||||
}
|
||||
VmxExitReason::CPUID => {
|
||||
info!("VM exit reason: CPUID");
|
||||
cpuid::handle_cpuid_vmexit(self);
|
||||
self.step_next_inst()?;
|
||||
}
|
||||
VmxExitReason::RDMSR => {
|
||||
msr::ShadowMsr::handle_read_msr_vmexit(self);
|
||||
self.step_next_inst()?;
|
||||
}
|
||||
VmxExitReason::WRMSR => {
|
||||
msr::ShadowMsr::handle_wrmsr_vmexit(self);
|
||||
self.step_next_inst()?;
|
||||
}
|
||||
VmxExitReason::EPT_VIOLATION => {
|
||||
let guest_address = vmread(vmcs::ro::GUEST_PHYSICAL_ADDR_FULL)?;
|
||||
info!("EPT Violation at guest address: {:#x}", guest_address);
|
||||
@ -107,6 +119,8 @@ impl IntelVCpu {
|
||||
}
|
||||
|
||||
fn vmentry(&mut self) -> Result<(), InstructionError> {
|
||||
msr::update_msrs(self).unwrap();
|
||||
|
||||
let success = {
|
||||
let result: u16;
|
||||
unsafe {
|
||||
@ -141,6 +155,7 @@ impl IntelVCpu {
|
||||
controls::setup_exit_controls()?;
|
||||
Self::setup_host_state()?;
|
||||
self.setup_guest_state()?;
|
||||
msr::register_msrs(self).map_err(|_| "MSR error")?;
|
||||
|
||||
self.init_guest_memory(frame_allocator)?;
|
||||
|
||||
@ -623,6 +638,8 @@ impl VCpu for IntelVCpu {
|
||||
ept,
|
||||
eptp,
|
||||
guest_memory_size: 1024 * 1024 * 256, // 256 MiB
|
||||
host_msr: ShadowMsr::new(),
|
||||
guest_msr: ShadowMsr::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user