[libvirt PATCH v7 00/18] qemu: Introduce hvf domain type for Hypervisor.framework

In order to hopefully address [libvirt#147] at long last, I've picked up Roman's patches from 2018 and attempted to forward-port them. More specifically, I've used the [roolebo/hvf-domain] branch as a starting point, since it seems to contain a few improvements over [v2] and was just easier to pick up. The code is mostly his own, so I've retained the existing authorship information, but I've dropped Reviewed-by tags for commits that have been modified in non-trivial ways. I've applied very minimal style tweaks along the way, but overall I've tried to modify the existing patches as little as possible. The new test cases, such as they are, pass, and no regressions to KVM support appear to have been introduced in the process. I don't currently have access to a machine running macOS, so I can't verify that it's actually possible to start a hardware-accelerated VM by myself, but a couple of users have confirmed that the new feature works. Changes from [v6]: * addressed review comments; * moved virQEMUCapsAccelStr() and friends closer to the existing virQEMUCapsGetAccel() since they are very similar in purpose; * squashed my "fixup!" commits into the original ones now that they have been reviewed. Changes from [v5]: * rebased on top of master, dealing with a couple of straightforward merge conflicts in the process; * moved NEWS entry to the 8.1.0 section. Changes from [v4]: * fixed an issue that prevented machine types from being probed correctly, effectively making the entire thing non functional; * only report HVF support as available when the guest architecture and the host architecture match. Changes from [v3]: * reintroduced the patch that was missing in the initial version of the forward-port; * converted the documentation to reStructuredText and trimmed it significantly; * reworked virQEMUCapsAccelStr() based on Dan's suggestions; * reworked macOS support in the test suite based on Dan's suggestions; * fixed a few minor issues found while doing the above. Changes from [v2]: * rebased on top of master; * added a couple of simple test cases. Useful links: * GitLab: [abologna/hvf] * CI: [pipeline] [libvirt#147] https://gitlab.com/libvirt/libvirt/-/issues/147 [roolebo/hvf-domain] https://github.com/roolebo/libvirt/tree/hvf-domain [abologna/hvf] https://gitlab.com/abologna/libvirt/-/commits/hvf [pipeline] https://gitlab.com/abologna/libvirt/-/pipelines/453678312 [v6] https://listman.redhat.com/archives/libvir-list/2022-January/msg00685.html [v5] https://listman.redhat.com/archives/libvir-list/2022-January/msg00411.html [v4] https://listman.redhat.com/archives/libvir-list/2022-January/msg00280.html [v3] https://listman.redhat.com/archives/libvir-list/2022-January/msg00131.html [v2] https://listman.redhat.com/archives/libvir-list/2018-November/msg00802.html Andrea Bolognani (5): qemu: Only probe KVM on Linux tests: Introduce testQemuHostOS tests: Add macOS support to testutilsqemu tests: Add macOS support to qemuxml2*test tests: Add HVF test cases Roman Bolshakov (13): qemu: Add KVM CPUs into cache only if KVM is present conf: Add hvf domain type qemu: Define hvf capability qemu: Query hvf capability on macOS qemu: Expose hvf domain type if hvf is supported qemu: Introduce virQEMUCapsAccelStr qemu: Introduce virQEMUCapsTypeIsAccelerated qemu: Introduce virQEMUCapsHaveAccel qemu: Correct CPU capabilities probing for hvf docs: Add hvf on QEMU driver page docs: Note hvf support for domain elements docs: Add support page for libvirt on macOS news: Mention hvf domain type NEWS.rst | 5 + docs/docs.html.in | 3 + docs/drvqemu.rst | 48 +++++- docs/formatdomain.rst | 22 +-- docs/index.html.in | 4 +- docs/macos.rst | 44 ++++++ docs/meson.build | 1 + docs/schemas/domaincommon.rng | 1 + src/conf/domain_conf.c | 1 + src/conf/domain_conf.h | 1 + src/qemu/qemu_capabilities.c | 146 ++++++++++++++++-- src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 4 + src/qemu/qemu_process.c | 10 +- .../hvf-aarch64-virt-headless.args | 48 ++++++ .../hvf-aarch64-virt-headless.xml | 45 ++++++ .../hvf-x86_64-q35-headless.args | 47 ++++++ .../hvf-x86_64-q35-headless.x86_64-latest.err | 1 + .../hvf-x86_64-q35-headless.xml | 44 ++++++ tests/qemuxml2argvtest.c | 43 +++++- .../hvf-aarch64-virt-headless.xml | 94 +++++++++++ .../hvf-x86_64-q35-headless.xml | 97 ++++++++++++ tests/qemuxml2xmltest.c | 43 +++++- tests/testutilsqemu.c | 146 ++++++++++++++---- tests/testutilsqemu.h | 10 ++ 25 files changed, 845 insertions(+), 64 deletions(-) create mode 100644 docs/macos.rst create mode 100644 tests/qemuxml2argvdata/hvf-aarch64-virt-headless.args create mode 100644 tests/qemuxml2argvdata/hvf-aarch64-virt-headless.xml create mode 100644 tests/qemuxml2argvdata/hvf-x86_64-q35-headless.args create mode 100644 tests/qemuxml2argvdata/hvf-x86_64-q35-headless.x86_64-latest.err create mode 100644 tests/qemuxml2argvdata/hvf-x86_64-q35-headless.xml create mode 100644 tests/qemuxml2xmloutdata/hvf-aarch64-virt-headless.xml create mode 100644 tests/qemuxml2xmloutdata/hvf-x86_64-q35-headless.xml -- 2.34.1

We already know it's not going to be available on other platforms. Suggested-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Ani Sinha <ani@anisinha.ca> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_process.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 336f0bab2e..82cf6bbfd8 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -9239,6 +9239,12 @@ qemuProcessQMPInit(qemuProcessQMP *proc) } +#if defined(__linux__) +# define hwaccel "kvm:tcg" +#else +# define hwaccel "tcg" +#endif + static int qemuProcessQMPLaunch(qemuProcessQMP *proc) { @@ -9249,7 +9255,7 @@ qemuProcessQMPLaunch(qemuProcessQMP *proc) if (proc->forceTCG) machine = "none,accel=tcg"; else - machine = "none,accel=kvm:tcg"; + machine = "none,accel=" hwaccel; VIR_DEBUG("Try to probe capabilities of '%s' via QMP, machine %s", proc->binary, machine); -- 2.34.1

From: Roman Bolshakov <r.bolshakov@yadro.com> virQEMUCapsFormatCache/virQEMUCapsLoadCache adds/reads KVM CPUs to/from capabilities cache regardless of QEMU_CAPS_KVM. That can cause undesired side-effects when KVM CPUs are present in the cache on a platform that doesn't support it, e.g. macOS or Linux without KVM support. Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 461a818776..40c68e200f 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4411,8 +4411,11 @@ virQEMUCapsLoadCache(virArch hostArch, return -1; } - if (virQEMUCapsLoadAccel(qemuCaps, ctxt, VIR_DOMAIN_VIRT_KVM) < 0 || - virQEMUCapsLoadAccel(qemuCaps, ctxt, VIR_DOMAIN_VIRT_QEMU) < 0) + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM) && + virQEMUCapsLoadAccel(qemuCaps, ctxt, VIR_DOMAIN_VIRT_KVM) < 0) { + return -1; + } + if (virQEMUCapsLoadAccel(qemuCaps, ctxt, VIR_DOMAIN_VIRT_QEMU) < 0) return -1; if (virQEMUCapsParseGIC(qemuCaps, ctxt) < 0) @@ -4421,7 +4424,8 @@ virQEMUCapsLoadCache(virArch hostArch, if (virQEMUCapsParseSEVInfo(qemuCaps, ctxt) < 0) return -1; - virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) + virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM); virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_QEMU); if (virXPathBoolean("boolean(./kvmSupportsNesting)", ctxt) > 0) @@ -4654,7 +4658,8 @@ virQEMUCapsFormatCache(virQEMUCaps *qemuCaps) virBufferAsprintf(&buf, "<arch>%s</arch>\n", virArchToString(qemuCaps->arch)); - virQEMUCapsFormatAccel(qemuCaps, &buf, VIR_DOMAIN_VIRT_KVM); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) + virQEMUCapsFormatAccel(qemuCaps, &buf, VIR_DOMAIN_VIRT_KVM); virQEMUCapsFormatAccel(qemuCaps, &buf, VIR_DOMAIN_VIRT_QEMU); for (i = 0; i < qemuCaps->ngicCapabilities; i++) { @@ -5508,7 +5513,8 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch, qemuCaps->libvirtCtime = virGetSelfLastChanged(); qemuCaps->libvirtVersion = LIBVIR_VERSION_NUMBER; - virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) + virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM); virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_QEMU); if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) { -- 2.34.1

From: Roman Bolshakov <r.bolshakov@yadro.com> QEMU supports Hypervisor.framework since 2.12 as hvf accel. Hypervisor.framework provides a lightweight interface to run a virtual cpu on macOS without the need to install third-party kernel extensions (KEXTs). It's supported since macOS 10.10 on machines with Intel VT-x feature set that includes Extended Page Tables (EPT) and Unrestricted Mode. Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- docs/formatdomain.rst | 3 ++- docs/schemas/domaincommon.rng | 1 + src/conf/domain_conf.c | 1 + src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 4 ++++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index acd9020830..477e775229 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -20,7 +20,8 @@ Element and attribute overview The root element required for all virtual machines is named ``domain``. It has two attributes, the ``type`` specifies the hypervisor used for running the -domain. The allowed values are driver specific, but include "xen", "kvm", "qemu" +domain. The allowed values are driver specific, but include "xen", "kvm", +"hvf" (:since:`since 8.0.0 and QEMU 2.12`), "qemu" and "lxc". The second attribute is ``id`` which is a unique integer identifier for the running guest machine. Inactive machines have no id value. diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 169b8d8dee..64a797de46 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -230,6 +230,7 @@ <value>phyp</value> <!-- NOT USED ANYMORE --> <value>vz</value> <value>bhyve</value> + <value>hvf</value> </choice> </attribute> </define> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index b39136119f..f5b15cff33 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -125,6 +125,7 @@ VIR_ENUM_IMPL(virDomainVirt, "parallels", "bhyve", "vz", + "hvf", ); VIR_ENUM_IMPL(virDomainOS, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 3e63d2513b..7770badf5b 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -139,6 +139,7 @@ typedef enum { VIR_DOMAIN_VIRT_PARALLELS, VIR_DOMAIN_VIRT_BHYVE, VIR_DOMAIN_VIRT_VZ, + VIR_DOMAIN_VIRT_HVF, VIR_DOMAIN_VIRT_LAST } virDomainVirtType; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 662d15e28e..ecc28f15b2 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7215,6 +7215,10 @@ qemuBuildAccelCommandLine(virCommand *cmd, } break; + case VIR_DOMAIN_VIRT_HVF: + virBufferAddLit(&buf, "hvf"); + break; + case VIR_DOMAIN_VIRT_KQEMU: case VIR_DOMAIN_VIRT_XEN: case VIR_DOMAIN_VIRT_LXC: -- 2.34.1

From: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 1 + src/qemu/qemu_capabilities.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 40c68e200f..994dc3dad2 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -657,6 +657,7 @@ VIR_ENUM_IMPL(virQEMUCaps, /* 420 */ "device.json+hotplug", /* QEMU_CAPS_DEVICE_JSON */ + "hvf", /* QEMU_CAPS_HVF */ ); diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 7d42e3a714..c6fb87a73a 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -636,6 +636,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 420 */ QEMU_CAPS_DEVICE_JSON, /* -device accepts JSON (and works with hot-unplug) */ + QEMU_CAPS_HVF, /* Whether Hypervisor.framework is available */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; -- 2.34.1

From: Roman Bolshakov <r.bolshakov@yadro.com> There's no QMP command for querying if hvf is supported, therefore we use sysctl interface that tells if Hypervisor.framework works/available on the host. Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 994dc3dad2..d01be3e892 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -56,6 +56,10 @@ #include <unistd.h> #include <stdarg.h> #include <sys/utsname.h> +#ifdef __APPLE__ +# include <sys/types.h> +# include <sys/sysctl.h> +#endif #define VIR_FROM_THIS VIR_FROM_QEMU @@ -3192,6 +3196,42 @@ virQEMUCapsProbeQMPKVMState(virQEMUCaps *qemuCaps, return 0; } +#ifdef __APPLE__ +static int +virQEMUCapsProbeHVF(virQEMUCaps *qemuCaps) +{ + int hv_support = 0; + size_t len = sizeof(hv_support); + virArch hostArch = virArchFromHost(); + + /* Guest and host arch need to match for hardware acceleration + * to be usable */ + if (qemuCaps->arch != hostArch) + return 0; + + /* We don't have a nice way to probe whether the QEMU binary + * contains HVF support, but we know that versions older than + * QEMU 2.12 didn't have the feature at all */ + if (qemuCaps->version < 2012000) + return 0; + + /* We need the OS to report Hypervisor.framework availability */ + if (sysctlbyname("kern.hv_support", &hv_support, &len, NULL, 0) < 0) + return 0; + + if (hv_support) + virQEMUCapsSet(qemuCaps, QEMU_CAPS_HVF); + + return 0; +} +#else +static int +virQEMUCapsProbeHVF(virQEMUCaps *qemuCaps G_GNUC_UNUSED) +{ + return 0; +} +#endif + struct virQEMUCapsCommandLineProps { const char *option; const char *param; @@ -5333,6 +5373,9 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps, if (virQEMUCapsProbeQMPKVMState(qemuCaps, mon) < 0) return -1; + if (virQEMUCapsProbeHVF(qemuCaps) < 0) + return -1; + type = virQEMUCapsGetVirtType(qemuCaps); accel = virQEMUCapsGetAccel(qemuCaps, type); -- 2.34.1

From: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index d01be3e892..dac9fa11fc 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -1085,6 +1085,10 @@ virQEMUCapsInitGuestFromBinary(virCaps *caps, virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM, NULL, NULL, 0, NULL); } + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF)) { + virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_HVF, + NULL, NULL, 0, NULL); + } if ((ARCH_IS_X86(guestarch) || guestarch == VIR_ARCH_AARCH64)) virCapabilitiesAddGuestFeatureWithToggle(guest, VIR_CAPS_GUEST_FEATURE_TYPE_ACPI, -- 2.34.1

From: Roman Bolshakov <r.bolshakov@yadro.com> This makes possible to add more accelerators by touching less code and reduces code duplication. Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> --- src/qemu/qemu_capabilities.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index dac9fa11fc..f27d2fd241 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -839,6 +839,16 @@ virQEMUCapsFindTarget(virArch hostarch, } +static const char * +virQEMUCapsAccelStr(virDomainVirtType type) +{ + if (type == VIR_DOMAIN_VIRT_KVM) + return "kvm"; + + return "tcg"; +} + + static virQEMUCapsAccel * virQEMUCapsGetAccel(virQEMUCaps *qemuCaps, virDomainVirtType type) @@ -4067,7 +4077,7 @@ virQEMUCapsLoadAccel(virQEMUCaps *qemuCaps, virDomainVirtType type) { virQEMUCapsAccel *caps = virQEMUCapsGetAccel(qemuCaps, type); - const char *typeStr = type == VIR_DOMAIN_VIRT_KVM ? "kvm" : "tcg"; + const char *typeStr = virQEMUCapsAccelStr(type); if (virQEMUCapsLoadHostCPUModelInfo(caps, ctxt, typeStr) < 0) return -1; @@ -4620,7 +4630,7 @@ virQEMUCapsFormatAccel(virQEMUCaps *qemuCaps, virDomainVirtType type) { virQEMUCapsAccel *caps = virQEMUCapsGetAccel(qemuCaps, type); - const char *typeStr = type == VIR_DOMAIN_VIRT_KVM ? "kvm" : "tcg"; + const char *typeStr = virQEMUCapsAccelStr(type); virQEMUCapsFormatHostCPUModelInfo(caps, buf, typeStr); virQEMUCapsFormatCPUModels(caps, buf, typeStr); -- 2.34.1

On Fri, Jan 21, 2022 at 06:54:47PM +0100, Andrea Bolognani wrote:
From: Roman Bolshakov <r.bolshakov@yadro.com>
This makes possible to add more accelerators by touching less code and reduces code duplication.
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> --- src/qemu/qemu_capabilities.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

From: Roman Bolshakov <r.bolshakov@yadro.com> It replaces hardcoded checks for KVM. It'll be cleaner to use the function once multiple accelerators are supported in the QEMU driver. Explicit KVM domain checks should be done only when a feature is available only for KVM. Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> --- src/qemu/qemu_capabilities.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index f27d2fd241..61b674b89f 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -839,6 +839,13 @@ virQEMUCapsFindTarget(virArch hostarch, } +static bool +virQEMUCapsTypeIsAccelerated(virDomainVirtType type) +{ + return type != VIR_DOMAIN_VIRT_QEMU; +} + + static const char * virQEMUCapsAccelStr(virDomainVirtType type) { @@ -2339,7 +2346,7 @@ virQEMUCapsIsCPUModeSupported(virQEMUCaps *qemuCaps, switch (mode) { case VIR_CPU_MODE_HOST_PASSTHROUGH: - return type == VIR_DOMAIN_VIRT_KVM && + return virQEMUCapsTypeIsAccelerated(type) && virQEMUCapsGuestIsNative(hostarch, qemuCaps->arch); case VIR_CPU_MODE_HOST_MODEL: @@ -3001,7 +3008,7 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCaps *qemuCaps, qemuMonitor *mon, virDomainVirtType virtType) { - const char *model = virtType == VIR_DOMAIN_VIRT_KVM ? "host" : "max"; + const char *model = virQEMUCapsTypeIsAccelerated(virtType) ? "host" : "max"; g_autoptr(qemuMonitorCPUModelInfo) modelInfo = NULL; g_autoptr(qemuMonitorCPUModelInfo) nonMigratable = NULL; g_autoptr(GHashTable) hash = NULL; @@ -3721,7 +3728,7 @@ virQEMUCapsInitHostCPUModel(virQEMUCaps *qemuCaps, virArchToString(qemuCaps->arch), virDomainVirtTypeToString(type)); goto error; - } else if (type == VIR_DOMAIN_VIRT_KVM && + } else if (virQEMUCapsTypeIsAccelerated(type) && virCPUGetHostIsSupported(qemuCaps->arch)) { if (!(fullCPU = virQEMUCapsProbeHostCPU(qemuCaps->arch, NULL))) goto error; @@ -5846,10 +5853,10 @@ virQEMUCapsCacheLookupDefault(virFileCache *cache, if (virttype == VIR_DOMAIN_VIRT_NONE) virttype = capsType; - if (virttype == VIR_DOMAIN_VIRT_KVM && capsType == VIR_DOMAIN_VIRT_QEMU) { + if (virQEMUCapsTypeIsAccelerated(virttype) && capsType == VIR_DOMAIN_VIRT_QEMU) { virReportError(VIR_ERR_INVALID_ARG, - _("KVM is not supported by '%s' on this host"), - binary); + _("the accel '%s' is not supported by '%s' on this host"), + virQEMUCapsAccelStr(virttype), binary); return NULL; } -- 2.34.1

On Fri, Jan 21, 2022 at 06:54:48PM +0100, Andrea Bolognani wrote:
From: Roman Bolshakov <r.bolshakov@yadro.com>
It replaces hardcoded checks for KVM. It'll be cleaner to use the function once multiple accelerators are supported in the QEMU driver.
Explicit KVM domain checks should be done only when a feature is available only for KVM.
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> --- src/qemu/qemu_capabilities.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

From: Roman Bolshakov <r.bolshakov@yadro.com> The function should be used to check if qemu capabilities include a hardware acceleration, i.e. accel is not TCG. Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 61b674b89f..bb5744cd6b 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -846,6 +846,13 @@ virQEMUCapsTypeIsAccelerated(virDomainVirtType type) } +static bool +virQEMUCapsHaveAccel(virQEMUCaps *qemuCaps) +{ + return virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM); +} + + static const char * virQEMUCapsAccelStr(virDomainVirtType type) { @@ -5019,7 +5026,7 @@ virQEMUCapsIsValid(void *data, return false; } - if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) { + if (virQEMUCapsHaveAccel(qemuCaps)) { if (STRNEQ_NULLABLE(priv->hostCPUSignature, qemuCaps->hostCPUSignature)) { VIR_DEBUG("Outdated capabilities for '%s': host CPU changed " "('%s' vs '%s')", @@ -5053,7 +5060,9 @@ virQEMUCapsIsValid(void *data, qemuCaps->binary); return false; } + } + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) { kvmSupportsNesting = virQEMUCapsKVMSupportsNesting(); if (kvmSupportsNesting != qemuCaps->kvmSupportsNesting) { VIR_DEBUG("Outdated capabilities for '%s': kvm kernel nested " @@ -5518,7 +5527,7 @@ virQEMUCapsInitQMP(virQEMUCaps *qemuCaps, * for TCG capabilities by asking the same binary again and turning KVM * off. */ - if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM) && + if (virQEMUCapsHaveAccel(qemuCaps) && virQEMUCapsGet(qemuCaps, QEMU_CAPS_TCG) && virQEMUCapsInitQMPSingle(qemuCaps, libDir, runUid, runGid, true) < 0) return -1; @@ -5582,13 +5591,15 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch, virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM); virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_QEMU); - if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) { + if (virQEMUCapsHaveAccel(qemuCaps)) { qemuCaps->hostCPUSignature = g_strdup(hostCPUSignature); qemuCaps->microcodeVersion = microcodeVersion; qemuCaps->cpuData = virCPUDataNewCopy(cpuData); qemuCaps->kernelVersion = g_strdup(kernelVersion); + } + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) { qemuCaps->kvmSupportsNesting = virQEMUCapsKVMSupportsNesting(); qemuCaps->kvmSupportsSecureGuest = virQEMUCapsKVMSupportsSecureGuest(); -- 2.34.1

From: Roman Bolshakov <r.bolshakov@yadro.com> With this change virsh domcapabilites shows: <mode name='host-passthrough' supported='yes'/> https://gitlab.com/libvirt/libvirt/-/issues/147 Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- src/qemu/qemu_capabilities.c | 34 ++++++++++++++++++++++++++++++++-- src/qemu/qemu_process.c | 2 ++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index bb5744cd6b..dae9d1163d 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -745,6 +745,7 @@ struct _virQEMUCaps { /* Capabilities which may differ depending on the accelerator. */ virQEMUCapsAccel kvm; + virQEMUCapsAccel hvf; virQEMUCapsAccel tcg; }; @@ -849,7 +850,8 @@ virQEMUCapsTypeIsAccelerated(virDomainVirtType type) static bool virQEMUCapsHaveAccel(virQEMUCaps *qemuCaps) { - return virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM); + return virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM) || + virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF); } @@ -858,6 +860,8 @@ virQEMUCapsAccelStr(virDomainVirtType type) { if (type == VIR_DOMAIN_VIRT_KVM) return "kvm"; + else if (type == VIR_DOMAIN_VIRT_HVF) + return "hvf"; return "tcg"; } @@ -869,6 +873,8 @@ virQEMUCapsGetAccel(virQEMUCaps *qemuCaps, { if (type == VIR_DOMAIN_VIRT_KVM) return &qemuCaps->kvm; + else if (type == VIR_DOMAIN_VIRT_HVF) + return &qemuCaps->hvf; return &qemuCaps->tcg; } @@ -999,6 +1005,8 @@ virQEMUCapsGetMachineTypesCaps(virQEMUCaps *qemuCaps, * take the set of machine types we probed first. */ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) accel = &qemuCaps->kvm; + else if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF)) + accel = &qemuCaps->hvf; else accel = &qemuCaps->tcg; @@ -2013,6 +2021,7 @@ virQEMUCaps *virQEMUCapsNewCopy(virQEMUCaps *qemuCaps) ret->cpuData = virCPUDataNewCopy(qemuCaps->cpuData); if (virQEMUCapsAccelCopy(&ret->kvm, &qemuCaps->kvm) < 0 || + virQEMUCapsAccelCopy(&ret->hvf, &qemuCaps->hvf) < 0 || virQEMUCapsAccelCopy(&ret->tcg, &qemuCaps->tcg) < 0) return NULL; @@ -2066,6 +2075,7 @@ void virQEMUCapsDispose(void *obj) virSEVCapabilitiesFree(qemuCaps->sevCapabilities); virQEMUCapsAccelClear(&qemuCaps->kvm); + virQEMUCapsAccelClear(&qemuCaps->hvf); virQEMUCapsAccelClear(&qemuCaps->tcg); } @@ -2317,6 +2327,10 @@ virQEMUCapsIsVirtTypeSupported(virQEMUCaps *qemuCaps, virQEMUCapsGet(qemuCaps, QEMU_CAPS_TCG)) return true; + if (virtType == VIR_DOMAIN_VIRT_HVF && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF)) + return true; + if (virtType == VIR_DOMAIN_VIRT_KVM && virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) return true; @@ -2794,7 +2808,9 @@ bool virQEMUCapsHasMachines(virQEMUCaps *qemuCaps) { - return !!qemuCaps->kvm.nmachineTypes || !!qemuCaps->tcg.nmachineTypes; + return !!qemuCaps->kvm.nmachineTypes || + !!qemuCaps->hvf.nmachineTypes || + !!qemuCaps->tcg.nmachineTypes; } @@ -4484,6 +4500,10 @@ virQEMUCapsLoadCache(virArch hostArch, virQEMUCapsLoadAccel(qemuCaps, ctxt, VIR_DOMAIN_VIRT_KVM) < 0) { return -1; } + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF) && + virQEMUCapsLoadAccel(qemuCaps, ctxt, VIR_DOMAIN_VIRT_HVF) < 0) { + return -1; + } if (virQEMUCapsLoadAccel(qemuCaps, ctxt, VIR_DOMAIN_VIRT_QEMU) < 0) return -1; @@ -4495,6 +4515,8 @@ virQEMUCapsLoadCache(virArch hostArch, if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF)) + virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_HVF); virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_QEMU); if (virXPathBoolean("boolean(./kvmSupportsNesting)", ctxt) > 0) @@ -4729,6 +4751,8 @@ virQEMUCapsFormatCache(virQEMUCaps *qemuCaps) if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) virQEMUCapsFormatAccel(qemuCaps, &buf, VIR_DOMAIN_VIRT_KVM); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF)) + virQEMUCapsFormatAccel(qemuCaps, &buf, VIR_DOMAIN_VIRT_HVF); virQEMUCapsFormatAccel(qemuCaps, &buf, VIR_DOMAIN_VIRT_QEMU); for (i = 0; i < qemuCaps->ngicCapabilities; i++) { @@ -5351,6 +5375,9 @@ virQEMUCapsGetVirtType(virQEMUCaps *qemuCaps) if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) return VIR_DOMAIN_VIRT_KVM; + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF)) + return VIR_DOMAIN_VIRT_HVF; + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_TCG)) return VIR_DOMAIN_VIRT_QEMU; @@ -5589,6 +5616,8 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch, if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF)) + virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_HVF); virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_QEMU); if (virQEMUCapsHaveAccel(qemuCaps)) { @@ -6583,5 +6612,6 @@ void virQEMUCapsStripMachineAliases(virQEMUCaps *qemuCaps) { virQEMUCapsStripMachineAliasesForVirtType(qemuCaps, VIR_DOMAIN_VIRT_KVM); + virQEMUCapsStripMachineAliasesForVirtType(qemuCaps, VIR_DOMAIN_VIRT_HVF); virQEMUCapsStripMachineAliasesForVirtType(qemuCaps, VIR_DOMAIN_VIRT_QEMU); } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 82cf6bbfd8..b8c70da566 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -9241,6 +9241,8 @@ qemuProcessQMPInit(qemuProcessQMP *proc) #if defined(__linux__) # define hwaccel "kvm:tcg" +#elif defined(__APPLE__) +# define hwaccel "hvf:tcg" #else # define hwaccel "tcg" #endif -- 2.34.1

This new enumeration provides a way to specify the host OS that a specific test case expects. The default is Linux, which has been the implicit host OS until now; when Linux is selected as the host OS, KVM support is advertised in capabilies data exposed to test cases. This commit doesn't result in any functional change, and simply sets the stage for introducing macOS host OS support later. Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- tests/testutilsqemu.c | 86 +++++++++++++++++++++++++++---------------- tests/testutilsqemu.h | 4 ++ 2 files changed, 58 insertions(+), 32 deletions(-) diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index cb665e501b..a27e290c6b 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -160,7 +160,8 @@ virHostCPUX86GetCPUID(uint32_t leaf, static int testQemuAddGuest(virCaps *caps, - virArch arch) + virArch arch, + testQemuHostOS hostOS) { size_t nmachines; virCapsGuestMachine **machines = NULL; @@ -193,16 +194,18 @@ testQemuAddGuest(virCaps *caps, virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU, NULL, NULL, 0, NULL); - if (kvm_machines[emu_arch] != NULL) { - nmachines = g_strv_length((char **)kvm_machines[emu_arch]); - machines = virCapabilitiesAllocMachines(kvm_machines[emu_arch], - nmachines); - if (machines == NULL) - goto error; - - virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM, - qemu_emulators[emu_arch], - NULL, nmachines, machines); + if (hostOS == HOST_OS_LINUX) { + if (kvm_machines[emu_arch] != NULL) { + nmachines = g_strv_length((char **)kvm_machines[emu_arch]); + machines = virCapabilitiesAllocMachines(kvm_machines[emu_arch], + nmachines); + if (machines == NULL) + goto error; + + virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM, + qemu_emulators[emu_arch], + NULL, nmachines, machines); + } } return 0; @@ -213,7 +216,8 @@ testQemuAddGuest(virCaps *caps, } -virCaps *testQemuCapsInit(void) +static virCaps* +testQemuCapsInitImpl(testQemuHostOS hostOS) { virCaps *caps; size_t i; @@ -233,7 +237,7 @@ virCaps *testQemuCapsInit(void) goto cleanup; for (i = 0; i < VIR_ARCH_LAST; i++) { - if (testQemuAddGuest(caps, i) < 0) + if (testQemuAddGuest(caps, i, hostOS) < 0) goto cleanup; } @@ -255,6 +259,12 @@ virCaps *testQemuCapsInit(void) return NULL; } +virCaps* +testQemuCapsInit(void) +{ + return testQemuCapsInitImpl(HOST_OS_LINUX); +} + void qemuTestSetHostArch(virQEMUDriver *driver, @@ -338,7 +348,8 @@ void qemuTestDriverFree(virQEMUDriver *driver) static void qemuTestCapsPopulateFakeMachines(virQEMUCaps *caps, - virArch arch) + virArch arch, + testQemuHostOS hostOS) { size_t i; const char *defaultRAMid = NULL; @@ -366,20 +377,22 @@ qemuTestCapsPopulateFakeMachines(virQEMUCaps *caps, virQEMUCapsSet(caps, QEMU_CAPS_TCG); } - if (kvm_machines[arch] != NULL) { - for (i = 0; kvm_machines[arch][i] != NULL; i++) { - virQEMUCapsAddMachine(caps, - VIR_DOMAIN_VIRT_KVM, - kvm_machines[arch][i], - NULL, - NULL, - 0, - false, - false, - true, - defaultRAMid, - false); - virQEMUCapsSet(caps, QEMU_CAPS_KVM); + if (hostOS == HOST_OS_LINUX) { + if (kvm_machines[arch] != NULL) { + for (i = 0; kvm_machines[arch][i] != NULL; i++) { + virQEMUCapsAddMachine(caps, + VIR_DOMAIN_VIRT_KVM, + kvm_machines[arch][i], + NULL, + NULL, + 0, + false, + false, + true, + defaultRAMid, + false); + virQEMUCapsSet(caps, QEMU_CAPS_KVM); + } } } } @@ -399,8 +412,10 @@ qemuTestCapsCacheInsertData(virFileCache *cache, } -int qemuTestCapsCacheInsert(virFileCache *cache, - virQEMUCaps *caps) +static int +qemuTestCapsCacheInsertImpl(virFileCache *cache, + virQEMUCaps *caps, + testQemuHostOS hostOS) { size_t i; @@ -425,7 +440,7 @@ int qemuTestCapsCacheInsert(virFileCache *cache, if (!(copyCaps = effCaps = virQEMUCapsNewCopy(caps))) return -1; - qemuTestCapsPopulateFakeMachines(copyCaps, arch); + qemuTestCapsPopulateFakeMachines(copyCaps, arch, hostOS); } if (qemuTestCapsCacheInsertData(cache, qemu_emulators[arch], effCaps) < 0) @@ -460,7 +475,7 @@ int qemuTestCapsCacheInsert(virFileCache *cache, if (!tmp) return -1; - qemuTestCapsPopulateFakeMachines(tmp, i); + qemuTestCapsPopulateFakeMachines(tmp, i, hostOS); if (qemuTestCapsCacheInsertData(cache, qemu_emulators[i], tmp) < 0) return -1; @@ -470,6 +485,13 @@ int qemuTestCapsCacheInsert(virFileCache *cache, return 0; } +int +qemuTestCapsCacheInsert(virFileCache *cache, + virQEMUCaps *caps) +{ + return qemuTestCapsCacheInsertImpl(cache, caps, HOST_OS_LINUX); +} + # define STATEDIRTEMPLATE abs_builddir "/qemustatedir-XXXXXX" # define CONFIGDIRTEMPLATE abs_builddir "/qemuconfigdir-XXXXXX" diff --git a/tests/testutilsqemu.h b/tests/testutilsqemu.h index d59fa53239..a8de6eb52b 100644 --- a/tests/testutilsqemu.h +++ b/tests/testutilsqemu.h @@ -33,6 +33,10 @@ enum { GIC_BOTH, }; +typedef enum { + HOST_OS_LINUX = 0, +} testQemuHostOS; + typedef enum { ARG_QEMU_CAPS = QEMU_CAPS_LAST + 1, ARG_GIC, -- 2.34.1

This exposes a couple of macOS-specific variants of existing APIs, which can be used when implementing test programs and result in HVF support being advertised. Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- tests/testutilsqemu.c | 58 +++++++++++++++++++++++++++++++++++++++++++ tests/testutilsqemu.h | 4 +++ 2 files changed, 62 insertions(+) diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index a27e290c6b..e48e449f02 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -97,6 +97,18 @@ static const char *const *kvm_machines[VIR_ARCH_LAST] = { [VIR_ARCH_S390X] = s390x_machines, }; +static const char *const *hvf_machines[VIR_ARCH_LAST] = { + [VIR_ARCH_I686] = NULL, + [VIR_ARCH_X86_64] = x86_64_machines, + [VIR_ARCH_AARCH64] = aarch64_machines, + [VIR_ARCH_ARMV7L] = NULL, + [VIR_ARCH_PPC64] = NULL, + [VIR_ARCH_PPC] = NULL, + [VIR_ARCH_RISCV32] = NULL, + [VIR_ARCH_RISCV64] = NULL, + [VIR_ARCH_S390X] = NULL, +}; + static const char *qemu_default_ram_id[VIR_ARCH_LAST] = { [VIR_ARCH_I686] = "pc.ram", [VIR_ARCH_X86_64] = "pc.ram", @@ -208,6 +220,20 @@ testQemuAddGuest(virCaps *caps, } } + if (hostOS == HOST_OS_MACOS) { + if (hvf_machines[emu_arch] != NULL) { + nmachines = g_strv_length((char **)hvf_machines[emu_arch]); + machines = virCapabilitiesAllocMachines(hvf_machines[emu_arch], + nmachines); + if (machines == NULL) + goto error; + + virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_HVF, + qemu_emulators[emu_arch], + NULL, nmachines, machines); + } + } + return 0; error: @@ -265,6 +291,12 @@ testQemuCapsInit(void) return testQemuCapsInitImpl(HOST_OS_LINUX); } +virCaps* +testQemuCapsInitMacOS(void) +{ + return testQemuCapsInitImpl(HOST_OS_MACOS); +} + void qemuTestSetHostArch(virQEMUDriver *driver, @@ -395,6 +427,25 @@ qemuTestCapsPopulateFakeMachines(virQEMUCaps *caps, } } } + + if (hostOS == HOST_OS_MACOS) { + if (hvf_machines[arch] != NULL) { + for (i = 0; hvf_machines[arch][i] != NULL; i++) { + virQEMUCapsAddMachine(caps, + VIR_DOMAIN_VIRT_HVF, + hvf_machines[arch][i], + NULL, + NULL, + 0, + false, + false, + true, + defaultRAMid, + false); + virQEMUCapsSet(caps, QEMU_CAPS_HVF); + } + } + } } @@ -492,6 +543,13 @@ qemuTestCapsCacheInsert(virFileCache *cache, return qemuTestCapsCacheInsertImpl(cache, caps, HOST_OS_LINUX); } +int +qemuTestCapsCacheInsertMacOS(virFileCache *cache, + virQEMUCaps *caps) +{ + return qemuTestCapsCacheInsertImpl(cache, caps, HOST_OS_MACOS); +} + # define STATEDIRTEMPLATE abs_builddir "/qemustatedir-XXXXXX" # define CONFIGDIRTEMPLATE abs_builddir "/qemuconfigdir-XXXXXX" diff --git a/tests/testutilsqemu.h b/tests/testutilsqemu.h index a8de6eb52b..a9202d2ae6 100644 --- a/tests/testutilsqemu.h +++ b/tests/testutilsqemu.h @@ -35,6 +35,7 @@ enum { typedef enum { HOST_OS_LINUX = 0, + HOST_OS_MACOS, } testQemuHostOS; typedef enum { @@ -92,6 +93,7 @@ struct testQemuInfo { }; virCaps *testQemuCapsInit(void); +virCaps *testQemuCapsInitMacOS(void); virDomainXMLOption *testQemuXMLConfInit(void); @@ -113,6 +115,8 @@ int qemuTestDriverInit(virQEMUDriver *driver); void qemuTestDriverFree(virQEMUDriver *driver); int qemuTestCapsCacheInsert(virFileCache *cache, virQEMUCaps *caps); +int qemuTestCapsCacheInsertMacOS(virFileCache *cache, + virQEMUCaps *caps); int testQemuCapsSetGIC(virQEMUCaps *qemuCaps, int gic); -- 2.34.1

The new DO_TEST_MACOS() macro makes it possible to create test cases that verify the behavior of libvirt on a macOS machine with HVF support available. Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- tests/qemuxml2argvtest.c | 25 ++++++++++++++++++++++++- tests/qemuxml2xmltest.c | 27 ++++++++++++++++++++++++++- tests/testutilsqemu.c | 4 ++++ tests/testutilsqemu.h | 2 ++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 9d2de2a569..69bcdd0120 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -39,6 +39,8 @@ # define VIR_FROM_THIS VIR_FROM_QEMU static virQEMUDriver driver; +static virCaps *linuxCaps; +static virCaps *macOSCaps; static unsigned char * fakeSecretGetValue(virSecretPtr obj G_GNUC_UNUSED, @@ -716,12 +718,18 @@ testCompareXMLToArgv(const void *data) g_autofree char *archstr = NULL; virArch arch = VIR_ARCH_NONE; g_autoptr(virIdentity) sysident = virIdentityGetSystem(); + int rc; memset(&monitor_chr, 0, sizeof(monitor_chr)); if (testQemuInfoInitArgs((struct testQemuInfo *) info) < 0) goto cleanup; + if (info->args.hostOS == HOST_OS_MACOS) + driver.caps = macOSCaps; + else + driver.caps = linuxCaps; + if (info->arch != VIR_ARCH_NONE && info->arch != VIR_ARCH_X86_64) qemuTestSetHostArch(&driver, info->arch); @@ -771,7 +779,11 @@ testCompareXMLToArgv(const void *data) goto cleanup; } - if (qemuTestCapsCacheInsert(driver.qemuCapsCache, info->qemuCaps) < 0) + if (info->args.hostOS == HOST_OS_MACOS) + rc = qemuTestCapsCacheInsertMacOS(driver.qemuCapsCache, info->qemuCaps); + else + rc = qemuTestCapsCacheInsert(driver.qemuCapsCache, info->qemuCaps); + if (rc < 0) goto cleanup; if (info->migrateFrom && @@ -934,6 +946,13 @@ mymain(void) if (qemuTestDriverInit(&driver) < 0) return EXIT_FAILURE; + /* By default, the driver gets a virCaps instance that's suitable for + * tests that expect Linux as the host OS. We create another one for + * macOS and keep around pointers to both: this allows us to later + * pick the appropriate one for each test case */ + linuxCaps = driver.caps; + macOSCaps = testQemuCapsInitMacOS(); + driver.privileged = true; VIR_FREE(driver.config->defaultTLSx509certdir); @@ -1074,6 +1093,10 @@ mymain(void) DO_TEST_FULL(name, "", \ ARG_GIC, gic, \ ARG_QEMU_CAPS, __VA_ARGS__, QEMU_CAPS_LAST, ARG_END) +# define DO_TEST_MACOS(name, ...) \ + DO_TEST_FULL(name, "", \ + ARG_HOST_OS, HOST_OS_MACOS, \ + ARG_QEMU_CAPS, __VA_ARGS__, QEMU_CAPS_LAST, ARG_END) # define DO_TEST_FAILURE(name, ...) \ DO_TEST_FULL(name, "", \ diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index ce1cac31c8..e3f3e481af 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -21,6 +21,8 @@ #define VIR_FROM_THIS VIR_FROM_NONE static virQEMUDriver driver; +static virCaps *linuxCaps; +static virCaps *macOSCaps; enum { WHEN_INACTIVE = 1, @@ -32,13 +34,24 @@ enum { static int testXML2XMLCommon(const struct testQemuInfo *info) { + int rc; + if (testQemuInfoInitArgs((struct testQemuInfo *) info) < 0) return -1; + if (info->args.hostOS == HOST_OS_MACOS) + driver.caps = macOSCaps; + else + driver.caps = linuxCaps; + if (!(info->flags & FLAG_REAL_CAPS)) virQEMUCapsInitQMPBasicArch(info->qemuCaps); - if (qemuTestCapsCacheInsert(driver.qemuCapsCache, info->qemuCaps) < 0) + if (info->args.hostOS == HOST_OS_MACOS) + rc = qemuTestCapsCacheInsertMacOS(driver.qemuCapsCache, info->qemuCaps); + else + rc = qemuTestCapsCacheInsert(driver.qemuCapsCache, info->qemuCaps); + if (rc < 0) return -1; return 0; @@ -143,6 +156,13 @@ mymain(void) if (qemuTestDriverInit(&driver) < 0) return EXIT_FAILURE; + /* By default, the driver gets a virCaps instance that's suitable for + * tests that expect Linux as the host OS. We create another one for + * macOS and keep around pointers to both: this allows us to later + * pick the appropriate one for each test case */ + linuxCaps = driver.caps; + macOSCaps = testQemuCapsInitMacOS(); + cfg = virQEMUDriverGetConfig(&driver); driver.privileged = true; @@ -206,6 +226,11 @@ mymain(void) #define DO_TEST_NOCAPS(name) \ DO_TEST_FULL(name, "", WHEN_BOTH, ARG_END) +#define DO_TEST_MACOS(name, ...) \ + DO_TEST_FULL(name, "", WHEN_BOTH, \ + ARG_HOST_OS, HOST_OS_MACOS, \ + ARG_QEMU_CAPS, __VA_ARGS__, QEMU_CAPS_LAST, ARG_END) + /* Unset or set all envvars here that are copied in qemudBuildCommandLine * using ADD_ENV_COPY, otherwise these tests may fail due to unexpected * values for these envvars */ diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index e48e449f02..a77d1e6fe6 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -870,6 +870,10 @@ testQemuInfoSetArgs(struct testQemuInfo *info, info->args.capsver = va_arg(argptr, char *); break; + case ARG_HOST_OS: + info->args.hostOS = va_arg(argptr, int); + break; + case ARG_END: default: info->args.invalidarg = true; diff --git a/tests/testutilsqemu.h b/tests/testutilsqemu.h index a9202d2ae6..51139e6a97 100644 --- a/tests/testutilsqemu.h +++ b/tests/testutilsqemu.h @@ -47,6 +47,7 @@ typedef enum { ARG_PARSEFLAGS, ARG_CAPS_ARCH, ARG_CAPS_VER, + ARG_HOST_OS, ARG_END, } testQemuInfoArgName; @@ -72,6 +73,7 @@ struct testQemuArgs { char *capsver; char *capsarch; int gic; + testQemuHostOS hostOS; bool invalidarg; }; -- 2.34.1

We need to use a hardcoded list of capabilities because we don't yet have proper replies files obtained from QEMU running on actual macOS machines. Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- .../hvf-aarch64-virt-headless.args | 48 +++++++++ .../hvf-aarch64-virt-headless.xml | 45 +++++++++ .../hvf-x86_64-q35-headless.args | 47 +++++++++ .../hvf-x86_64-q35-headless.x86_64-latest.err | 1 + .../hvf-x86_64-q35-headless.xml | 44 +++++++++ tests/qemuxml2argvtest.c | 18 ++++ .../hvf-aarch64-virt-headless.xml | 94 ++++++++++++++++++ .../hvf-x86_64-q35-headless.xml | 97 +++++++++++++++++++ tests/qemuxml2xmltest.c | 16 +++ 9 files changed, 410 insertions(+) create mode 100644 tests/qemuxml2argvdata/hvf-aarch64-virt-headless.args create mode 100644 tests/qemuxml2argvdata/hvf-aarch64-virt-headless.xml create mode 100644 tests/qemuxml2argvdata/hvf-x86_64-q35-headless.args create mode 100644 tests/qemuxml2argvdata/hvf-x86_64-q35-headless.x86_64-latest.err create mode 100644 tests/qemuxml2argvdata/hvf-x86_64-q35-headless.xml create mode 100644 tests/qemuxml2xmloutdata/hvf-aarch64-virt-headless.xml create mode 100644 tests/qemuxml2xmloutdata/hvf-x86_64-q35-headless.xml diff --git a/tests/qemuxml2argvdata/hvf-aarch64-virt-headless.args b/tests/qemuxml2argvdata/hvf-aarch64-virt-headless.args new file mode 100644 index 0000000000..0f1eed66c2 --- /dev/null +++ b/tests/qemuxml2argvdata/hvf-aarch64-virt-headless.args @@ -0,0 +1,48 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-test \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-test/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-test/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-test/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-aarch64 \ +-name guest=test,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-test/master-key.aes \ +-machine virt,usb=off,dump-guest-core=off,gic-version=2 \ +-accel hvf \ +-drive file=/usr/share/edk2/aarch64/QEMU_EFI-silent-pflash.raw,if=pflash,format=raw,unit=0,readonly=on \ +-drive file=/var/lib/libvirt/qemu/nvram/test_VARS.fd,if=pflash,format=raw,unit=1 \ +-m 4096 \ +-realtime mlock=off \ +-smp 2,sockets=2,cores=1,threads=1 \ +-uuid 1b826c23-8767-47ad-a6b5-c83a88277f71 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-test/monitor.sock,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc,driftfix=slew \ +-no-shutdown \ +-boot strict=on \ +-device pcie-root-port,port=8,chassis=1,id=pci.1,bus=pcie.0,multifunction=on,addr=0x1 \ +-device pcie-root-port,port=9,chassis=2,id=pci.2,bus=pcie.0,addr=0x1.0x1 \ +-device pcie-root-port,port=10,chassis=3,id=pci.3,bus=pcie.0,addr=0x1.0x2 \ +-device pcie-root-port,port=11,chassis=4,id=pci.4,bus=pcie.0,addr=0x1.0x3 \ +-device pcie-root-port,port=12,chassis=5,id=pci.5,bus=pcie.0,addr=0x1.0x4 \ +-device pcie-root-port,port=13,chassis=6,id=pci.6,bus=pcie.0,addr=0x1.0x5 \ +-device virtio-serial-pci,id=virtio-serial0,bus=pci.2,addr=0x0 \ +-drive file=/var/lib/libvirt/images/test.qcow2,format=qcow2,if=none,id=drive-virtio-disk0 \ +-device virtio-blk-pci,bus=pci.3,addr=0x0,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 \ +-netdev user,id=hostnet0 \ +-device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:9a:e6:c6,bus=pci.1,addr=0x0 \ +-chardev pty,id=charserial0 \ +-serial chardev:charserial0 \ +-chardev socket,id=charchannel0,path=/tmp/channel/domain--1-test/org.qemu.guest_agent.0,server=on,wait=off \ +-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=org.qemu.guest_agent.0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.4,addr=0x0 \ +-object rng-random,id=objrng0,filename=/dev/urandom \ +-device virtio-rng-pci,rng=objrng0,id=rng0,bus=pci.5,addr=0x0 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/hvf-aarch64-virt-headless.xml b/tests/qemuxml2argvdata/hvf-aarch64-virt-headless.xml new file mode 100644 index 0000000000..ef13820e17 --- /dev/null +++ b/tests/qemuxml2argvdata/hvf-aarch64-virt-headless.xml @@ -0,0 +1,45 @@ +<domain type='hvf'> + <name>test</name> + <uuid>1b826c23-8767-47ad-a6b5-c83a88277f71</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>2</vcpu> + <os> + <type arch='aarch64' machine='virt'>hvm</type> + <loader readonly='yes' type='pflash'>/usr/share/edk2/aarch64/QEMU_EFI-silent-pflash.raw</loader> + <nvram>/var/lib/libvirt/qemu/nvram/test_VARS.fd</nvram> + <boot dev='hd'/> + </os> + <features> + <acpi/> + </features> + <clock offset='utc'> + <timer name='rtc' tickpolicy='catchup'/> + <timer name='pit' tickpolicy='delay'/> + <timer name='hpet' present='no'/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-aarch64</emulator> + <disk type='file' device='disk'> + <driver name='qemu' type='qcow2'/> + <source file='/var/lib/libvirt/images/test.qcow2'/> + <target dev='vda' bus='virtio'/> + </disk> + <controller type='usb' model='none'/> + <interface type='user'> + <mac address='52:54:00:9a:e6:c6'/> + <model type='virtio'/> + </interface> + <console type='pty'/> + <channel type='unix'> + <target type='virtio' name='org.qemu.guest_agent.0'/> + </channel> + <memballoon model='virtio'/> + <rng model='virtio'> + <backend model='random'>/dev/urandom</backend> + </rng> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/hvf-x86_64-q35-headless.args b/tests/qemuxml2argvdata/hvf-x86_64-q35-headless.args new file mode 100644 index 0000000000..3e6fd7104f --- /dev/null +++ b/tests/qemuxml2argvdata/hvf-x86_64-q35-headless.args @@ -0,0 +1,47 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-test \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-test/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-test/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-test/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-x86_64 \ +-name guest=test,debug-threads=on \ +-S \ +-object secret,id=masterKey0,format=raw,file=/tmp/lib/domain--1-test/master-key.aes \ +-machine q35,usb=off,dump-guest-core=off \ +-accel hvf \ +-m 4096 \ +-realtime mlock=off \ +-smp 2,sockets=2,cores=1,threads=1 \ +-uuid 1b826c23-8767-47ad-a6b5-c83a88277f71 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-test/monitor.sock,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc,driftfix=slew \ +-no-hpet \ +-no-shutdown \ +-boot strict=on \ +-device pcie-root-port,port=8,chassis=1,id=pci.1,bus=pcie.0,multifunction=on,addr=0x1 \ +-device pcie-root-port,port=9,chassis=2,id=pci.2,bus=pcie.0,addr=0x1.0x1 \ +-device pcie-root-port,port=10,chassis=3,id=pci.3,bus=pcie.0,addr=0x1.0x2 \ +-device pcie-root-port,port=11,chassis=4,id=pci.4,bus=pcie.0,addr=0x1.0x3 \ +-device pcie-root-port,port=12,chassis=5,id=pci.5,bus=pcie.0,addr=0x1.0x4 \ +-device pcie-root-port,port=13,chassis=6,id=pci.6,bus=pcie.0,addr=0x1.0x5 \ +-device virtio-serial-pci,id=virtio-serial0,bus=pci.2,addr=0x0 \ +-drive file=/var/lib/libvirt/images/test.qcow2,format=qcow2,if=none,id=drive-virtio-disk0 \ +-device virtio-blk-pci,bus=pci.3,addr=0x0,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 \ +-netdev user,id=hostnet0 \ +-device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:9a:e6:c6,bus=pci.1,addr=0x0 \ +-chardev pty,id=charserial0 \ +-device isa-serial,chardev=charserial0,id=serial0,index=0 \ +-chardev socket,id=charchannel0,path=/tmp/channel/domain--1-test/org.qemu.guest_agent.0,server=on,wait=off \ +-device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=org.qemu.guest_agent.0 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.4,addr=0x0 \ +-object rng-random,id=objrng0,filename=/dev/urandom \ +-device virtio-rng-pci,rng=objrng0,id=rng0,bus=pci.5,addr=0x0 \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/hvf-x86_64-q35-headless.x86_64-latest.err b/tests/qemuxml2argvdata/hvf-x86_64-q35-headless.x86_64-latest.err new file mode 100644 index 0000000000..374992ce71 --- /dev/null +++ b/tests/qemuxml2argvdata/hvf-x86_64-q35-headless.x86_64-latest.err @@ -0,0 +1 @@ +unsupported configuration: Emulator '/usr/bin/qemu-system-x86_64' does not support virt type 'hvf' diff --git a/tests/qemuxml2argvdata/hvf-x86_64-q35-headless.xml b/tests/qemuxml2argvdata/hvf-x86_64-q35-headless.xml new file mode 100644 index 0000000000..cad560e9ca --- /dev/null +++ b/tests/qemuxml2argvdata/hvf-x86_64-q35-headless.xml @@ -0,0 +1,44 @@ +<domain type='hvf'> + <name>test</name> + <uuid>1b826c23-8767-47ad-a6b5-c83a88277f71</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + <apic/> + </features> + <clock offset='utc'> + <timer name='rtc' tickpolicy='catchup'/> + <timer name='pit' tickpolicy='delay'/> + <timer name='hpet' present='no'/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type='file' device='disk'> + <driver name='qemu' type='qcow2'/> + <source file='/var/lib/libvirt/images/test.qcow2'/> + <target dev='vda' bus='virtio'/> + </disk> + <controller type='usb' model='none'/> + <interface type='user'> + <mac address='52:54:00:9a:e6:c6'/> + <model type='virtio'/> + </interface> + <console type='pty'/> + <channel type='unix'> + <target type='virtio' name='org.qemu.guest_agent.0'/> + </channel> + <memballoon model='virtio'/> + <rng model='virtio'> + <backend model='random'>/dev/urandom</backend> + </rng> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 69bcdd0120..3054ae92e9 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -3501,6 +3501,24 @@ mymain(void) DO_TEST_CAPS_LATEST("devices-acpi-index"); + DO_TEST_MACOS("hvf-x86_64-q35-headless", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_PCIE_ROOT_PORT, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_ISA_SERIAL, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM); + DO_TEST_MACOS("hvf-aarch64-virt-headless", + QEMU_CAPS_OBJECT_GPEX, + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_PCIE_ROOT_PORT, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_PL011, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM); + /* HVF guests should not work on Linux with KVM */ + DO_TEST_CAPS_LATEST_PARSE_ERROR("hvf-x86_64-q35-headless"); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) virFileDeleteTree(fakerootdir); diff --git a/tests/qemuxml2xmloutdata/hvf-aarch64-virt-headless.xml b/tests/qemuxml2xmloutdata/hvf-aarch64-virt-headless.xml new file mode 100644 index 0000000000..b5193a02b4 --- /dev/null +++ b/tests/qemuxml2xmloutdata/hvf-aarch64-virt-headless.xml @@ -0,0 +1,94 @@ +<domain type='hvf'> + <name>test</name> + <uuid>1b826c23-8767-47ad-a6b5-c83a88277f71</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>2</vcpu> + <os> + <type arch='aarch64' machine='virt'>hvm</type> + <loader readonly='yes' type='pflash'>/usr/share/edk2/aarch64/QEMU_EFI-silent-pflash.raw</loader> + <nvram>/var/lib/libvirt/qemu/nvram/test_VARS.fd</nvram> + <boot dev='hd'/> + </os> + <features> + <acpi/> + <gic version='2'/> + </features> + <clock offset='utc'> + <timer name='rtc' tickpolicy='catchup'/> + <timer name='pit' tickpolicy='delay'/> + <timer name='hpet' present='no'/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-aarch64</emulator> + <disk type='file' device='disk'> + <driver name='qemu' type='qcow2'/> + <source file='/var/lib/libvirt/images/test.qcow2'/> + <target dev='vda' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </disk> + <controller type='usb' index='0' model='none'/> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='virtio-serial' index='0'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='2' port='0x9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0xa'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='4' port='0xb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x3'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='5' port='0xc'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x4'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='6' port='0xd'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x5'/> + </controller> + <interface type='user'> + <mac address='52:54:00:9a:e6:c6'/> + <model type='virtio'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </interface> + <serial type='pty'> + <target type='system-serial' port='0'> + <model name='pl011'/> + </target> + </serial> + <console type='pty'> + <target type='serial' port='0'/> + </console> + <channel type='unix'> + <target type='virtio' name='org.qemu.guest_agent.0'/> + <address type='virtio-serial' controller='0' bus='0' port='1'/> + </channel> + <audio id='1' type='none'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </memballoon> + <rng model='virtio'> + <backend model='random'>/dev/urandom</backend> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </rng> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/hvf-x86_64-q35-headless.xml b/tests/qemuxml2xmloutdata/hvf-x86_64-q35-headless.xml new file mode 100644 index 0000000000..fd2b376b9b --- /dev/null +++ b/tests/qemuxml2xmloutdata/hvf-x86_64-q35-headless.xml @@ -0,0 +1,97 @@ +<domain type='hvf'> + <name>test</name> + <uuid>1b826c23-8767-47ad-a6b5-c83a88277f71</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + <apic/> + </features> + <clock offset='utc'> + <timer name='rtc' tickpolicy='catchup'/> + <timer name='pit' tickpolicy='delay'/> + <timer name='hpet' present='no'/> + </clock> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type='file' device='disk'> + <driver name='qemu' type='qcow2'/> + <source file='/var/lib/libvirt/images/test.qcow2'/> + <target dev='vda' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/> + </disk> + <controller type='usb' index='0' model='none'/> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='virtio-serial' index='0'> + <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x8'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='2' port='0x9'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='3' port='0xa'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='4' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='4' port='0xb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x3'/> + </controller> + <controller type='pci' index='5' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='5' port='0xc'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x4'/> + </controller> + <controller type='pci' index='6' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='6' port='0xd'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x5'/> + </controller> + <interface type='user'> + <mac address='52:54:00:9a:e6:c6'/> + <model type='virtio'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </interface> + <serial type='pty'> + <target type='isa-serial' port='0'> + <model name='isa-serial'/> + </target> + </serial> + <console type='pty'> + <target type='serial' port='0'/> + </console> + <channel type='unix'> + <target type='virtio' name='org.qemu.guest_agent.0'/> + <address type='virtio-serial' controller='0' bus='0' port='1'/> + </channel> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </memballoon> + <rng model='virtio'> + <backend model='random'>/dev/urandom</backend> + <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> + </rng> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index e3f3e481af..935fd955f4 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -1447,6 +1447,22 @@ mymain(void) DO_TEST_CAPS_LATEST("devices-acpi-index"); + DO_TEST_MACOS("hvf-x86_64-q35-headless", + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_PCIE_ROOT_PORT, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_ISA_SERIAL, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM); + DO_TEST_MACOS("hvf-aarch64-virt-headless", + QEMU_CAPS_OBJECT_GPEX, + QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY, + QEMU_CAPS_DEVICE_PCIE_ROOT_PORT, + QEMU_CAPS_DEVICE_VIRTIO_NET, + QEMU_CAPS_DEVICE_PL011, + QEMU_CAPS_DEVICE_VIRTIO_RNG, + QEMU_CAPS_OBJECT_RNG_RANDOM); + cleanup: if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) virFileDeleteTree(fakerootdir); -- 2.34.1

From: Roman Bolshakov <r.bolshakov@yadro.com> It's worth to make the domain type a little bit more visible than a row in news. An example of hvf domain is available on QEMU driver page. While at it, mention Hypervisor.framework on index page. Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- docs/drvqemu.rst | 48 +++++++++++++++++++++++++++++++++++++++++++--- docs/index.html.in | 1 + 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/docs/drvqemu.rst b/docs/drvqemu.rst index e18075d865..9d7dd2656b 100644 --- a/docs/drvqemu.rst +++ b/docs/drvqemu.rst @@ -1,13 +1,18 @@ .. role:: since .. role:: removed -========================== -KVM/QEMU hypervisor driver -========================== +============================== +QEMU/KVM/HVF hypervisor driver +============================== The libvirt KVM/QEMU driver can manage any QEMU emulator from version 2.11.0 or later. +It supports multiple QEMU accelerators: software +emulation also known as TCG, hardware-assisted virtualization on Linux +with KVM and hardware-assisted virtualization on macOS with +Hypervisor.framework (:since:`since 8.1.0`). + .. contents:: Project Links @@ -15,6 +20,7 @@ Project Links - The `KVM <https://www.linux-kvm.org/>`__ Linux hypervisor - The `QEMU <https://wiki.qemu.org/Index.html>`__ emulator +- `Hypervisor.framework`<https://developer.apple.com/documentation/hypervisor>__` reference Deployment pre-requisites ------------------------- @@ -27,6 +33,9 @@ Deployment pre-requisites - **KVM hypervisor**: The driver will probe ``/usr/bin`` for the presence of ``qemu-kvm`` and ``/dev/kvm`` device node. If both are found, then KVM fully virtualized, hardware accelerated guests will be available. +- **Hypervisor.framework (HVF)**: The driver will probe ``sysctl`` for the + presence of ``Hypervisor.framework``. If it is found and QEMU is newer than + 2.12, then it will be possible to create hardware accelerated guests. Connections to QEMU driver -------------------------- @@ -634,3 +643,36 @@ KVM hardware accelerated guest on i686 <graphics type='vnc' port='-1' keymap='de'/> </devices> </domain> + +HVF hardware accelerated guest on x86_64 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + <domain type='hvf'> + <name>hvf-demo</name> + <uuid>4dea24b3-1d52-d8f3-2516-782e98a23fa0</uuid> + <memory>131072</memory> + <vcpu>1</vcpu> + <os> + <type arch="x86_64">hvm</type> + </os> + <features> + <acpi/> + </features> + <clock sync="localtime"/> + <devices> + <emulator>/usr/local/bin/qemu-system-x86_64</emulator> + <controller type='scsi' index='0' model='virtio-scsi'/> + <disk type='volume' device='disk'> + <driver name='qemu' type='qcow2'/> + <source pool='default' volume='myos'/> + <target bus='scsi' dev='sda'/> + </disk> + <interface type='user'> + <mac address='24:42:53:21:52:45'/> + <model type='virtio'/> + </interface> + <graphics type='vnc' port='-1'/> + </devices> + </domain> diff --git a/docs/index.html.in b/docs/index.html.in index bf164edb58..2c4aa7c6d0 100644 --- a/docs/index.html.in +++ b/docs/index.html.in @@ -21,6 +21,7 @@ <li>is accessible from C, Python, Perl, Go and more</li> <li>is licensed under open source licenses</li> <li>supports <a href="drvqemu.html">KVM</a>, + <a href="drvqemu.html">Hypervisor.framework</a>, <a href="drvqemu.html">QEMU</a>, <a href="drvxen.html">Xen</a>, <a href="drvvirtuozzo.html">Virtuozzo</a>, <a href="drvesx.html">VMWare ESX</a>, -- 2.34.1

From: Roman Bolshakov <r.bolshakov@yadro.com> Many domain elements have "QEMU and KVM only" or "QEMU/KVM since x.y.z" remarks. Most of the elements work for HVF domain, so it makes sense to add respective notices for HVF domain. All the elements have been manually tested. Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- docs/formatdomain.rst | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 477e775229..e2f99c60a6 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -21,7 +21,7 @@ Element and attribute overview The root element required for all virtual machines is named ``domain``. It has two attributes, the ``type`` specifies the hypervisor used for running the domain. The allowed values are driver specific, but include "xen", "kvm", -"hvf" (:since:`since 8.0.0 and QEMU 2.12`), "qemu" +"hvf" (:since:`since 8.1.0 and QEMU 2.12`), "qemu" and "lxc". The second attribute is ``id`` which is a unique integer identifier for the running guest machine. Inactive machines have no id value. @@ -1452,7 +1452,8 @@ In case no restrictions need to be put on CPU model and its features, a simpler :since:`Since 7.1.0` with the QEMU driver. Both ``host-model`` and ``host-passthrough`` modes make sense when a domain - can run directly on the host CPUs (for example, domains with type ``kvm``). + can run directly on the host CPUs (for example, domains with type ``kvm`` + or ``hvf``). The actual host CPU is irrelevant for domains with emulated virtual CPUs (such as domains with type ``qemu``). However, for backward compatibility ``host-model`` may be implemented even for domains running on emulated CPUs @@ -1776,7 +1777,7 @@ Each of these states allow for the same four possible actions. The domain will be terminated and then restarted with a new name. (Only supported by the libxl hypervisor driver.) -QEMU/KVM supports the ``on_poweroff`` and ``on_reboot`` events handling the +QEMU/KVM/HVF supports the ``on_poweroff`` and ``on_reboot`` events handling the ``destroy`` and ``restart`` actions, but the combination of ``on_poweroff`` set to ``restart`` and ``on_reboot`` set to ``destroy`` is forbidden. @@ -1911,8 +1912,8 @@ are: Physical address extension mode allows 32-bit guests to address more than 4 GB of memory. ``acpi`` - ACPI is useful for power management, for example, with KVM guests it is - required for graceful shutdown to work. + ACPI is useful for power management, for example, with KVM or HVF guests it + is required for graceful shutdown to work. ``apic`` APIC allows the use of programmable IRQ management. :since:`Since 0.10.2 (QEMU only)` there is an optional attribute ``eoi`` with values ``on`` and @@ -6221,14 +6222,16 @@ A video device. You can provide the amount of video memory in kibibytes (blocks of 1024 bytes) using ``vram``. This is supported only for guest type of "vz", "qemu", - "vbox", "vmx" and "xen". If no value is provided the default is used. If the + "kvm", "hvf", "vbox", "vmx" and "xen". + If no value is provided the default is used. If the size is not a power of two it will be rounded to closest one. The number of screen can be set using ``heads``. This is supported only for - guests type of "vz", "kvm", "vbox" and "vmx". + guests type of "vz", "kvm", "hvf", "vbox" and "vmx". - For guest type of "kvm" or "qemu" and model type "qxl" there are optional - attributes. Attribute ``ram`` ( :since:`since 1.0.2` ) specifies the size of + For guest type of "kvm", "hvf" or "qemu" and model type "qxl" there are + optional attributes. + Attribute ``ram`` ( :since:`since 1.0.2` ) specifies the size of the primary bar, while the attribute ``vram`` specifies the secondary bar size. If ``ram`` or ``vram`` are not supplied a default value is used. The ``ram`` should also be rounded to power of two as ``vram``. There is also -- 2.34.1

From: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- docs/docs.html.in | 3 +++ docs/index.html.in | 3 ++- docs/macos.rst | 44 ++++++++++++++++++++++++++++++++++++++++++++ docs/meson.build | 1 + 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 docs/macos.rst diff --git a/docs/docs.html.in b/docs/docs.html.in index 8132090762..225827b693 100644 --- a/docs/docs.html.in +++ b/docs/docs.html.in @@ -16,6 +16,9 @@ <dt><a href="windows.html">Windows</a></dt> <dd>Downloads for Windows</dd> + <dt><a href="macos.html">macOS</a></dt> + <dd>Working with libvirt on macOS</dd> + <dt><a href="migration.html">Migration</a></dt> <dd>Migrating guests between machines</dd> diff --git a/docs/index.html.in b/docs/index.html.in index 2c4aa7c6d0..3c065badb7 100644 --- a/docs/index.html.in +++ b/docs/index.html.in @@ -28,7 +28,8 @@ <a href="drvlxc.html">LXC</a>, <a href="drvbhyve.html">BHyve</a> and <a href="drivers.html">more</a></li> - <li>targets Linux, FreeBSD, <a href="windows.html">Windows</a> and macOS</li> + <li>targets Linux, FreeBSD, <a href="windows.html">Windows</a> and + <a href="macos.html">macOS</a></li> <li>is used by many <a href="apps.html">applications</a></li> </ul> <p>Recent / forthcoming <a href="news.html">release changes</a></p> diff --git a/docs/macos.rst b/docs/macos.rst new file mode 100644 index 0000000000..84ff8192b5 --- /dev/null +++ b/docs/macos.rst @@ -0,0 +1,44 @@ +.. role:: since + +============= +macOS support +============= + +.. contents:: + +Libvirt works both as client (for most drivers) and server (for the +`QEMU driver <drvqemu.html>`__) on macOS. + +:since:`Since 8.1.0`, the "hvf" domain type can be used to run +hardware-accelerated VMs on macOS via +`Hypervisor.framework <https://developer.apple.com/documentation/hypervisor>`__. +QEMU version 2.12 or newer is needed for this to work. + + +Installation +============ + +libvirt client (virsh), server (libvirtd) and development headers can be +installed from `Homebrew <https://brew.sh>`__: + +:: + + brew install libvirt + + +Running libvirtd locally +======================== + +The server can be started manually: + +:: + + $ libvirtd + +or on system boot: + +:: + + $ brew services start libvirt + +Once started, you can use virsh as you would on Linux. diff --git a/docs/meson.build b/docs/meson.build index 50c12cc3c2..4168bebc8b 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -106,6 +106,7 @@ docs_rst_files = [ 'hacking', 'libvirt-go', 'libvirt-go-xml', + 'macos', 'migration', 'newreposetup', 'pci-addresses', -- 2.34.1

From: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com> Signed-off-by: Andrea Bolognani <abologna@redhat.com> Tested-by: Brad Laue <brad@brad-x.com> Tested-by: Christophe Fergeau <cfergeau@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> --- NEWS.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index cbfc9b4a15..666a593b58 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -17,6 +17,11 @@ v8.1.0 (unreleased) * **New features** + * qemu: Add hvf domain type for Hypervisor.framework + + It works on Intel machines as well as recent machines powered by Apple + Silicon. QEMU 6.2.0 is needed for Apple Silicon support. + * **Improvements** * packaging: sysconfig files no longer installed -- 2.34.1
participants (2)
-
Andrea Bolognani
-
Daniel P. Berrangé