use x86::msr::{rdmsr, wrmsr};
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
#[allow(non_camel_case_types, dead_code)]
pub enum Msr {
IA32_FEATURE_CONTROL = 0x3a,
IA32_PAT = 0x277,
IA32_VMX_BASIC = 0x480,
IA32_VMX_PINBASED_CTLS = 0x481,
IA32_VMX_PROCBASED_CTLS = 0x482,
IA32_VMX_EXIT_CTLS = 0x483,
IA32_VMX_ENTRY_CTLS = 0x484,
IA32_VMX_MISC = 0x485,
IA32_VMX_CR0_FIXED0 = 0x486,
IA32_VMX_CR0_FIXED1 = 0x487,
IA32_VMX_CR4_FIXED0 = 0x488,
IA32_VMX_CR4_FIXED1 = 0x489,
IA32_VMX_PROCBASED_CTLS2 = 0x48b,
IA32_VMX_EPT_VPID_CAP = 0x48c,
IA32_VMX_TRUE_PINBASED_CTLS = 0x48d,
IA32_VMX_TRUE_PROCBASED_CTLS = 0x48e,
IA32_VMX_TRUE_EXIT_CTLS = 0x48f,
IA32_VMX_TRUE_ENTRY_CTLS = 0x490,
IA32_XSS = 0xda0,
IA32_EFER = 0xc000_0080,
IA32_STAR = 0xc000_0081,
IA32_LSTAR = 0xc000_0082,
IA32_CSTAR = 0xc000_0083,
IA32_FMASK = 0xc000_0084,
IA32_FS_BASE = 0xc000_0100,
IA32_GS_BASE = 0xc000_0101,
IA32_KERNEL_GSBASE = 0xc000_0102,
}
impl Msr {
#[inline(always)]
pub fn read(self) -> u64 {
unsafe { rdmsr(self as _) }
}
#[inline(always)]
pub unsafe fn write(self, value: u64) {
unsafe { wrmsr(self as _, value) }
}
}
pub(super) trait MsrReadWrite {
const MSR: Msr;
fn read_raw() -> u64 {
Self::MSR.read()
}
unsafe fn write_raw(flags: u64) {
unsafe {
Self::MSR.write(flags);
}
}
}
#[cfg(test)]
mod tests {
use alloc::format;
use super::*;
#[test]
fn test_msr_enum_values() {
assert_eq!(Msr::IA32_FEATURE_CONTROL as u32, 0x3a);
assert_eq!(Msr::IA32_PAT as u32, 0x277);
assert_eq!(Msr::IA32_VMX_BASIC as u32, 0x480);
assert_eq!(Msr::IA32_EFER as u32, 0xc000_0080);
assert_eq!(Msr::IA32_LSTAR as u32, 0xc000_0082);
}
#[test]
fn test_msr_debug() {
let msr = Msr::IA32_VMX_BASIC;
let debug_str = format!("{:?}", msr);
assert!(!debug_str.is_empty());
assert!(debug_str.contains("IA32_VMX_BASIC"));
}
#[test]
fn test_msr_copy_clone() {
let msr1 = Msr::IA32_EFER;
let msr2 = msr1; let msr3 = msr1.clone();
assert_eq!(msr1 as u32, msr2 as u32);
assert_eq!(msr1 as u32, msr3 as u32);
}
#[test]
fn test_vmx_msr_ranges() {
assert!(Msr::IA32_VMX_BASIC as u32 >= 0x480);
assert!(Msr::IA32_VMX_TRUE_ENTRY_CTLS as u32 <= 0x490);
assert_eq!(
Msr::IA32_VMX_BASIC as u32 + 1,
Msr::IA32_VMX_PINBASED_CTLS as u32
);
assert_eq!(
Msr::IA32_VMX_PINBASED_CTLS as u32 + 1,
Msr::IA32_VMX_PROCBASED_CTLS as u32
);
}
#[test]
fn test_fs_gs_base_msr_values() {
assert_eq!(Msr::IA32_FS_BASE as u32, 0xc000_0100);
assert_eq!(Msr::IA32_GS_BASE as u32, 0xc000_0101);
assert_eq!(Msr::IA32_KERNEL_GSBASE as u32, 0xc000_0102);
assert_eq!(Msr::IA32_FS_BASE as u32 + 1, Msr::IA32_GS_BASE as u32);
assert_eq!(Msr::IA32_GS_BASE as u32 + 1, Msr::IA32_KERNEL_GSBASE as u32);
}
#[test]
fn test_system_call_msr_values() {
assert_eq!(Msr::IA32_STAR as u32, 0xc000_0081);
assert_eq!(Msr::IA32_LSTAR as u32, 0xc000_0082);
assert_eq!(Msr::IA32_CSTAR as u32, 0xc000_0083);
assert_eq!(Msr::IA32_FMASK as u32, 0xc000_0084);
assert_eq!(Msr::IA32_STAR as u32 + 1, Msr::IA32_LSTAR as u32);
assert_eq!(Msr::IA32_LSTAR as u32 + 1, Msr::IA32_CSTAR as u32);
assert_eq!(Msr::IA32_CSTAR as u32 + 1, Msr::IA32_FMASK as u32);
}
struct TestMsr;
impl MsrReadWrite for TestMsr {
const MSR: Msr = Msr::IA32_PAT;
}
#[test]
fn test_msr_read_write_trait() {
assert_eq!(TestMsr::MSR as u32, 0x277);
}
#[test]
fn test_msr_as_u32_conversion() {
let msrs = [
Msr::IA32_FEATURE_CONTROL,
Msr::IA32_VMX_BASIC,
Msr::IA32_EFER,
Msr::IA32_LSTAR,
];
for msr in msrs.iter() {
let value = *msr as u32;
assert!(value > 0);
assert!(value < 0xffff_ffff);
}
}
}