From 0a086e6cbec6b8f46bf4a845a026769628522e2a Mon Sep 17 00:00:00 2001 From: Xiong Zhang Date: Thu, 19 Nov 2020 11:02:22 +0800 Subject: [PATCH] x86_64/cpuid.rs: Add cpu topology when no_smt isn't set When no_smt isn't set, guest works with hyperthread enabled, but crosvm doesn't emulate processor topology cpuid at this case, so the output of guest /proc/cpuinfo and lscpu is inconsitent, and guest cpuid is wrong. This commit adds such support. If vcpu_num is >1 and is even, threads per core is 2 and cores_num is vcpu_num/2. If vcpu_num is >1 and is odd, threads per core is vcpu_num and cores_num is 1. BUG=None TEST=Check guest /proc/cpuinfo, lscpu, cpuid at different vcpu number Change-Id: I8d9aaeac3fc911ee91bf2eb0586e457aac27a185 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2548450 Tested-by: kokoro Commit-Queue: Dylan Reid Reviewed-by: Daniel Verkamp --- x86_64/src/cpuid.rs | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/x86_64/src/cpuid.rs b/x86_64/src/cpuid.rs index f8cd977507..d965a2f51c 100644 --- a/x86_64/src/cpuid.rs +++ b/x86_64/src/cpuid.rs @@ -42,6 +42,7 @@ const EDX_HTT_SHIFT: u32 = 28; // Hyper Threading Enabled. const ECX_TOPO_TYPE_SHIFT: u32 = 8; // Topology Level type. const ECX_TOPO_SMT_TYPE: u32 = 1; // SMT type. const ECX_TOPO_CORE_TYPE: u32 = 2; // CORE type. +const EAX_CPU_CORES_SHIFT: u32 = 26; // Index of cpu cores in the same physical package. fn filter_cpuid( vcpu_id: usize, @@ -90,6 +91,16 @@ fn filter_cpuid( entry.edx = result.edx; } entry.eax &= !0xFC000000; + if cpu_count > 1 { + let cpu_cores = if no_smt { + cpu_count as u32 + } else if cpu_count % 2 == 0 { + (cpu_count >> 1) as u32 + } else { + 1 + }; + entry.eax |= (cpu_cores - 1) << EAX_CPU_CORES_SHIFT; + } } 6 => { // Clear X86 EPB feature. No frequency selection in the hypervisor. @@ -100,22 +111,32 @@ fn filter_cpuid( // NOTE: these will need to be split if any of the fields that differ between // the two versions are to be set. entry.edx = vcpu_id as u32; // x2APIC ID - if no_smt { - // Make it so that all VCPUs appear as different, - // non-hyperthreaded cores on the same package. - if entry.index == 0 { + if entry.index == 0 { + if no_smt || (cpu_count == 1) { + // Make it so that all VCPUs appear as different, + // non-hyperthreaded cores on the same package. entry.eax = 0; // Shift to get id of next level entry.ebx = 1; // Number of logical cpus at this level - entry.ecx = (ECX_TOPO_SMT_TYPE << ECX_TOPO_TYPE_SHIFT) | entry.index; - } else if entry.index == 1 { - entry.eax = 4; - entry.ebx = (cpu_count as u32) & 0xffff; - entry.ecx = (ECX_TOPO_CORE_TYPE << ECX_TOPO_TYPE_SHIFT) | entry.index; + } else if cpu_count % 2 == 0 { + // Each core has 2 hyperthreads + entry.eax = 1; // Shift to get id of next level + entry.ebx = 2; // Number of logical cpus at this level } else { - entry.eax = 0; - entry.ebx = 0; - entry.ecx = 0; + // One core contain all the cpu_count hyperthreads + let cpu_bits: u32 = 32 - ((cpu_count - 1) as u32).leading_zeros(); + entry.eax = cpu_bits; // Shift to get id of next level + entry.ebx = cpu_count as u32; // Number of logical cpus at this level } + entry.ecx = (ECX_TOPO_SMT_TYPE << ECX_TOPO_TYPE_SHIFT) | entry.index; + } else if entry.index == 1 { + let cpu_bits: u32 = 32 - ((cpu_count - 1) as u32).leading_zeros(); + entry.eax = cpu_bits; + entry.ebx = (cpu_count as u32) & 0xffff; // Number of logical cpus at this level + entry.ecx = (ECX_TOPO_CORE_TYPE << ECX_TOPO_TYPE_SHIFT) | entry.index; + } else { + entry.eax = 0; + entry.ebx = 0; + entry.ecx = 0; } } _ => (),