Skip to content

Commit

Permalink
i386/kvm: handle Xen HVM cpuid leaves
Browse files Browse the repository at this point in the history
Introduce support for emulating CPUID for Xen HVM guests. It doesn't make
sense to advertise the KVM leaves to a Xen guest, so do Xen unconditionally
when the xen-version machine property is set.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
[dwmw2: Obtain xen_version from KVM property, make it automatic]
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
  • Loading branch information
jpemartins authored and dwmw2 committed Mar 1, 2023
1 parent 61491cf commit f66b8a8
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 6 deletions.
1 change: 1 addition & 0 deletions target/i386/cpu.c
Expand Up @@ -7200,6 +7200,7 @@ 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-vapic", X86CPU, xen_vapic, false),

/*
* From "Requirements for Implementing the Microsoft
Expand Down
2 changes: 2 additions & 0 deletions target/i386/cpu.h
Expand Up @@ -1975,6 +1975,8 @@ struct ArchCPU {
int32_t thread_id;

int32_t hv_max_vps;

bool xen_vapic;
};


Expand Down
77 changes: 75 additions & 2 deletions target/i386/kvm/kvm.c
Expand Up @@ -22,6 +22,7 @@

#include <linux/kvm.h>
#include "standard-headers/asm-x86/kvm_para.h"
#include "hw/xen/interface/arch-x86/cpuid.h"

#include "cpu.h"
#include "host-cpu.h"
Expand Down Expand Up @@ -1819,7 +1820,77 @@ int kvm_arch_init_vcpu(CPUState *cs)
has_msr_hv_hypercall = true;
}

if (cpu->expose_kvm) {
if (cs->kvm_state->xen_version) {
#ifdef CONFIG_XEN_EMU
struct kvm_cpuid_entry2 *xen_max_leaf;

memcpy(signature, "XenVMMXenVMM", 12);

xen_max_leaf = c = &cpuid_data.entries[cpuid_i++];
c->function = kvm_base + XEN_CPUID_SIGNATURE;
c->eax = kvm_base + XEN_CPUID_TIME;
c->ebx = signature[0];
c->ecx = signature[1];
c->edx = signature[2];

c = &cpuid_data.entries[cpuid_i++];
c->function = kvm_base + XEN_CPUID_VENDOR;
c->eax = cs->kvm_state->xen_version;
c->ebx = 0;
c->ecx = 0;
c->edx = 0;

c = &cpuid_data.entries[cpuid_i++];
c->function = kvm_base + XEN_CPUID_HVM_MSR;
/* Number of hypercall-transfer pages */
c->eax = 1;
/* Hypercall MSR base address */
if (hyperv_enabled(cpu)) {
c->ebx = XEN_HYPERCALL_MSR_HYPERV;
kvm_xen_init(cs->kvm_state, c->ebx);
} else {
c->ebx = XEN_HYPERCALL_MSR;
}
c->ecx = 0;
c->edx = 0;

c = &cpuid_data.entries[cpuid_i++];
c->function = kvm_base + 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 = kvm_base + XEN_CPUID_HVM;
xen_max_leaf->eax = kvm_base + XEN_CPUID_HVM;
if (cs->kvm_state->xen_version >= XEN_VERSION(4, 5)) {
c->function = kvm_base + 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 (cs->kvm_state->xen_version >= XEN_VERSION(4, 6)) {
c->eax |= XEN_HVM_CPUID_VCPU_ID_PRESENT;
c->ebx = cs->cpu_index;
}
}

kvm_base += 0x100;
#else /* CONFIG_XEN_EMU */
/* This should never happen as kvm_arch_init() would have died first. */
fprintf(stderr, "Cannot enable Xen CPUID without Xen support\n");
abort();
#endif
} else if (cpu->expose_kvm) {
memcpy(signature, "KVMKVMKVM\0\0\0", 12);
c = &cpuid_data.entries[cpuid_i++];
c->function = KVM_CPUID_SIGNATURE | kvm_base;
Expand Down Expand Up @@ -2539,7 +2610,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
error_report("kvm: Xen support only available in PC machine");
return -ENOTSUP;
}
ret = kvm_xen_init(s);
/* hyperv_enabled() doesn't work yet. */
uint32_t msr = XEN_HYPERCALL_MSR;
ret = kvm_xen_init(s, msr);
if (ret < 0) {
return ret;
}
Expand Down
4 changes: 2 additions & 2 deletions target/i386/kvm/xen-emu.c
Expand Up @@ -15,12 +15,12 @@
#include "kvm/kvm_i386.h"
#include "xen-emu.h"

int kvm_xen_init(KVMState *s)
int kvm_xen_init(KVMState *s, uint32_t hypercall_msr)
{
const int required_caps = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR |
KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL | KVM_XEN_HVM_CONFIG_SHARED_INFO;
struct kvm_xen_hvm_config cfg = {
.msr = XEN_HYPERCALL_MSR,
.msr = hypercall_msr,
.flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL,
};
int xen_caps, ret;
Expand Down
13 changes: 11 additions & 2 deletions target/i386/kvm/xen-emu.h
Expand Up @@ -12,8 +12,17 @@
#ifndef QEMU_I386_KVM_XEN_EMU_H
#define QEMU_I386_KVM_XEN_EMU_H

#define XEN_HYPERCALL_MSR 0x40000000
#define XEN_HYPERCALL_MSR 0x40000000
#define XEN_HYPERCALL_MSR_HYPERV 0x40000200

int kvm_xen_init(KVMState *s);
#define XEN_CPUID_SIGNATURE 0
#define XEN_CPUID_VENDOR 1
#define XEN_CPUID_HVM_MSR 2
#define XEN_CPUID_TIME 3
#define XEN_CPUID_HVM 4

#define XEN_VERSION(maj, min) ((maj) << 16 | (min))

int kvm_xen_init(KVMState *s, uint32_t hypercall_msr);

#endif /* QEMU_I386_KVM_XEN_EMU_H */

0 comments on commit f66b8a8

Please sign in to comment.