diff --git a/alioth/src/arch/x86_64/msr.rs b/alioth/src/arch/x86_64/msr.rs index c21a6e38..3065ffce 100644 --- a/alioth/src/arch/x86_64/msr.rs +++ b/alioth/src/arch/x86_64/msr.rs @@ -18,6 +18,7 @@ use crate::{bitflags, consts}; // Intel Vol.4, Table 2-2. consts! { + #[derive(Default)] pub struct Msr(u32) { EFER = 0xc000_0080; STAR = 0xc000_0081; diff --git a/alioth/src/hv/hv.rs b/alioth/src/hv/hv.rs index dd9de1b7..c706d575 100644 --- a/alioth/src/hv/hv.rs +++ b/alioth/src/hv/hv.rs @@ -86,6 +86,9 @@ pub enum Error { #[cfg(target_arch = "x86_64")] #[snafu(display("Failed to configure guest MSRs"))] GuestMsr { error: std::io::Error }, + #[cfg(target_arch = "x86_64")] + #[snafu(display("Failed to configure guest XSAVE"))] + GuestXsave { error: std::io::Error }, #[snafu(display("Failed to configure memory encryption"))] MemEncrypt { error: std::io::Error }, #[snafu(display("Cannot create multiple VM memories"))] @@ -205,12 +208,21 @@ pub trait Vcpu { fn run(&mut self, entry: VmEntry) -> Result; + #[cfg(target_arch = "x86_64")] + fn get_cpuids(&self) -> Result>; #[cfg(target_arch = "x86_64")] fn set_cpuids(&mut self, cpuids: HashMap) -> Result<(), Error>; + #[cfg(target_arch = "x86_64")] + fn get_msrs(&self, msrs: &[Msr]) -> Result>; #[cfg(target_arch = "x86_64")] fn set_msrs(&mut self, msrs: &[(Msr, u64)]) -> Result<()>; + #[cfg(target_arch = "x86_64")] + fn get_xsave(&self) -> Result<[u32; 1024]>; + #[cfg(target_arch = "x86_64")] + fn set_xsave(&mut self, xsave: &[u32; 1024]) -> Result<()>; + fn dump(&self) -> Result<(), Error>; #[cfg(target_arch = "aarch64")] diff --git a/alioth/src/hv/kvm/vcpu/vcpu.rs b/alioth/src/hv/kvm/vcpu/vcpu.rs index 4c80509e..80bde64d 100644 --- a/alioth/src/hv/kvm/vcpu/vcpu.rs +++ b/alioth/src/hv/kvm/vcpu/vcpu.rs @@ -223,16 +223,36 @@ impl Vcpu for KvmVcpu { } } + #[cfg(target_arch = "x86_64")] + fn get_cpuids(&self) -> Result> { + self.kvm_get_cpuids() + } + #[cfg(target_arch = "x86_64")] fn set_cpuids(&mut self, cpuids: HashMap) -> Result<(), Error> { self.kvm_set_cpuids(&cpuids) } + #[cfg(target_arch = "x86_64")] + fn get_msrs(&self, msrs: &[Msr]) -> Result> { + self.kvm_get_msrs(msrs) + } + #[cfg(target_arch = "x86_64")] fn set_msrs(&mut self, msrs: &[(Msr, u64)]) -> Result<()> { self.kvm_set_msrs(msrs) } + #[cfg(target_arch = "x86_64")] + fn get_xsave(&self) -> Result<[u32; 1024]> { + self.kvm_get_xsave() + } + + #[cfg(target_arch = "x86_64")] + fn set_xsave(&mut self, xsave: &[u32; 1024]) -> Result<()> { + self.kvm_set_xsave(xsave) + } + fn dump(&self) -> Result<(), Error> { Ok(()) } 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 12100062..58aa80ea 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 @@ -20,6 +20,7 @@ use std::iter::zip; use std::os::fd::{FromRawFd, OwnedFd}; use snafu::ResultExt; +use zerocopy::{FromBytes, IntoBytes, transmute}; use crate::arch::cpuid::CpuidIn; use crate::arch::msr::{Efer, Msr}; @@ -30,8 +31,9 @@ use crate::hv::kvm::vm::KvmVm; use crate::hv::{Error, Result, error}; use crate::sys::kvm::{ KVM_MAX_CPUID_ENTRIES, KvmCpuid2, KvmCpuid2Flag, KvmCpuidEntry2, KvmMsrEntry, KvmMsrs, KvmRegs, - MAX_IO_MSRS, kvm_create_vcpu, kvm_get_regs, kvm_get_sregs, kvm_get_sregs2, kvm_kvmclock_ctrl, - kvm_set_cpuid2, kvm_set_msrs, kvm_set_regs, kvm_set_sregs, kvm_set_sregs2, + KvmXsave, MAX_IO_MSRS, kvm_create_vcpu, kvm_get_cpuid2, kvm_get_msrs, kvm_get_regs, + kvm_get_sregs, kvm_get_sregs2, kvm_get_xsave, kvm_kvmclock_ctrl, kvm_set_cpuid2, kvm_set_msrs, + kvm_set_regs, kvm_set_sregs, kvm_set_sregs2, kvm_set_xsave, }; #[derive(Debug)] @@ -312,6 +314,38 @@ impl KvmVcpu { Ok(val) } + pub fn kvm_get_cpuids(&self) -> Result> { + let mut kvm_cpuid2 = KvmCpuid2 { + nent: KVM_MAX_CPUID_ENTRIES as u32, + padding: 0, + entries: [KvmCpuidEntry2::default(); KVM_MAX_CPUID_ENTRIES], + }; + unsafe { kvm_get_cpuid2(&self.fd, &mut kvm_cpuid2) }.context(error::GuestCpuid)?; + let cpuids: HashMap = kvm_cpuid2 + .entries + .iter() + .take(kvm_cpuid2.nent as usize) + .map(|e| { + let in_ = CpuidIn { + func: e.function, + index: if e.flags.contains(KvmCpuid2Flag::SIGNIFCANT_INDEX) { + Some(e.index) + } else { + None + }, + }; + let out = CpuidResult { + eax: e.eax, + ebx: e.ebx, + ecx: e.ecx, + edx: e.edx, + }; + (in_, out) + }) + .collect(); + Ok(cpuids) + } + pub fn kvm_set_cpuids(&mut self, cpuids: &HashMap) -> Result<(), Error> { if cpuids.len() > KVM_MAX_CPUID_ENTRIES { return kvm_error::CpuidTableTooLong.fail()?; @@ -338,6 +372,22 @@ impl KvmVcpu { Ok(()) } + pub fn kvm_get_msrs(&self, msrs: &[Msr]) -> Result> { + let mut kvm_msrs = KvmMsrs { + nmsrs: msrs.len() as u32, + _pad: 0, + entries: [KvmMsrEntry::default(); MAX_IO_MSRS], + }; + for (i, index) in msrs.iter().enumerate() { + kvm_msrs.entries[i].index = *index; + } + unsafe { kvm_get_msrs(&self.fd, &mut kvm_msrs) }.context(error::GuestMsr)?; + Ok(kvm_msrs.entries[..msrs.len()] + .iter() + .map(|e| e.data) + .collect()) + } + pub fn kvm_set_msrs(&mut self, msrs: &[(Msr, u64)]) -> Result<()> { let mut kvm_msrs = KvmMsrs { nmsrs: msrs.len() as u32, @@ -345,12 +395,23 @@ impl KvmVcpu { entries: [KvmMsrEntry::default(); MAX_IO_MSRS], }; for (i, (index, data)) in msrs.iter().enumerate() { - kvm_msrs.entries[i].index = index.raw(); + kvm_msrs.entries[i].index = *index; kvm_msrs.entries[i].data = *data; } unsafe { kvm_set_msrs(&self.fd, &kvm_msrs) }.context(error::GuestMsr)?; Ok(()) } + + pub fn kvm_get_xsave(&self) -> Result<[u32; 1024]> { + let kvm_xsave = unsafe { kvm_get_xsave(&self.fd) }.context(error::GuestXsave)?; + Ok(transmute!(kvm_xsave.region)) + } + + pub fn kvm_set_xsave(&mut self, xsave: &[u32; 1024]) -> Result<()> { + let kvm_xsave = KvmXsave::ref_from_bytes(xsave.as_bytes()).unwrap(); + unsafe { kvm_set_xsave(&self.fd, kvm_xsave) }.context(error::GuestXsave)?; + Ok(()) + } } #[cfg(test)] diff --git a/alioth/src/sys/linux/kvm.rs b/alioth/src/sys/linux/kvm.rs index 680efb1e..700f4a3b 100644 --- a/alioth/src/sys/linux/kvm.rs +++ b/alioth/src/sys/linux/kvm.rs @@ -15,8 +15,9 @@ use std::fmt::{Debug, Formatter, Result}; use bitfield::bitfield; +use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout}; -use crate::arch::x86_64::msr::{ApicBase, Efer}; +use crate::arch::x86_64::msr::{ApicBase, Efer, Msr}; use crate::arch::x86_64::reg::{Cr0, Cr3, Cr4}; use crate::sys::ioctl::{ioctl_ior, ioctl_iowr}; use crate::{ @@ -99,7 +100,7 @@ bitflags! { #[repr(C)] #[derive(Debug, Copy, Clone, Default)] pub struct KvmMsrEntry { - pub index: u32, + pub index: Msr, pub _reserved: u32, pub data: u64, } @@ -567,6 +568,12 @@ pub struct KvmEnableCap { pub pad: [u8; 64], } +#[repr(C, align(16))] +#[derive(Debug, Clone, FromBytes, KnownLayout, Immutable, IntoBytes)] +pub struct KvmXsave { + pub region: [u32; 1024], +} + #[repr(C)] #[derive(Debug, Copy, Clone, Default)] pub struct KvmOneReg { @@ -691,13 +698,18 @@ ioctl_read!(kvm_get_regs, KVMIO, 0x81, KvmRegs); ioctl_write_ptr!(kvm_set_regs, KVMIO, 0x82, KvmRegs); ioctl_read!(kvm_get_sregs, KVMIO, 0x83, KvmSregs); ioctl_write_ptr!(kvm_set_sregs, KVMIO, 0x84, KvmSregs); +ioctl_writeread_buf!(kvm_get_msrs, KVMIO, 0x88, KvmMsrs); ioctl_write_buf!(kvm_set_msrs, KVMIO, 0x89, KvmMsrs); ioctl_write_buf!(kvm_set_cpuid2, KVMIO, 0x90, KvmCpuid2); +ioctl_writeread_buf!(kvm_get_cpuid2, KVMIO, 0x91, KvmCpuid2); ioctl_write_ptr!(kvm_enable_cap, KVMIO, 0xa3, KvmEnableCap); ioctl_write_ptr!(kvm_signal_msi, KVMIO, 0xa5, KvmMsi); +ioctl_read!(kvm_get_xsave, KVMIO, 0xa4, KvmXsave); +ioctl_write_ptr!(kvm_set_xsave, KVMIO, 0xa5, KvmXsave); + ioctl_write_ptr!(kvm_get_one_reg, KVMIO, 0xab, KvmOneReg); ioctl_write_ptr!(kvm_set_one_reg, KVMIO, 0xac, KvmOneReg);