From a74c6fc14f7ef12c925e8f6deba45dd8b47e3976 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 16 Jun 2020 14:48:37 +0100 Subject: [PATCH] vmm, arch: x86_64: Fill the CPUID leaves with the topology There are two CPUID leaves for handling CPU topology, 0xb and 0x1f. The difference between the two is that the 0x1f leaf (Extended Topology Leaf) supports exposing multiple die packages. Fixes: #1284 Signed-off-by: Rob Bradford --- arch/src/x86_64/mod.rs | 63 ++++++++++++++++++++++++++++++++++++++++++ vmm/src/cpu.rs | 15 ++++++++-- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/arch/src/x86_64/mod.rs b/arch/src/x86_64/mod.rs index a743b3000..1e1ad9346 100644 --- a/arch/src/x86_64/mod.rs +++ b/arch/src/x86_64/mod.rs @@ -629,6 +629,69 @@ pub fn check_required_kvm_extensions(kvm: &Kvm) -> super::Result<()> { Ok(()) } +pub fn update_cpuid_topology( + cpuid: &mut CpuId, + threads_per_core: u8, + cores_per_die: u8, + dies_per_package: u8, +) { + let thread_width = 8 - (threads_per_core - 1).leading_zeros(); + let core_width = (8 - (cores_per_die - 1).leading_zeros()) + thread_width; + let die_width = (8 - (dies_per_package - 1).leading_zeros()) + core_width; + + // CPU Topology leaf 0xb + CpuidPatch::set_cpuid_reg(cpuid, 0xb, Some(0), CpuidReg::EAX, thread_width); + CpuidPatch::set_cpuid_reg( + cpuid, + 0xb, + Some(0), + CpuidReg::EBX, + u32::from(threads_per_core), + ); + CpuidPatch::set_cpuid_reg(cpuid, 0xb, Some(0), CpuidReg::ECX, 1 << 8); + + CpuidPatch::set_cpuid_reg(cpuid, 0xb, Some(1), CpuidReg::EAX, die_width); + CpuidPatch::set_cpuid_reg( + cpuid, + 0xb, + Some(1), + CpuidReg::EBX, + u32::from(dies_per_package * cores_per_die * threads_per_core), + ); + CpuidPatch::set_cpuid_reg(cpuid, 0xb, Some(1), CpuidReg::ECX, 2 << 8); + + // CPU Topology leaf 0x1f + CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(0), CpuidReg::EAX, thread_width); + CpuidPatch::set_cpuid_reg( + cpuid, + 0x1f, + Some(0), + CpuidReg::EBX, + u32::from(threads_per_core), + ); + CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(0), CpuidReg::ECX, 1 << 8); + + CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(1), CpuidReg::EAX, core_width); + CpuidPatch::set_cpuid_reg( + cpuid, + 0x1f, + Some(1), + CpuidReg::EBX, + u32::from(cores_per_die * threads_per_core), + ); + CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(1), CpuidReg::ECX, 2 << 8); + + CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(2), CpuidReg::EAX, die_width); + CpuidPatch::set_cpuid_reg( + cpuid, + 0x1f, + Some(2), + CpuidReg::EBX, + u32::from(dies_per_package * cores_per_die * threads_per_core), + ); + CpuidPatch::set_cpuid_reg(cpuid, 0x1f, Some(2), CpuidReg::ECX, 5 << 8); +} + #[cfg(test)] mod tests { use super::*; diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index dd0cc065f..edbeef563 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -11,7 +11,7 @@ // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause // -use crate::config::CpusConfig; +use crate::config::{CpuTopology, CpusConfig}; use crate::device_manager::DeviceManager; use crate::CPU_MANAGER_SNAPSHOT_ID; #[cfg(feature = "acpi")] @@ -686,7 +686,7 @@ impl CpuManager { let device_manager = device_manager.lock().unwrap(); #[cfg(target_arch = "x86_64")] - let cpuid = CpuManager::patch_cpuid(kvm)?; + let cpuid = CpuManager::patch_cpuid(kvm, &config.topology)?; let cpu_manager = Arc::new(Mutex::new(CpuManager { config: config.clone(), #[cfg(target_arch = "x86_64")] @@ -725,7 +725,7 @@ impl CpuManager { } #[cfg(target_arch = "x86_64")] - fn patch_cpuid(kvm: &Kvm) -> Result { + fn patch_cpuid(kvm: &Kvm, topology: &Option) -> Result { let mut cpuid_patches = Vec::new(); // Patch tsc deadline timer bit @@ -757,6 +757,15 @@ impl CpuManager { CpuidPatch::patch_cpuid(&mut cpuid, cpuid_patches); + if let Some(t) = topology { + arch::x86_64::update_cpuid_topology( + &mut cpuid, + t.threads_per_core, + t.cores_per_die, + t.dies_per_package, + ); + } + Ok(cpuid) }