qemu: Move firmware selection from startup to postparse

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@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
Andrea Bolognani 2023-01-24 17:01:48 +01:00
parent 68b80a705c
commit 9567f3ba1f
31 changed files with 317 additions and 137 deletions

View File

@ -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)

View File

@ -6646,8 +6646,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)) {

View File

@ -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_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
virDomainLoaderDef *loader = def->os.loader;
size_t i;
if (!loader)
return 0;
if (loader->type != VIR_DOMAIN_LOADER_TYPE_PFLASH) {
VIR_DEBUG("Ignoring legacy entries for '%s' loader",
virDomainLoaderTypeToString(loader->type));
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;
}
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;
bool needResult = true;
const bool reset_nvram = flags & VIR_QEMU_PROCESS_START_RESET_NVRAM;
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 (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 (!reset_nvram && virFileExists(def->os.loader->nvram->path))
return 0;
}
/* ... 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;
}
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

View File

@ -44,8 +44,7 @@ qemuFirmwareFetchConfigs(char ***firmwares,
int
qemuFirmwareFillDomain(virQEMUDriver *driver,
virDomainDef *def,
unsigned int flags);
virDomainDef *def);
int
qemuFirmwareGetSupported(const char *machine,

View File

@ -4601,42 +4601,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,
@ -6769,7 +6768,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;

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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'/>

View File

@ -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'/>

View File

@ -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'/>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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'/>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>