Commit b827df585be820c228fa91f9d05a80db4e32a357

Authored by Avi Kivity
Committed by Anthony Liguori
1 parent ad7b8b33

kvm: Add support for querying supported cpu features

kvm does not support all cpu features; add support for dunamically querying
the supported feature set.

Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing 2 changed files with 83 additions and 0 deletions
... ... @@ -120,6 +120,9 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg);
120 120  
121 121 int kvm_check_extension(KVMState *s, unsigned int extension);
122 122  
  123 +uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
  124 + int reg);
  125 +
123 126 /* generic hooks - to be moved/refactored once there are more users */
124 127  
125 128 static inline void cpu_synchronize_state(CPUState *env, int modified)
... ...
target-i386/kvm.c
... ... @@ -34,6 +34,86 @@
34 34 do { } while (0)
35 35 #endif
36 36  
  37 +#ifdef KVM_CAP_EXT_CPUID
  38 +
  39 +static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max)
  40 +{
  41 + struct kvm_cpuid2 *cpuid;
  42 + int r, size;
  43 +
  44 + size = sizeof(*cpuid) + max * sizeof(*cpuid->entries);
  45 + cpuid = (struct kvm_cpuid2 *)qemu_mallocz(size);
  46 + cpuid->nent = max;
  47 + r = kvm_ioctl(s, KVM_GET_SUPPORTED_CPUID, cpuid);
  48 + if (r < 0) {
  49 + if (r == -E2BIG) {
  50 + qemu_free(cpuid);
  51 + return NULL;
  52 + } else {
  53 + fprintf(stderr, "KVM_GET_SUPPORTED_CPUID failed: %s\n",
  54 + strerror(-r));
  55 + exit(1);
  56 + }
  57 + }
  58 + return cpuid;
  59 +}
  60 +
  61 +uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, int reg)
  62 +{
  63 + struct kvm_cpuid2 *cpuid;
  64 + int i, max;
  65 + uint32_t ret = 0;
  66 + uint32_t cpuid_1_edx;
  67 +
  68 + if (!kvm_check_extension(env->kvm_state, KVM_CAP_EXT_CPUID)) {
  69 + return -1U;
  70 + }
  71 +
  72 + max = 1;
  73 + while ((cpuid = try_get_cpuid(env->kvm_state, max)) == NULL) {
  74 + max *= 2;
  75 + }
  76 +
  77 + for (i = 0; i < cpuid->nent; ++i) {
  78 + if (cpuid->entries[i].function == function) {
  79 + switch (reg) {
  80 + case R_EAX:
  81 + ret = cpuid->entries[i].eax;
  82 + break;
  83 + case R_EBX:
  84 + ret = cpuid->entries[i].ebx;
  85 + break;
  86 + case R_ECX:
  87 + ret = cpuid->entries[i].ecx;
  88 + break;
  89 + case R_EDX:
  90 + ret = cpuid->entries[i].edx;
  91 + if (function == 0x80000001) {
  92 + /* On Intel, kvm returns cpuid according to the Intel spec,
  93 + * so add missing bits according to the AMD spec:
  94 + */
  95 + cpuid_1_edx = kvm_arch_get_supported_cpuid(env, 1, R_EDX);
  96 + ret |= cpuid_1_edx & 0xdfeff7ff;
  97 + }
  98 + break;
  99 + }
  100 + }
  101 + }
  102 +
  103 + qemu_free(cpuid);
  104 +
  105 + return ret;
  106 +}
  107 +
  108 +#else
  109 +
  110 +uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, int reg)
  111 +{
  112 + return -1U;
  113 +}
  114 +
  115 +#endif
  116 +
37 117 int kvm_arch_init_vcpu(CPUState *env)
38 118 {
39 119 struct {
... ...