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 <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2020-06-16 14:48:37 +01:00 committed by Sebastien Boeuf
parent e19079782d
commit a74c6fc14f
2 changed files with 75 additions and 3 deletions

View File

@ -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::*;

View File

@ -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<CpuId> {
fn patch_cpuid(kvm: &Kvm, topology: &Option<CpuTopology>) -> Result<CpuId> {
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)
}