From 30063eff7e29860583aea02603ed593a0723a99d Mon Sep 17 00:00:00 2001 From: Oliver Anderson Date: Wed, 22 Jul 2026 18:41:13 +0200 Subject: [PATCH] hypervisor: Include feature MSRs in boot_msr_entries Whenever a CPU profile is selected there will be feature MSRs that need to be set when the CPU is configured. We thus adapt the boot_msr_entries method to include the feature MSRs that are passed to the vCPU upon construction. Since KVM applies compatibility checks for all feature MSRs (except IA32_ARCH_CAPABILITIES) we can only proceed if all MSR boot entries are successfully set upon vCPU configuration. This new check also applies to the regular boot entries when the host profile is selected (the default), but that is arguably an improvement in terms of correctness. Signed-off-by: Oliver Anderson On-behalf-of: SAP oliver.anderson@sap.com --- arch/src/x86_64/regs.rs | 28 +++++++++++++++++++++++++++- hypervisor/src/cpu.rs | 2 +- hypervisor/src/kvm/mod.rs | 10 +++++++--- hypervisor/src/mshv/mod.rs | 4 ++-- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/arch/src/x86_64/regs.rs b/arch/src/x86_64/regs.rs index e96aa9d43..48c283830 100644 --- a/arch/src/x86_64/regs.rs +++ b/arch/src/x86_64/regs.rs @@ -11,6 +11,8 @@ use std::result; use hypervisor::arch::x86::gdt::{gdt_entry, segment_from_gdt}; use hypervisor::arch::x86::regs::CR0_PE; use hypervisor::arch::x86::{FpuState, SpecialRegisters}; +#[cfg(all(feature = "kvm", not(feature = "sev_snp")))] +use log::error; use thiserror::Error; use vm_memory::{Address, Bytes, GuestMemoryBackend, GuestMemoryError}; @@ -33,6 +35,9 @@ pub enum Error { /// Setting up MSRs failed. #[error("Setting up MSRs failed")] SetModelSpecificRegisters(#[source] hypervisor::HypervisorCpuError), + /// Setting up MSRs failed because not all setup entries were set. + #[error("Some MSRs could not be set")] + SetModelSpecificRegistersAll, /// Failed to set SREGs for this CPU. #[error("Failed to set SREGs for this CPU")] SetStatusRegisters(#[source] hypervisor::HypervisorCpuError), @@ -81,10 +86,31 @@ pub fn setup_fpu(vcpu: &dyn hypervisor::Vcpu) -> Result<()> { /// # Arguments /// /// * `vcpu` - Structure for the VCPU that holds the VCPU's fd. +#[cfg_attr( + any(not(feature = "kvm"), feature = "sev_snp"), + allow(unused_variables) +)] pub fn setup_msrs(vcpu: &dyn hypervisor::Vcpu) -> Result<()> { - vcpu.set_msrs(vcpu.boot_msr_entries()) + let setup_entries = vcpu.boot_msr_entries(); + let num_msrs_set = vcpu + .set_msrs(&setup_entries) .map_err(Error::SetModelSpecificRegisters)?; + // Check that all setup entries were set. We can only do this for KVM + // (when SEV-SNP is not enabled) as MSHV always returns Ok(0) on success. + #[cfg(all(feature = "kvm", not(feature = "sev_snp")))] + if matches!(vcpu.hypervisor_type(), hypervisor::HypervisorType::Kvm) + && num_msrs_set != setup_entries.len() + { + for msr in &setup_entries[num_msrs_set..] { + error!( + "Could not set MSR with register address={:#x} and value={:#x}", + msr.index, msr.data + ); + } + + return Err(Error::SetModelSpecificRegistersAll); + } Ok(()) } diff --git a/hypervisor/src/cpu.rs b/hypervisor/src/cpu.rs index ce24e7b6f..8da9aefdd 100644 --- a/hypervisor/src/cpu.rs +++ b/hypervisor/src/cpu.rs @@ -614,7 +614,7 @@ pub trait Vcpu: Send + Sync { /// /// Return the list of initial MSR entries for a VCPU /// - fn boot_msr_entries(&self) -> &'static [MsrEntry]; + fn boot_msr_entries(&self) -> Vec; #[cfg(target_arch = "x86_64")] /// diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 4c84feb88..4fde4b278 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -3549,10 +3549,12 @@ impl cpu::Vcpu for KvmVcpu { /// /// Return the list of initial MSR entries for a VCPU /// - fn boot_msr_entries(&self) -> &'static [MsrEntry] { + fn boot_msr_entries(&self) -> Vec { use crate::arch::x86::{MTRR_ENABLE, MTRR_MEM_TYPE_WB, msr_index}; - &[ + let mut boot_entries = self.feature_msrs.clone(); + + boot_entries.extend([ msr!(msr_index::MSR_IA32_SYSENTER_CS), msr!(msr_index::MSR_IA32_SYSENTER_ESP), msr!(msr_index::MSR_IA32_SYSENTER_EIP), @@ -3567,7 +3569,9 @@ impl cpu::Vcpu for KvmVcpu { msr_index::MSR_IA32_MISC_ENABLE_FAST_STRING as u64 ), msr_data!(msr_index::MSR_MTRRdefType, MTRR_ENABLE | MTRR_MEM_TYPE_WB), - ] + ]); + + boot_entries } #[cfg(target_arch = "aarch64")] diff --git a/hypervisor/src/mshv/mod.rs b/hypervisor/src/mshv/mod.rs index a56a290d8..a5378e87d 100644 --- a/hypervisor/src/mshv/mod.rs +++ b/hypervisor/src/mshv/mod.rs @@ -1564,10 +1564,10 @@ impl cpu::Vcpu for MshvVcpu { /// /// Return the list of initial MSR entries for a VCPU /// - fn boot_msr_entries(&self) -> &'static [MsrEntry] { + fn boot_msr_entries(&self) -> Vec { use crate::arch::x86::{MTRR_ENABLE, MTRR_MEM_TYPE_WB, msr_index}; - &[ + vec![ msr!(msr_index::MSR_IA32_SYSENTER_CS), msr!(msr_index::MSR_IA32_SYSENTER_ESP), msr!(msr_index::MSR_IA32_SYSENTER_EIP),