From 3657db7843aa1d9c408ed7a0a5797da507d9f7b8 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Mon, 22 Dec 2025 21:06:52 +0000 Subject: [PATCH] vmm: mshv: Set PROCESSORS_PER_SOCKET property for CPU topologies On MSHV, exposing multithreaded CPU topologies requires setting the PROCESSORS_PER_SOCKET partition property so that CPUID.0xB reports correct logical processor counts and topology levels to the guest. This property must be set after all vCPUs are configured, as the hypervisor uses the complete vCPU layout to derive and report CPU topology information. Signed-off-by: Anatol Belski --- hypervisor/src/mshv/mod.rs | 11 +++++++++++ vmm/src/cpu.rs | 23 +++++++++++++++++++++++ vmm/src/vm.rs | 9 +++++++++ 3 files changed, 43 insertions(+) diff --git a/hypervisor/src/mshv/mod.rs b/hypervisor/src/mshv/mod.rs index 40d8796e9..8ef150294 100644 --- a/hypervisor/src/mshv/mod.rs +++ b/hypervisor/src/mshv/mod.rs @@ -69,6 +69,7 @@ pub use x86_64::{VcpuMshvState, emulator}; /// Export generically-named wrappers of mshv-bindings for Unix-based platforms /// pub use { + mshv_bindings::hv_partition_property_code_HV_PARTITION_PROPERTY_PROCESSORS_PER_SOCKET as HV_PARTITION_PROPERTY_PROCESSORS_PER_SOCKET, mshv_bindings::mshv_create_device as CreateDevice, mshv_bindings::mshv_device_attr as DeviceAttr, mshv_ioctls, mshv_ioctls::DeviceFd, }; @@ -1712,6 +1713,16 @@ impl MshvVm { .map_err(|e| vm::HypervisorVmError::CreateDevice(e.into()))?; Ok(VfioDeviceFd::new_from_mshv(device_fd)) } + + /// + /// Sets a partition property. + /// + /// This allows runtime configuration of partition properties. + pub fn set_partition_property(&self, code: u32, value: u64) -> anyhow::Result<()> { + self.fd + .set_partition_property(code, value) + .map_err(|e| anyhow!("Failed to set partition property: {e:?}")) + } } /// diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index ea030fb0c..bba78e642 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -216,6 +216,10 @@ pub enum Error { #[cfg(target_arch = "x86_64")] #[error("Failed to inject NMI")] NmiError(#[source] hypervisor::HypervisorCpuError), + + #[cfg(feature = "mshv")] + #[error("Failed to set partition property")] + SetPartitionProperty(#[source] anyhow::Error), } pub type Result = result::Result; @@ -1374,6 +1378,25 @@ impl CpuManager { self.activate_vcpus(self.boot_vcpus(), false, Some(paused)) } + #[cfg(feature = "mshv")] + pub fn set_processors_per_socket_property(&self) -> Result<()> { + if let Some(mshv_vm) = self.vm.as_any().downcast_ref::() { + let threads_per_core = if let Some(ref topology) = self.config.topology { + topology.threads_per_core as u64 + } else { + 1u64 + }; + + mshv_vm + .set_partition_property( + hypervisor::mshv::HV_PARTITION_PROPERTY_PROCESSORS_PER_SOCKET, + threads_per_core, + ) + .map_err(Error::SetPartitionProperty)?; + } + Ok(()) + } + pub fn start_restored_vcpus(&mut self) -> Result<()> { self.activate_vcpus(self.vcpus.len() as u32, false, Some(true)) .map_err(|e| { diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 536481885..441d0bcaf 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -2415,6 +2415,15 @@ impl Vm { .map_err(Error::CpuManager)?; } + #[cfg(feature = "mshv")] + { + self.cpu_manager + .lock() + .unwrap() + .set_processors_per_socket_property() + .ok(); + } + #[cfg(feature = "tdx")] let (sections, guid_found) = if tdx_enabled { self.extract_tdvf_sections()?