There are multiple places where CPUID family/model/stepping info
are retrieved from env->cpuid_version.
Besides, the calculation of family and model inside host_cpu_vendor_fms()
doesn't comply to what Intel and AMD define. For family, both Intel
and AMD define that Extended Family ID needs to be counted only when
(base) Family is 0xF. For model, Intel counts Extended Model when
(base) Family is 0x6 or 0xF, while AMD counts EXtended MOdel when
(base) Family is 0xF.
Introduce generic helper functions to get family, model and stepping
from the EAX value of CPUID leaf 1, with the correct calculation
formula.
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
Note, for the calculation of model, it uses the same algorithm as Linux
kernel that counts Extended model when (base) Family is >= 6. To me, this
has the assumption that AMD always has a (base) Family of 0xF and Intel
doens't have processor with (base) Family between (0x6, 0xF).
I'm not sure about the rule on Zhaoxin and Hygon so that not sure if the
contidition of base Family >= 6 works for them or not.
For Zhaoxin, there is "YongFeng" defined in QEMU, which has Family 7 and
model 11. The model 11 doesn't require the Extended model field. So
I'm not sure the rule on Zhaoxin.
For Hygon, there is "Dhyana" defined in QEMU, which has Family 24 and
model 0. The model 0 doens't requrie the Extended model field as well.
---
target/i386/cpu.c | 12 ++++--------
target/i386/cpu.h | 30 ++++++++++++++++++++++++++++++
target/i386/host-cpu.c | 6 +++---
target/i386/kvm/kvm.c | 2 +-
4 files changed, 38 insertions(+), 12 deletions(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 83858358f5ec..51fcc8ba9867 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6324,10 +6324,7 @@ static void x86_cpuid_version_get_family(Object *obj, Visitor *v,
CPUX86State *env = &cpu->env;
uint64_t value;
- value = (env->cpuid_version >> 8) & 0xf;
- if (value == 0xf) {
- value += (env->cpuid_version >> 20) & 0xff;
- }
+ value = x86_cpu_family(env->cpuid_version);
visit_type_uint64(v, name, &value, errp);
}
@@ -6365,8 +6362,7 @@ static void x86_cpuid_version_get_model(Object *obj, Visitor *v,
CPUX86State *env = &cpu->env;
uint64_t value;
- value = (env->cpuid_version >> 4) & 0xf;
- value |= ((env->cpuid_version >> 16) & 0xf) << 4;
+ value = x86_cpu_model(env->cpuid_version);
visit_type_uint64(v, name, &value, errp);
}
@@ -6400,7 +6396,7 @@ static void x86_cpuid_version_get_stepping(Object *obj, Visitor *v,
CPUX86State *env = &cpu->env;
uint64_t value;
- value = env->cpuid_version & 0xf;
+ value = x86_cpu_stepping(env->cpuid_version);
visit_type_uint64(v, name, &value, errp);
}
@@ -8154,7 +8150,7 @@ static void mce_init(X86CPU *cpu)
CPUX86State *cenv = &cpu->env;
unsigned int bank;
- if (((cenv->cpuid_version >> 8) & 0xf) >= 6
+ if (x86_cpu_family(cenv->cpuid_version) >= 6
&& (cenv->features[FEAT_1_EDX] & (CPUID_MCE | CPUID_MCA)) ==
(CPUID_MCE | CPUID_MCA)) {
cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF |
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index b83c521d9fbb..b589a00c80d7 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2671,6 +2671,36 @@ static inline int32_t x86_get_a20_mask(CPUX86State *env)
}
}
+static inline uint32_t x86_cpu_family(uint32_t eax)
+{
+ uint32_t family = (eax >> 8) & 0xf;
+
+ if (family == 0xf) {
+ family += (eax >> 20) & 0xff;
+ }
+
+ return family;
+}
+
+static inline uint32_t x86_cpu_model(uint32_t eax)
+{
+ uint32_t family, model;
+
+ family = x86_cpu_family(eax);
+ model = (eax >> 4) & 0xf;
+
+ if (family >= 0x6) {
+ model += ((eax >> 16) & 0xf) << 4;
+ }
+
+ return model;
+}
+
+static inline uint32_t x86_cpu_stepping(uint32_t eax)
+{
+ return eax & 0xf;
+}
+
static inline bool cpu_has_vmx(CPUX86State *env)
{
return env->features[FEAT_1_ECX] & CPUID_EXT_VMX;
diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c
index 16c236478e2b..383c42d4ae3d 100644
--- a/target/i386/host-cpu.c
+++ b/target/i386/host-cpu.c
@@ -117,13 +117,13 @@ void host_cpu_vendor_fms(char *vendor, int *family, int *model, int *stepping)
host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
if (family) {
- *family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
+ *family = x86_cpu_family(eax);
}
if (model) {
- *model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
+ *model = x86_cpu_model(eax);
}
if (stepping) {
- *stepping = eax & 0x0F;
+ *stepping = x86_cpu_stepping(eax);
}
}
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 234878c613f6..650d96210192 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -2259,7 +2259,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
cpuid_i = kvm_x86_build_cpuid(env, cpuid_data.entries, cpuid_i);
cpuid_data.cpuid.nent = cpuid_i;
- if (((env->cpuid_version >> 8)&0xF) >= 6
+ if (x86_cpu_family(env->cpuid_version) >= 6
&& (env->features[FEAT_1_EDX] & (CPUID_MCE | CPUID_MCA)) ==
(CPUID_MCE | CPUID_MCA)) {
uint64_t mcg_cap, unsupported_caps;
--
2.43.0
© 2016 - 2025 Red Hat, Inc.