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 <oliver.anderson@cyberus-technology.de>
On-behalf-of: SAP oliver.anderson@sap.com
This commit is contained in:
Oliver Anderson
2026-07-22 18:41:13 +02:00
committed by Rob Bradford
parent d2d13beb28
commit 30063eff7e
4 changed files with 37 additions and 7 deletions

View File

@@ -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(())
}

View File

@@ -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<MsrEntry>;
#[cfg(target_arch = "x86_64")]
///

View File

@@ -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<MsrEntry> {
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")]

View File

@@ -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<MsrEntry> {
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),