From 549f3d6c047af66809fc0e10c784e7659b6e36fd Mon Sep 17 00:00:00 2001 From: Oliver Anderson Date: Tue, 7 Oct 2025 05:34:22 +0200 Subject: [PATCH] misc: Make CPU profile part of various configs We integrate the CPU profile into the various configs that ultimately get set by the user. This quickly ends up involving multiple files, luckily Rust helps us find which ones via compilation errors. Signed-off-by: Oliver Anderson On-behalf-of: SAP oliver.anderson@sap.com --- arch/src/x86_64/mod.rs | 3 ++- cloud-hypervisor/src/main.rs | 1 + fuzz/fuzz_targets/http_api.rs | 1 + vmm/src/config.rs | 11 ++++++++++- vmm/src/cpu.rs | 1 + vmm/src/lib.rs | 22 ++++++++++++++++++---- vmm/src/vm.rs | 21 +++++++++++++++------ vmm/src/vm_config.rs | 5 +++++ 8 files changed, 53 insertions(+), 12 deletions(-) diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index 5d3941eab..5ca200702 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -37,7 +37,7 @@ use vm_memory::{ GuestMemoryRegion, }; -use crate::{GuestMemoryMmap, InitramfsConfig, RegionType}; +use crate::{CpuProfile, GuestMemoryMmap, InitramfsConfig, RegionType}; // While modern architectures support more than 255 CPUs via x2APIC, // legacy devices such as mptable support at most 254 CPUs. @@ -99,6 +99,7 @@ pub struct CpuidConfig { #[cfg(feature = "tdx")] pub tdx: bool, pub amx: bool, + pub profile: CpuProfile, } #[derive(Debug, Error)] diff --git a/cloud-hypervisor/src/main.rs b/cloud-hypervisor/src/main.rs index 8fb9a8318..750f7aba9 100644 --- a/cloud-hypervisor/src/main.rs +++ b/cloud-hypervisor/src/main.rs @@ -985,6 +985,7 @@ mod unit_tests { features: CpuFeatures::default(), nested: true, core_scheduling: CoreScheduling::Vm, + profile: Default::default(), }, memory: MemoryConfig { size: 536_870_912, diff --git a/fuzz/fuzz_targets/http_api.rs b/fuzz/fuzz_targets/http_api.rs index a4687f490..16957983e 100644 --- a/fuzz/fuzz_targets/http_api.rs +++ b/fuzz/fuzz_targets/http_api.rs @@ -136,6 +136,7 @@ impl RequestHandler for StubApiRequestHandler { max_phys_bits: 46, affinity: None, features: CpuFeatures::default(), + profile: Default::default(), nested: true, core_scheduling: CoreScheduling::default(), }, diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 40f043a51..c9ba9c064 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -11,6 +11,7 @@ use std::result; use std::str::FromStr; use std::sync::LazyLock; +use arch::CpuProfile; use block::ImageType; use clap::ArgMatches; use log::{debug, warn}; @@ -697,7 +698,8 @@ impl CpusConfig { .add("affinity") .add("features") .add("nested") - .add("core_scheduling"); + .add("core_scheduling") + .add("profile"); parser.parse(cpus).map_err(Error::ParseCpus)?; let boot_vcpus: u32 = parser @@ -729,6 +731,12 @@ impl CpusConfig { }) .collect() }); + + let profile = parser + .convert::("profile") + .map_err(Error::ParseCpus)? + .unwrap_or_default(); + let features_list = parser .convert::("features") .map_err(Error::ParseCpus)? @@ -771,6 +779,7 @@ impl CpusConfig { features, nested, core_scheduling, + profile, }) } } diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index 6a905d837..e7a6056e8 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -963,6 +963,7 @@ impl CpuManager { #[cfg(feature = "tdx")] tdx, amx: self.config.features.amx, + profile: self.config.profile, }, ) .map_err(Error::CommonCpuId)? diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 58abd061f..548eb23fe 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -1428,17 +1428,27 @@ impl Vmm { ))); } - let amx = vm_config.lock().unwrap().cpus.features.amx; - let phys_bits = - vm::physical_bits(hypervisor, vm_config.lock().unwrap().cpus.max_phys_bits); + let (amx, max_phys_bits, profile, kvm_hyperv) = { + let guard = vm_config.lock().unwrap(); + ( + guard.cpus.features.amx, + guard.cpus.max_phys_bits, + guard.cpus.profile, + guard.cpus.kvm_hyperv, + ) + }; + + let phys_bits = vm::physical_bits(hypervisor, max_phys_bits); + arch::generate_common_cpuid( hypervisor, &arch::CpuidConfig { phys_bits, - kvm_hyperv: vm_config.lock().unwrap().cpus.kvm_hyperv, + kvm_hyperv, #[cfg(feature = "tdx")] tdx: false, amx, + profile, }, ) .map_err(|e| { @@ -1584,6 +1594,7 @@ impl Vmm { #[cfg(feature = "tdx")] tdx: false, amx: vm_config.cpus.features.amx, + profile: vm_config.cpus.profile, }, ) .map_err(|e| { @@ -2653,6 +2664,8 @@ const DEVICE_MANAGER_SNAPSHOT_ID: &str = "device-manager"; mod unit_tests { use std::path::PathBuf; + use arch::CpuProfile; + use super::*; #[cfg(target_arch = "x86_64")] use crate::vm_config::DebugConsoleConfig; @@ -2690,6 +2703,7 @@ mod unit_tests { features: CpuFeatures::default(), nested: true, core_scheduling: CoreScheduling::default(), + profile: CpuProfile::default(), }, memory: MemoryConfig { size: 536_870_912, diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index cfcb71fa1..69d02e07b 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -3359,19 +3359,28 @@ impl Snapshottable for Vm { #[cfg(all(feature = "kvm", target_arch = "x86_64"))] let common_cpuid = { - let amx = self.config.lock().unwrap().cpus.features.amx; - let phys_bits = physical_bits( - self.hypervisor.as_ref(), - self.config.lock().unwrap().cpus.max_phys_bits, - ); + let (amx, max_phys_bits, kvm_hyperv, profile) = { + let guard = self.config.lock().unwrap(); + let VmConfig { cpus, .. } = &*guard; + ( + cpus.features.amx, + cpus.max_phys_bits, + cpus.kvm_hyperv, + cpus.profile, + ) + }; + + let phys_bits = physical_bits(self.hypervisor.as_ref(), max_phys_bits); + arch::generate_common_cpuid( self.hypervisor.as_ref(), &arch::CpuidConfig { phys_bits, - kvm_hyperv: self.config.lock().unwrap().cpus.kvm_hyperv, + kvm_hyperv, #[cfg(feature = "tdx")] tdx: false, amx, + profile, }, ) .map_err(|e| { diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs index b6f0eb17f..745ae0d69 100644 --- a/vmm/src/vm_config.rs +++ b/vmm/src/vm_config.rs @@ -9,6 +9,7 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{fs, result}; +use arch::CpuProfile; use block::ImageType; pub use block::fcntl::LockGranularityChoice; use log::{debug, warn}; @@ -84,6 +85,9 @@ pub struct CpusConfig { pub nested: bool, #[serde(default)] pub core_scheduling: CoreScheduling, + // Defaults to "Host" if no profile is given. + #[serde(default)] + pub profile: CpuProfile, } pub const DEFAULT_VCPUS: u32 = 1; @@ -100,6 +104,7 @@ impl Default for CpusConfig { features: CpuFeatures::default(), nested: true, core_scheduling: CoreScheduling::default(), + profile: CpuProfile::default(), } } }