</os>
...
+ <!-- QEMU with UEFI manual firmware, secure boot and with NVRAM type 'file'-->
+ ...
+ <os>
+ <type>hvm</type>
+ <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
+ <nvram type='file' template='/usr/share/OVMF/OVMF_VARS.fd'>
+ <source file='/var/lib/libvirt/nvram/guest_VARS.fd'/>
+ </nvram>
+ <boot dev='hd'/>
+ </os>
+ ...
+
+ <!-- QEMU with UEFI manual firmware, secure boot and with network backed NVRAM'-->
+ ...
+ <os>
+ <type>hvm</type>
+ <loader readonly='yes' secure='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
+ <nvram type='network'>
+ <source protocol='iscsi' name='iqn.2013-07.com.example:iscsi-nopool/0'>
+ <host name='example.com' port='6000'/>
+ <auth username='myname'>
+ <secret type='iscsi' usage='mycluster_myname'/>
+ </auth>
+ </source>
+ </nvram>
+ <boot dev='hd'/>
+ </os>
+ ...
+
<!-- QEMU with automatic UEFI firmware and secure boot -->
...
<os firmware='efi'>
if the NVRAM file has been created by libvirt it is left behind and it is
management application's responsibility to save and remove file (if needed to
be persistent). :since:`Since 1.2.8`
+
+ :since:`Since 8.5.0`, it's possible for the element to have ``type`` attribute
+ (accepts values ``file``, ``block`` and ``network``) in that case the NVRAM
+ storage is described by a ``<source>`` sub-element with the same syntax as
+ ``disk``'s source. See `Hard drives, floppy disks, CDROMs`_.
+
+ **Note:** ``network`` backed NVRAM the variables are not instantiated from
+ the ``template`` and it's user's responsibility to provide a valid NVRAM image.
+
``boot``
The ``dev`` attribute takes one of the values "fd", "hd", "cdrom" or
"network" and is used to specify the next boot device to consider. The
}
+static int
+virDomainNvramDefParseXML(virDomainLoaderDef *loader,
+ xmlXPathContextPtr ctxt,
+ virDomainXMLOption *xmlopt,
+ unsigned int flags)
+{
+ g_autofree char *nvramType = virXPathString("string(./os/nvram/@type)", ctxt);
+ g_autoptr(virStorageSource) src = virStorageSourceNew();
+
+ src->type = VIR_STORAGE_TYPE_FILE;
+ src->format = VIR_STORAGE_FILE_RAW;
+
+ if (!nvramType) {
+ char *nvramPath = NULL;
+
+ if (!(nvramPath = virXPathString("string(./os/nvram[1])", ctxt)))
+ return 0; /* no nvram */
+
+ src->path = nvramPath;
+ } else {
+ xmlNodePtr sourceNode;
+
+ if ((src->type = virStorageTypeFromString(nvramType)) <= 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown disk type '%s'"), nvramType);
+ return -1;
+ }
+
+ if (!(sourceNode = virXPathNode("./os/nvram/source[1]", ctxt))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing source element for nvram"));
+ return -1;
+ }
+
+ if (virDomainStorageSourceParse(sourceNode, ctxt, src, flags, xmlopt) < 0)
+ return -1;
+
+ loader->newStyleNVRAM = true;
+ }
+
+ loader->nvram = g_steal_pointer(&src);
+ return 0;
+}
+
+
static int
virDomainSchedulerParseCommonAttrs(xmlNodePtr node,
virProcessSchedPolicy *policy,
static int
virDomainDefParseBootLoaderOptions(virDomainDef *def,
- xmlXPathContextPtr ctxt)
+ xmlXPathContextPtr ctxt,
+ virDomainXMLOption *xmlopt,
+ unsigned int flags)
{
xmlNodePtr loader_node = virXPathNode("./os/loader[1]", ctxt);
const bool fwAutoSelect = def->os.firmware != VIR_DOMAIN_OS_DEF_FIRMWARE_NONE;
- g_autofree char *nvramPath = NULL;
if (!loader_node)
return 0;
fwAutoSelect) < 0)
return -1;
- if ((nvramPath = virXPathString("string(./os/nvram[1])", ctxt))) {
- def->os.loader->nvram = virStorageSourceNew();
- def->os.loader->nvram->path = g_steal_pointer(&nvramPath);
- def->os.loader->nvram->type = VIR_STORAGE_TYPE_FILE;
- def->os.loader->nvram->format = VIR_STORAGE_FILE_RAW;
- }
+ if (virDomainNvramDefParseXML(def->os.loader, ctxt, xmlopt, flags) < 0)
+ return -1;
if (!fwAutoSelect)
def->os.loader->nvramTemplate = virXPathString("string(./os/nvram[1]/@template)", ctxt);
static int
virDomainDefParseBootOptions(virDomainDef *def,
- xmlXPathContextPtr ctxt)
+ xmlXPathContextPtr ctxt,
+ virDomainXMLOption *xmlopt,
+ unsigned int flags)
{
/*
* Booting options for different OS types....
if (virDomainDefParseBootFirmwareOptions(def, ctxt) < 0)
return -1;
- if (virDomainDefParseBootLoaderOptions(def, ctxt) < 0)
+ if (virDomainDefParseBootLoaderOptions(def, ctxt, xmlopt, flags) < 0)
return -1;
if (virDomainDefParseBootAcpiOptions(def, ctxt) < 0)
case VIR_DOMAIN_OSTYPE_UML:
virDomainDefParseBootKernelOptions(def, ctxt);
- if (virDomainDefParseBootLoaderOptions(def, ctxt) < 0)
+ if (virDomainDefParseBootLoaderOptions(def, ctxt, xmlopt, flags) < 0)
return -1;
break;
if (virDomainDefClockParse(def, ctxt) < 0)
return NULL;
- if (virDomainDefParseBootOptions(def, ctxt) < 0)
+ if (virDomainDefParseBootOptions(def, ctxt, xmlopt, flags) < 0)
return NULL;
/* analysis of the disk devices */
}
-static void
+static int
virDomainLoaderDefFormatNvram(virBuffer *buf,
- virDomainLoaderDef *loader)
+ virDomainLoaderDef *loader,
+ virDomainXMLOption *xmlopt,
+ unsigned int flags)
{
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
- g_auto(virBuffer) childBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) childBufDirect = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) childBufChild = VIR_BUFFER_INIT_CHILD(buf);
+ virBuffer *childBuf = &childBufDirect;
+ bool childNewline = false;
virBufferEscapeString(&attrBuf, " template='%s'", loader->nvramTemplate);
+
if (loader->nvram) {
- if (loader->nvram->type == VIR_STORAGE_TYPE_FILE)
- virBufferEscapeString(&childBuf, "%s", loader->nvram->path);
+ virStorageSource *src = loader->nvram;
+
+ if (!loader->newStyleNVRAM) {
+ virBufferEscapeString(&childBufDirect, "%s", src->path);
+ } else {
+ childNewline = true;
+ childBuf = &childBufChild;
+
+ virBufferAsprintf(&attrBuf, " type='%s'", virStorageTypeToString(src->type));
+
+ if (virDomainDiskSourceFormat(&childBufChild, src, "source", 0,
+ false, flags, false, false, xmlopt) < 0)
+ return -1;
+ }
}
- virXMLFormatElementInternal(buf, "nvram", &attrBuf, &childBuf, false, false);
+ virXMLFormatElementInternal(buf, "nvram", &attrBuf, childBuf, false, childNewline);
+
+ return 0;
}
-static void
+static int
virDomainLoaderDefFormat(virBuffer *buf,
- virDomainLoaderDef *loader)
+ virDomainLoaderDef *loader,
+ virDomainXMLOption *xmlopt,
+ unsigned int flags)
{
g_auto(virBuffer) loaderAttrBuf = VIR_BUFFER_INITIALIZER;
g_auto(virBuffer) loaderChildBuf = VIR_BUFFER_INITIALIZER;
virXMLFormatElementInternal(buf, "loader", &loaderAttrBuf, &loaderChildBuf, false, false);
- virDomainLoaderDefFormatNvram(buf, loader);
+ if (virDomainLoaderDefFormatNvram(buf, loader, xmlopt, flags) < 0)
+ return -1;
+
+ return 0;
}
static void
if (def->os.initgroup)
virBufferAsprintf(buf, "<initgroup>%s</initgroup>\n", def->os.initgroup);
- if (def->os.loader)
- virDomainLoaderDefFormat(buf, def->os.loader);
+ if (def->os.loader &&
+ virDomainLoaderDefFormat(buf, def->os.loader, xmlopt, flags) < 0)
+ return -1;
virBufferEscapeString(buf, "<kernel>%s</kernel>\n",
def->os.kernel);
virBufferEscapeString(buf, "<initrd>%s</initrd>\n",