From b3baa152aaef1905876670590275c2dd0bbb088c Mon Sep 17 00:00:00 2001 From: "brillywu@viatech.com.cn" Date: Wed, 1 Jun 2011 09:59:52 +0800 Subject: [PATCH] kvm: Add CPUID support for VIA CPU When KVM is running on VIA CPU with host cpu's model, the feautures of VIA CPU will be passed into kvm guest by calling the CPUID instruction for Centaur. Signed-off-by: BrillyWu Signed-off-by: KaryJin Signed-off-by: Marcelo Tosatti --- target-i386/cpu.h | 9 +++++++- target-i386/cpuid.c | 53 +++++++++++++++++++++++++++++++++++++++++++-- target-i386/kvm.c | 15 +++++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/target-i386/cpu.h b/target-i386/cpu.h index fe658862c2..9c3340da3f 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -438,9 +438,13 @@ #define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */ #define CPUID_VENDOR_AMD_1 0x68747541 /* "Auth" */ -#define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */ +#define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */ #define CPUID_VENDOR_AMD_3 0x444d4163 /* "cAMD" */ +#define CPUID_VENDOR_VIA_1 0x746e6543 /* "Cent" */ +#define CPUID_VENDOR_VIA_2 0x48727561 /* "aurH" */ +#define CPUID_VENDOR_VIA_3 0x736c7561 /* "auls" */ + #define CPUID_MWAIT_IBE (1 << 1) /* Interrupts can exit capability */ #define CPUID_MWAIT_EMX (1 << 0) /* enumeration supported */ @@ -716,6 +720,9 @@ typedef struct CPUX86State { uint32_t cpuid_ext3_features; uint32_t cpuid_apic_id; int cpuid_vendor_override; + /* Store the results of Centaur's CPUID instructions */ + uint32_t cpuid_xlevel2; + uint32_t cpuid_ext4_features; /* MTRRs */ uint64_t mtrr_fixed[11]; diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index e479a4dbd7..40a73c7d11 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -230,6 +230,9 @@ typedef struct x86_def_t { char model_id[48]; int vendor_override; uint32_t flags; + /* Store the results of Centaur's CPUID instructions */ + uint32_t ext4_features; + uint32_t xlevel2; } x86_def_t; #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE) @@ -522,6 +525,18 @@ static int cpu_x86_fill_host(x86_def_t *x86_cpu_def) cpu_x86_fill_model_id(x86_cpu_def->model_id); x86_cpu_def->vendor_override = 0; + /* Call Centaur's CPUID instruction. */ + if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 && + x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 && + x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) { + host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx); + if (eax >= 0xC0000001) { + /* Support VIA max extended level */ + x86_cpu_def->xlevel2 = eax; + host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx); + x86_cpu_def->ext4_features = edx; + } + } /* * Every SVM feature requires emulation support in KVM - so we can't just @@ -855,6 +870,8 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model) env->cpuid_xlevel = def->xlevel; env->cpuid_kvm_features = def->kvm_features; env->cpuid_svm_features = def->svm_features; + env->cpuid_ext4_features = def->ext4_features; + env->cpuid_xlevel2 = def->xlevel2; if (!kvm_enabled()) { env->cpuid_features &= TCG_FEATURES; env->cpuid_ext_features &= TCG_EXT_FEATURES; @@ -1035,8 +1052,18 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, { /* test if maximum index reached */ if (index & 0x80000000) { - if (index > env->cpuid_xlevel) - index = env->cpuid_level; + if (index > env->cpuid_xlevel) { + if (env->cpuid_xlevel2 > 0) { + /* Handle the Centaur's CPUID instruction. */ + if (index > env->cpuid_xlevel2) { + index = env->cpuid_xlevel2; + } else if (index < 0xC0000000) { + index = env->cpuid_xlevel; + } + } else { + index = env->cpuid_xlevel; + } + } } else { if (index > env->cpuid_level) index = env->cpuid_level; @@ -1231,6 +1258,28 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *edx = 0; } break; + case 0xC0000000: + *eax = env->cpuid_xlevel2; + *ebx = 0; + *ecx = 0; + *edx = 0; + break; + case 0xC0000001: + /* Support for VIA CPU's CPUID instruction */ + *eax = env->cpuid_version; + *ebx = 0; + *ecx = 0; + *edx = env->cpuid_ext4_features; + break; + case 0xC0000002: + case 0xC0000003: + case 0xC0000004: + /* Reserved for the future, and now filled with zero */ + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + break; default: /* reserved values: zero */ *eax = 0; diff --git a/target-i386/kvm.c b/target-i386/kvm.c index faedc6c254..1ae2d61740 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -482,6 +482,21 @@ int kvm_arch_init_vcpu(CPUState *env) cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx); } + /* Call Centaur's CPUID instructions they are supported. */ + if (env->cpuid_xlevel2 > 0) { + env->cpuid_ext4_features &= + kvm_arch_get_supported_cpuid(env, 0xC0000001, 0, R_EDX); + cpu_x86_cpuid(env, 0xC0000000, 0, &limit, &unused, &unused, &unused); + + for (i = 0xC0000000; i <= limit; i++) { + c = &cpuid_data.entries[cpuid_i++]; + + c->function = i; + c->flags = 0; + cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx); + } + } + cpuid_data.cpuid.nent = cpuid_i; #ifdef KVM_CAP_MCE -- 2.39.2