From d56253196bfda3c472abfbdd71300b81715a3f5a Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Tue, 21 Apr 2026 18:58:15 +0000 Subject: [PATCH] vmm: Enforce threads_per_core to be at most two Microsoft Hypervisor's hyperclear technology supports at most two threads per core. Practically all x64 CPUs nowadays only support two threads per core. Enforce this in the common code. Assisted-by: OpenAI:ChatGPT-5.4 [Test cases written by an LLM ] Signed-off-by: Wei Liu --- cloud-hypervisor/tests/integration.rs | 1 + vmm/src/config.rs | 47 +++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/cloud-hypervisor/tests/integration.rs b/cloud-hypervisor/tests/integration.rs index f8915ec4a..d0a7b49c8 100644 --- a/cloud-hypervisor/tests/integration.rs +++ b/cloud-hypervisor/tests/integration.rs @@ -66,6 +66,7 @@ mod common_parallel { } #[test] + #[cfg_attr(target_arch = "x86_64", should_panic)] fn test_cpu_topology_421() { test_cpu_topology(4, 2, 1, false); } diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 7efda7c05..3faa7ff75 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -250,6 +250,9 @@ pub enum ValidationError { /// CPU topology count doesn't match max #[error("Product of CPU topology parts does not match maximum vCPU")] CpuTopologyCount, + /// CPU topology uses too many threads per core + #[error("CPU topology supports at most 2 threads per core")] + CpuTopologyThreadsPerCore, /// One part of the CPU topology was zero #[error("No part of the CPU topology can be zero")] CpuTopologyZeroPart, @@ -2982,6 +2985,11 @@ impl VmConfig { return Err(ValidationError::CpuTopologyZeroPart); } + #[cfg(target_arch = "x86_64")] + if t.threads_per_core > 2 { + return Err(ValidationError::CpuTopologyThreadsPerCore); + } + // The setting of dies doesn't apply on AArch64. // Only '1' value is accepted, so its impact on the vcpu topology // setting can be ignored. @@ -5043,6 +5051,45 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" Err(ValidationError::CpuTopologyCount) ); + let mut still_valid_config = valid_config.clone(); + still_valid_config.cpus.max_vcpus = 8; + still_valid_config.cpus.boot_vcpus = 8; + still_valid_config.cpus.topology = Some(CpuTopology { + threads_per_core: 1, + cores_per_die: 8, + dies_per_package: 1, + packages: 1, + }); + still_valid_config.validate().unwrap(); + + let mut still_valid_config = valid_config.clone(); + still_valid_config.cpus.max_vcpus = 8; + still_valid_config.cpus.boot_vcpus = 8; + still_valid_config.cpus.topology = Some(CpuTopology { + threads_per_core: 2, + cores_per_die: 4, + dies_per_package: 1, + packages: 1, + }); + still_valid_config.validate().unwrap(); + + #[cfg(target_arch = "x86_64")] + { + let mut invalid_config = valid_config.clone(); + invalid_config.cpus.max_vcpus = 6; + invalid_config.cpus.boot_vcpus = 6; + invalid_config.cpus.topology = Some(CpuTopology { + threads_per_core: 3, + cores_per_die: 2, + dies_per_package: 1, + packages: 1, + }); + assert_eq!( + invalid_config.validate(), + Err(ValidationError::CpuTopologyThreadsPerCore) + ); + } + let mut invalid_config = valid_config.clone(); invalid_config.disks = Some(vec![DiskConfig { vhost_socket: Some("/path/to/sock".to_owned()),