diff --git a/alioth/src/arch/x86_64/msr.rs b/alioth/src/arch/x86_64/msr.rs index 61e37a7b..c21a6e38 100644 --- a/alioth/src/arch/x86_64/msr.rs +++ b/alioth/src/arch/x86_64/msr.rs @@ -14,22 +14,28 @@ use bitfield::bitfield; -use crate::bitflags; +use crate::{bitflags, consts}; // Intel Vol.4, Table 2-2. -pub const IA32_EFER: u32 = 0xc000_0080; -pub const IA32_STAR: u32 = 0xc000_0081; -pub const IA32_LSTAR: u32 = 0xc000_0082; -pub const IA32_CSTAR: u32 = 0xc000_0083; -pub const IA32_FMASK: u32 = 0xc000_0084; -pub const IA32_FS_BASE: u32 = 0xc000_0100; -pub const IA32_GS_BASE: u32 = 0xc000_0101; -pub const IA32_KERNEL_GS_BASE: u32 = 0xc000_0102; -pub const IA32_TSC_AUX: u32 = 0xc000_0103; -pub const IA32_MISC_ENABLE: u32 = 0x0000_01a0; +consts! { + pub struct Msr(u32) { + EFER = 0xc000_0080; + STAR = 0xc000_0081; + LSTAR = 0xc000_0082; + CSTAR = 0xc000_0083; + FMASK = 0xc000_0084; + FS_BASE = 0xc000_0100; + GS_BASE = 0xc000_0101; + KERNEL_GS_BASE = 0xc000_0102; + TSC_AUX = 0xc000_0103; + MISC_ENABLE = 0x0000_01a0; + APIC_BASE = 0x0000_001b; + } +} bitflags! { - pub struct Efer(u32) { + #[derive(Default)] + pub struct Efer(u64) { /// SYSCALL enable SCE = 1 << 0; /// IA-32e mode enable diff --git a/alioth/src/arch/x86_64/reg.rs b/alioth/src/arch/x86_64/reg.rs index e167bfe2..b72b1ff3 100644 --- a/alioth/src/arch/x86_64/reg.rs +++ b/alioth/src/arch/x86_64/reg.rs @@ -58,7 +58,8 @@ bitflags! { } bitflags! { - pub struct Cr0(u32) { + #[derive(Default)] + pub struct Cr0(u64) { /// CarryProtected Mode Enable PE = 1 << 0; /// CarryMonitor co-processor @@ -85,6 +86,7 @@ bitflags! { } bitflags! { + #[derive(Default)] pub struct Cr3(u64) { /// CarryPage-level write-through PWT = 1 << 3; @@ -94,7 +96,8 @@ bitflags! { } bitflags! { - pub struct Cr4(u32) { + #[derive(Default)] + pub struct Cr4(u64) { /// CarryVirtual 8086 Mode Extensions VME = 1 << 0; /// CarryProtected-mode Virtual Interrupts @@ -195,8 +198,6 @@ pub enum SReg { Cr3, Cr4, Cr8, - Efer, - ApicBase, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] diff --git a/alioth/src/board/board_x86_64/board_x86_64.rs b/alioth/src/board/board_x86_64/board_x86_64.rs index 521e4396..385f525e 100644 --- a/alioth/src/board/board_x86_64/board_x86_64.rs +++ b/alioth/src/board/board_x86_64/board_x86_64.rs @@ -31,7 +31,7 @@ use crate::arch::layout::{ BIOS_DATA_END, EBDA_END, EBDA_START, IOAPIC_START, MEM_64_START, PORT_ACPI_RESET, PORT_ACPI_SLEEP_CONTROL, PORT_ACPI_TIMER, RAM_32_SIZE, }; -use crate::arch::msr::{IA32_MISC_ENABLE, MiscEnable}; +use crate::arch::msr::{MiscEnable, Msr}; use crate::board::{Board, BoardConfig, CpuTopology, PCIE_MMIO_64_SIZE, Result, VcpuGuard, error}; use crate::device::ioapic::IoApic; use crate::firmware::acpi::bindings::{ @@ -241,6 +241,7 @@ where return Ok(()); } vcpu.set_sregs(&init_state.sregs, &init_state.seg_regs, &init_state.dt_regs)?; + vcpu.set_msrs(&init_state.msrs)?; vcpu.set_regs(&init_state.regs)?; Ok(()) } @@ -257,7 +258,7 @@ where } } vcpu.set_cpuids(cpuids)?; - vcpu.set_msrs(&[(IA32_MISC_ENABLE, MiscEnable::FAST_STRINGS.bits())])?; + vcpu.set_msrs(&[(Msr::MISC_ENABLE, MiscEnable::FAST_STRINGS.bits())])?; Ok(()) } diff --git a/alioth/src/hv/hv.rs b/alioth/src/hv/hv.rs index 0958e51f..741f1658 100644 --- a/alioth/src/hv/hv.rs +++ b/alioth/src/hv/hv.rs @@ -35,6 +35,8 @@ use snafu::{AsErrorSource, Snafu}; #[cfg(target_arch = "x86_64")] use crate::arch::cpuid::CpuidIn; #[cfg(target_arch = "x86_64")] +use crate::arch::msr::Msr; +#[cfg(target_arch = "x86_64")] use crate::arch::reg::{DtReg, DtRegVal, SegReg, SegRegVal}; use crate::arch::reg::{Reg, SReg}; #[cfg(target_arch = "x86_64")] @@ -207,7 +209,7 @@ pub trait Vcpu { fn set_cpuids(&mut self, cpuids: HashMap) -> Result<(), Error>; #[cfg(target_arch = "x86_64")] - fn set_msrs(&mut self, msrs: &[(u32, u64)]) -> Result<()>; + fn set_msrs(&mut self, msrs: &[(Msr, u64)]) -> Result<()>; fn dump(&self) -> Result<(), Error>; diff --git a/alioth/src/hv/kvm/vcpu/vcpu.rs b/alioth/src/hv/kvm/vcpu/vcpu.rs index 07de7090..4c80509e 100644 --- a/alioth/src/hv/kvm/vcpu/vcpu.rs +++ b/alioth/src/hv/kvm/vcpu/vcpu.rs @@ -37,6 +37,8 @@ use snafu::ResultExt; #[cfg(target_arch = "x86_64")] use crate::arch::cpuid::CpuidIn; #[cfg(target_arch = "x86_64")] +use crate::arch::msr::Msr; +#[cfg(target_arch = "x86_64")] use crate::arch::reg::{DtReg, DtRegVal, SegReg, SegRegVal}; use crate::arch::reg::{Reg, SReg}; use crate::ffi; @@ -227,7 +229,7 @@ impl Vcpu for KvmVcpu { } #[cfg(target_arch = "x86_64")] - fn set_msrs(&mut self, msrs: &[(u32, u64)]) -> Result<()> { + fn set_msrs(&mut self, msrs: &[(Msr, u64)]) -> Result<()> { self.kvm_set_msrs(msrs) } diff --git a/alioth/src/hv/kvm/vcpu/vcpu_x86_64/vcpu_x86_64.rs b/alioth/src/hv/kvm/vcpu/vcpu_x86_64/vcpu_x86_64.rs index 9f34c927..12100062 100644 --- a/alioth/src/hv/kvm/vcpu/vcpu_x86_64/vcpu_x86_64.rs +++ b/alioth/src/hv/kvm/vcpu/vcpu_x86_64/vcpu_x86_64.rs @@ -22,7 +22,8 @@ use std::os::fd::{FromRawFd, OwnedFd}; use snafu::ResultExt; use crate::arch::cpuid::CpuidIn; -use crate::arch::reg::{DtReg, DtRegVal, Reg, SReg, SegAccess, SegReg, SegRegVal}; +use crate::arch::msr::{Efer, Msr}; +use crate::arch::reg::{Cr0, Cr3, Cr4, DtReg, DtRegVal, Reg, SReg, SegAccess, SegReg, SegRegVal}; use crate::hv::kvm::kvm_error; use crate::hv::kvm::vcpu::KvmVcpu; use crate::hv::kvm::vm::KvmVm; @@ -47,13 +48,11 @@ impl VcpuArch { macro_rules! set_kvm_sreg { ($kvm_sregs:ident, $sreg:ident, $val:expr) => { match $sreg { - SReg::Cr0 => $kvm_sregs.cr0 = $val, + SReg::Cr0 => $kvm_sregs.cr0 = Cr0::from_bits_retain($val), SReg::Cr2 => $kvm_sregs.cr2 = $val, - SReg::Cr3 => $kvm_sregs.cr3 = $val, - SReg::Cr4 => $kvm_sregs.cr4 = $val, + SReg::Cr3 => $kvm_sregs.cr3 = Cr3::from_bits_retain($val), + SReg::Cr4 => $kvm_sregs.cr4 = Cr4::from_bits_retain($val), SReg::Cr8 => $kvm_sregs.cr8 = $val, - SReg::Efer => $kvm_sregs.efer = $val, - SReg::ApicBase => $kvm_sregs.apic_base = $val, } }; } @@ -99,13 +98,21 @@ macro_rules! set_kvm_seg_reg { macro_rules! get_kvm_sreg { ($kvm_sregs:ident, $sreg:ident) => { match $sreg { - SReg::Cr0 => $kvm_sregs.cr0, + SReg::Cr0 => $kvm_sregs.cr0.bits(), SReg::Cr2 => $kvm_sregs.cr2, - SReg::Cr3 => $kvm_sregs.cr3, - SReg::Cr4 => $kvm_sregs.cr4, + SReg::Cr3 => $kvm_sregs.cr3.bits(), + SReg::Cr4 => $kvm_sregs.cr4.bits(), SReg::Cr8 => $kvm_sregs.cr8, - SReg::Efer => $kvm_sregs.efer, - SReg::ApicBase => $kvm_sregs.apic_base, + } + }; +} + +macro_rules! fix_kvm_efer { + ($kvm_sregs:ident) => { + if $kvm_sregs.cr0.contains(Cr0::PG) && $kvm_sregs.cr4.contains(Cr4::PAE) { + $kvm_sregs.efer |= Efer::LME | Efer::LMA; + } else { + $kvm_sregs.efer &= !(Efer::LME | Efer::LMA); } }; } @@ -243,6 +250,7 @@ impl KvmVcpu { for (reg, val) in seg_regs { set_kvm_seg_reg!(kvm_sregs2, reg, val); } + fix_kvm_efer!(kvm_sregs2); unsafe { kvm_set_sregs2(&self.fd, &kvm_sregs2) }.context(error::VcpuReg)?; Ok(()) } @@ -281,6 +289,7 @@ impl KvmVcpu { for (reg, val) in seg_regs { set_kvm_seg_reg!(kvm_sregs, reg, val); } + fix_kvm_efer!(kvm_sregs); unsafe { kvm_set_sregs(&self.fd, &kvm_sregs) }.context(error::VcpuReg)?; Ok(()) } @@ -329,14 +338,14 @@ impl KvmVcpu { Ok(()) } - pub fn kvm_set_msrs(&mut self, msrs: &[(u32, u64)]) -> Result<()> { + pub fn kvm_set_msrs(&mut self, msrs: &[(Msr, u64)]) -> Result<()> { let mut kvm_msrs = KvmMsrs { nmsrs: msrs.len() as u32, _pad: 0, entries: [KvmMsrEntry::default(); MAX_IO_MSRS], }; for (i, (index, data)) in msrs.iter().enumerate() { - kvm_msrs.entries[i].index = *index; + kvm_msrs.entries[i].index = index.raw(); kvm_msrs.entries[i].data = *data; } unsafe { kvm_set_msrs(&self.fd, &kvm_msrs) }.context(error::GuestMsr)?; diff --git a/alioth/src/hv/kvm/vcpu/vcpu_x86_64/vcpu_x86_64_test.rs b/alioth/src/hv/kvm/vcpu/vcpu_x86_64/vcpu_x86_64_test.rs index 8407debf..ec773c70 100644 --- a/alioth/src/hv/kvm/vcpu/vcpu_x86_64/vcpu_x86_64_test.rs +++ b/alioth/src/hv/kvm/vcpu/vcpu_x86_64/vcpu_x86_64_test.rs @@ -18,7 +18,7 @@ use std::ptr::null_mut; use assert_matches::assert_matches; use libc::{MAP_ANONYMOUS, MAP_FAILED, MAP_SHARED, PROT_EXEC, PROT_READ, PROT_WRITE, mmap}; -use crate::arch::msr::Efer; +use crate::arch::msr::{Efer, Msr}; use crate::arch::paging::Entry; use crate::arch::reg::{Cr0, Cr4, Reg, SegAccess}; use crate::ffi; @@ -68,8 +68,6 @@ fn test_vcpu_regs() { (SReg::Cr3, 0x1362d001), (SReg::Cr4, 1 << 5), (SReg::Cr8, 0x0), - (SReg::Efer, (1 << 8) | (1 << 10)), - (SReg::ApicBase, 0xfee00900), ]; let seg_regs = [ ( @@ -280,10 +278,9 @@ fn test_kvm_run() { let idtr = DtRegVal { base: 0, limit: 0 }; vcpu.set_sregs( &[ - (SReg::Efer, (Efer::LMA | Efer::LME).bits() as u64), - (SReg::Cr0, (Cr0::NE | Cr0::PE | Cr0::PG).bits() as u64), + (SReg::Cr0, (Cr0::NE | Cr0::PE | Cr0::PG).bits()), (SReg::Cr3, 0x2000), - (SReg::Cr4, Cr4::PAE.bits() as u64), + (SReg::Cr4, Cr4::PAE.bits()), ], &[ (SegReg::Cs, cs), @@ -298,6 +295,8 @@ fn test_kvm_run() { &[(DtReg::Gdtr, gdtr), (DtReg::Idtr, idtr)], ) .unwrap(); + vcpu.set_msrs(&[(Msr::EFER, (Efer::LMA | Efer::LME).bits())]) + .unwrap(); vcpu.set_regs(&[ (Reg::Rip, 0x1000), (Reg::Rax, 0x2), diff --git a/alioth/src/loader/firmware/firmware_x86_64.rs b/alioth/src/loader/firmware/firmware_x86_64.rs index e4523b14..2f34eeaf 100644 --- a/alioth/src/loader/firmware/firmware_x86_64.rs +++ b/alioth/src/loader/firmware/firmware_x86_64.rs @@ -20,6 +20,7 @@ use std::sync::Arc; use snafu::ResultExt; use crate::arch::layout::MEM_64_START; +use crate::arch::msr::Msr; use crate::arch::reg::{Cr0, DtReg, DtRegVal, Reg, Rflags, SReg, SegAccess, SegReg, SegRegVal}; use crate::loader::{InitState, Result, error}; use crate::mem::mapped::ArcMemPages; @@ -98,13 +99,13 @@ pub fn load>(memory: &Memory, path: P) -> Result<(InitState, ArcM (Reg::Rflags, Rflags::RESERVED_1.bits() as u64), ], sregs: vec![ - (SReg::Cr0, (Cr0::ET | Cr0::NW | Cr0::CD).bits() as u64), + (SReg::Cr0, (Cr0::ET | Cr0::NW | Cr0::CD).bits()), (SReg::Cr2, 0), (SReg::Cr3, 0), (SReg::Cr4, 0), (SReg::Cr8, 0), - (SReg::Efer, 0), ], + msrs: vec![(Msr::EFER, 0)], seg_regs: vec![ (SegReg::Cs, boot_cs), (SegReg::Ds, boot_ds), diff --git a/alioth/src/loader/linux/linux_x86_64.rs b/alioth/src/loader/linux/linux_x86_64.rs index ae028713..982ef7df 100644 --- a/alioth/src/loader/linux/linux_x86_64.rs +++ b/alioth/src/loader/linux/linux_x86_64.rs @@ -25,7 +25,7 @@ use crate::arch::layout::{ APIC_START, BOOT_GDT_START, BOOT_PAGING_START, EBDA_START, KERNEL_CMDLINE_LIMIT, KERNEL_CMDLINE_START, KERNEL_IMAGE_START, LINUX_BOOT_PARAMS_START, }; -use crate::arch::msr::{ApicBase, Efer}; +use crate::arch::msr::{ApicBase, Efer, Msr}; use crate::arch::paging::Entry; use crate::arch::reg::{ Cr0, Cr4, DtReg, DtRegVal, Reg, Rflags, SReg, SegAccess, SegReg, SegRegVal, @@ -251,11 +251,9 @@ pub fn load>( (Reg::Rflags, Rflags::RESERVED_1.bits() as u64), ], sregs: vec![ - (SReg::Efer, (Efer::LMA | Efer::LME).bits() as u64), - (SReg::Cr0, (Cr0::NE | Cr0::PE | Cr0::PG).bits() as u64), + (SReg::Cr0, (Cr0::NE | Cr0::PE | Cr0::PG).bits()), (SReg::Cr3, pml4_start), - (SReg::Cr4, Cr4::PAE.bits() as u64), - (SReg::ApicBase, apic_base.0), + (SReg::Cr4, Cr4::PAE.bits()), ], seg_regs: vec![ (SegReg::Cs, boot_cs), @@ -268,6 +266,10 @@ pub fn load>( (SegReg::Ldtr, boot_ldtr), ], dt_regs: vec![(DtReg::Gdtr, gdtr), (DtReg::Idtr, idtr)], + msrs: vec![ + (Msr::EFER, (Efer::LMA | Efer::LME).bits()), + (Msr::APIC_BASE, apic_base.0), + ], initramfs: initramfs_range, }) } diff --git a/alioth/src/loader/loader.rs b/alioth/src/loader/loader.rs index 3d87c3bc..bfdb753e 100644 --- a/alioth/src/loader/loader.rs +++ b/alioth/src/loader/loader.rs @@ -28,6 +28,8 @@ use std::path::Path; use serde::Deserialize; use snafu::Snafu; +#[cfg(target_arch = "x86_64")] +use crate::arch::msr::Msr; #[cfg(target_arch = "x86_64")] use crate::arch::reg::{DtReg, DtRegVal, SegReg, SegRegVal}; use crate::arch::reg::{Reg, SReg}; @@ -57,6 +59,8 @@ pub struct InitState { pub dt_regs: Vec<(DtReg, DtRegVal)>, #[cfg(target_arch = "x86_64")] pub seg_regs: Vec<(SegReg, SegRegVal)>, + #[cfg(target_arch = "x86_64")] + pub msrs: Vec<(Msr, u64)>, pub initramfs: Option>, } diff --git a/alioth/src/loader/xen/xen.rs b/alioth/src/loader/xen/xen.rs index e0ff14f5..00802b05 100644 --- a/alioth/src/loader/xen/xen.rs +++ b/alioth/src/loader/xen/xen.rs @@ -28,7 +28,7 @@ use crate::arch::layout::{ APIC_START, BOOT_GDT_START, EBDA_START, HVM_START_INFO_START, KERNEL_CMDLINE_LIMIT, KERNEL_CMDLINE_START, }; -use crate::arch::msr::ApicBase; +use crate::arch::msr::{ApicBase, Msr}; use crate::arch::reg::{Cr0, DtReg, DtRegVal, Reg, Rflags, SReg, SegAccess, SegReg, SegRegVal}; use crate::loader::elf::{ ELF_HEADER_MAGIC, ELF_IDENT_CLASS_64, ELF_IDENT_LITTLE_ENDIAN, Elf64Header, Elf64Note, @@ -317,12 +317,7 @@ pub fn load>( (Reg::Rflags, Rflags::RESERVED_1.bits() as u64), (Reg::Rip, entry_point), ], - sregs: vec![ - (SReg::Cr0, Cr0::PE.bits() as u64), - (SReg::Cr4, 0), - (SReg::Efer, 0), - (SReg::ApicBase, apic_base.0), - ], + sregs: vec![(SReg::Cr0, Cr0::PE.bits()), (SReg::Cr4, 0)], seg_regs: vec![ (SegReg::Cs, boot_cs), (SegReg::Ds, boot_ds), @@ -334,6 +329,7 @@ pub fn load>( (SegReg::Ldtr, boot_ldtr), ], dt_regs: vec![(DtReg::Gdtr, gdtr), (DtReg::Idtr, idtr)], + msrs: vec![(Msr::APIC_BASE, apic_base.0), (Msr::EFER, 0)], initramfs: initramfs_range, }) } diff --git a/alioth/src/sys/linux/kvm.rs b/alioth/src/sys/linux/kvm.rs index 74debad0..680efb1e 100644 --- a/alioth/src/sys/linux/kvm.rs +++ b/alioth/src/sys/linux/kvm.rs @@ -16,6 +16,8 @@ use std::fmt::{Debug, Formatter, Result}; use bitfield::bitfield; +use crate::arch::x86_64::msr::{ApicBase, Efer}; +use crate::arch::x86_64::reg::{Cr0, Cr3, Cr4}; use crate::sys::ioctl::{ioctl_ior, ioctl_iowr}; use crate::{ bitflags, consts, ioctl_none, ioctl_read, ioctl_write_buf, ioctl_write_ptr, ioctl_write_val, @@ -231,13 +233,13 @@ pub struct KvmSregs { pub ldt: KvmSegment, pub gdt: KvmDtable, pub idt: KvmDtable, - pub cr0: u64, + pub cr0: Cr0, pub cr2: u64, - pub cr3: u64, - pub cr4: u64, + pub cr3: Cr3, + pub cr4: Cr4, pub cr8: u64, - pub efer: u64, - pub apic_base: u64, + pub efer: Efer, + pub apic_base: ApicBase, pub interrupt_bitmap: [u64; 4], } @@ -254,13 +256,13 @@ pub struct KvmSregs2 { pub ldt: KvmSegment, pub gdt: KvmDtable, pub idt: KvmDtable, - pub cr0: u64, + pub cr0: Cr0, pub cr2: u64, - pub cr3: u64, - pub cr4: u64, + pub cr3: Cr3, + pub cr4: Cr4, pub cr8: u64, - pub efer: u64, - pub apic_base: u64, + pub efer: Efer, + pub apic_base: ApicBase, pub flags: u64, pub pdptrs: [u64; 4], }