diff options
author | Like Xu <like.xu@linux.intel.com> | 2019-06-20 13:45:23 +0800 |
---|---|---|
committer | Eduardo Habkost <ehabkost@redhat.com> | 2019-07-05 17:08:04 -0300 |
commit | a94e1428991f741e2c6636e7c8df7f8d1905d983 (patch) | |
tree | f09158d8e90fc8ee9c5dcf9aad90902fc57e6fa4 /target | |
parent | 1c809535e3083d4299899e9843a3f4e44b191a9c (diff) |
target/i386: Add CPUID.1F generation support for multi-dies PCMachine
The CPUID.1F as Intel V2 Extended Topology Enumeration Leaf would be
exposed if guests want to emulate multiple software-visible die within
each package. Per Intel's SDM, the 0x1f is a superset of 0xb, thus they
can be generated by almost same code as 0xb except die_offset setting.
If the number of dies per package is greater than 1, the cpuid_min_level
would be adjusted to 0x1f regardless of whether the host supports CPUID.1F.
Likewise, the CPUID.1F wouldn't be exposed if env->nr_dies < 2.
Suggested-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Like Xu <like.xu@linux.intel.com>
Message-Id: <20190620054525.37188-2-like.xu@linux.intel.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Diffstat (limited to 'target')
-rw-r--r-- | target/i386/cpu.c | 41 | ||||
-rw-r--r-- | target/i386/cpu.h | 1 | ||||
-rw-r--r-- | target/i386/kvm.c | 12 |
3 files changed, 54 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); diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 85319f4ae1..0a96c78669 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -736,6 +736,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_TOPOLOGY_LEVEL_INVALID (0U << 8) #define CPUID_TOPOLOGY_LEVEL_SMT (1U << 8) #define CPUID_TOPOLOGY_LEVEL_CORE (2U << 8) +#define CPUID_TOPOLOGY_LEVEL_DIE (5U << 8) /* MSR Feature Bits */ #define MSR_ARCH_CAP_RDCL_NO (1U << 0) diff --git a/target/i386/kvm.c b/target/i386/kvm.c index e4b4f5756a..473a17e9a5 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -1451,6 +1451,10 @@ int kvm_arch_init_vcpu(CPUState *cs) } break; } + case 0x1f: + if (env->nr_dies < 2) { + break; + } case 4: case 0xb: case 0xd: @@ -1458,6 +1462,11 @@ int kvm_arch_init_vcpu(CPUState *cs) if (i == 0xd && j == 64) { break; } + + if (i == 0x1f && j == 64) { + break; + } + c->function = i; c->flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX; c->index = j; @@ -1469,6 +1478,9 @@ int kvm_arch_init_vcpu(CPUState *cs) if (i == 0xb && !(c->ecx & 0xff00)) { break; } + if (i == 0x1f && !(c->ecx & 0xff00)) { + break; + } if (i == 0xd && c->eax == 0) { continue; } |