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 <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski 2025-12-22 21:06:52 +00:00 committed by Bo Chen
parent dccdb223b7
commit 3657db7843
3 changed files with 43 additions and 0 deletions

View file

@ -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:?}"))
}
}
///

View file

@ -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<T> = result::Result<T, Error>;
@ -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::<hypervisor::mshv::MshvVm>() {
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| {

View file

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