From 8da6ff2ea82377ef275ffdaf193dac69fad874bc Mon Sep 17 00:00:00 2001 From: Changyuan Lyu Date: Tue, 21 Apr 2026 16:46:05 -0700 Subject: [PATCH 1/3] feat(hv): get x86 CPU MSRs Signed-off-by: Changyuan Lyu --- alioth/src/arch/x86_64/msr.rs | 1 + alioth/src/hv/hv.rs | 2 ++ alioth/src/hv/kvm/vcpu/vcpu.rs | 5 +++++ .../hv/kvm/vcpu/vcpu_x86_64/vcpu_x86_64.rs | 22 ++++++++++++++++--- alioth/src/sys/linux/kvm.rs | 5 +++-- 5 files changed, 30 insertions(+), 5 deletions(-) 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..7e502647 100644 --- a/alioth/src/hv/hv.rs +++ b/alioth/src/hv/hv.rs @@ -208,6 +208,8 @@ pub trait Vcpu { #[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<()>; diff --git a/alioth/src/hv/kvm/vcpu/vcpu.rs b/alioth/src/hv/kvm/vcpu/vcpu.rs index 4c80509e..0175c017 100644 --- a/alioth/src/hv/kvm/vcpu/vcpu.rs +++ b/alioth/src/hv/kvm/vcpu/vcpu.rs @@ -228,6 +228,11 @@ impl Vcpu for KvmVcpu { 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) 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..2320818a 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 @@ -30,8 +30,8 @@ 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, + MAX_IO_MSRS, kvm_create_vcpu, kvm_get_msrs, 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, }; #[derive(Debug)] @@ -338,6 +338,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,7 +361,7 @@ 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)?; diff --git a/alioth/src/sys/linux/kvm.rs b/alioth/src/sys/linux/kvm.rs index 680efb1e..dd357d2d 100644 --- a/alioth/src/sys/linux/kvm.rs +++ b/alioth/src/sys/linux/kvm.rs @@ -16,7 +16,7 @@ use std::fmt::{Debug, Formatter, Result}; use bitfield::bitfield; -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 +99,7 @@ bitflags! { #[repr(C)] #[derive(Debug, Copy, Clone, Default)] pub struct KvmMsrEntry { - pub index: u32, + pub index: Msr, pub _reserved: u32, pub data: u64, } @@ -691,6 +691,7 @@ 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); From fae013eef61d11ea8af1fc25eef08690ae2266bd Mon Sep 17 00:00:00 2001 From: Changyuan Lyu Date: Tue, 21 Apr 2026 16:52:14 -0700 Subject: [PATCH 2/3] feat(hv): get x86 CPUIDs Signed-off-by: Changyuan Lyu --- alioth/src/hv/hv.rs | 2 + alioth/src/hv/kvm/vcpu/vcpu.rs | 5 +++ .../hv/kvm/vcpu/vcpu_x86_64/vcpu_x86_64.rs | 37 ++++++++++++++++++- alioth/src/sys/linux/kvm.rs | 1 + 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/alioth/src/hv/hv.rs b/alioth/src/hv/hv.rs index 7e502647..25d4b783 100644 --- a/alioth/src/hv/hv.rs +++ b/alioth/src/hv/hv.rs @@ -205,6 +205,8 @@ 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>; diff --git a/alioth/src/hv/kvm/vcpu/vcpu.rs b/alioth/src/hv/kvm/vcpu/vcpu.rs index 0175c017..6eb62bbf 100644 --- a/alioth/src/hv/kvm/vcpu/vcpu.rs +++ b/alioth/src/hv/kvm/vcpu/vcpu.rs @@ -223,6 +223,11 @@ 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) 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 2320818a..005675b5 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 @@ -30,8 +30,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_msrs, 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, + MAX_IO_MSRS, kvm_create_vcpu, kvm_get_cpuid2, kvm_get_msrs, 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, }; #[derive(Debug)] @@ -312,6 +313,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()?; diff --git a/alioth/src/sys/linux/kvm.rs b/alioth/src/sys/linux/kvm.rs index dd357d2d..4f6c1942 100644 --- a/alioth/src/sys/linux/kvm.rs +++ b/alioth/src/sys/linux/kvm.rs @@ -695,6 +695,7 @@ 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); From d0c15618a24b914eec334c9838e431689ac01b00 Mon Sep 17 00:00:00 2001 From: Changyuan Lyu Date: Tue, 21 Apr 2026 17:20:31 -0700 Subject: [PATCH 3/3] feat(hv): get/set x86 XSAVE area Signed-off-by: Changyuan Lyu --- alioth/src/hv/hv.rs | 8 ++++++++ alioth/src/hv/kvm/vcpu/vcpu.rs | 10 ++++++++++ .../src/hv/kvm/vcpu/vcpu_x86_64/vcpu_x86_64.rs | 18 +++++++++++++++--- alioth/src/sys/linux/kvm.rs | 10 ++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/alioth/src/hv/hv.rs b/alioth/src/hv/hv.rs index 25d4b783..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"))] @@ -215,6 +218,11 @@ pub trait Vcpu { #[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 6eb62bbf..80bde64d 100644 --- a/alioth/src/hv/kvm/vcpu/vcpu.rs +++ b/alioth/src/hv/kvm/vcpu/vcpu.rs @@ -243,6 +243,16 @@ impl Vcpu for KvmVcpu { 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 005675b5..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,9 +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_cpuid2, kvm_get_msrs, 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)] @@ -400,6 +401,17 @@ impl KvmVcpu { 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 4f6c1942..700f4a3b 100644 --- a/alioth/src/sys/linux/kvm.rs +++ b/alioth/src/sys/linux/kvm.rs @@ -15,6 +15,7 @@ use std::fmt::{Debug, Formatter, Result}; use bitfield::bitfield; +use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout}; use crate::arch::x86_64::msr::{ApicBase, Efer, Msr}; use crate::arch::x86_64::reg::{Cr0, Cr3, Cr4}; @@ -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 { @@ -700,6 +707,9 @@ 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);