[libvirt PATCH 20/33] qemu: Move firmware selection from startup to postparse

Andrea Bolognani abologna at redhat.com
Wed Feb 15 10:42:17 UTC 2023


Currently, firmware selection is performed as part of the
domain startup process. This mostly works fine, but there's a
significant downside to this approach: since the process is
affected by factors outside of libvirt's control, specifically
the contents of the various JSON firmware descriptors and
their names, it's pretty much impossible to guarantee that the
outcome is always going to be the same. It would only take an
edk2 update, or a change made by the local admin, to render a
domain unbootable or downgrade its boot security.

To avoid this, move firmware selection to the postparse phase.
This way it will only be performed once, when the domain is
first defined; subsequent boots will not need to go through
the process again, as all the paths that were picked during
firmware selection are recorded in the domain XML.

Care is taken to ensure that existing domains are handled
correctly, even if their firmware configuration can't be
successfully resolved. Failure to complete the firmware
selection process is only considered fatal when defining a
new domain; in all other cases the error will be reported
during startup, as is already the case today.

Signed-off-by: Andrea Bolognani <abologna at redhat.com>
---
 src/qemu/qemu_domain.c                        |  40 ++-
 src/qemu/qemu_driver.c                        |   2 -
 src/qemu/qemu_firmware.c                      | 268 ++++++++++++++----
 src/qemu/qemu_firmware.h                      |   3 +-
 src/qemu/qemu_process.c                       |  33 ++-
 .../aarch64-virt-graphics.aarch64-latest.xml  |   2 +-
 .../aarch64-virt-headless.aarch64-latest.xml  |   2 +-
 ...ware-auto-bios-stateless.x86_64-latest.xml |   4 +-
 .../firmware-auto-bios.x86_64-latest.xml      |   3 +-
 ...rmware-auto-efi-aarch64.aarch64-latest.xml |   4 +-
 ...e-auto-efi-enrolled-keys.x86_64-latest.xml |   9 +-
 ...e-auto-efi-loader-secure.x86_64-latest.xml |   6 +-
 ...uto-efi-no-enrolled-keys.x86_64-latest.xml |   7 +-
 ...ware-auto-efi-no-secboot.x86_64-latest.xml |   7 +-
 ...ware-auto-efi-nvram-file.x86_64-latest.xml |   5 +-
 ...-efi-nvram-network-iscsi.x86_64-latest.xml |   3 +-
 ...to-efi-nvram-network-nbd.x86_64-latest.xml |   3 +-
 .../firmware-auto-efi-nvram.x86_64-latest.xml |   6 +-
 ...irmware-auto-efi-secboot.x86_64-latest.xml |   8 +-
 ...irmware-auto-efi-smm-off.x86_64-latest.xml |   4 +-
 ...mware-auto-efi-stateless.x86_64-latest.xml |   4 +-
 .../firmware-auto-efi.x86_64-latest.xml       |   5 +-
 ...manual-efi-acpi-aarch64.aarch64-latest.xml |   2 +-
 ...ware-manual-efi-acpi-q35.x86_64-latest.xml |   2 +-
 ...nual-efi-noacpi-aarch64.aarch64-latest.xml |   2 +-
 ...re-manual-efi-nvram-file.x86_64-latest.xml |   2 +-
 ...rmware-manual-efi-secure.x86_64-latest.xml |   2 +-
 .../firmware-manual-efi.x86_64-latest.xml     |   2 +-
 .../virtio-iommu-aarch64.aarch64-latest.xml   |   4 +-
 29 files changed, 310 insertions(+), 134 deletions(-)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index da1a2413a5..fad46fec1b 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -27,6 +27,7 @@
 #include "qemu_cgroup.h"
 #include "qemu_command.h"
 #include "qemu_capabilities.h"
+#include "qemu_firmware.h"
 #include "qemu_hostdev.h"
 #include "qemu_migration_params.h"
 #include "qemu_security.h"
@@ -4427,21 +4428,42 @@ qemuDomainRecheckInternalPaths(virDomainDef *def,
 
 static int
 qemuDomainDefBootPostParse(virDomainDef *def,
-                           virQEMUDriverConfig *cfg)
+                           virQEMUDriver *driver,
+                           unsigned int parseFlags)
 {
+    bool abiUpdate = !!(parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE);
+
     if (def->os.bootloader || def->os.bootloaderArgs) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("bootloader is not supported by QEMU"));
         return -1;
     }
 
-    if (virDomainDefHasOldStyleROUEFI(def) &&
-        !def->os.loader->nvram &&
-        def->os.loader->stateless != VIR_TRISTATE_BOOL_YES) {
-        def->os.loader->nvram = virStorageSourceNew();
-        def->os.loader->nvram->type = VIR_STORAGE_TYPE_FILE;
-        def->os.loader->nvram->format = VIR_STORAGE_FILE_RAW;
-        qemuDomainNVRAMPathFormat(cfg, def, &def->os.loader->nvram->path);
+    /* Firmware selection can fail for a number of reasons, but the
+     * most likely one is that the requested configuration contains
+     * mistakes or includes constraints that are impossible to
+     * satisfy on the current system.
+     *
+     * If that happens, we have to react differently based on the
+     * situation: if we're defining a new domain or updating its ABI,
+     * we should let the user know immediately so that they can
+     * change the requested configuration, hopefully into one that we
+     * can work with; if we're loading the configuration of an
+     * existing domain from disk, however, we absolutely cannot error
+     * out here, or the domain will disappear.
+     *
+     * To handle the second case gracefully, we clear any reported
+     * errors and continue as if nothing had happened. When it's time
+     * to start the domain, qemuFirmwareFillDomain() will be run
+     * again, fail in the same way, and at that point we'll have a
+     * chance to inform the user of any issues */
+    if (qemuFirmwareFillDomain(driver, def) < 0) {
+        if (abiUpdate) {
+            return -1;
+        } else {
+            virResetLastError();
+            return 0;
+        }
     }
 
     return 0;
@@ -4818,7 +4840,7 @@ qemuDomainDefPostParse(virDomainDef *def,
     if (qemuDomainDefMachinePostParse(def, qemuCaps) < 0)
         return -1;
 
-    if (qemuDomainDefBootPostParse(def, cfg) < 0)
+    if (qemuDomainDefBootPostParse(def, driver, parseFlags) < 0)
         return -1;
 
     if (qemuDomainDefAddDefaultDevices(driver, def, qemuCaps) < 0)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 6154fe9bfe..b102b7787e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6570,8 +6570,6 @@ qemuDomainUndefineFlags(virDomainPtr dom,
     if (vm->def->os.loader && vm->def->os.loader->nvram &&
         virStorageSourceIsLocalStorage(vm->def->os.loader->nvram)) {
         nvram_path = g_strdup(vm->def->os.loader->nvram->path);
-    } else if (vm->def->os.firmware == VIR_DOMAIN_OS_DEF_FIRMWARE_EFI) {
-        qemuDomainNVRAMPathFormat(cfg, vm->def, &nvram_path);
     }
 
     if (nvram_path && virFileExists(nvram_path)) {
diff --git a/src/qemu/qemu_firmware.c b/src/qemu/qemu_firmware.c
index 72036bd82b..4a6adedfcb 100644
--- a/src/qemu/qemu_firmware.c
+++ b/src/qemu/qemu_firmware.c
@@ -26,6 +26,7 @@
 #include "qemu_capabilities.h"
 #include "qemu_domain.h"
 #include "qemu_process.h"
+#include "domain_validate.h"
 #include "virarch.h"
 #include "virjson.h"
 #include "virlog.h"
@@ -1176,11 +1177,10 @@ qemuFirmwareMatchDomain(const virDomainDef *def,
 
 
 static int
-qemuFirmwareEnableFeatures(virQEMUDriver *driver,
-                           virDomainDef *def,
-                           const qemuFirmware *fw)
+qemuFirmwareEnableFeaturesModern(virQEMUDriverConfig *cfg,
+                                 virDomainDef *def,
+                                 const qemuFirmware *fw)
 {
-    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
     const qemuFirmwareMappingFlash *flash = &fw->mapping.data.flash;
     const qemuFirmwareMappingKernel *kernel = &fw->mapping.data.kernel;
     const qemuFirmwareMappingMemory *memory = &fw->mapping.data.memory;
@@ -1216,10 +1216,8 @@ qemuFirmwareEnableFeatures(virQEMUDriver *driver,
             }
         }
 
-        VIR_DEBUG("decided on firmware '%s' template '%s' NVRAM '%s'",
-                  loader->path,
-                  NULLSTR(loader->nvramTemplate),
-                  NULLSTR(loader->nvram ? loader->nvram->path : NULL));
+        VIR_DEBUG("decided on firmware '%s' template '%s'",
+                  loader->path, NULLSTR(loader->nvramTemplate));
         break;
 
     case QEMU_FIRMWARE_DEVICE_KERNEL:
@@ -1360,58 +1358,99 @@ qemuFirmwareFetchParsedConfigs(bool privileged,
 }
 
 
-int
-qemuFirmwareFillDomain(virQEMUDriver *driver,
-                       virDomainDef *def,
-                       unsigned int flags)
+/**
+ * qemuFirmwareFillDomainLegacy:
+ * @driver: QEMU driver
+ * @def: domain definition
+ *
+ * Go through the legacy list of CODE:VARS pairs looking for a
+ * suitable NVRAM template for the user-provided firmware path.
+ *
+ * Should only be used as a fallback in case looking at the firmware
+ * descriptors yielded no results.
+ *
+ * Returns: 0 on success,
+ *          1 if a matching firmware could not be found,
+ *          -1 on error.
+ */
+static int
+qemuFirmwareFillDomainLegacy(virQEMUDriver *driver,
+                             virDomainDef *def)
 {
-    g_auto(GStrv) paths = NULL;
-    qemuFirmware **firmwares = NULL;
-    ssize_t nfirmwares = 0;
-    const qemuFirmware *theone = NULL;
-    bool needResult = true;
-    const bool reset_nvram = flags & VIR_QEMU_PROCESS_START_RESET_NVRAM;
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+    virDomainLoaderDef *loader = def->os.loader;
     size_t i;
-    int ret = -1;
 
-    /* Fill in FW paths if either os.firmware is enabled, or
-     * loader path was provided with no nvram varstore. */
-    if (def->os.firmware == VIR_DOMAIN_OS_DEF_FIRMWARE_NONE) {
-        /* This is horrific check, but loosely said, if UEFI
-         * image was provided by the old method (by specifying
-         * its path in domain XML) but no template for NVRAM was
-         * specified and the varstore doesn't exist ... */
-        if (!virDomainDefHasOldStyleROUEFI(def) ||
-            def->os.loader->nvramTemplate)
-            return 0;
+    if (!loader)
+        return 0;
 
-        if (def->os.loader->nvram) {
-            if (!virStorageSourceIsLocalStorage(def->os.loader->nvram)) {
-                if (reset_nvram) {
-                    virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
-                                   _("resetting of nvram is not supported with network backed nvram"));
-                    return -1;
-                }
-
-                /* we don't scrutinize whether NVRAM image accessed via network
-                 * is present */
-                return 0;
-            }
+    if (loader->type != VIR_DOMAIN_LOADER_TYPE_PFLASH) {
+        VIR_DEBUG("Ignoring legacy entries for '%s' loader",
+                  virDomainLoaderTypeToString(loader->type));
+        return 0;
+    }
 
-            if (!reset_nvram && virFileExists(def->os.loader->nvram->path))
-                return 0;
+    if (loader->stateless == VIR_TRISTATE_BOOL_YES) {
+        VIR_DEBUG("Ignoring legacy entries for stateless loader");
+        return 0;
+    }
+
+    for (i = 0; i < cfg->nfirmwares; i++) {
+        virFirmware *fw = cfg->firmwares[i];
+
+        if (STRNEQ(fw->name, loader->path)) {
+            VIR_DEBUG("Not matching loader path '%s' for user provided path '%s'",
+                      fw->name, loader->path);
+            continue;
         }
 
-        /* ... then we want to consult JSON FW descriptors first,
-         * but we don't want to fail if we haven't found a match. */
-        needResult = false;
-    } else {
-        /* Domain has FW autoselection enabled => do nothing if
-         * we are not starting it from scratch. */
-        if (!(flags & VIR_QEMU_PROCESS_START_NEW))
-            return 0;
+        loader->type = VIR_DOMAIN_LOADER_TYPE_PFLASH;
+        loader->readonly = VIR_TRISTATE_BOOL_YES;
+        loader->nvramTemplate = g_strdup(cfg->firmwares[i]->nvram);
+
+        if (!loader->nvram) {
+            loader->nvram = virStorageSourceNew();
+            loader->nvram->type = VIR_STORAGE_TYPE_FILE;
+            loader->nvram->format = VIR_STORAGE_FILE_RAW;
+            qemuDomainNVRAMPathFormat(cfg, def, &loader->nvram->path);
+        }
+
+        VIR_DEBUG("decided on firmware '%s' template '%s'",
+                  loader->path, NULLSTR(loader->nvramTemplate));
+
+        return 0;
     }
 
+    return 1;
+}
+
+
+/**
+ * qemuFirmwareFillDomainModern:
+ * @driver: QEMU driver
+ * @def: domain definition
+ *
+ * Look at the firmware descriptors available on the system and try
+ * to find one that matches the user's requested configuration. If
+ * successful, @def will be updated so that it explicitly points to
+ * the corresponding paths.
+ *
+ * Returns: 0 on success,
+ *          1 if a matching firmware could not be found,
+ *          -1 on error.
+ */
+static int
+qemuFirmwareFillDomainModern(virQEMUDriver *driver,
+                             virDomainDef *def)
+{
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+    g_auto(GStrv) paths = NULL;
+    qemuFirmware **firmwares = NULL;
+    ssize_t nfirmwares = 0;
+    const qemuFirmware *theone = NULL;
+    size_t i;
+    int ret = -1;
+
     if ((nfirmwares = qemuFirmwareFetchParsedConfigs(driver->privileged,
                                                      &firmwares, &paths)) < 0)
         return -1;
@@ -1426,16 +1465,7 @@ qemuFirmwareFillDomain(virQEMUDriver *driver,
     }
 
     if (!theone) {
-        if (needResult) {
-            virReportError(VIR_ERR_OPERATION_FAILED,
-                           _("Unable to find any firmware to satisfy '%s'"),
-                           virDomainOsDefFirmwareTypeToString(def->os.firmware));
-        } else {
-            VIR_DEBUG("Unable to find NVRAM template for '%s', "
-                      "falling back to old style",
-                      NULLSTR(def->os.loader ? def->os.loader->path : NULL));
-            ret = 0;
-        }
+        ret = 1;
         goto cleanup;
     }
 
@@ -1444,13 +1474,14 @@ qemuFirmwareFillDomain(virQEMUDriver *driver,
      * likely that admin/FW manufacturer messed up. */
     qemuFirmwareSanityCheck(theone, paths[i]);
 
-    if (qemuFirmwareEnableFeatures(driver, def, theone) < 0)
+    if (qemuFirmwareEnableFeaturesModern(cfg, def, theone) < 0)
         goto cleanup;
 
     def->os.firmware = VIR_DOMAIN_OS_DEF_FIRMWARE_NONE;
     VIR_FREE(def->os.firmwareFeatures);
 
     ret = 0;
+
  cleanup:
     for (i = 0; i < nfirmwares; i++)
         qemuFirmwareFree(firmwares[i]);
@@ -1459,6 +1490,119 @@ qemuFirmwareFillDomain(virQEMUDriver *driver,
 }
 
 
+/**
+ * qemuFirmwareFillDomain:
+ * @driver: QEMU driver
+ * @def: domain definition
+ *
+ * Perform firmware selection.
+ *
+ * When firmware autoselection is used, this means looking at the
+ * firmware descriptors available on the system and finding one that
+ * matches the user's requested parameters; when manual firmware
+ * selection is used, the path to the firmware itself is usually
+ * already provided, but other information such as the path to the
+ * NVRAM template might be missing.
+ *
+ * The idea is that calling this function a first time (at PostParse
+ * time) will convert whatever partial configuration the user might
+ * have provided into a fully specified firmware configuration, such
+ * as that calling it a second time (at domain start time) will
+ * result in an early successful exit. The same thing should happen
+ * if the input configuration wasn't missing any information in the
+ * first place.
+ *
+ * Returns: 0 on success,
+ *          -1 on error.
+ */
+int
+qemuFirmwareFillDomain(virQEMUDriver *driver,
+                       virDomainDef *def)
+{
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+    virDomainLoaderDef *loader = def->os.loader;
+    bool autoSelection = (def->os.firmware != VIR_DOMAIN_OS_DEF_FIRMWARE_NONE);
+    int ret;
+
+    /* Start by performing a thorough validation of the input.
+     *
+     * We need to do this here because the firmware selection logic
+     * can only work correctly if the request is constructed
+     * properly; at the same time, we can't rely on Validate having
+     * been called ahead of time, because in some situations (such as
+     * when loading the configuration of existing domains from disk)
+     * that entire phase is intentionally skipped */
+    if (virDomainDefOSValidate(def, NULL) < 0)
+        return -1;
+
+    /* If firmware autoselection is disabled and the loader is a ROM
+     * instead of a PFLASH device, then we're using BIOS and we don't
+     * need any information at all */
+    if (!autoSelection &&
+        (!loader || (loader && loader->type == VIR_DOMAIN_LOADER_TYPE_ROM))) {
+        return 0;
+    }
+
+    /* For UEFI with firmware autoselection disabled, even if some of
+     * the information is missing we might still be able to avoid
+     * having to look at firmware descriptors */
+    if (!autoSelection &&
+        virDomainDefHasOldStyleROUEFI(def) &&
+        loader->path) {
+
+        /* For stateless firmwares, the firmware path is all we need */
+        if (loader->stateless == VIR_TRISTATE_BOOL_YES)
+            return 0;
+
+        /* If the path to the NVRAM file is already provided and it
+         * points to a non-local source, we don't need to look up any
+         * other information */
+        if (loader->nvram && !virStorageSourceIsLocalStorage(loader->nvram))
+            return 0;
+
+        /* If we have the path to both the firmware itself and the
+         * corresponding NVRAM template we might still need to
+         * generate a path to the domain-specific NVRAM file, but
+         * otherwise we're good to go */
+        if (loader->nvramTemplate) {
+            if (!loader->nvram) {
+                loader->nvram = virStorageSourceNew();
+                loader->nvram->type = VIR_STORAGE_TYPE_FILE;
+                loader->nvram->format = VIR_STORAGE_FILE_RAW;
+                qemuDomainNVRAMPathFormat(cfg, def, &loader->nvram->path);
+            }
+            return 0;
+        }
+    }
+
+    /* Look for the information we need in firmware descriptors */
+    if ((ret = qemuFirmwareFillDomainModern(driver, def)) < 0)
+        return -1;
+
+    if (ret == 1) {
+        /* If we haven't found any match among firmware descriptors,
+         * that would normally be the end of it.
+         *
+         * However, in order to handle legacy configurations
+         * correctly, we make another attempt at locating the missing
+         * information by going through the hardcoded list of
+         * CODE:NVRAM pairs that might have been provided at build
+         * time */
+        if (!autoSelection) {
+            if (qemuFirmwareFillDomainLegacy(driver, def) < 0)
+                return -1;
+        } else {
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("Unable to find any firmware to satisfy '%s'"),
+                           virDomainOsDefFirmwareTypeToString(def->os.firmware));
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+
 /**
  * qemuFirmwareGetSupported:
  * @machine: machine type
diff --git a/src/qemu/qemu_firmware.h b/src/qemu/qemu_firmware.h
index 103b6e4643..1ce0920713 100644
--- a/src/qemu/qemu_firmware.h
+++ b/src/qemu/qemu_firmware.h
@@ -44,8 +44,7 @@ qemuFirmwareFetchConfigs(char ***firmwares,
 
 int
 qemuFirmwareFillDomain(virQEMUDriver *driver,
-                       virDomainDef *def,
-                       unsigned int flags);
+                       virDomainDef *def);
 
 int
 qemuFirmwareGetSupported(const char *machine,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index d4499c6f84..d302144ed1 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4583,42 +4583,41 @@ qemuPrepareNVRAM(virQEMUDriver *driver,
     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
     VIR_AUTOCLOSE srcFD = -1;
     virDomainLoaderDef *loader = vm->def->os.loader;
-    const char *master_nvram_path;
     struct qemuPrepareNVRAMHelperData data;
 
-    if (!loader || !loader->nvram ||
-        !virStorageSourceIsLocalStorage(loader->nvram) ||
-        (virFileExists(loader->nvram->path) && !reset_nvram))
+    if (!loader || !loader->nvram)
         return 0;
 
-    master_nvram_path = loader->nvramTemplate;
-    if (!loader->nvramTemplate) {
-        size_t i;
-        for (i = 0; i < cfg->nfirmwares; i++) {
-            if (STREQ(cfg->firmwares[i]->name, loader->path)) {
-                master_nvram_path = cfg->firmwares[i]->nvram;
-                break;
-            }
+    if (!virStorageSourceIsLocalStorage(loader->nvram)) {
+        if (!reset_nvram) {
+            return 0;
+        } else {
+            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                    _("resetting of nvram is not supported with network backed nvram"));
+            return -1;
         }
     }
 
-    if (!master_nvram_path) {
+    if (virFileExists(loader->nvram->path) && !reset_nvram)
+        return 0;
+
+    if (!loader->nvramTemplate) {
         virReportError(VIR_ERR_OPERATION_FAILED,
                        _("unable to find any master var store for "
                          "loader: %s"), loader->path);
         return -1;
     }
 
-    if ((srcFD = virFileOpenAs(master_nvram_path, O_RDONLY,
+    if ((srcFD = virFileOpenAs(loader->nvramTemplate, O_RDONLY,
                                0, -1, -1, 0)) < 0) {
         virReportSystemError(-srcFD,
                              _("Failed to open file '%s'"),
-                             master_nvram_path);
+                             loader->nvramTemplate);
         return -1;
     }
 
     data.srcFD = srcFD;
-    data.srcPath = master_nvram_path;
+    data.srcPath = loader->nvramTemplate;
 
     if (virFileRewrite(loader->nvram->path,
                        S_IRUSR | S_IWUSR,
@@ -6751,7 +6750,7 @@ qemuProcessPrepareDomain(virQEMUDriver *driver,
         return -1;
 
     VIR_DEBUG("Prepare bios/uefi paths");
-    if (qemuFirmwareFillDomain(driver, vm->def, flags) < 0)
+    if (qemuFirmwareFillDomain(driver, vm->def) < 0)
         return -1;
     if (qemuDomainInitializePflashStorageSource(vm, cfg) < 0)
         return -1;
diff --git a/tests/qemuxml2xmloutdata/aarch64-virt-graphics.aarch64-latest.xml b/tests/qemuxml2xmloutdata/aarch64-virt-graphics.aarch64-latest.xml
index b4e7e0a944..24109a11c3 100644
--- a/tests/qemuxml2xmloutdata/aarch64-virt-graphics.aarch64-latest.xml
+++ b/tests/qemuxml2xmloutdata/aarch64-virt-graphics.aarch64-latest.xml
@@ -12,7 +12,7 @@
   <os>
     <type arch='aarch64' machine='virt'>hvm</type>
     <loader readonly='yes' type='pflash'>/usr/share/AAVMF/AAVMF_CODE.fd</loader>
-    <nvram>/some/user/nvram/path/guest_VARS.fd</nvram>
+    <nvram template='/usr/share/AAVMF/AAVMF_VARS.fd'>/some/user/nvram/path/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/aarch64-virt-headless.aarch64-latest.xml b/tests/qemuxml2xmloutdata/aarch64-virt-headless.aarch64-latest.xml
index 3a7961df10..6182da4dc6 100644
--- a/tests/qemuxml2xmloutdata/aarch64-virt-headless.aarch64-latest.xml
+++ b/tests/qemuxml2xmloutdata/aarch64-virt-headless.aarch64-latest.xml
@@ -12,7 +12,7 @@
   <os>
     <type arch='aarch64' machine='virt'>hvm</type>
     <loader readonly='yes' type='pflash'>/usr/share/AAVMF/AAVMF_CODE.fd</loader>
-    <nvram>/some/user/nvram/path/guest_VARS.fd</nvram>
+    <nvram template='/usr/share/AAVMF/AAVMF_VARS.fd'>/some/user/nvram/path/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-bios-stateless.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-bios-stateless.x86_64-latest.xml
index 9d42e210c3..c7c6e23ea1 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-bios-stateless.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-bios-stateless.x86_64-latest.xml
@@ -4,9 +4,9 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='bios'>
+  <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
-    <loader stateless='yes'/>
+    <loader type='rom' stateless='yes'>/usr/share/seabios/bios-256k.bin</loader>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-bios.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-bios.x86_64-latest.xml
index 11f95f04eb..4e0b45cccd 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-bios.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-bios.x86_64-latest.xml
@@ -4,8 +4,9 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='bios'>
+  <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
+    <loader type='rom'>/usr/share/seabios/bios-256k.bin</loader>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-aarch64.aarch64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-aarch64.aarch64-latest.xml
index 5f4432db36..b53f39a72e 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-aarch64.aarch64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-aarch64.aarch64-latest.xml
@@ -4,8 +4,10 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='aarch64' machine='virt-4.0'>hvm</type>
+    <loader readonly='yes' type='pflash'>/usr/share/AAVMF/AAVMF_CODE.fd</loader>
+    <nvram template='/usr/share/AAVMF/AAVMF_VARS.fd'>/var/lib/libvirt/qemu/nvram/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-enrolled-keys.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-enrolled-keys.x86_64-latest.xml
index 3923d1d4f2..6814784721 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-enrolled-keys.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-enrolled-keys.x86_64-latest.xml
@@ -4,16 +4,15 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
-    <firmware>
-      <feature enabled='yes' name='enrolled-keys'/>
-      <feature enabled='yes' name='secure-boot'/>
-    </firmware>
+    <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.secboot.fd</loader>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.secboot.fd'>/var/lib/libvirt/qemu/nvram/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
     <acpi/>
+    <smm state='on'/>
   </features>
   <cpu mode='custom' match='exact' check='none'>
     <model fallback='forbid'>qemu64</model>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-loader-secure.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-loader-secure.x86_64-latest.xml
index c655d81454..6814784721 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-loader-secure.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-loader-secure.x86_64-latest.xml
@@ -4,13 +4,15 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
-    <loader secure='yes'/>
+    <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.secboot.fd</loader>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.secboot.fd'>/var/lib/libvirt/qemu/nvram/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
     <acpi/>
+    <smm state='on'/>
   </features>
   <cpu mode='custom' match='exact' check='none'>
     <model fallback='forbid'>qemu64</model>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-no-enrolled-keys.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-no-enrolled-keys.x86_64-latest.xml
index 326b1d5faf..8b3853dc17 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-no-enrolled-keys.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-no-enrolled-keys.x86_64-latest.xml
@@ -4,11 +4,10 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
-    <firmware>
-      <feature enabled='no' name='enrolled-keys'/>
-    </firmware>
+    <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/var/lib/libvirt/qemu/nvram/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-no-secboot.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-no-secboot.x86_64-latest.xml
index 9e8107cb4d..8b3853dc17 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-no-secboot.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-no-secboot.x86_64-latest.xml
@@ -4,11 +4,10 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
-    <firmware>
-      <feature enabled='no' name='secure-boot'/>
-    </firmware>
+    <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/var/lib/libvirt/qemu/nvram/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-file.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-file.x86_64-latest.xml
index 961e97472d..cdb5d2b31a 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-file.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-file.x86_64-latest.xml
@@ -4,9 +4,10 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-i440fx-4.0'>hvm</type>
-    <nvram type='file'>
+    <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.fd' type='file'>
       <source file='/path/to/guest_VARS.fd'/>
     </nvram>
     <boot dev='hd'/>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-network-iscsi.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-network-iscsi.x86_64-latest.xml
index 446266fbf0..5a2e8715a0 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-network-iscsi.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-network-iscsi.x86_64-latest.xml
@@ -4,8 +4,9 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-i440fx-4.0'>hvm</type>
+    <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
     <nvram type='network'>
       <source protocol='iscsi' name='iqn.2013-07.com.example:iscsi-nopool'>
         <host name='example.com' port='6000'/>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-network-nbd.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-network-nbd.x86_64-latest.xml
index 4f0d9bef1e..208257bb5b 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-network-nbd.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram-network-nbd.x86_64-latest.xml
@@ -4,8 +4,9 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-i440fx-4.0'>hvm</type>
+    <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
     <nvram type='network'>
       <source protocol='nbd' name='bar'>
         <host name='example.org' port='6000'/>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram.x86_64-latest.xml
index 2090a770c6..f039d79ae4 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-nvram.x86_64-latest.xml
@@ -4,13 +4,15 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
-    <nvram>/path/to/guest_VARS.fd</nvram>
+    <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.secboot.fd</loader>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.secboot.fd'>/path/to/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
     <acpi/>
+    <smm state='on'/>
   </features>
   <cpu mode='custom' match='exact' check='none'>
     <model fallback='forbid'>qemu64</model>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-secboot.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-secboot.x86_64-latest.xml
index 22a26554c8..6814784721 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-secboot.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-secboot.x86_64-latest.xml
@@ -4,15 +4,15 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
-    <firmware>
-      <feature enabled='yes' name='secure-boot'/>
-    </firmware>
+    <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.secboot.fd</loader>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.secboot.fd'>/var/lib/libvirt/qemu/nvram/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
     <acpi/>
+    <smm state='on'/>
   </features>
   <cpu mode='custom' match='exact' check='none'>
     <model fallback='forbid'>qemu64</model>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-smm-off.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-smm-off.x86_64-latest.xml
index 7274753f9d..3a50158fba 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-smm-off.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-smm-off.x86_64-latest.xml
@@ -4,8 +4,10 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
+    <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/var/lib/libvirt/qemu/nvram/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi-stateless.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi-stateless.x86_64-latest.xml
index 143756dbff..3bc9a7341e 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi-stateless.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi-stateless.x86_64-latest.xml
@@ -4,9 +4,9 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
-    <loader stateless='yes'/>
+    <loader readonly='yes' type='pflash' stateless='yes'>/usr/share/OVMF/OVMF.sev.fd</loader>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-auto-efi.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-auto-efi.x86_64-latest.xml
index 72f2ea1321..6814784721 100644
--- a/tests/qemuxml2xmloutdata/firmware-auto-efi.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-auto-efi.x86_64-latest.xml
@@ -4,12 +4,15 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
+    <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.secboot.fd</loader>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.secboot.fd'>/var/lib/libvirt/qemu/nvram/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
     <acpi/>
+    <smm state='on'/>
   </features>
   <cpu mode='custom' match='exact' check='none'>
     <model fallback='forbid'>qemu64</model>
diff --git a/tests/qemuxml2xmloutdata/firmware-manual-efi-acpi-aarch64.aarch64-latest.xml b/tests/qemuxml2xmloutdata/firmware-manual-efi-acpi-aarch64.aarch64-latest.xml
index 24e4de6fc6..34257e4f80 100644
--- a/tests/qemuxml2xmloutdata/firmware-manual-efi-acpi-aarch64.aarch64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-manual-efi-acpi-aarch64.aarch64-latest.xml
@@ -7,7 +7,7 @@
   <os>
     <type arch='aarch64' machine='virt-4.0'>hvm</type>
     <loader readonly='yes' type='pflash'>/usr/share/AAVMF/AAVMF_CODE.fd</loader>
-    <nvram>/path/to/guest_VARS.fd</nvram>
+    <nvram template='/usr/share/AAVMF/AAVMF_VARS.fd'>/path/to/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-manual-efi-acpi-q35.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-manual-efi-acpi-q35.x86_64-latest.xml
index 2a36c46737..ff7793a377 100644
--- a/tests/qemuxml2xmloutdata/firmware-manual-efi-acpi-q35.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-manual-efi-acpi-q35.x86_64-latest.xml
@@ -7,7 +7,7 @@
   <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
     <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
-    <nvram>/path/to/guest_VARS.fd</nvram>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/path/to/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-manual-efi-noacpi-aarch64.aarch64-latest.xml b/tests/qemuxml2xmloutdata/firmware-manual-efi-noacpi-aarch64.aarch64-latest.xml
index 414c1d6611..1f642cd179 100644
--- a/tests/qemuxml2xmloutdata/firmware-manual-efi-noacpi-aarch64.aarch64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-manual-efi-noacpi-aarch64.aarch64-latest.xml
@@ -7,7 +7,7 @@
   <os>
     <type arch='aarch64' machine='virt-4.0'>hvm</type>
     <loader readonly='yes' type='pflash'>/usr/share/AAVMF/AAVMF_CODE.fd</loader>
-    <nvram>/path/to/guest_VARS.fd</nvram>
+    <nvram template='/usr/share/AAVMF/AAVMF_VARS.fd'>/path/to/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-manual-efi-nvram-file.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-manual-efi-nvram-file.x86_64-latest.xml
index 482d7987f6..cdb5d2b31a 100644
--- a/tests/qemuxml2xmloutdata/firmware-manual-efi-nvram-file.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-manual-efi-nvram-file.x86_64-latest.xml
@@ -7,7 +7,7 @@
   <os>
     <type arch='x86_64' machine='pc-i440fx-4.0'>hvm</type>
     <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
-    <nvram type='file'>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.fd' type='file'>
       <source file='/path/to/guest_VARS.fd'/>
     </nvram>
     <boot dev='hd'/>
diff --git a/tests/qemuxml2xmloutdata/firmware-manual-efi-secure.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-manual-efi-secure.x86_64-latest.xml
index cd7de76034..aa90d3e2f2 100644
--- a/tests/qemuxml2xmloutdata/firmware-manual-efi-secure.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-manual-efi-secure.x86_64-latest.xml
@@ -7,7 +7,7 @@
   <os>
     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
     <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.secboot.fd</loader>
-    <nvram>/path/to/guest_VARS.fd</nvram>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.secboot.fd'>/path/to/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/firmware-manual-efi.x86_64-latest.xml b/tests/qemuxml2xmloutdata/firmware-manual-efi.x86_64-latest.xml
index 97a9a6c5e6..ff6460d7b0 100644
--- a/tests/qemuxml2xmloutdata/firmware-manual-efi.x86_64-latest.xml
+++ b/tests/qemuxml2xmloutdata/firmware-manual-efi.x86_64-latest.xml
@@ -7,7 +7,7 @@
   <os>
     <type arch='x86_64' machine='pc-i440fx-4.0'>hvm</type>
     <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
-    <nvram>/path/to/guest_VARS.fd</nvram>
+    <nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/path/to/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
diff --git a/tests/qemuxml2xmloutdata/virtio-iommu-aarch64.aarch64-latest.xml b/tests/qemuxml2xmloutdata/virtio-iommu-aarch64.aarch64-latest.xml
index 19b881ce31..2813e742d1 100644
--- a/tests/qemuxml2xmloutdata/virtio-iommu-aarch64.aarch64-latest.xml
+++ b/tests/qemuxml2xmloutdata/virtio-iommu-aarch64.aarch64-latest.xml
@@ -4,8 +4,10 @@
   <memory unit='KiB'>1048576</memory>
   <currentMemory unit='KiB'>1048576</currentMemory>
   <vcpu placement='static'>1</vcpu>
-  <os firmware='efi'>
+  <os>
     <type arch='aarch64' machine='virt-6.0'>hvm</type>
+    <loader readonly='yes' type='pflash'>/usr/share/AAVMF/AAVMF_CODE.fd</loader>
+    <nvram template='/usr/share/AAVMF/AAVMF_VARS.fd'>/var/lib/libvirt/qemu/nvram/guest_VARS.fd</nvram>
     <boot dev='hd'/>
   </os>
   <features>
-- 
2.39.1



More information about the libvir-list mailing list