From c68067d5c0654a155047eef1e2ee42ead328e7ef Mon Sep 17 00:00:00 2001 From: Joao Martins Date: Tue, 12 Jun 2018 21:10:42 +0100 Subject: [PATCH] i386/kvm: handle Xen HVM cpuid leaves 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 --- target/i386/cpu.c | 4 +++ target/i386/cpu.h | 5 ++++ target/i386/kvm.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index d3aa6a815b..b1911d49f3 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -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 diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 95112b9118..cef37a8a2b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -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) diff --git a/target/i386/kvm.c b/target/i386/kvm.c index beae1b99da..8bb5d2d2e9 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -19,6 +19,7 @@ #include #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++]; -- 2.50.1