mirror of
https://github.com/mii443/nel_os.git
synced 2025-08-22 16:15:38 +00:00
msr
This commit is contained in:
134
src/vmm/cpuid.rs
134
src/vmm/cpuid.rs
@ -9,6 +9,28 @@ pub fn handle_cpuid_exit(vcpu: &mut VCpu) {
|
||||
let vendor: &[u8; 12] = b"miimiimiimii";
|
||||
let vendor = unsafe { core::mem::transmute::<&[u8; 12], &[u32; 3]>(vendor) };
|
||||
match VmxLeaf::from(regs.rax) {
|
||||
VmxLeaf::EXTENDED_FEATURE => match regs.rcx {
|
||||
0 => {
|
||||
info!("CPUID extended feature");
|
||||
let mut ebx = ExtFeatureEbx0::default();
|
||||
ebx.smep = true;
|
||||
ebx.invpcid = false;
|
||||
ebx.smap = true;
|
||||
regs.rax = 1;
|
||||
regs.rbx = ebx.as_u32() as u64;
|
||||
regs.rcx = 0;
|
||||
regs.rdx = 0;
|
||||
}
|
||||
1 => {
|
||||
invalid(vcpu);
|
||||
}
|
||||
2 => {
|
||||
invalid(vcpu);
|
||||
}
|
||||
_ => {
|
||||
panic!("Unhandled CPUID leaf: {:#x}.{:#x}", regs.rax, regs.rcx);
|
||||
}
|
||||
},
|
||||
VmxLeaf::EXTENDED_PROCESSOR_SIGNATURE => {
|
||||
info!("CPUID extended processor signature");
|
||||
let signature = cpuid!(0x80000001, 0);
|
||||
@ -270,3 +292,115 @@ impl FeatureInfoEdx {
|
||||
| (self.pbe as u32) << 31
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExtFeatureEbx0 {
|
||||
pub fsgsbase: bool,
|
||||
pub tsc_adjust: bool,
|
||||
pub sgx: bool,
|
||||
pub bmi1: bool,
|
||||
pub hle: bool,
|
||||
pub avx2: bool,
|
||||
pub fdp: bool,
|
||||
pub smep: bool,
|
||||
pub bmi2: bool,
|
||||
pub erms: bool,
|
||||
pub invpcid: bool,
|
||||
pub rtm: bool,
|
||||
pub rdtm: bool,
|
||||
pub fpucsds: bool,
|
||||
pub mpx: bool,
|
||||
pub rdta: bool,
|
||||
pub avx512f: bool,
|
||||
pub avx512dq: bool,
|
||||
pub rdseed: bool,
|
||||
pub adx: bool,
|
||||
pub smap: bool,
|
||||
pub avx512ifma: bool,
|
||||
pub _reserved1: bool,
|
||||
pub clflushopt: bool,
|
||||
pub clwb: bool,
|
||||
pub pt: bool,
|
||||
pub avx512pf: bool,
|
||||
pub avx512er: bool,
|
||||
pub avx512cd: bool,
|
||||
pub sha: bool,
|
||||
pub avx512bw: bool,
|
||||
pub avx512vl: bool,
|
||||
}
|
||||
|
||||
impl Default for ExtFeatureEbx0 {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
fsgsbase: false,
|
||||
tsc_adjust: false,
|
||||
sgx: false,
|
||||
bmi1: false,
|
||||
hle: false,
|
||||
avx2: false,
|
||||
fdp: false,
|
||||
smep: false,
|
||||
bmi2: false,
|
||||
erms: false,
|
||||
invpcid: false,
|
||||
rtm: false,
|
||||
rdtm: false,
|
||||
fpucsds: false,
|
||||
mpx: false,
|
||||
rdta: false,
|
||||
avx512f: false,
|
||||
avx512dq: false,
|
||||
rdseed: false,
|
||||
adx: false,
|
||||
smap: false,
|
||||
avx512ifma: false,
|
||||
_reserved1: false,
|
||||
clflushopt: false,
|
||||
clwb: false,
|
||||
pt: false,
|
||||
avx512pf: false,
|
||||
avx512er: false,
|
||||
avx512cd: false,
|
||||
sha: false,
|
||||
avx512bw: false,
|
||||
avx512vl: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtFeatureEbx0 {
|
||||
pub fn as_u32(&self) -> u32 {
|
||||
(self.fsgsbase as u32)
|
||||
| (self.tsc_adjust as u32) << 1
|
||||
| (self.sgx as u32) << 2
|
||||
| (self.bmi1 as u32) << 3
|
||||
| (self.hle as u32) << 4
|
||||
| (self.avx2 as u32) << 5
|
||||
| (self.fdp as u32) << 6
|
||||
| (self.smep as u32) << 7
|
||||
| (self.bmi2 as u32) << 8
|
||||
| (self.erms as u32) << 9
|
||||
| (self.invpcid as u32) << 10
|
||||
| (self.rtm as u32) << 11
|
||||
| (self.rdtm as u32) << 12
|
||||
| (self.fpucsds as u32) << 13
|
||||
| (self.mpx as u32) << 14
|
||||
| (self.rdta as u32) << 15
|
||||
| (self.avx512f as u32) << 16
|
||||
| (self.avx512dq as u32) << 17
|
||||
| (self.rdseed as u32) << 18
|
||||
| (self.adx as u32) << 19
|
||||
| (self.smap as u32) << 20
|
||||
| (self.avx512ifma as u32) << 21
|
||||
| (self._reserved1 as u32) << 22
|
||||
| (self.clflushopt as u32) << 23
|
||||
| (self.clwb as u32) << 24
|
||||
| (self.pt as u32) << 25
|
||||
| (self.avx512pf as u32) << 26
|
||||
| (self.avx512er as u32) << 27
|
||||
| (self.avx512cd as u32) << 28
|
||||
| (self.sha as u32) << 29
|
||||
| (self.avx512bw as u32) << 30
|
||||
| (self.avx512vl as u32) << 31
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ pub mod cpuid;
|
||||
pub mod ept;
|
||||
pub mod error;
|
||||
pub mod linux;
|
||||
pub mod msr;
|
||||
pub mod register;
|
||||
pub mod support;
|
||||
pub mod vcpu;
|
||||
|
165
src/vmm/msr.rs
Normal file
165
src/vmm/msr.rs
Normal file
@ -0,0 +1,165 @@
|
||||
use core::u64;
|
||||
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use x86::bits64::vmx::{vmread, vmwrite};
|
||||
use x86::vmx::vmcs;
|
||||
use x86_64::structures::paging::{OffsetPageTable, Translate};
|
||||
use x86_64::{PhysAddr, VirtAddr};
|
||||
|
||||
use super::vcpu::VCpu;
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
impl ShadowMsr {
|
||||
pub fn new() -> Self {
|
||||
let ents = vec![SavedMsr::default(); MAX_NUM_ENTS];
|
||||
|
||||
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, mapper: &OffsetPageTable<'static>) -> PhysAddr {
|
||||
mapper
|
||||
.translate_addr(VirtAddr::from_ptr(&self.ents))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn concat(r1: u64, r2: u64) -> u64 {
|
||||
((r1 & 0xFFFFFFFF) << 32) | (r2 & 0xFFFFFFFF)
|
||||
}
|
||||
|
||||
pub fn set_ret_val(vcpu: &mut VCpu, 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 VCpu, 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 VCpu, 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");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_rdmsr_vmexit(vcpu: &mut VCpu) {
|
||||
let msr_kind = vcpu.guest_registers.rcx as u32;
|
||||
|
||||
match msr_kind {
|
||||
x86::msr::APIC_BASE => Self::set_ret_val(vcpu, u64::MAX),
|
||||
x86::msr::IA32_EFER => Self::set_ret_val(vcpu, unsafe {
|
||||
vmread(vmcs::guest::IA32_EFER_FULL).unwrap()
|
||||
}),
|
||||
x86::msr::IA32_FS_BASE => {
|
||||
Self::set_ret_val(vcpu, unsafe { vmread(vmcs::guest::FS_BASE).unwrap() })
|
||||
}
|
||||
x86::msr::IA32_GS_BASE => {
|
||||
Self::set_ret_val(vcpu, unsafe { vmread(vmcs::guest::GS_BASE).unwrap() })
|
||||
}
|
||||
x86::msr::IA32_KERNEL_GSBASE => Self::shadow_read(vcpu, msr_kind),
|
||||
_ => {
|
||||
panic!("Unhandled RDMSR: {}", msr_kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_wrmsr_vmexit(vcpu: &mut VCpu) {
|
||||
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::SYSENTER_CS_MSR => unsafe {
|
||||
vmwrite(vmcs::guest::IA32_SYSENTER_CS, value).unwrap()
|
||||
},
|
||||
x86::msr::SYSENTER_EIP_MSR => unsafe {
|
||||
vmwrite(vmcs::guest::IA32_SYSENTER_EIP, value).unwrap()
|
||||
},
|
||||
x86::msr::SYSENTER_ESP_MSR => unsafe {
|
||||
vmwrite(vmcs::guest::IA32_SYSENTER_ESP, value).unwrap()
|
||||
},
|
||||
x86::msr::IA32_EFER => unsafe { vmwrite(vmcs::guest::IA32_EFER_FULL, value).unwrap() },
|
||||
x86::msr::IA32_FS_BASE => unsafe { vmwrite(vmcs::guest::FS_BASE, value).unwrap() },
|
||||
x86::msr::IA32_GS_BASE => unsafe { vmwrite(vmcs::guest::GS_BASE, value).unwrap() },
|
||||
_ => {
|
||||
panic!("Unhandled WRMSR: {}", msr_kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
103
src/vmm/vcpu.rs
103
src/vmm/vcpu.rs
@ -6,13 +6,13 @@ use x86::{
|
||||
msr::{rdmsr, IA32_EFER, IA32_FS_BASE},
|
||||
vmx::{vmcs, VmFail},
|
||||
};
|
||||
use x86_64::{registers::control::Cr4Flags, VirtAddr};
|
||||
use x86_64::{registers::control::Cr4Flags, structures::paging::OffsetPageTable, VirtAddr};
|
||||
|
||||
use crate::{
|
||||
info,
|
||||
memory::BootInfoFrameAllocator,
|
||||
vmm::{
|
||||
cpuid,
|
||||
cpuid, msr,
|
||||
vmcs::{
|
||||
DescriptorType, EntryControls, Granularity, PrimaryExitControls,
|
||||
PrimaryProcessorBasedVmExecutionControls, SecondaryProcessorBasedVmExecutionControls,
|
||||
@ -24,6 +24,7 @@ use crate::{
|
||||
use super::{
|
||||
ept::{EPT, EPTP},
|
||||
linux::{self, BootParams, E820Type},
|
||||
msr::ShadowMsr,
|
||||
register::GuestRegisters,
|
||||
vmcs::{InstructionError, PinBasedVmExecutionControls, Vmcs},
|
||||
vmxon::Vmxon,
|
||||
@ -38,6 +39,8 @@ pub struct VCpu {
|
||||
pub launch_done: bool,
|
||||
pub ept: EPT,
|
||||
pub eptp: EPTP,
|
||||
pub host_msr: ShadowMsr,
|
||||
pub guest_msr: ShadowMsr,
|
||||
}
|
||||
|
||||
const TEMP_STACK_SIZE: usize = 4096;
|
||||
@ -59,6 +62,8 @@ impl VCpu {
|
||||
launch_done: false,
|
||||
ept,
|
||||
eptp,
|
||||
host_msr: ShadowMsr::new(),
|
||||
guest_msr: ShadowMsr::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,6 +196,88 @@ impl VCpu {
|
||||
unsafe { vmwrite(vmcs::control::EPTP_FULL, eptp.0).unwrap() };
|
||||
}
|
||||
|
||||
pub fn register_msrs(&mut self, mapper: OffsetPageTable<'static>) {
|
||||
unsafe {
|
||||
// tsc_aux, star, lstar, cstar, fmask, kernel_gs_base.
|
||||
self.host_msr
|
||||
.set(x86::msr::IA32_TSC_AUX, rdmsr(x86::msr::IA32_TSC_AUX) as u64)
|
||||
.unwrap();
|
||||
self.host_msr
|
||||
.set(x86::msr::IA32_STAR, rdmsr(x86::msr::IA32_STAR) as u64)
|
||||
.unwrap();
|
||||
self.host_msr
|
||||
.set(x86::msr::IA32_LSTAR, rdmsr(x86::msr::IA32_LSTAR) as u64)
|
||||
.unwrap();
|
||||
self.host_msr
|
||||
.set(x86::msr::IA32_CSTAR, rdmsr(x86::msr::IA32_CSTAR) as u64)
|
||||
.unwrap();
|
||||
self.host_msr
|
||||
.set(x86::msr::IA32_FMASK, rdmsr(x86::msr::IA32_FMASK) as u64)
|
||||
.unwrap();
|
||||
self.host_msr
|
||||
.set(
|
||||
x86::msr::IA32_KERNEL_GSBASE,
|
||||
rdmsr(x86::msr::IA32_KERNEL_GSBASE) as u64,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
self.guest_msr.set(x86::msr::IA32_TSC_AUX, 0).unwrap();
|
||||
self.guest_msr.set(x86::msr::IA32_STAR, 0).unwrap();
|
||||
self.guest_msr.set(x86::msr::IA32_LSTAR, 0).unwrap();
|
||||
self.guest_msr.set(x86::msr::IA32_CSTAR, 0).unwrap();
|
||||
self.guest_msr.set(x86::msr::IA32_FMASK, 0).unwrap();
|
||||
self.guest_msr.set(x86::msr::IA32_KERNEL_GSBASE, 0).unwrap();
|
||||
|
||||
vmwrite(
|
||||
vmcs::control::VMEXIT_MSR_LOAD_ADDR_FULL,
|
||||
self.host_msr.phys(&mapper).as_u64(),
|
||||
)
|
||||
.unwrap();
|
||||
vmwrite(
|
||||
vmcs::control::VMEXIT_MSR_STORE_ADDR_FULL,
|
||||
self.guest_msr.phys(&mapper).as_u64(),
|
||||
)
|
||||
.unwrap();
|
||||
vmwrite(
|
||||
vmcs::control::VMENTRY_MSR_LOAD_ADDR_FULL,
|
||||
self.guest_msr.phys(&mapper).as_u64(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_msrs(&mut self) {
|
||||
let indices_to_update: alloc::vec::Vec<u32> = self
|
||||
.host_msr
|
||||
.saved_ents()
|
||||
.iter()
|
||||
.map(|entry| entry.index)
|
||||
.collect();
|
||||
|
||||
for index in indices_to_update {
|
||||
let value = unsafe { rdmsr(index) };
|
||||
self.host_msr.set_by_index(index, value).unwrap();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
vmwrite(
|
||||
vmcs::control::VMEXIT_MSR_LOAD_COUNT,
|
||||
self.host_msr.saved_ents().len() as u64,
|
||||
)
|
||||
.unwrap();
|
||||
vmwrite(
|
||||
vmcs::control::VMEXIT_MSR_STORE_COUNT,
|
||||
self.guest_msr.saved_ents().len() as u64,
|
||||
)
|
||||
.unwrap();
|
||||
vmwrite(
|
||||
vmcs::control::VMENTRY_MSR_LOAD_COUNT,
|
||||
self.guest_msr.saved_ents().len() as u64,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_exec_ctrls(&mut self) -> Result<(), VmFail> {
|
||||
info!("Setting up pin based execution controls");
|
||||
let basic_msr = unsafe { rdmsr(x86::msr::IA32_VMX_BASIC) };
|
||||
@ -222,6 +309,7 @@ impl VCpu {
|
||||
primary_exec_ctrl.set_hlt(false);
|
||||
primary_exec_ctrl.set_activate_secondary_controls(true);
|
||||
primary_exec_ctrl.set_use_tpr_shadow(true);
|
||||
primary_exec_ctrl.set_use_msr_bitmap(false);
|
||||
|
||||
primary_exec_ctrl.write();
|
||||
|
||||
@ -555,10 +643,19 @@ impl VCpu {
|
||||
info!("HLT instruction executed");
|
||||
}
|
||||
VmxExitReason::CPUID => {
|
||||
info!("CPUID instruction executed");
|
||||
cpuid::handle_cpuid_exit(self);
|
||||
self.step_next_inst().unwrap();
|
||||
}
|
||||
VmxExitReason::RDMSR => {
|
||||
info!("RDMSR instruction executed");
|
||||
msr::ShadowMsr::handle_rdmsr_vmexit(self);
|
||||
self.step_next_inst().unwrap();
|
||||
}
|
||||
VmxExitReason::WRMSR => {
|
||||
info!("WRMSR instruction executed");
|
||||
msr::ShadowMsr::handle_wrmsr_vmexit(self);
|
||||
self.step_next_inst().unwrap();
|
||||
}
|
||||
_ => {
|
||||
panic!("VMExit reason: {:?}", info.get_reason());
|
||||
}
|
||||
|
Reference in New Issue
Block a user