aboutsummaryrefslogtreecommitdiff
path: root/target/i386/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/i386/cpu.c')
-rw-r--r--target/i386/cpu.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index b9d6f32945..296ef6c918 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -4416,6 +4416,42 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
assert(!(*eax & ~0x1f));
*ebx &= 0xffff; /* The count doesn't need to be reliable. */
break;
+ case 0x1F:
+ /* V2 Extended Topology Enumeration Leaf */
+ if (env->nr_dies < 2) {
+ *eax = *ebx = *ecx = *edx = 0;
+ break;
+ }
+
+ *ecx = count & 0xff;
+ *edx = cpu->apic_id;
+ switch (count) {
+ case 0:
+ *eax = apicid_core_offset(env->nr_dies, cs->nr_cores,
+ cs->nr_threads);
+ *ebx = cs->nr_threads;
+ *ecx |= CPUID_TOPOLOGY_LEVEL_SMT;
+ break;
+ case 1:
+ *eax = apicid_die_offset(env->nr_dies, cs->nr_cores,
+ cs->nr_threads);
+ *ebx = cs->nr_cores * cs->nr_threads;
+ *ecx |= CPUID_TOPOLOGY_LEVEL_CORE;
+ break;
+ case 2:
+ *eax = apicid_pkg_offset(env->nr_dies, cs->nr_cores,
+ cs->nr_threads);
+ *ebx = env->nr_dies * cs->nr_cores * cs->nr_threads;
+ *ecx |= CPUID_TOPOLOGY_LEVEL_DIE;
+ break;
+ default:
+ *eax = 0;
+ *ebx = 0;
+ *ecx |= CPUID_TOPOLOGY_LEVEL_INVALID;
+ }
+ assert(!(*eax & ~0x1f));
+ *ebx &= 0xffff; /* The count doesn't need to be reliable. */
+ break;
case 0xD: {
/* Processor Extended State */
*eax = 0;
@@ -5094,6 +5130,11 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
x86_cpu_adjust_level(cpu, &cpu->env.cpuid_min_level, 0x14);
}
+ /* CPU topology with multi-dies support requires CPUID[0x1F] */
+ if (env->nr_dies > 1) {
+ x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x1F);
+ }
+
/* SVM requires CPUID[0x8000000A] */
if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
x86_cpu_adjust_level(cpu, &env->cpuid_min_xlevel, 0x8000000A);