i386/kvm: handle Xen HVM cpuid leaves
authorJoao Martins <joao.m.martins@oracle.com>
Tue, 12 Jun 2018 20:10:42 +0000 (21:10 +0100)
committerJoao Martins <joao.m.martins@oracle.com>
Tue, 19 Feb 2019 14:00:57 +0000 (09:00 -0500)
Introduce support for emulating CPUID for Xen HVM guests via
xen, xen_vapic, xen_{major,minor}_version as changeable params.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
target/i386/cpu.c
target/i386/cpu.h
target/i386/kvm.c

index d3aa6a815b0968459aef90fe59f66c6597df21c7..b1911d49f3d5f5636b9d645cba6369d2bcb0ab59 100644 (file)
@@ -5808,6 +5808,10 @@ static Property x86_cpu_properties[] = {
      * own cache information (see x86_cpu_load_def()).
      */
     DEFINE_PROP_BOOL("legacy-cache", X86CPU, legacy_cache, true),
+    DEFINE_PROP_BOOL("xen", X86CPU, xen, false),
+    DEFINE_PROP_BOOL("xen-vapic", X86CPU, xen_vapic, false),
+    DEFINE_PROP_UINT32("xen-major-version", X86CPU, xen_major_version, 3),
+    DEFINE_PROP_UINT32("xen-minor-version", X86CPU, xen_minor_version, 2),
 
     /*
      * From "Requirements for Implementing the Microsoft
index 95112b9118875555df4001d75ef42ebf0b61542b..cef37a8a2b9c5096ec8107913e53667910342096 100644 (file)
@@ -1483,6 +1483,11 @@ struct X86CPU {
     int32_t thread_id;
 
     int32_t hv_max_vps;
+
+    bool xen;
+    bool xen_vapic;
+    uint32_t xen_major_version;
+    uint32_t xen_minor_version;
 };
 
 static inline X86CPU *x86_env_get_cpu(CPUX86State *env)
index beae1b99daba0a51f02ebca4eeece8df1fcea7ac..8bb5d2d2e9a23496bebd478e8508edcc5711c042 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/kvm.h>
 #include "standard-headers/asm-x86/kvm_para.h"
+#include "standard-headers/xen/arch-x86/cpuid.h"
 
 #include "qemu-common.h"
 #include "cpu.h"
@@ -650,6 +651,17 @@ static bool hyperv_enabled(X86CPU *cpu)
             cpu->hyperv_ipi);
 }
 
+#define XEN_CPUID_SIGNATURE        0x40000000
+#define XEN_CPUID_VENDOR           0x40000001
+#define XEN_CPUID_HVM_MSR          0x40000002
+#define XEN_CPUID_TIME             0x40000003
+#define XEN_CPUID_HVM              0x40000004
+
+static bool xen_enabled_on_kvm(X86CPU *cpu)
+{
+    return cpu->xen;
+}
+
 static int kvm_arch_set_tsc_khz(CPUState *cs)
 {
     X86CPU *cpu = X86_CPU(cs);
@@ -1024,6 +1036,68 @@ int kvm_arch_init_vcpu(CPUState *cs)
         }
     }
 
+    if (xen_enabled_on_kvm(cpu) && kvm_base == XEN_CPUID_SIGNATURE) {
+        struct kvm_cpuid_entry2 *xen_max_leaf;
+
+        memcpy(signature, "XenVMMXenVMM", 12);
+
+        xen_max_leaf = c = &cpuid_data.entries[cpuid_i++];
+        c->function = XEN_CPUID_SIGNATURE;
+        c->eax = XEN_CPUID_TIME;
+        c->ebx = signature[0];
+        c->ecx = signature[1];
+        c->edx = signature[2];
+
+        c = &cpuid_data.entries[cpuid_i++];
+        c->function = XEN_CPUID_VENDOR;
+        c->eax = cpu->xen_major_version << 16 | cpu->xen_minor_version;
+        c->ebx = 0;
+        c->ecx = 0;
+        c->edx = 0;
+
+        c = &cpuid_data.entries[cpuid_i++];
+        c->function = XEN_CPUID_HVM_MSR;
+        /* Number of hypercall-transfer pages */
+        c->eax = 0;
+        /* Hypercall MSR base address */
+        c->ebx = XEN_CPUID_SIGNATURE;
+        c->ecx = 0;
+        c->edx = 0;
+
+        c = &cpuid_data.entries[cpuid_i++];
+        c->function = XEN_CPUID_TIME;
+        c->eax = ((!!tsc_is_stable_and_known(env) << 1) |
+            (!!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_RDTSCP) << 2));
+        /* default=0 (emulate if necessary) */
+        c->ebx = 0;
+        /* guest tsc frequency */
+        c->ecx = env->user_tsc_khz;
+        /* guest tsc incarnation (migration count) */
+        c->edx = 0;
+
+        c = &cpuid_data.entries[cpuid_i++];
+        c->function = XEN_CPUID_HVM;
+        xen_max_leaf->eax = XEN_CPUID_HVM;
+        if (cpu->xen_major_version >= 4 && cpu->xen_minor_version >= 5) {
+            c->function = XEN_CPUID_HVM;
+
+            if (cpu->xen_vapic) {
+                c->eax |= XEN_HVM_CPUID_APIC_ACCESS_VIRT;
+                c->eax |= XEN_HVM_CPUID_X2APIC_VIRT;
+            }
+
+            c->eax |= XEN_HVM_CPUID_IOMMU_MAPPINGS;
+
+            if (cpu->xen_major_version >= 4 && cpu->xen_minor_version >= 6) {
+                c->eax |= XEN_HVM_CPUID_VCPU_ID_PRESENT;
+                c->ebx = cs->cpu_index;
+            }
+        }
+
+        kvm_base = KVM_CPUID_SIGNATURE_NEXT;
+    }
+
+
     if (cpu->expose_kvm) {
         memcpy(signature, "KVMKVMKVM\0\0\0", 12);
         c = &cpuid_data.entries[cpuid_i++];