From: David Woodhouse Date: Sat, 3 Dec 2022 17:51:13 +0000 (-0800) Subject: i386/xen: Add xen-version machine property and init KVM Xen support X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=47b220bc3622f2d4ba1f71517753db7bfb91729c;p=users%2Fdwmw2%2Fqemu.git i386/xen: Add xen-version machine property and init KVM Xen support This is a machine property for two main reasons. One is that it allows us to set it in default_machine_opts for the xenfv platform when not running on actual Xen. The other is that theoretically we *could* do this with TCG too; we'd just have to implement a bunch of the stuff that KVM already does for us. Signed-off-by: David Woodhouse --- diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 546b703cb4..9bada1a8ff 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1811,6 +1811,32 @@ static void pc_machine_set_max_fw_size(Object *obj, Visitor *v, pcms->max_fw_size = value; } +static void pc_machine_get_xen_version(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + uint32_t value = pcms->xen_version; + + visit_type_uint32(v, name, &value, errp); +} + +static void pc_machine_set_xen_version(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + PCMachineState *pcms = PC_MACHINE(obj); + Error *error = NULL; + uint32_t value; + + visit_type_uint32(v, name, &value, &error); + if (error) { + error_propagate(errp, error); + return; + } + + pcms->xen_version = value; +} static void pc_machine_initfn(Object *obj) { @@ -1978,6 +2004,12 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) NULL, NULL); object_class_property_set_description(oc, PC_MACHINE_SMBIOS_EP, "SMBIOS Entry Point type [32, 64]"); + + object_class_property_add(oc, "xen-version", "uint32", + pc_machine_get_xen_version, pc_machine_set_xen_version, + NULL, NULL); + object_class_property_set_description(oc, "xen-version", + "Xen version to be emulated (in XENVER_version form e.g. 0x4000a for 4.10)"); } static const TypeInfo pc_machine_info = { diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 0ad0ed1603..13286d0739 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -876,7 +876,10 @@ static void xenfv_4_2_machine_options(MachineClass *m) pc_i440fx_4_2_machine_options(m); m->desc = "Xen Fully-virtualized PC"; m->max_cpus = HVM_MAX_VCPUS; - m->default_machine_opts = "accel=xen,suppress-vmdesc=on"; + if (xen_enabled()) + m->default_machine_opts = "accel=xen,suppress-vmdesc=on"; + else + m->default_machine_opts = "accel=kvm,xen-version=0x40002"; } DEFINE_PC_MACHINE(xenfv_4_2, "xenfv-4.2", pc_xen_hvm_init, @@ -888,7 +891,10 @@ static void xenfv_3_1_machine_options(MachineClass *m) m->desc = "Xen Fully-virtualized PC"; m->alias = "xenfv"; m->max_cpus = HVM_MAX_VCPUS; - m->default_machine_opts = "accel=xen,suppress-vmdesc=on"; + if (xen_enabled()) + m->default_machine_opts = "accel=xen,suppress-vmdesc=on"; + else + m->default_machine_opts = "accel=kvm,xen-version=0x30001"; } DEFINE_PC_MACHINE(xenfv, "xenfv-3.1", pc_xen_hvm_init, diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index c95333514e..9b14b18836 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -52,6 +52,9 @@ typedef struct PCMachineState { bool default_bus_bypass_iommu; uint64_t max_fw_size; + /* Xen HVM emulation */ + uint32_t xen_version; + /* ACPI Memory hotplug IO base address */ hwaddr memhp_io_base; diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index a213209379..0a2069b117 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -31,6 +31,7 @@ #include "sysemu/runstate.h" #include "kvm_i386.h" #include "sev.h" +#include "xen.h" #include "hyperv.h" #include "hyperv-proto.h" @@ -774,6 +775,17 @@ static inline bool freq_within_bounds(int freq, int target_freq) return false; } +static uint32_t kvm_arch_xen_version(MachineState *ms) +{ + uint32_t v = object_property_get_int(OBJECT(ms), "xen-version", NULL); + + /* If it was unset, return zero */ + if (v == (uint32_t) -1) + return 0; + + return v; +} + static int kvm_arch_set_tsc_khz(CPUState *cs) { X86CPU *cpu = X86_CPU(cs); @@ -2459,6 +2471,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) { uint64_t identity_base = 0xfffbc000; uint64_t shadow_mem; + uint32_t xen_version; int ret; struct utsname utsname; Error *local_err = NULL; @@ -2513,6 +2526,19 @@ int kvm_arch_init(MachineState *ms, KVMState *s) } } + xen_version = kvm_arch_xen_version(ms); + if (xen_version) { +#ifdef CONFIG_XEN_EMU + ret = kvm_xen_init(s, xen_version); + if (ret < 0) { + return ret; + } +#else + error_report("kvm: Xen support not enabled in qemu"); + return -ENOTSUP; +#endif + } + ret = kvm_get_supported_msrs(s); if (ret < 0) { return ret; diff --git a/target/i386/meson.build b/target/i386/meson.build index ae38dc9563..9f3ef246b8 100644 --- a/target/i386/meson.build +++ b/target/i386/meson.build @@ -7,6 +7,7 @@ i386_ss.add(files( 'cpu-dump.c', )) i386_ss.add(when: 'CONFIG_SEV', if_true: files('host-cpu.c')) +i386_ss.add(when: 'CONFIG_XEN_EMU', if_true: files('xen.c')) # x86 cpu type i386_ss.add(when: 'CONFIG_KVM', if_true: files('host-cpu.c')) diff --git a/target/i386/xen.c b/target/i386/xen.c new file mode 100644 index 0000000000..bc183dce4e --- /dev/null +++ b/target/i386/xen.c @@ -0,0 +1,49 @@ +/* + * Xen HVM emulation support in KVM + * + * Copyright © 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright © 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "kvm/kvm_i386.h" +#include "xen.h" + +int kvm_xen_init(KVMState *s, uint32_t xen_version) +{ + 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, + .flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL, + }; + int xen_caps, ret; + + xen_caps = kvm_check_extension(s, KVM_CAP_XEN_HVM); + if (required_caps & ~xen_caps) { + error_report("kvm: Xen HVM guest support not present or insufficient"); + return -ENOSYS; + } + + if (xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_SEND) { + struct kvm_xen_hvm_attr ha = { + .type = KVM_XEN_ATTR_TYPE_XEN_VERSION, + .u.xen_version = xen_version, + }; + (void)kvm_vm_ioctl(s, KVM_XEN_HVM_SET_ATTR, &ha); + + cfg.flags |= KVM_XEN_HVM_CONFIG_EVTCHN_SEND; + } + + ret = kvm_vm_ioctl(s, KVM_XEN_HVM_CONFIG, &cfg); + if (ret < 0) { + error_report("kvm: Failed to enable Xen HVM support: %s", strerror(-ret)); + return ret; + } + + return 0; +} diff --git a/target/i386/xen.h b/target/i386/xen.h new file mode 100644 index 0000000000..6c4f3b7822 --- /dev/null +++ b/target/i386/xen.h @@ -0,0 +1,19 @@ +/* + * Xen HVM emulation support in KVM + * + * Copyright © 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright © 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_I386_XEN_H +#define QEMU_I386_XEN_H + +#define XEN_HYPERCALL_MSR 0x40000000 + +int kvm_xen_init(KVMState *s, uint32_t xen_version); + +#endif /* QEMU_I386_XEN_H */