提交 5232d00a 编写于 作者: R Radim Krčmář 提交者: Eduardo Habkost

target-i386: Implement CPUID[0xB] (Extended Topology Enumeration)

I looked at a dozen Intel CPU that have this CPUID and all of them
always had Core offset as 1 (a wasted bit when hyperthreading is
disabled) and Package offset at least 4 (wasted bits at <= 4 cores).

QEMU uses more compact IDs and it doesn't make much sense to change it
now.  I keep the SMT and Core sub-leaves even if there is just one
thread/core;  it makes the code simpler and there should be no harm.
Signed-off-by: NRadim Krčmář <rkrcmar@redhat.com>
Reviewed-by: NEduardo Habkost <ehabkost@redhat.com>
Signed-off-by: NEduardo Habkost <ehabkost@redhat.com>
上级 d86c1451
...@@ -357,7 +357,12 @@ int e820_get_num_entries(void); ...@@ -357,7 +357,12 @@ int e820_get_num_entries(void);
bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
#define PC_COMPAT_2_6 \ #define PC_COMPAT_2_6 \
HW_COMPAT_2_6 HW_COMPAT_2_6 \
{\
.driver = TYPE_X86_CPU,\
.property = "cpuid-0xb",\
.value = "off",\
},
#define PC_COMPAT_2_5 \ #define PC_COMPAT_2_5 \
PC_COMPAT_2_6 \ PC_COMPAT_2_6 \
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "hw/i386/topology.h"
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "hw/hw.h" #include "hw/hw.h"
...@@ -2492,6 +2493,36 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, ...@@ -2492,6 +2493,36 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*edx = 0; *edx = 0;
} }
break; break;
case 0xB:
/* Extended Topology Enumeration Leaf */
if (!cpu->enable_cpuid_0xb) {
*eax = *ebx = *ecx = *edx = 0;
break;
}
*ecx = count & 0xff;
*edx = cpu->apic_id;
switch (count) {
case 0:
*eax = apicid_core_offset(smp_cores, smp_threads);
*ebx = smp_threads;
*ecx |= CPUID_TOPOLOGY_LEVEL_SMT;
break;
case 1:
*eax = apicid_pkg_offset(smp_cores, smp_threads);
*ebx = smp_cores * smp_threads;
*ecx |= CPUID_TOPOLOGY_LEVEL_CORE;
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: { case 0xD: {
KVMState *s = cs->kvm_state; KVMState *s = cs->kvm_state;
uint64_t ena_mask; uint64_t ena_mask;
...@@ -3251,6 +3282,7 @@ static Property x86_cpu_properties[] = { ...@@ -3251,6 +3282,7 @@ static Property x86_cpu_properties[] = {
DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, 0), DEFINE_PROP_UINT32("xlevel", X86CPU, env.cpuid_xlevel, 0),
DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, 0), DEFINE_PROP_UINT32("xlevel2", X86CPU, env.cpuid_xlevel2, 0),
DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor_id), DEFINE_PROP_STRING("hv-vendor-id", X86CPU, hyperv_vendor_id),
DEFINE_PROP_BOOL("cpuid-0xb", X86CPU, enable_cpuid_0xb, true),
DEFINE_PROP_END_OF_LIST() DEFINE_PROP_END_OF_LIST()
}; };
......
...@@ -636,6 +636,11 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; ...@@ -636,6 +636,11 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
#define CPUID_MWAIT_IBE (1U << 1) /* Interrupts can exit capability */ #define CPUID_MWAIT_IBE (1U << 1) /* Interrupts can exit capability */
#define CPUID_MWAIT_EMX (1U << 0) /* enumeration supported */ #define CPUID_MWAIT_EMX (1U << 0) /* enumeration supported */
/* CPUID[0xB].ECX level types */
#define CPUID_TOPOLOGY_LEVEL_INVALID (0U << 8)
#define CPUID_TOPOLOGY_LEVEL_SMT (1U << 8)
#define CPUID_TOPOLOGY_LEVEL_CORE (2U << 8)
#ifndef HYPERV_SPINLOCK_NEVER_RETRY #ifndef HYPERV_SPINLOCK_NEVER_RETRY
#define HYPERV_SPINLOCK_NEVER_RETRY 0xFFFFFFFF #define HYPERV_SPINLOCK_NEVER_RETRY 0xFFFFFFFF
#endif #endif
...@@ -1173,6 +1178,9 @@ struct X86CPU { ...@@ -1173,6 +1178,9 @@ struct X86CPU {
*/ */
bool enable_pmu; bool enable_pmu;
/* Compatibility bits for old machine types: */
bool enable_cpuid_0xb;
/* in order to simplify APIC support, we leave this pointer to the /* in order to simplify APIC support, we leave this pointer to the
user */ user */
struct DeviceState *apic_state; struct DeviceState *apic_state;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册