From: Roman Bogorodskiy Date: Mon, 12 Jan 2026 18:44:35 +0000 (+0100) Subject: qemu: introduce the "virtualization" feature X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b9d9ff39d3ef76559c7eeaa077e004008df749fb;p=thirdparty%2Flibvirt.git qemu: introduce the "virtualization" feature The "virt" board in QEMU has a "virtualization" option that is documented like this: virtualization Set ``on``/``off`` to enable/disable emulating a guest CPU which implements the Arm Virtualization Extensions. The default is ``off``. (from system/arm/virt.rst) According to the documentation, the "virtualiaztion" option is related to the "gic-version" option. Specifically, gic version=4 requires virtualization to be enabled. And gic version=max will use version=4 when virtualization is enabled, and 3 when not. Libvirt does not currently model neither gic version "4" nor "max" though. It is also documented for the "vexpress-a(9|15)" boards, where it is also disabled by default: - QEMU defaults to providing a CPU which does not provide either TrustZone or the Virtualization Extensions: if you want these you must enable them with ``-machine secure=on`` and ``-machine virtualization=on`` (system/arm/vexpress.rst). On the command line it looks like: qemu-system-aarch64 -machine type=virt,virtualization=on .. Model it using the "virtualization" element in the "features" section: Signed-off-by: Roman Bogorodskiy Reviewed-by: Michal Privoznik --- diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 04ef319a73..ad74d91950 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -2378,6 +2378,10 @@ are: one IMSIC device present per core), or ``none`` (no support for AIA). If the attribute is not defined, the hypervisor default will be used. :since:`Since 11.1.0` (QEMU/KVM and RISC-V guests only) +``virtualization`` + Enable emulating a guest CPU which implements the Arm Virtualization Extensions. + If the attribute is not defined, the hypervisor default will be used. + :since:`Since 12.1.0` (QEMU/KVM and ARM virt guests only) Time keeping ------------ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 9672168df9..016750b059 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -188,6 +188,7 @@ VIR_ENUM_IMPL(virDomainFeature, "ras", "ps2", "aia", + "virtualization", ); VIR_ENUM_IMPL(virDomainCapabilitiesPolicy, @@ -17492,6 +17493,7 @@ virDomainFeaturesDefParse(virDomainDef *def, case VIR_DOMAIN_FEATURE_PAE: case VIR_DOMAIN_FEATURE_VIRIDIAN: case VIR_DOMAIN_FEATURE_PRIVNET: + case VIR_DOMAIN_FEATURE_VIRTUALIZATION: def->features[val] = VIR_TRISTATE_SWITCH_ON; break; @@ -21701,6 +21703,7 @@ virDomainDefFeaturesCheckABIStability(virDomainDef *src, case VIR_DOMAIN_FEATURE_CCF_ASSIST: case VIR_DOMAIN_FEATURE_RAS: case VIR_DOMAIN_FEATURE_PS2: + case VIR_DOMAIN_FEATURE_VIRTUALIZATION: if (src->features[i] != dst->features[i]) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("State of feature '%1$s' differs: source: '%2$s', destination: '%3$s'"), @@ -28932,6 +28935,7 @@ virDomainDefFormatFeatures(virBuffer *buf, case VIR_DOMAIN_FEATURE_PAE: case VIR_DOMAIN_FEATURE_VIRIDIAN: case VIR_DOMAIN_FEATURE_PRIVNET: + case VIR_DOMAIN_FEATURE_VIRTUALIZATION: /* NOTE: This is for old style booleans. New XML * should use the explicit state=on|off output below */ switch ((virTristateSwitch) def->features[i]) { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 83d49969d3..10ce7a2972 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2243,6 +2243,7 @@ typedef enum { VIR_DOMAIN_FEATURE_RAS, VIR_DOMAIN_FEATURE_PS2, VIR_DOMAIN_FEATURE_AIA, + VIR_DOMAIN_FEATURE_VIRTUALIZATION, VIR_DOMAIN_FEATURE_LAST } virDomainFeature; diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 114dd3f96f..8669d8f791 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -7180,6 +7180,11 @@ + + + + + diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index e81efdfde7..fde2e30924 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7011,6 +7011,15 @@ qemuAppendDomainFeaturesMachineParam(virBuffer *buf, } } + if (def->features[VIR_DOMAIN_FEATURE_VIRTUALIZATION] == VIR_TRISTATE_SWITCH_ON) { + if (virQEMUCapsGetArch(qemuCaps) != VIR_ARCH_AARCH64) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("virtualization option is not available with this QEMU binary")); + return -1; + } + virBufferAddLit(buf, ",virtualization=on"); + } + if (def->features[VIR_DOMAIN_FEATURE_HTM] != VIR_TRISTATE_SWITCH_ABSENT) { const char *str; str = virTristateSwitchTypeToString(def->features[VIR_DOMAIN_FEATURE_HTM]); diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 184c23d307..5474d00ecd 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -182,6 +182,7 @@ qemuValidateDomainDefFeatures(const virDomainDef *def, break; case VIR_DOMAIN_FEATURE_GIC: + case VIR_DOMAIN_FEATURE_VIRTUALIZATION: if (def->features[i] == VIR_TRISTATE_SWITCH_ON && !qemuDomainIsARMVirt(def)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, diff --git a/tests/qemuxmlconfdata/aarch64-virt-virtualization.aarch64-latest.args b/tests/qemuxmlconfdata/aarch64-virt-virtualization.aarch64-latest.args new file mode 100644 index 0000000000..be04ecc641 --- /dev/null +++ b/tests/qemuxmlconfdata/aarch64-virt-virtualization.aarch64-latest.args @@ -0,0 +1,38 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/var/lib/libvirt/qemu/domain--1-aarch64-virt-default \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-aarch64-virt-default/.local/share \ +XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-aarch64-virt-default/.cache \ +XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-aarch64-virt-default/.config \ +/usr/bin/qemu-system-aarch64 \ +-name guest=aarch64-virt-default-nic,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-aarch64-virt-default/master-key.aes"}' \ +-machine virt,usb=off,gic-version=2,virtualization=on,dump-guest-core=off,memory-backend=mach-virt.ram,acpi=off \ +-accel tcg \ +-cpu cortex-a53 \ +-m size=1048576k \ +-object '{"qom-type":"memory-backend-ram","id":"mach-virt.ram","size":1073741824}' \ +-overcommit mem-lock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 6ba410c5-1e5c-4d57-bee7-2228e7ffa32f \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-boot strict=on \ +-kernel /aarch64.kernel \ +-initrd /aarch64.initrd \ +-append console=ttyAMA0 \ +-device '{"driver":"pcie-root-port","port":8,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x1"}' \ +-device '{"driver":"pcie-root-port","port":9,"chassis":2,"id":"pci.2","bus":"pcie.0","addr":"0x1.0x1"}' \ +-netdev '{"type":"user","id":"hostnet0"}' \ +-device '{"driver":"virtio-net-pci","netdev":"hostnet0","id":"net0","mac":"52:54:00:09:a4:37","bus":"pci.1","addr":"0x0"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxmlconfdata/aarch64-virt-virtualization.aarch64-latest.xml b/tests/qemuxmlconfdata/aarch64-virt-virtualization.aarch64-latest.xml new file mode 100644 index 0000000000..7636046257 --- /dev/null +++ b/tests/qemuxmlconfdata/aarch64-virt-virtualization.aarch64-latest.xml @@ -0,0 +1,45 @@ + + aarch64-virt-default-nic + 6ba410c5-1e5c-4d57-bee7-2228e7ffa32f + 1048576 + 1048576 + 1 + + hvm + /aarch64.kernel + /aarch64.initrd + console=ttyAMA0 + + + + + + + + cortex-a53 + + + destroy + restart + destroy + + /usr/bin/qemu-system-aarch64 + + + + +
+ + + + +
+ + + + +
+ +