mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 18:20:34 +00:00
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 <noreply+kokoro@google.com> Commit-Queue: Dylan Reid <dgreid@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
b1394f719d
commit
0a086e6cbe
1 changed files with 33 additions and 12 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
|
Loading…
Reference in a new issue