[libvirt] Don't mess up labelling of /dev/net/tun (bz #1141879) pflash/nvram support for UEFI/OVMF
Cole Robinson
crobinso at fedoraproject.org
Thu Sep 18 19:36:07 UTC 2014
commit 3ec523d168820f5c30a7cc63ab567b9cb063f152
Author: Cole Robinson <crobinso at redhat.com>
Date: Thu Sep 18 15:36:06 2014 -0400
Don't mess up labelling of /dev/net/tun (bz #1141879)
pflash/nvram support for UEFI/OVMF
...ke-daemon-spawning-a-bit-more-intelligent.patch | 50 +-
...Don-t-build-wireshark-on-f21-non-upstream.patch | 2 +-
0009-spec-Fix-preun-script-for-daemon.patch | 2 +-
...SELinuxSetTapFDLabel-Temporarily-revert-t.patch | 98 ++
0011-conf-Extend-loader-and-introduce-nvram.patch | 1296 ++++++++++++++++++++
...-qemu-Implement-extended-loader-and-nvram.patch | 222 ++++
0013-qemu-Automatically-create-NVRAM-store.patch | 579 +++++++++
0014-nvram-Fix-permissions.patch | 53 +
...DomainUndefineFlags-Allow-NVRAM-unlinking.patch | 148 +++
...n-Update-loader-example-to-match-the-rest.patch | 32 +
0017-domaincaps-Expose-UEFI-capability.patch | 338 +++++
...lities-Change-virQEMUCapsFillDomainCaps-s.patch | 192 +++
...caps-Expose-UEFI-binary-path-if-it-exists.patch | 444 +++++++
...est-Run-cleanly-on-systems-missing-OVMF-f.patch | 40 +
libvirt.spec | 36 +-
15 files changed, 3510 insertions(+), 22 deletions(-)
---
diff --git a/0007-rpc-make-daemon-spawning-a-bit-more-intelligent.patch b/0007-rpc-make-daemon-spawning-a-bit-more-intelligent.patch
index a8563b5..cbff862 100644
--- a/0007-rpc-make-daemon-spawning-a-bit-more-intelligent.patch
+++ b/0007-rpc-make-daemon-spawning-a-bit-more-intelligent.patch
@@ -1,6 +1,6 @@
-From 28b27787c5bb545df3c178fef682151c45b66784 Mon Sep 17 00:00:00 2001
+From b2735463b886ac88027cec0ff1a4dbaa4f8be739 Mon Sep 17 00:00:00 2001
From: Martin Kletzander <mkletzan at redhat.com>
-Date: Mon, 8 Sep 2014 07:46:39 +0200
+Date: Sun, 7 Sep 2014 20:41:11 +0200
Subject: [PATCH] rpc: make daemon spawning a bit more intelligent
This way it behaves more like the daemon itself does (acquiring a
@@ -10,12 +10,13 @@ Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=927369
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1138604
Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
+(cherry picked from commit bd9ad91a4036649645fffb1598213339263478de)
---
- src/rpc/virnetsocket.c | 57 ++++++++++++++++++++++++++++++++++++++++++++------
- 1 file changed, 51 insertions(+), 6 deletions(-)
+ src/rpc/virnetsocket.c | 67 ++++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 59 insertions(+), 8 deletions(-)
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
-index 306c9ea..fa9ba99 100644
+index 306c9ea..5feccf6 100644
--- a/src/rpc/virnetsocket.c
+++ b/src/rpc/virnetsocket.c
@@ -51,9 +51,11 @@
@@ -41,7 +42,7 @@ index 306c9ea..fa9ba99 100644
virSocketAddr localAddr;
virSocketAddr remoteAddr;
-@@ -583,16 +588,45 @@ int virNetSocketNewConnectUNIX(const char *path,
+@@ -583,16 +588,46 @@ int virNetSocketNewConnectUNIX(const char *path,
goto error;
}
@@ -55,7 +56,8 @@ index 306c9ea..fa9ba99 100644
+ if (virPidFileConstructPath(false, NULL, binname, &pidpath) < 0)
+ goto error;
+
-+ if ((pidfd = virPidFileAcquirePath(pidpath, false, getpid())) < 0) {
++ pidfd = virPidFileAcquirePath(pidpath, false, getpid());
++ if (pidfd < 0) {
+ /*
+ * This can happen in a very rare case of two clients spawning two
+ * daemons at the same time, and the error in the logs that gets
@@ -76,7 +78,7 @@ index 306c9ea..fa9ba99 100644
- * per-process, chmod() is racy and fchmod() has undefined
- * behaviour on sockets according to POSIX, so it doesn't
- * work outside Linux.
-+ * We already even acquired the pidfile, so noone else should be using
++ * We already even acquired the pidfile, so no one else should be using
+ * @path right now. So we're OK to unlink it and paying attention to
+ * the return value makes no real sense here. Only if it's not an
+ * abstract socket, of course.
@@ -91,19 +93,28 @@ index 306c9ea..fa9ba99 100644
*/
if ((pid = virFork()) < 0)
goto error;
-@@ -612,8 +646,9 @@ int virNetSocketNewConnectUNIX(const char *path,
+@@ -610,12 +645,16 @@ int virNetSocketNewConnectUNIX(const char *path,
+
+ if (status != EXIT_SUCCESS) {
/*
- * OK, so the subprocces failed to bind() the socket. This may mean
- * that another daemon was starting at the same time and succeeded
+- * OK, so the subprocces failed to bind() the socket. This may mean
+- * that another daemon was starting at the same time and succeeded
- * with its bind(). So we'll try connecting again, but this time
- * without spawning the daemon.
-+ * with its bind() (even though it should not happen because we
-+ * using a pidfile for the race). So we'll try connecting again,
-+ * but this time without spawning the daemon.
++ * OK, so the child failed to bind() the socket. This may mean that
++ * another daemon was starting at the same time and succeeded with
++ * its bind() (even though it should not happen because we using a
++ * pidfile for the race). So we'll try connecting again, but this
++ * time without spawning the daemon.
*/
spawnDaemon = false;
++ virPidFileDeletePath(pidpath);
++ VIR_FORCE_CLOSE(pidfd);
++ VIR_FORCE_CLOSE(passfd);
goto retry;
-@@ -632,6 +667,12 @@ int virNetSocketNewConnectUNIX(const char *path,
+ }
+
+@@ -632,6 +671,12 @@ int virNetSocketNewConnectUNIX(const char *path,
goto error;
}
@@ -116,11 +127,16 @@ index 306c9ea..fa9ba99 100644
if (virNetSocketForkDaemon(binary, passfd) < 0)
goto error;
}
-@@ -648,8 +689,12 @@ int virNetSocketNewConnectUNIX(const char *path,
+@@ -645,11 +690,17 @@ int virNetSocketNewConnectUNIX(const char *path,
+ if (!(*retsock = virNetSocketNew(&localAddr, &remoteAddr, true, fd, -1, 0)))
+ goto error;
+
++ VIR_FREE(pidpath);
++
return 0;
error:
-+ if (pidfd > 0)
++ if (pidfd >= 0)
+ virPidFileDeletePath(pidpath);
+ VIR_FREE(pidpath);
VIR_FORCE_CLOSE(fd);
diff --git a/0008-spec-Don-t-build-wireshark-on-f21-non-upstream.patch b/0008-spec-Don-t-build-wireshark-on-f21-non-upstream.patch
index 13fb17d..af15af4 100644
--- a/0008-spec-Don-t-build-wireshark-on-f21-non-upstream.patch
+++ b/0008-spec-Don-t-build-wireshark-on-f21-non-upstream.patch
@@ -1,4 +1,4 @@
-From 2950887a9e7800e0421dadb0b9c348adb087deca Mon Sep 17 00:00:00 2001
+From d437ccd8fef17c2bb119e98a034bdc56ff9425b2 Mon Sep 17 00:00:00 2001
From: Cole Robinson <crobinso at redhat.com>
Date: Mon, 15 Sep 2014 14:49:35 -0400
Subject: [PATCH] spec: Don't build wireshark on f21 (non upstream)
diff --git a/0009-spec-Fix-preun-script-for-daemon.patch b/0009-spec-Fix-preun-script-for-daemon.patch
index a273573..ec9d1c7 100644
--- a/0009-spec-Fix-preun-script-for-daemon.patch
+++ b/0009-spec-Fix-preun-script-for-daemon.patch
@@ -1,4 +1,4 @@
-From 09f0ff32b8925131c058de768751d3368f47a722 Mon Sep 17 00:00:00 2001
+From abb9c206877a937c2a509ec534c190b27c0b0e55 Mon Sep 17 00:00:00 2001
From: Jiri Denemark <jdenemar at redhat.com>
Date: Wed, 3 Sep 2014 10:51:14 +0200
Subject: [PATCH] spec: Fix preun script for daemon
diff --git a/0010-virSecuritySELinuxSetTapFDLabel-Temporarily-revert-t.patch b/0010-virSecuritySELinuxSetTapFDLabel-Temporarily-revert-t.patch
new file mode 100644
index 0000000..d83e534
--- /dev/null
+++ b/0010-virSecuritySELinuxSetTapFDLabel-Temporarily-revert-t.patch
@@ -0,0 +1,98 @@
+From c414cb524bdbc3555a5332fe75b40f8cf3ded0f4 Mon Sep 17 00:00:00 2001
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Thu, 18 Sep 2014 15:17:29 +0200
+Subject: [PATCH] virSecuritySELinuxSetTapFDLabel: Temporarily revert to old
+ behavior
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1141879
+
+A long time ago I've implemented support for so called multiqueue
+net. The idea was to let guest network traffic be processed by
+multiple host CPUs and thus increasing performance. However, this
+behavior is enabled by QEMU via special ioctl() iterated over the
+all tap FDs passed in by libvirt. Unfortunately, SELinux comes in
+and disallows the ioctl() call because the /dev/net/tun has label
+system_u:object_r:tun_tap_device_t:s0 and 'attach_queue' ioctl()
+is not allowed on tun_tap_device_t type. So after discussion with
+a SELinux developer we've decided that the FDs passed to the QEMU
+should be labelled with svirt_t type and SELinux policy will
+allow the ioctl(). Therefore I've made a patch
+(cf976d9dcf4e592261b14f03572) that does exactly this. The patch
+was fixed then by a4431931393aeb1ac5893f121151fa3df4fde612 and
+b635b7a1af0e64754016d758376f382470bc11e7. However, things are not
+that easy - even though the API to label FD is called
+(fsetfilecon_raw) the underlying file is labelled too! So
+effectively we are mangling /dev/net/tun label. Yes, that broke
+dozen of other application from openvpn, or boxes, to qemu
+running other domains.
+
+The best solution would be if SELinux provides a way to label an
+FD only, which could be then labeled when passed to the qemu.
+However that's a long path to go and we should fix this
+regression AQAP. So I went to talk to the SELinux developer again
+and we agreed on temporary solution that:
+
+1) All the three patches are reverted
+2) SELinux temporarily allows 'attach_queue' on the
+tun_tap_device_t
+
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+(cherry picked from commit ba7468dbb13f552a9177d01ea8bad155f9877bc3)
+---
+ src/security/security_selinux.c | 34 ++++++++++++++++++++++++++++++++--
+ 1 file changed, 32 insertions(+), 2 deletions(-)
+
+diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
+index e8c13db..c078cab 100644
+--- a/src/security/security_selinux.c
++++ b/src/security/security_selinux.c
+@@ -2330,17 +2330,47 @@ virSecuritySELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ }
+
+ static int
+-virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
++virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr def,
+ int fd)
+ {
++ struct stat buf;
++ security_context_t fcon = NULL;
+ virSecurityLabelDefPtr secdef;
++ char *str = NULL;
++ int rc = -1;
+
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+ if (!secdef || !secdef->label)
+ return 0;
+
+- return virSecuritySELinuxFSetFilecon(fd, secdef->imagelabel);
++ if (fstat(fd, &buf) < 0) {
++ virReportSystemError(errno, _("cannot stat tap fd %d"), fd);
++ goto cleanup;
++ }
++
++ if ((buf.st_mode & S_IFMT) != S_IFCHR) {
++ virReportError(VIR_ERR_INTERNAL_ERROR,
++ _("tap fd %d is not character device"), fd);
++ goto cleanup;
++ }
++
++ if (getContext(mgr, "/dev/tap.*", buf.st_mode, &fcon) < 0) {
++ virReportError(VIR_ERR_INTERNAL_ERROR,
++ _("cannot lookup default selinux label for tap fd %d"), fd);
++ goto cleanup;
++ }
++
++ if (!(str = virSecuritySELinuxContextAddRange(secdef->label, fcon))) {
++ goto cleanup;
++ } else {
++ rc = virSecuritySELinuxFSetFilecon(fd, str);
++ }
++
++ cleanup:
++ freecon(fcon);
++ VIR_FREE(str);
++ return rc;
+ }
+
+ static char *
diff --git a/0011-conf-Extend-loader-and-introduce-nvram.patch b/0011-conf-Extend-loader-and-introduce-nvram.patch
new file mode 100644
index 0000000..82bd6cd
--- /dev/null
+++ b/0011-conf-Extend-loader-and-introduce-nvram.patch
@@ -0,0 +1,1296 @@
+From 589e1c627bcfe2d8f26c6cb9ea0c68e9b902a931 Mon Sep 17 00:00:00 2001
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Wed, 6 Aug 2014 13:18:53 +0200
+Subject: [PATCH] conf: Extend <loader/> and introduce <nvram/>
+
+Up to now, users can configure BIOS via the <loader/> element. With
+the upcoming implementation of UEFI this is not enough as BIOS and
+UEFI are conceptually different. For instance, while BIOS is ROM, UEFI
+is programmable flash (although all writes to code section are
+denied). Therefore we need new attribute @type which will
+differentiate the two. Then, new attribute @readonly is introduced to
+reflect the fact that some images are RO.
+
+Moreover, the OVMF (which is going to be used mostly), works in two
+modes:
+1) Code and UEFI variable store is mixed in one file.
+2) Code and UEFI variable store is separated in two files
+
+The latter has advantage of updating the UEFI code without losing the
+configuration. However, in order to represent the latter case we need
+yet another XML element: <nvram/>. Currently, it has no additional
+attributes, it's just a bare element containing path to the variable
+store file.
+
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+Acked-by: Laszlo Ersek <lersek at redhat.com>
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+(cherry picked from commit 68bf13dbef8342eaee0bf57c73cebb60b7de11e8)
+---
+ docs/formatdomain.html.in | 19 ++++-
+ docs/schemas/domaincommon.rng | 21 ++++++
+ src/conf/domain_conf.c | 87 +++++++++++++++++++++-
+ src/conf/domain_conf.h | 22 +++++-
+ src/libvirt_private.syms | 3 +
+ src/qemu/qemu_command.c | 5 +-
+ src/security/virt-aa-helper.c | 4 +-
+ src/vbox/vbox_common.c | 7 +-
+ src/xenapi/xenapi_driver.c | 3 +-
+ src/xenconfig/xen_common.c | 7 +-
+ src/xenconfig/xen_sxpr.c | 16 ++--
+ tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.xml | 40 ++++++++++
+ .../qemuxml2xmlout-pci-bridge-many-disks.xml | 2 +-
+ tests/qemuxml2xmltest.c | 2 +
+ tests/sexpr2xmldata/sexpr2xml-fv-autoport.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-empty-kernel.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-force-hpet.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-force-nohpet.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-localtime.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-net-ioemu.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-net-netfront.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-parallel-tcp.xml | 2 +-
+ .../sexpr2xml-fv-serial-dev-2-ports.xml | 2 +-
+ .../sexpr2xml-fv-serial-dev-2nd-port.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-serial-file.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-serial-null.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-serial-pipe.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-serial-pty.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-serial-stdio.xml | 2 +-
+ .../sexpr2xml-fv-serial-tcp-telnet.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-serial-udp.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-serial-unix.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-sound-all.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-sound.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-usbtablet.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-utc.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv-v2.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-fv.xml | 2 +-
+ tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml | 2 +-
+ tests/xmconfigdata/test-escape-paths.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-force-hpet.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-force-nohpet.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-localtime.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-net-ioemu.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-net-netfront.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-new-cdrom.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-old-cdrom.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-parallel-tcp.xml | 2 +-
+ .../test-fullvirt-serial-dev-2-ports.xml | 2 +-
+ .../test-fullvirt-serial-dev-2nd-port.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-serial-file.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-serial-null.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-serial-pipe.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-serial-pty.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-serial-stdio.xml | 2 +-
+ .../test-fullvirt-serial-tcp-telnet.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-serial-tcp.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-serial-udp.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-serial-unix.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-sound.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-usbmouse.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-usbtablet.xml | 2 +-
+ tests/xmconfigdata/test-fullvirt-utc.xml | 2 +-
+ tests/xmconfigdata/test-no-source-cdrom.xml | 2 +-
+ tests/xmconfigdata/test-pci-devs.xml | 2 +-
+ 69 files changed, 269 insertions(+), 79 deletions(-)
+ create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.xml
+
+diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
+index 94236dd..757035a 100644
+--- a/docs/formatdomain.html.in
++++ b/docs/formatdomain.html.in
+@@ -102,7 +102,8 @@
+ ...
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader readonly='on' type='rom'>/usr/lib/xen/boot/hvmloader</loader>
++ <nvram>/var/lib/libvirt/nvram/guest_VARS.fd</nvram>
+ <boot dev='hd'/>
+ <boot dev='cdrom'/>
+ <bootmenu enable='yes' timeout='3000'/>
+@@ -129,7 +130,21 @@
+ used to assist the domain creation process. It is used by Xen
+ fully virtualized domains as well as setting the QEMU BIOS file
+ path for QEMU/KVM domains. <span class="since">Xen since 0.1.0,
+- QEMU/KVM since 0.9.12</span></dd>
++ QEMU/KVM since 0.9.12</span> Then, <span class="since">since
++ 1.2.8</span> it's possible for the element to have two
++ optional attributes: <code>readonly</code> (accepted values are
++ <code>yes</code> and <code>no</code>) to reflect the fact that the
++ image should be writable or read-only. The second attribute
++ <code>type</code> accepts values <code>rom</code> and
++ <code>pflash</code>. It tells the hypervisor where in the guest
++ memory the file should be mapped. For instance, if the loader
++ path points to an UEFI image, <code>type</code> should be
++ <code>pflash</code>.</dd>
++ <dt><code>nvram</code></dt>
++ <dd>Some UEFI firmwares may want to use a non-volatile memory to store
++ some variables. In the host, this is represented as a file and the
++ path to the file is stored in this element. <span class="since">Since
++ 1.2.8</span></dd>
+ <dt><code>boot</code></dt>
+ <dd>The <code>dev</code> attribute takes one of the values "fd", "hd",
+ "cdrom" or "network" and is used to specify the next boot device
+diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
+index cedceae..5d9c21c 100644
+--- a/docs/schemas/domaincommon.rng
++++ b/docs/schemas/domaincommon.rng
+@@ -242,6 +242,27 @@
+ <interleave>
+ <optional>
+ <element name="loader">
++ <optional>
++ <attribute name="readonly">
++ <choice>
++ <value>yes</value>
++ <value>no</value>
++ </choice>
++ </attribute>
++ </optional>
++ <optional>
++ <attribute name="type">
++ <choice>
++ <value>rom</value>
++ <value>pflash</value>
++ </choice>
++ </attribute>
++ </optional>
++ <ref name="absFilePath"/>
++ </element>
++ </optional>
++ <optional>
++ <element name="nvram">
+ <ref name="absFilePath"/>
+ </element>
+ </optional>
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 53ef694..6ee5c17 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -777,6 +777,11 @@ VIR_ENUM_IMPL(virDomainDiskMirrorState, VIR_DOMAIN_DISK_MIRROR_STATE_LAST,
+ "abort",
+ "pivot")
+
++VIR_ENUM_IMPL(virDomainLoader,
++ VIR_DOMAIN_LOADER_TYPE_LAST,
++ "rom",
++ "pflash")
++
+ /* Internal mapping: subset of block job types that can be present in
+ * <mirror> XML (remaining types are not two-phase). */
+ VIR_ENUM_DECL(virDomainBlockJob)
+@@ -2010,6 +2015,17 @@ virDomainPanicDefFree(virDomainPanicDefPtr panic)
+ VIR_FREE(panic);
+ }
+
++void
++virDomainLoaderDefFree(virDomainLoaderDefPtr loader)
++{
++ if (!loader)
++ return;
++
++ VIR_FREE(loader->path);
++ VIR_FREE(loader->nvram);
++ VIR_FREE(loader);
++}
++
+ void virDomainDefFree(virDomainDefPtr def)
+ {
+ size_t i;
+@@ -2115,7 +2131,7 @@ void virDomainDefFree(virDomainDefPtr def)
+ VIR_FREE(def->os.cmdline);
+ VIR_FREE(def->os.dtb);
+ VIR_FREE(def->os.root);
+- VIR_FREE(def->os.loader);
++ virDomainLoaderDefFree(def->os.loader);
+ VIR_FREE(def->os.bootloader);
+ VIR_FREE(def->os.bootloaderArgs);
+
+@@ -11661,6 +11677,42 @@ virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDefPtr def)
+ return 0;
+ }
+
++static int
++virDomainLoaderDefParseXML(xmlNodePtr node,
++ virDomainLoaderDefPtr loader)
++{
++ int ret = -1;
++ char *readonly_str = NULL;
++ char *type_str = NULL;
++
++ readonly_str = virXMLPropString(node, "readonly");
++ type_str = virXMLPropString(node, "type");
++ loader->path = (char *) xmlNodeGetContent(node);
++
++ if (readonly_str &&
++ (loader->readonly = virTristateBoolTypeFromString(readonly_str)) <= 0) {
++ virReportError(VIR_ERR_XML_DETAIL,
++ _("unknown readonly value: %s"), readonly_str);
++ goto cleanup;
++ }
++
++ if (type_str) {
++ int type;
++ if ((type = virDomainLoaderTypeFromString(type_str)) < 0) {
++ virReportError(VIR_ERR_XML_DETAIL,
++ _("unknown type value: %s"), type_str);
++ goto cleanup;
++ }
++ loader->type = type;
++ }
++
++ ret = 0;
++ cleanup:
++ VIR_FREE(readonly_str);
++ VIR_FREE(type_str);
++ return ret;
++}
++
+ static virDomainDefPtr
+ virDomainDefParseXML(xmlDocPtr xml,
+ xmlNodePtr root,
+@@ -12701,12 +12753,22 @@ virDomainDefParseXML(xmlDocPtr xml,
+ if (STREQ(def->os.type, "xen") ||
+ STREQ(def->os.type, "hvm") ||
+ STREQ(def->os.type, "uml")) {
++ xmlNodePtr loader_node;
++
+ def->os.kernel = virXPathString("string(./os/kernel[1])", ctxt);
+ def->os.initrd = virXPathString("string(./os/initrd[1])", ctxt);
+ def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt);
+ def->os.dtb = virXPathString("string(./os/dtb[1])", ctxt);
+ def->os.root = virXPathString("string(./os/root[1])", ctxt);
+- def->os.loader = virXPathString("string(./os/loader[1])", ctxt);
++ if ((loader_node = virXPathNode("./os/loader[1]", ctxt))) {
++ if (VIR_ALLOC(def->os.loader) < 0)
++ goto error;
++
++ if (virDomainLoaderDefParseXML(loader_node, def->os.loader) < 0)
++ goto error;
++
++ def->os.loader->nvram = virXPathString("string(./os/nvram[1])", ctxt);
++ }
+ }
+
+ if (STREQ(def->os.type, "hvm")) {
+@@ -17789,6 +17851,23 @@ virDomainHugepagesFormat(virBufferPtr buf,
+ virBufferAddLit(buf, "</hugepages>\n");
+ }
+
++static void
++virDomainLoaderDefFormat(virBufferPtr buf,
++ virDomainLoaderDefPtr loader)
++{
++ const char *readonly = virTristateBoolTypeToString(loader->readonly);
++ const char *type = virDomainLoaderTypeToString(loader->type);
++
++ virBufferAddLit(buf, "<loader");
++
++ if (loader->readonly)
++ virBufferAsprintf(buf, " readonly='%s'", readonly);
++
++ virBufferAsprintf(buf, " type='%s'>", type);
++
++ virBufferEscapeString(buf, "%s</loader>\n", loader->path);
++ virBufferEscapeString(buf, "<nvram>%s</nvram>\n", loader->nvram);
++}
+
+ static bool
+ virDomainDefHasCapabilitiesFeatures(virDomainDefPtr def)
+@@ -18109,8 +18188,8 @@ virDomainDefFormatInternal(virDomainDefPtr def,
+ for (i = 0; def->os.initargv && def->os.initargv[i]; i++)
+ virBufferEscapeString(buf, "<initarg>%s</initarg>\n",
+ def->os.initargv[i]);
+- virBufferEscapeString(buf, "<loader>%s</loader>\n",
+- def->os.loader);
++ if (def->os.loader)
++ virDomainLoaderDefFormat(buf, def->os.loader);
+ virBufferEscapeString(buf, "<kernel>%s</kernel>\n",
+ def->os.kernel);
+ virBufferEscapeString(buf, "<initrd>%s</initrd>\n",
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index 9586c3b..c97a10c 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -1628,6 +1628,26 @@ struct _virDomainBIOSDef {
+ int rt_delay;
+ };
+
++typedef enum {
++ VIR_DOMAIN_LOADER_TYPE_ROM = 0,
++ VIR_DOMAIN_LOADER_TYPE_PFLASH,
++
++ VIR_DOMAIN_LOADER_TYPE_LAST
++} virDomainLoader;
++
++VIR_ENUM_DECL(virDomainLoader)
++
++typedef struct _virDomainLoaderDef virDomainLoaderDef;
++typedef virDomainLoaderDef *virDomainLoaderDefPtr;
++struct _virDomainLoaderDef {
++ char *path;
++ int readonly; /* enum virTristateBool */
++ virDomainLoader type;
++ char *nvram; /* path to non-volatile RAM */
++};
++
++void virDomainLoaderDefFree(virDomainLoaderDefPtr loader);
++
+ /* Operating system configuration data & machine / arch */
+ typedef struct _virDomainOSDef virDomainOSDef;
+ typedef virDomainOSDef *virDomainOSDefPtr;
+@@ -1647,7 +1667,7 @@ struct _virDomainOSDef {
+ char *cmdline;
+ char *dtb;
+ char *root;
+- char *loader;
++ virDomainLoaderDefPtr loader;
+ char *bootloader;
+ char *bootloaderArgs;
+ int smbios_mode;
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index f8d9b95..18cf0c2 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -313,6 +313,9 @@ virDomainLifecycleTypeFromString;
+ virDomainLifecycleTypeToString;
+ virDomainListFree;
+ virDomainLiveConfigHelperMethod;
++virDomainLoaderDefFree;
++virDomainLoaderTypeFromString;
++virDomainLoaderTypeToString;
+ virDomainLockFailureTypeFromString;
+ virDomainLockFailureTypeToString;
+ virDomainMemballoonModelTypeFromString;
+diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
+index 2184caa..3cb2e0b 100644
+--- a/src/qemu/qemu_command.c
++++ b/src/qemu/qemu_command.c
+@@ -7527,7 +7527,7 @@ qemuBuildCommandLine(virConnectPtr conn,
+
+ if (def->os.loader) {
+ virCommandAddArg(cmd, "-bios");
+- virCommandAddArg(cmd, def->os.loader);
++ virCommandAddArg(cmd, def->os.loader->path);
+ }
+
+ /* Set '-m MB' based on maxmem, because the lower 'memory' limit
+@@ -11347,7 +11347,8 @@ qemuParseCommandLine(virCapsPtr qemuCaps,
+ goto error;
+ } else if (STREQ(arg, "-bios")) {
+ WANT_VALUE();
+- if (VIR_STRDUP(def->os.loader, val) < 0)
++ if (VIR_ALLOC(def->os.loader) < 0 ||
++ VIR_STRDUP(def->os.loader->path, val) < 0)
+ goto error;
+ } else if (STREQ(arg, "-initrd")) {
+ WANT_VALUE();
+diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
+index a0b104c..311ce3b 100644
+--- a/src/security/virt-aa-helper.c
++++ b/src/security/virt-aa-helper.c
+@@ -1006,8 +1006,8 @@ get_files(vahControl * ctl)
+ if (vah_add_file(&buf, ctl->def->os.dtb, "r") != 0)
+ goto cleanup;
+
+- if (ctl->def->os.loader && ctl->def->os.loader)
+- if (vah_add_file(&buf, ctl->def->os.loader, "r") != 0)
++ if (ctl->def->os.loader && ctl->def->os.loader->path)
++ if (vah_add_file(&buf, ctl->def->os.loader->path, "r") != 0)
+ goto cleanup;
+
+ for (i = 0; i < ctl->def->ngraphics; i++) {
+diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c
+index b186ea8..6f56c59 100644
+--- a/src/vbox/vbox_common.c
++++ b/src/vbox/vbox_common.c
+@@ -988,7 +988,12 @@ vboxSetBootDeviceOrder(virDomainDefPtr def, vboxGlobalData *data,
+ VIR_DEBUG("def->os.initrd %s", def->os.initrd);
+ VIR_DEBUG("def->os.cmdline %s", def->os.cmdline);
+ VIR_DEBUG("def->os.root %s", def->os.root);
+- VIR_DEBUG("def->os.loader %s", def->os.loader);
++ if (def->os.loader) {
++ VIR_DEBUG("def->os.loader->path %s", def->os.loader->path);
++ VIR_DEBUG("def->os.loader->readonly %d", def->os.loader->readonly);
++ VIR_DEBUG("def->os.loader->type %d", def->os.loader->type);
++ VIR_DEBUG("def->os.loader->nvram %s", def->os.loader->nvram);
++ }
+ VIR_DEBUG("def->os.bootloader %s", def->os.bootloader);
+ VIR_DEBUG("def->os.bootloaderArgs %s", def->os.bootloaderArgs);
+
+diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c
+index 50331c9..a6eaccc 100644
+--- a/src/xenapi/xenapi_driver.c
++++ b/src/xenapi/xenapi_driver.c
+@@ -1427,7 +1427,8 @@ xenapiDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
+ VIR_FREE(boot_policy);
+ goto error;
+ }
+- if (VIR_STRDUP(defPtr->os.loader, "pygrub") < 0) {
++ if (VIR_ALLOC(defPtr->os.loader) < 0 ||
++ VIR_STRDUP(defPtr->os.loader->path, "pygrub") < 0) {
+ VIR_FREE(boot_policy);
+ goto error;
+ }
+diff --git a/src/xenconfig/xen_common.c b/src/xenconfig/xen_common.c
+index 9beaf6c..abd77b5 100644
+--- a/src/xenconfig/xen_common.c
++++ b/src/xenconfig/xen_common.c
+@@ -1065,7 +1065,8 @@ xenParseOS(virConfPtr conf, virDomainDefPtr def)
+ if (STREQ(def->os.type, "hvm")) {
+ const char *boot;
+
+- if (xenConfigCopyString(conf, "kernel", &def->os.loader) < 0)
++ if (VIR_ALLOC(def->os.loader) < 0 ||
++ xenConfigCopyString(conf, "kernel", &def->os.loader->path) < 0)
+ return -1;
+
+ if (xenConfigGetString(conf, "boot", &boot, "c") < 0)
+@@ -1740,8 +1741,8 @@ xenFormatOS(virConfPtr conf, virDomainDefPtr def)
+ if (xenXMConfigSetString(conf, "builder", "hvm") < 0)
+ return -1;
+
+- if (def->os.loader &&
+- xenXMConfigSetString(conf, "kernel", def->os.loader) < 0)
++ if (def->os.loader && def->os.loader->path &&
++ xenXMConfigSetString(conf, "kernel", def->os.loader->path) < 0)
+ return -1;
+
+ for (i = 0; i < def->os.nBootDevs; i++) {
+diff --git a/src/xenconfig/xen_sxpr.c b/src/xenconfig/xen_sxpr.c
+index ff81c36..e8b9f59 100644
+--- a/src/xenconfig/xen_sxpr.c
++++ b/src/xenconfig/xen_sxpr.c
+@@ -93,13 +93,15 @@ xenParseSxprOS(const struct sexpr *node,
+ int hvm)
+ {
+ if (hvm) {
+- if (sexpr_node_copy(node, "domain/image/hvm/loader", &def->os.loader) < 0)
++ if (VIR_ALLOC(def->os.loader) < 0)
+ goto error;
+- if (def->os.loader == NULL) {
+- if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.loader) < 0)
++ if (sexpr_node_copy(node, "domain/image/hvm/loader", &def->os.loader->path) < 0)
++ goto error;
++ if (def->os.loader->path == NULL) {
++ if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.loader->path) < 0)
+ goto error;
+
+- if (def->os.loader == NULL) {
++ if (def->os.loader->path == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("domain information incomplete, missing HVM loader"));
+ return -1;
+@@ -128,7 +130,7 @@ xenParseSxprOS(const struct sexpr *node,
+ /* If HVM kenrel == loader, then old xend, so kill off kernel */
+ if (hvm &&
+ def->os.kernel &&
+- STREQ(def->os.kernel, def->os.loader)) {
++ STREQ(def->os.kernel, def->os.loader->path)) {
+ VIR_FREE(def->os.kernel);
+ }
+ /* Drop kernel argument that has no value */
+@@ -2279,9 +2281,9 @@ xenFormatSxpr(virConnectPtr conn,
+ if (hvm) {
+ char bootorder[VIR_DOMAIN_BOOT_LAST+1];
+ if (def->os.kernel)
+- virBufferEscapeSexpr(&buf, "(loader '%s')", def->os.loader);
++ virBufferEscapeSexpr(&buf, "(loader '%s')", def->os.loader->path);
+ else
+- virBufferEscapeSexpr(&buf, "(kernel '%s')", def->os.loader);
++ virBufferEscapeSexpr(&buf, "(kernel '%s')", def->os.loader->path);
+
+ virBufferAsprintf(&buf, "(vcpus %u)", def->maxvcpus);
+ if (def->vcpus < def->maxvcpus)
+diff --git a/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.xml b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.xml
+new file mode 100644
+index 0000000..d8270b1
+--- /dev/null
++++ b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.xml
+@@ -0,0 +1,40 @@
++<domain type='qemu'>
++ <name>test-bios</name>
++ <uuid>362d1fc1-df7d-193e-5c18-49a71bd1da66</uuid>
++ <memory unit='KiB'>1048576</memory>
++ <currentMemory unit='KiB'>1048576</currentMemory>
++ <vcpu placement='static'>1</vcpu>
++ <os>
++ <type arch='x86_64' machine='pc'>hvm</type>
++ <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
++ <nvram>/usr/share/OVMF/OVMF_VARS.fd</nvram>
++ <boot dev='hd'/>
++ <bootmenu enable='yes'/>
++ </os>
++ <features>
++ <acpi/>
++ </features>
++ <clock offset='utc'/>
++ <on_poweroff>destroy</on_poweroff>
++ <on_reboot>restart</on_reboot>
++ <on_crash>restart</on_crash>
++ <devices>
++ <emulator>/usr/bin/qemu</emulator>
++ <disk type='block' device='disk'>
++ <source dev='/dev/HostVG/QEMUGuest1'/>
++ <target dev='hda' bus='ide'/>
++ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
++ </disk>
++ <controller type='usb' index='0'/>
++ <controller type='ide' index='0'/>
++ <controller type='pci' index='0' model='pci-root'/>
++ <serial type='pty'>
++ <target port='0'/>
++ </serial>
++ <console type='pty'>
++ <target type='serial' port='0'/>
++ </console>
++ <input type='tablet' bus='usb'/>
++ <memballoon model='virtio'/>
++ </devices>
++</domain>
+diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pci-bridge-many-disks.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pci-bridge-many-disks.xml
+index d469b8b..d49f5f4 100644
+--- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pci-bridge-many-disks.xml
++++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pci-bridge-many-disks.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-i440fx-1.4'>hvm</type>
+- <loader>/usr/share/seabios/bios.bin</loader>
++ <loader type='rom'>/usr/share/seabios/bios.bin</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
+index b4ab671..1835fe6 100644
+--- a/tests/qemuxml2xmltest.c
++++ b/tests/qemuxml2xmltest.c
+@@ -395,6 +395,8 @@ mymain(void)
+ DO_TEST_DIFFERENT("numatune-memnode");
+ DO_TEST("numatune-memnode-no-memory");
+
++ DO_TEST("bios-nvram");
++
+ virObjectUnref(driver.caps);
+ virObjectUnref(driver.xmlopt);
+
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-autoport.xml b/tests/sexpr2xmldata/sexpr2xml-fv-autoport.xml
+index 69fe9ef..761952c 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-autoport.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-autoport.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-empty-kernel.xml b/tests/sexpr2xmldata/sexpr2xml-fv-empty-kernel.xml
+index 3c3147d..2898098 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-empty-kernel.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-empty-kernel.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-force-hpet.xml b/tests/sexpr2xmldata/sexpr2xml-fv-force-hpet.xml
+index 716f16b..a0fe30d 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-force-hpet.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-force-hpet.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-force-nohpet.xml b/tests/sexpr2xmldata/sexpr2xml-fv-force-nohpet.xml
+index 3dd648b..851797d 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-force-nohpet.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-force-nohpet.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml b/tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml
+index 29c1335..09cfe19 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>2</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <kernel>/var/lib/xen/vmlinuz.2Dn2YT</kernel>
+ <initrd>/var/lib/xen/initrd.img.0u-Vhq</initrd>
+ <cmdline> method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os </cmdline>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.xml b/tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.xml
+index 9c59644..44c0f61 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-localtime.xml b/tests/sexpr2xmldata/sexpr2xml-fv-localtime.xml
+index 67b0b95..29007f0 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-localtime.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-localtime.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-net-ioemu.xml b/tests/sexpr2xmldata/sexpr2xml-fv-net-ioemu.xml
+index 86b32e9..3dbc999 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-net-ioemu.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-net-ioemu.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-net-netfront.xml b/tests/sexpr2xmldata/sexpr2xml-fv-net-netfront.xml
+index ed7da80..d96350e 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-net-netfront.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-net-netfront.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-parallel-tcp.xml b/tests/sexpr2xmldata/sexpr2xml-fv-parallel-tcp.xml
+index ed3fde6..7ad377c 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-parallel-tcp.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-parallel-tcp.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.xml
+index 7f5a729..adba6cb 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2-ports.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2nd-port.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2nd-port.xml
+index 10f84dc..b6c3601 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2nd-port.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-dev-2nd-port.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-file.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-file.xml
+index a3fd231..dabe679 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-serial-file.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-file.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-null.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-null.xml
+index b3f77c9..fb19d74 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-serial-null.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-null.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-pipe.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-pipe.xml
+index e217161..5aa425b 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-serial-pipe.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-pipe.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-pty.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-pty.xml
+index 3ad2264..3c2ca21 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-serial-pty.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-pty.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-stdio.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-stdio.xml
+index 001df56..160edbd 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-serial-stdio.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-stdio.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp-telnet.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp-telnet.xml
+index c2496fd..4396efc 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp-telnet.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp-telnet.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp.xml
+index 6dc047e..3d17b58 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-udp.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-udp.xml
+index 7ccaeac..fc3d457 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-serial-udp.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-udp.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-serial-unix.xml b/tests/sexpr2xmldata/sexpr2xml-fv-serial-unix.xml
+index b5ad413..14b54f1 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-serial-unix.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-serial-unix.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-sound-all.xml b/tests/sexpr2xmldata/sexpr2xml-fv-sound-all.xml
+index 7183e79..912df56 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-sound-all.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-sound-all.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-sound.xml b/tests/sexpr2xmldata/sexpr2xml-fv-sound.xml
+index 7183e79..912df56 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-sound.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-sound.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.xml b/tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.xml
+index ae90e33..19eac3b 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-usbtablet.xml b/tests/sexpr2xmldata/sexpr2xml-fv-usbtablet.xml
+index f81c47a..40ac8a9 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-usbtablet.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-usbtablet.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-utc.xml b/tests/sexpr2xmldata/sexpr2xml-fv-utc.xml
+index c783d93..97f2beb 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-utc.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-utc.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv-v2.xml b/tests/sexpr2xmldata/sexpr2xml-fv-v2.xml
+index bd3b107..493d1b5 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv-v2.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv-v2.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-fv.xml b/tests/sexpr2xmldata/sexpr2xml-fv.xml
+index c783d93..97f2beb 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-fv.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-fv.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml b/tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml
+index 00d18ce..a3cd7be 100644
+--- a/tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml
++++ b/tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-escape-paths.xml b/tests/xmconfigdata/test-escape-paths.xml
+index de3a7e2..623eaa1 100644
+--- a/tests/xmconfigdata/test-escape-paths.xml
++++ b/tests/xmconfigdata/test-escape-paths.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader&test</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader&test</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-force-hpet.xml b/tests/xmconfigdata/test-fullvirt-force-hpet.xml
+index 75f8724..57a6531 100644
+--- a/tests/xmconfigdata/test-fullvirt-force-hpet.xml
++++ b/tests/xmconfigdata/test-fullvirt-force-hpet.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-force-nohpet.xml b/tests/xmconfigdata/test-fullvirt-force-nohpet.xml
+index e5741b6..f6ebcf6 100644
+--- a/tests/xmconfigdata/test-fullvirt-force-nohpet.xml
++++ b/tests/xmconfigdata/test-fullvirt-force-nohpet.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-localtime.xml b/tests/xmconfigdata/test-fullvirt-localtime.xml
+index 8b97e5b..36ab389 100644
+--- a/tests/xmconfigdata/test-fullvirt-localtime.xml
++++ b/tests/xmconfigdata/test-fullvirt-localtime.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-net-ioemu.xml b/tests/xmconfigdata/test-fullvirt-net-ioemu.xml
+index f22c085..3618bae 100644
+--- a/tests/xmconfigdata/test-fullvirt-net-ioemu.xml
++++ b/tests/xmconfigdata/test-fullvirt-net-ioemu.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-net-netfront.xml b/tests/xmconfigdata/test-fullvirt-net-netfront.xml
+index 177bb6a..6a2a439 100644
+--- a/tests/xmconfigdata/test-fullvirt-net-netfront.xml
++++ b/tests/xmconfigdata/test-fullvirt-net-netfront.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-new-cdrom.xml b/tests/xmconfigdata/test-fullvirt-new-cdrom.xml
+index f22c085..3618bae 100644
+--- a/tests/xmconfigdata/test-fullvirt-new-cdrom.xml
++++ b/tests/xmconfigdata/test-fullvirt-new-cdrom.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-old-cdrom.xml b/tests/xmconfigdata/test-fullvirt-old-cdrom.xml
+index a592630..7d6014d 100644
+--- a/tests/xmconfigdata/test-fullvirt-old-cdrom.xml
++++ b/tests/xmconfigdata/test-fullvirt-old-cdrom.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-parallel-tcp.xml b/tests/xmconfigdata/test-fullvirt-parallel-tcp.xml
+index 738e5ab..9b1fd26 100644
+--- a/tests/xmconfigdata/test-fullvirt-parallel-tcp.xml
++++ b/tests/xmconfigdata/test-fullvirt-parallel-tcp.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-serial-dev-2-ports.xml b/tests/xmconfigdata/test-fullvirt-serial-dev-2-ports.xml
+index 753831a..a64d40b 100644
+--- a/tests/xmconfigdata/test-fullvirt-serial-dev-2-ports.xml
++++ b/tests/xmconfigdata/test-fullvirt-serial-dev-2-ports.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-serial-dev-2nd-port.xml b/tests/xmconfigdata/test-fullvirt-serial-dev-2nd-port.xml
+index 1a55080..ce2cddb 100644
+--- a/tests/xmconfigdata/test-fullvirt-serial-dev-2nd-port.xml
++++ b/tests/xmconfigdata/test-fullvirt-serial-dev-2nd-port.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-serial-file.xml b/tests/xmconfigdata/test-fullvirt-serial-file.xml
+index 0d2ac79..36883de 100644
+--- a/tests/xmconfigdata/test-fullvirt-serial-file.xml
++++ b/tests/xmconfigdata/test-fullvirt-serial-file.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-serial-null.xml b/tests/xmconfigdata/test-fullvirt-serial-null.xml
+index d4b4ae9..982f9d6 100644
+--- a/tests/xmconfigdata/test-fullvirt-serial-null.xml
++++ b/tests/xmconfigdata/test-fullvirt-serial-null.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-serial-pipe.xml b/tests/xmconfigdata/test-fullvirt-serial-pipe.xml
+index 6596dfc..82a1d9b 100644
+--- a/tests/xmconfigdata/test-fullvirt-serial-pipe.xml
++++ b/tests/xmconfigdata/test-fullvirt-serial-pipe.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-serial-pty.xml b/tests/xmconfigdata/test-fullvirt-serial-pty.xml
+index 6c55abb..56ccbea 100644
+--- a/tests/xmconfigdata/test-fullvirt-serial-pty.xml
++++ b/tests/xmconfigdata/test-fullvirt-serial-pty.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-serial-stdio.xml b/tests/xmconfigdata/test-fullvirt-serial-stdio.xml
+index 461f143..e2e9330 100644
+--- a/tests/xmconfigdata/test-fullvirt-serial-stdio.xml
++++ b/tests/xmconfigdata/test-fullvirt-serial-stdio.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-serial-tcp-telnet.xml b/tests/xmconfigdata/test-fullvirt-serial-tcp-telnet.xml
+index d2fa7bf..d68d77c 100644
+--- a/tests/xmconfigdata/test-fullvirt-serial-tcp-telnet.xml
++++ b/tests/xmconfigdata/test-fullvirt-serial-tcp-telnet.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-serial-tcp.xml b/tests/xmconfigdata/test-fullvirt-serial-tcp.xml
+index 60ab8bd..aa3ed5c 100644
+--- a/tests/xmconfigdata/test-fullvirt-serial-tcp.xml
++++ b/tests/xmconfigdata/test-fullvirt-serial-tcp.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-serial-udp.xml b/tests/xmconfigdata/test-fullvirt-serial-udp.xml
+index 6c21cd2..256c722 100644
+--- a/tests/xmconfigdata/test-fullvirt-serial-udp.xml
++++ b/tests/xmconfigdata/test-fullvirt-serial-udp.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-serial-unix.xml b/tests/xmconfigdata/test-fullvirt-serial-unix.xml
+index f21534e..235c8d4 100644
+--- a/tests/xmconfigdata/test-fullvirt-serial-unix.xml
++++ b/tests/xmconfigdata/test-fullvirt-serial-unix.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-sound.xml b/tests/xmconfigdata/test-fullvirt-sound.xml
+index f09c16d..1429d10 100644
+--- a/tests/xmconfigdata/test-fullvirt-sound.xml
++++ b/tests/xmconfigdata/test-fullvirt-sound.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-usbmouse.xml b/tests/xmconfigdata/test-fullvirt-usbmouse.xml
+index 18a7ff0..25857f1 100644
+--- a/tests/xmconfigdata/test-fullvirt-usbmouse.xml
++++ b/tests/xmconfigdata/test-fullvirt-usbmouse.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-usbtablet.xml b/tests/xmconfigdata/test-fullvirt-usbtablet.xml
+index 5cbb007..31b1176 100644
+--- a/tests/xmconfigdata/test-fullvirt-usbtablet.xml
++++ b/tests/xmconfigdata/test-fullvirt-usbtablet.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-fullvirt-utc.xml b/tests/xmconfigdata/test-fullvirt-utc.xml
+index f22c085..3618bae 100644
+--- a/tests/xmconfigdata/test-fullvirt-utc.xml
++++ b/tests/xmconfigdata/test-fullvirt-utc.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='cdrom'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-no-source-cdrom.xml b/tests/xmconfigdata/test-no-source-cdrom.xml
+index 2a457b2..74f1be1 100644
+--- a/tests/xmconfigdata/test-no-source-cdrom.xml
++++ b/tests/xmconfigdata/test-no-source-cdrom.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
+diff --git a/tests/xmconfigdata/test-pci-devs.xml b/tests/xmconfigdata/test-pci-devs.xml
+index f828056..1911734 100644
+--- a/tests/xmconfigdata/test-pci-devs.xml
++++ b/tests/xmconfigdata/test-pci-devs.xml
+@@ -6,7 +6,7 @@
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='xenfv'>hvm</type>
+- <loader>/usr/lib/xen/boot/hvmloader</loader>
++ <loader type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <boot dev='hd'/>
+ </os>
+ <features>
diff --git a/0012-qemu-Implement-extended-loader-and-nvram.patch b/0012-qemu-Implement-extended-loader-and-nvram.patch
new file mode 100644
index 0000000..c5e57f3
--- /dev/null
+++ b/0012-qemu-Implement-extended-loader-and-nvram.patch
@@ -0,0 +1,222 @@
+From ac0859aae7162255848effdc560368266845dfce Mon Sep 17 00:00:00 2001
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Thu, 7 Aug 2014 13:50:00 +0200
+Subject: [PATCH] qemu: Implement extended loader and nvram
+
+QEMU now supports UEFI with the following command line:
+
+ -drive file=/usr/share/OVMF/OVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on \
+ -drive file=/usr/share/OVMF/OVMF_VARS.fd,if=pflash,format=raw,unit=1 \
+
+where the first line reflects <loader> and the second one <nvram>.
+Moreover, these two lines obsolete the -bios argument.
+
+Note that UEFI is unusable without ACPI. This is handled properly now.
+Among with this extension, the variable file is expected to be
+writable and hence we need security drivers to label it.
+
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+Acked-by: Laszlo Ersek <lersek at redhat.com>
+(cherry picked from commit 542899168c382610dbad9a597d27ef3d7c699f68)
+---
+ src/qemu/qemu_command.c | 94 +++++++++++++++++++++-
+ src/security/security_dac.c | 8 ++
+ src/security/security_selinux.c | 8 ++
+ .../qemuxml2argvdata/qemuxml2argv-bios-nvram.args | 10 +++
+ tests/qemuxml2argvtest.c | 2 +
+ 5 files changed, 118 insertions(+), 4 deletions(-)
+ create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.args
+
+diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
+index 3cb2e0b..718533b 100644
+--- a/src/qemu/qemu_command.c
++++ b/src/qemu/qemu_command.c
+@@ -7370,6 +7370,94 @@ qemuBuildChrDeviceCommandLine(virCommandPtr cmd,
+ return 0;
+ }
+
++static int
++qemuBuildDomainLoaderCommandLine(virCommandPtr cmd,
++ virDomainDefPtr def,
++ virQEMUCapsPtr qemuCaps)
++{
++ int ret = -1;
++ virDomainLoaderDefPtr loader = def->os.loader;
++ virBuffer buf = VIR_BUFFER_INITIALIZER;
++ int unit = 0;
++
++ if (!loader)
++ return 0;
++
++ switch ((virDomainLoader) loader->type) {
++ case VIR_DOMAIN_LOADER_TYPE_ROM:
++ virCommandAddArg(cmd, "-bios");
++ virCommandAddArg(cmd, loader->path);
++ break;
++
++ case VIR_DOMAIN_LOADER_TYPE_PFLASH:
++ /* UEFI is supported only for x86_64 currently */
++ if (def->os.arch != VIR_ARCH_X86_64) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
++ _("pflash is not supported for %s guest architecture"),
++ virArchToString(def->os.arch));
++ goto cleanup;
++ }
++
++ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE)) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
++ _("this QEMU binary doesn't support -drive"));
++ goto cleanup;
++ }
++ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_FORMAT)) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
++ _("this QEMU binary doesn't support passing "
++ "drive format"));
++ goto cleanup;
++ }
++ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NO_ACPI) &&
++ def->features[VIR_DOMAIN_FEATURE_ACPI] != VIR_TRISTATE_SWITCH_ON) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
++ _("ACPI must be enabled in order to use UEFI"));
++ goto cleanup;
++ }
++
++ virBufferAsprintf(&buf,
++ "file=%s,if=pflash,format=raw,unit=%d",
++ loader->path, unit);
++ unit++;
++
++ if (loader->readonly) {
++ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_READONLY)) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
++ _("this qemu doesn't support passing "
++ "readonly attribute"));
++ goto cleanup;
++ }
++
++ virBufferAsprintf(&buf, ",readonly=%s",
++ virTristateSwitchTypeToString(loader->readonly));
++ }
++
++ virCommandAddArg(cmd, "-drive");
++ virCommandAddArgBuffer(cmd, &buf);
++
++ if (loader->nvram) {
++ virBufferFreeAndReset(&buf);
++ virBufferAsprintf(&buf,
++ "file=%s,if=pflash,format=raw,unit=%d",
++ loader->nvram, unit);
++
++ virCommandAddArg(cmd, "-drive");
++ virCommandAddArgBuffer(cmd, &buf);
++ }
++ break;
++
++ case VIR_DOMAIN_LOADER_TYPE_LAST:
++ /* nada */
++ break;
++ }
++
++ ret = 0;
++ cleanup:
++ virBufferFreeAndReset(&buf);
++ return ret;
++}
++
+ qemuBuildCommandLineCallbacks buildCommandLineCallbacks = {
+ .qemuGetSCSIDeviceSgName = virSCSIDeviceGetSgName,
+ };
+@@ -7525,10 +7613,8 @@ qemuBuildCommandLine(virConnectPtr conn,
+ virCommandAddArg(cmd, "-enable-nesting");
+ }
+
+- if (def->os.loader) {
+- virCommandAddArg(cmd, "-bios");
+- virCommandAddArg(cmd, def->os.loader->path);
+- }
++ if (qemuBuildDomainLoaderCommandLine(cmd, def, qemuCaps) < 0)
++ goto error;
+
+ /* Set '-m MB' based on maxmem, because the lower 'memory' limit
+ * is set post-startup using the balloon driver. If balloon driver
+diff --git a/src/security/security_dac.c b/src/security/security_dac.c
+index e62828e..e398d2c 100644
+--- a/src/security/security_dac.c
++++ b/src/security/security_dac.c
+@@ -960,6 +960,10 @@ virSecurityDACRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
+ rc = -1;
+ }
+
++ if (def->os.loader && def->os.loader->nvram &&
++ virSecurityDACRestoreSecurityFileLabel(def->os.loader->nvram) < 0)
++ rc = -1;
++
+ if (def->os.kernel &&
+ virSecurityDACRestoreSecurityFileLabel(def->os.kernel) < 0)
+ rc = -1;
+@@ -1036,6 +1040,10 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
+ if (virSecurityDACGetImageIds(secdef, priv, &user, &group))
+ return -1;
+
++ if (def->os.loader && def->os.loader->nvram &&
++ virSecurityDACSetOwnership(def->os.loader->nvram, user, group) < 0)
++ return -1;
++
+ if (def->os.kernel &&
+ virSecurityDACSetOwnership(def->os.kernel, user, group) < 0)
+ return -1;
+diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
+index c078cab..a409c19 100644
+--- a/src/security/security_selinux.c
++++ b/src/security/security_selinux.c
+@@ -1911,6 +1911,10 @@ virSecuritySELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
+ mgr) < 0)
+ rc = -1;
+
++ if (def->os.loader && def->os.loader->nvram &&
++ virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.loader->nvram) < 0)
++ rc = -1;
++
+ if (def->os.kernel &&
+ virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.kernel) < 0)
+ rc = -1;
+@@ -2294,6 +2298,10 @@ virSecuritySELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
+ mgr) < 0)
+ return -1;
+
++ if (def->os.loader && def->os.loader->nvram &&
++ virSecuritySELinuxSetFilecon(def->os.loader->nvram, data->content_context) < 0)
++ return -1;
++
+ if (def->os.kernel &&
+ virSecuritySELinuxSetFilecon(def->os.kernel, data->content_context) < 0)
+ return -1;
+diff --git a/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.args b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.args
+new file mode 100644
+index 0000000..b51e8f3
+--- /dev/null
++++ b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.args
+@@ -0,0 +1,10 @@
++LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
++/usr/bin/qemu -S -M pc \
++-drive file=/usr/share/OVMF/OVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on \
++-drive file=/usr/share/OVMF/OVMF_VARS.fd,if=pflash,format=raw,unit=1 \
++-m 1024 -smp 1 -nographic -nodefaults \
++-monitor unix:/tmp/test-monitor,server,nowait -boot c -usb \
++-drive file=/dev/HostVG/QEMUGuest1,if=none,id=drive-ide0-0-0,format=raw \
++-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
++-serial pty -device usb-tablet,id=input0 \
++-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
+diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
+index 3feb2fe..5c28253 100644
+--- a/tests/qemuxml2argvtest.c
++++ b/tests/qemuxml2argvtest.c
+@@ -642,6 +642,8 @@ mymain(void)
+ DO_TEST_FAILURE("reboot-timeout-enabled", NONE);
+
+ DO_TEST("bios", QEMU_CAPS_DEVICE, QEMU_CAPS_SGA);
++ DO_TEST("bios-nvram", QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE,
++ QEMU_CAPS_DRIVE_FORMAT, QEMU_CAPS_DRIVE_READONLY);
+ DO_TEST("clock-utc", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE);
+ DO_TEST("clock-localtime", NONE);
+ DO_TEST("clock-localtime-basis-localtime", QEMU_CAPS_RTC);
diff --git a/0013-qemu-Automatically-create-NVRAM-store.patch b/0013-qemu-Automatically-create-NVRAM-store.patch
new file mode 100644
index 0000000..21ca6ff
--- /dev/null
+++ b/0013-qemu-Automatically-create-NVRAM-store.patch
@@ -0,0 +1,579 @@
+From e2354416fdccb9649f080cdf912c5dc16d0eb578 Mon Sep 17 00:00:00 2001
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Thu, 7 Aug 2014 16:59:21 +0200
+Subject: [PATCH] qemu: Automatically create NVRAM store
+
+When using split UEFI image, it may come handy if libvirt manages per
+domain _VARS file automatically. While the _CODE file is RO and can be
+shared among multiple domains, you certainly don't want to do that on
+the _VARS file. This latter one needs to be per domain. So at the
+domain startup process, if it's determined that domain needs _VARS
+file it's copied from this master _VARS file. The location of the
+master file is configurable in qemu.conf.
+
+Temporary, on per domain basis the location of master NVRAM file can
+be overridden by this @template attribute I'm inventing to the
+<nvram/> element. All it does is holding path to the master NVRAM file
+from which local copy is created. If that's the case, the map in
+qemu.conf is not consulted.
+
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+Acked-by: Laszlo Ersek <lersek at redhat.com>
+(cherry picked from commit 742b08e30fd503bc992e864828cbabd7e6a099ec)
+---
+ docs/formatdomain.html.in | 11 +-
+ docs/schemas/domaincommon.rng | 9 +-
+ libvirt.spec.in | 2 +
+ src/Makefile.am | 1 +
+ src/conf/domain_conf.c | 11 +-
+ src/conf/domain_conf.h | 1 +
+ src/qemu/libvirtd_qemu.aug | 3 +
+ src/qemu/qemu.conf | 14 +++
+ src/qemu/qemu_conf.c | 94 ++++++++++++++
+ src/qemu/qemu_conf.h | 5 +
+ src/qemu/qemu_process.c | 137 +++++++++++++++++++++
+ src/qemu/test_libvirtd_qemu.aug.in | 3 +
+ tests/domainschemadata/domain-bios-nvram-empty.xml | 40 ++++++
+ 13 files changed, 325 insertions(+), 6 deletions(-)
+ create mode 100644 tests/domainschemadata/domain-bios-nvram-empty.xml
+
+diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
+index 757035a..a2ea758 100644
+--- a/docs/formatdomain.html.in
++++ b/docs/formatdomain.html.in
+@@ -103,7 +103,7 @@
+ <os>
+ <type>hvm</type>
+ <loader readonly='on' type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+- <nvram>/var/lib/libvirt/nvram/guest_VARS.fd</nvram>
++ <nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/var/lib/libvirt/nvram/guest_VARS.fd</nvram>
+ <boot dev='hd'/>
+ <boot dev='cdrom'/>
+ <bootmenu enable='yes' timeout='3000'/>
+@@ -142,9 +142,12 @@
+ <code>pflash</code>.</dd>
+ <dt><code>nvram</code></dt>
+ <dd>Some UEFI firmwares may want to use a non-volatile memory to store
+- some variables. In the host, this is represented as a file and the
+- path to the file is stored in this element. <span class="since">Since
+- 1.2.8</span></dd>
++ some variables. In the host, this is represented as a file and the path
++ to the file is stored in this element. Moreover, when the domain is
++ started up libvirt copies so called master NVRAM store file defined
++ in <code>qemu.conf</code>. If needed, the <code>template</code>
++ attribute can be used to per domain override map of master NVRAM stores
++ from the config file. <span class="since">Since 1.2.8</span></dd>
+ <dt><code>boot</code></dt>
+ <dd>The <code>dev</code> attribute takes one of the values "fd", "hd",
+ "cdrom" or "network" and is used to specify the next boot device
+diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
+index 5d9c21c..6ae940a 100644
+--- a/docs/schemas/domaincommon.rng
++++ b/docs/schemas/domaincommon.rng
+@@ -263,7 +263,14 @@
+ </optional>
+ <optional>
+ <element name="nvram">
+- <ref name="absFilePath"/>
++ <optional>
++ <attribute name="template">
++ <ref name="absFilePath"/>
++ </attribute>
++ </optional>
++ <optional>
++ <ref name="absFilePath"/>
++ </optional>
+ </element>
+ </optional>
+ <optional>
+diff --git a/libvirt.spec.in b/libvirt.spec.in
+index 6129f00..935b8c8 100644
+--- a/libvirt.spec.in
++++ b/libvirt.spec.in
+@@ -1970,6 +1970,7 @@ exit 0
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/target/
++%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/nvram/
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/cache/libvirt/qemu/
+ %{_datadir}/augeas/lenses/libvirtd_qemu.aug
+ %{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
+@@ -2072,6 +2073,7 @@ exit 0
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/target/
++%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/nvram/
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/cache/libvirt/qemu/
+ %{_datadir}/augeas/lenses/libvirtd_qemu.aug
+ %{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 46e411e..fa741a8 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -2679,6 +2679,7 @@ endif WITH_SANLOCK
+ if WITH_QEMU
+ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/qemu"
+ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/qemu/channel/target"
++ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/qemu/nvram"
+ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/qemu"
+ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/cache/libvirt/qemu"
+ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/log/libvirt/qemu"
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 6ee5c17..84f5f1d 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -2023,6 +2023,7 @@ virDomainLoaderDefFree(virDomainLoaderDefPtr loader)
+
+ VIR_FREE(loader->path);
+ VIR_FREE(loader->nvram);
++ VIR_FREE(loader->templt);
+ VIR_FREE(loader);
+ }
+
+@@ -12768,6 +12769,7 @@ virDomainDefParseXML(xmlDocPtr xml,
+ goto error;
+
+ def->os.loader->nvram = virXPathString("string(./os/nvram[1])", ctxt);
++ def->os.loader->templt = virXPathString("string(./os/nvram[1]/@template)", ctxt);
+ }
+ }
+
+@@ -17866,7 +17868,14 @@ virDomainLoaderDefFormat(virBufferPtr buf,
+ virBufferAsprintf(buf, " type='%s'>", type);
+
+ virBufferEscapeString(buf, "%s</loader>\n", loader->path);
+- virBufferEscapeString(buf, "<nvram>%s</nvram>\n", loader->nvram);
++ if (loader->nvram || loader->templt) {
++ virBufferAddLit(buf, "<nvram");
++ virBufferEscapeString(buf, " template='%s'", loader->templt);
++ if (loader->nvram)
++ virBufferEscapeString(buf, ">%s</nvram>\n", loader->nvram);
++ else
++ virBufferAddLit(buf, "/>\n");
++ }
+ }
+
+ static bool
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index c97a10c..3316fb6 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -1644,6 +1644,7 @@ struct _virDomainLoaderDef {
+ int readonly; /* enum virTristateBool */
+ virDomainLoader type;
+ char *nvram; /* path to non-volatile RAM */
++ char *templt; /* user override of path to master nvram */
+ };
+
+ void virDomainLoaderDefFree(virDomainLoaderDefPtr loader);
+diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug
+index e7db7fe..62951da 100644
+--- a/src/qemu/libvirtd_qemu.aug
++++ b/src/qemu/libvirtd_qemu.aug
+@@ -88,6 +88,8 @@ module Libvirtd_qemu =
+
+ let log_entry = bool_entry "log_timestamp"
+
++ let nvram_entry = str_array_entry "nvram"
++
+ (* Each entry in the config is one of the following ... *)
+ let entry = vnc_entry
+ | spice_entry
+@@ -100,6 +102,7 @@ module Libvirtd_qemu =
+ | rpc_entry
+ | network_entry
+ | log_entry
++ | nvram_entry
+
+ let comment = [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
+ let empty = [ label "#empty" . eol ]
+diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
+index 7bbbe09..79bba36 100644
+--- a/src/qemu/qemu.conf
++++ b/src/qemu/qemu.conf
+@@ -487,3 +487,17 @@
+ # Defaults to 1.
+ #
+ #log_timestamp = 0
++
++
++# Location of master nvram file
++#
++# When a domain is configured to use UEFI instead of standard
++# BIOS it may use a separate storage for UEFI variables. If
++# that's the case libvirt creates the variable store per domain
++# using this master file as image. Each UEFI firmware can,
++# however, have different variables store. Therefore the nvram is
++# a list of strings when a single item is in form of:
++# ${PATH_TO_UEFI_FW}:${PATH_TO_UEFI_VARS}.
++# Later, when libvirt creates per domain variable store, this
++# list is searched for the master image.
++#nvram = [ "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd" ]
+diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
+index e2ec54f..ac10b64 100644
+--- a/src/qemu/qemu_conf.c
++++ b/src/qemu/qemu_conf.c
+@@ -107,6 +107,9 @@ void qemuDomainCmdlineDefFree(qemuDomainCmdlineDefPtr def)
+ VIR_FREE(def);
+ }
+
++#define VIR_QEMU_LOADER_FILE_PATH "/usr/share/OVMF/OVMF_CODE.fd"
++#define VIR_QEMU_NVRAM_FILE_PATH "/usr/share/OVMF/OVMF_VARS.fd"
++
+ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
+ {
+ virQEMUDriverConfigPtr cfg;
+@@ -255,6 +258,15 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged)
+
+ cfg->logTimestamp = true;
+
++ if (VIR_ALLOC_N(cfg->loader, 1) < 0 ||
++ VIR_ALLOC_N(cfg->nvram, 1) < 0)
++ goto error;
++ cfg->nloader = 1;
++
++ if (VIR_STRDUP(cfg->loader[0], VIR_QEMU_LOADER_FILE_PATH) < 0 ||
++ VIR_STRDUP(cfg->nvram[0], VIR_QEMU_NVRAM_FILE_PATH) < 0)
++ goto error;
++
+ return cfg;
+
+ error:
+@@ -305,6 +317,14 @@ static void virQEMUDriverConfigDispose(void *obj)
+ virStringFreeList(cfg->securityDriverNames);
+
+ VIR_FREE(cfg->lockManagerName);
++
++ while (cfg->nloader) {
++ VIR_FREE(cfg->loader[cfg->nloader - 1]);
++ VIR_FREE(cfg->nvram[cfg->nloader - 1]);
++ cfg->nloader--;
++ }
++ VIR_FREE(cfg->loader);
++ VIR_FREE(cfg->nvram);
+ }
+
+
+@@ -328,6 +348,43 @@ virQEMUDriverConfigHugeTLBFSInit(virHugeTLBFSPtr hugetlbfs,
+ }
+
+
++static int
++virQEMUDriverConfigNVRAMParse(const char *str,
++ char **loader,
++ char **nvram)
++{
++ int ret = -1;
++ char **token;
++
++ if (!(token = virStringSplit(str, ":", 0)))
++ goto cleanup;
++
++ if (token[0]) {
++ virSkipSpaces((const char **) &token[0]);
++ if (token[1])
++ virSkipSpaces((const char **) &token[1]);
++ }
++
++ /* Exactly two tokens are expected */
++ if (!token[0] || !token[1] || token[2] ||
++ STREQ(token[0], "") || STREQ(token[1], "")) {
++ virReportError(VIR_ERR_CONF_SYNTAX,
++ _("Invalid nvram format: '%s'"),
++ str);
++ goto cleanup;
++ }
++
++ if (VIR_STRDUP(*loader, token[0]) < 0 ||
++ VIR_STRDUP(*nvram, token[1]) < 0)
++ goto cleanup;
++
++ ret = 0;
++ cleanup:
++ virStringFreeList(token);
++ return ret;
++}
++
++
+ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
+ const char *filename)
+ {
+@@ -654,6 +711,43 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg,
+
+ GET_VALUE_BOOL("log_timestamp", cfg->logTimestamp);
+
++ if ((p = virConfGetValue(conf, "nvram"))) {
++ size_t len;
++ virConfValuePtr pp;
++
++ CHECK_TYPE("nvram", VIR_CONF_LIST);
++
++ while (cfg->nloader) {
++ VIR_FREE(cfg->loader[cfg->nloader - 1]);
++ VIR_FREE(cfg->nvram[cfg->nloader - 1]);
++ cfg->nloader--;
++ }
++ VIR_FREE(cfg->loader);
++ VIR_FREE(cfg->nvram);
++
++ /* Calc length and check items */
++ for (len = 0, pp = p->list; pp; len++, pp = pp->next) {
++ if (pp->type != VIR_CONF_STRING) {
++ virReportError(VIR_ERR_CONF_SYNTAX, "%s",
++ _("nvram must be a list of strings"));
++ goto cleanup;
++ }
++ }
++
++ if (len &&
++ (VIR_ALLOC_N(cfg->loader, len) < 0 ||
++ VIR_ALLOC_N(cfg->nvram, len) < 0))
++ goto cleanup;
++ cfg->nloader = len;
++
++ for (i = 0, pp = p->list; pp; i++, pp = pp->next) {
++ if (virQEMUDriverConfigNVRAMParse(pp->str,
++ &cfg->loader[i],
++ &cfg->nvram[i]) < 0)
++ goto cleanup;
++ }
++ }
++
+ ret = 0;
+
+ cleanup:
+diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
+index ae7ac56..1f521e5 100644
+--- a/src/qemu/qemu_conf.h
++++ b/src/qemu/qemu_conf.h
+@@ -172,6 +172,11 @@ struct _virQEMUDriverConfig {
+ int migrationPortMax;
+
+ bool logTimestamp;
++
++ /* Pairs of loader:nvram paths. The list is @nloader items long */
++ char **loader;
++ char **nvram;
++ size_t nloader;
+ };
+
+ /* Main driver state */
+diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
+index f68dfbe..5b120d4 100644
+--- a/src/qemu/qemu_process.c
++++ b/src/qemu/qemu_process.c
+@@ -67,6 +67,7 @@
+ #include "virstring.h"
+ #include "virhostdev.h"
+ #include "storage/storage_driver.h"
++#include "configmake.h"
+
+ #define VIR_FROM_THIS VIR_FROM_QEMU
+
+@@ -3734,6 +3735,135 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver,
+ }
+
+
++static int
++qemuPrepareNVRAM(virQEMUDriverConfigPtr cfg,
++ virDomainDefPtr def,
++ bool migrated)
++{
++ int ret = -1;
++ int srcFD = -1;
++ int dstFD = -1;
++ virDomainLoaderDefPtr loader = def->os.loader;
++ bool generated = false;
++ bool created = false;
++
++ /* Unless domain has RO loader of pflash type, we have
++ * nothing to do here. If the loader is RW then it's not
++ * using split code and vars feature, so no nvram file needs
++ * to be created. */
++ if (!loader || loader->type != VIR_DOMAIN_LOADER_TYPE_PFLASH ||
++ loader->readonly != VIR_TRISTATE_SWITCH_ON)
++ return 0;
++
++ /* If the nvram path is configured already, there's nothing
++ * we need to do. Unless we are starting the destination side
++ * of migration in which case nvram is configured in the
++ * domain XML but the file doesn't exist yet. Moreover, after
++ * the migration is completed, qemu will invoke a
++ * synchronization write into the nvram file so we don't have
++ * to take care about transmitting the real data on the other
++ * side. */
++ if (loader->nvram && !migrated)
++ return 0;
++
++ /* Autogenerate nvram path if needed.*/
++ if (!loader->nvram) {
++ if (virAsprintf(&loader->nvram,
++ "%s/lib/libvirt/qemu/nvram/%s_VARS.fd",
++ LOCALSTATEDIR, def->name) < 0)
++ goto cleanup;
++
++ generated = true;
++ }
++
++ if (!virFileExists(loader->nvram)) {
++ const char *master_nvram_path = loader->templt;
++ ssize_t r;
++
++ if (!loader->templt) {
++ size_t i;
++ for (i = 0; i < cfg->nloader; i++) {
++ if (STREQ(cfg->loader[i], loader->path)) {
++ master_nvram_path = cfg->nvram[i];
++ break;
++ }
++ }
++ }
++
++ if (!master_nvram_path) {
++ virReportError(VIR_ERR_OPERATION_FAILED,
++ _("unable to find any master var store for "
++ "loader: %s"), loader->path);
++ goto cleanup;
++ }
++
++ if ((srcFD = virFileOpenAs(master_nvram_path, O_RDONLY,
++ 0, -1, -1, 0)) < 0) {
++ virReportSystemError(-srcFD,
++ _("Failed to open file '%s'"),
++ master_nvram_path);
++ goto cleanup;
++ }
++ if ((dstFD = virFileOpenAs(loader->nvram,
++ O_WRONLY | O_CREAT | O_EXCL,
++ S_IRUSR | S_IWUSR,
++ cfg->user, cfg->group, 0)) < 0) {
++ virReportSystemError(-dstFD,
++ _("Failed to create file '%s'"),
++ loader->nvram);
++ goto cleanup;
++ }
++ created = true;
++
++ do {
++ char buf[1024];
++
++ if ((r = saferead(srcFD, buf, sizeof(buf))) < 0) {
++ virReportSystemError(errno,
++ _("Unable to read from file '%s'"),
++ master_nvram_path);
++ goto cleanup;
++ }
++
++ if (safewrite(dstFD, buf, r) < 0) {
++ virReportSystemError(errno,
++ _("Unable to write to file '%s'"),
++ loader->nvram);
++ goto cleanup;
++ }
++ } while (r);
++
++ if (VIR_CLOSE(srcFD) < 0) {
++ virReportSystemError(errno,
++ _("Unable to close file '%s'"),
++ master_nvram_path);
++ goto cleanup;
++ }
++ if (VIR_CLOSE(dstFD) < 0) {
++ virReportSystemError(errno,
++ _("Unable to close file '%s'"),
++ loader->nvram);
++ goto cleanup;
++ }
++ }
++
++ ret = 0;
++ cleanup:
++ /* We successfully generated the nvram path, but failed to
++ * copy the file content. Roll back. */
++ if (ret < 0) {
++ if (created)
++ unlink(loader->nvram);
++ if (generated)
++ VIR_FREE(loader->nvram);
++ }
++
++ VIR_FORCE_CLOSE(srcFD);
++ VIR_FORCE_CLOSE(dstFD);
++ return ret;
++}
++
++
+ int qemuProcessStart(virConnectPtr conn,
+ virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+@@ -3802,6 +3932,13 @@ int qemuProcessStart(virConnectPtr conn,
+ if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
+ goto cleanup;
+
++ /* Some things, paths, ... are generated here and we want them to persist.
++ * Fill them in prior to setting the domain def as transient. */
++ VIR_DEBUG("Generating paths");
++
++ if (qemuPrepareNVRAM(cfg, vm->def, migrateFrom) < 0)
++ goto cleanup;
++
+ /* Do this upfront, so any part of the startup process can add
+ * runtime state to vm->def that won't be persisted. This let's us
+ * report implicit runtime defaults in the XML, like vnc listen/socket
+diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in
+index 7796acc..d2bc2c0 100644
+--- a/src/qemu/test_libvirtd_qemu.aug.in
++++ b/src/qemu/test_libvirtd_qemu.aug.in
+@@ -74,3 +74,6 @@ module Test_libvirtd_qemu =
+ { "migration_port_min" = "49152" }
+ { "migration_port_max" = "49215" }
+ { "log_timestamp" = "0" }
++{ "nvram"
++ { "1" = "/usr/share/OVMF/OVMF_CODE.fd:/usr/share/OVMF/OVMF_VARS.fd" }
++}
+diff --git a/tests/domainschemadata/domain-bios-nvram-empty.xml b/tests/domainschemadata/domain-bios-nvram-empty.xml
+new file mode 100644
+index 0000000..e7643f3
+--- /dev/null
++++ b/tests/domainschemadata/domain-bios-nvram-empty.xml
+@@ -0,0 +1,40 @@
++<domain type='qemu'>
++ <name>test-bios</name>
++ <uuid>362d1fc1-df7d-193e-5c18-49a71bd1da66</uuid>
++ <memory unit='KiB'>1048576</memory>
++ <currentMemory unit='KiB'>1048576</currentMemory>
++ <vcpu placement='static'>1</vcpu>
++ <os>
++ <type arch='x86_64' machine='pc'>hvm</type>
++ <loader readonly='yes' type='pflash'>/usr/share/OVMF/OVMF_CODE.fd</loader>
++ <nvram template='/usr/share/OVMF/OVMF_VARS.fd'/>
++ <boot dev='hd'/>
++ <bootmenu enable='yes'/>
++ </os>
++ <features>
++ <acpi/>
++ </features>
++ <clock offset='utc'/>
++ <on_poweroff>destroy</on_poweroff>
++ <on_reboot>restart</on_reboot>
++ <on_crash>restart</on_crash>
++ <devices>
++ <emulator>/usr/bin/qemu</emulator>
++ <disk type='block' device='disk'>
++ <source dev='/dev/HostVG/QEMUGuest1'/>
++ <target dev='hda' bus='ide'/>
++ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
++ </disk>
++ <controller type='usb' index='0'/>
++ <controller type='ide' index='0'/>
++ <controller type='pci' index='0' model='pci-root'/>
++ <serial type='pty'>
++ <target port='0'/>
++ </serial>
++ <console type='pty'>
++ <target type='serial' port='0'/>
++ </console>
++ <input type='tablet' bus='usb'/>
++ <memballoon model='virtio'/>
++ </devices>
++</domain>
diff --git a/0014-nvram-Fix-permissions.patch b/0014-nvram-Fix-permissions.patch
new file mode 100644
index 0000000..8f3d078
--- /dev/null
+++ b/0014-nvram-Fix-permissions.patch
@@ -0,0 +1,53 @@
+From 884ef00a28244b34d66ada97c8ddd3e7d7ea8ff1 Mon Sep 17 00:00:00 2001
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Thu, 11 Sep 2014 12:09:04 +0200
+Subject: [PATCH] nvram: Fix permissions
+
+I've noticed two problem with the automatically created NVRAM varstore
+file. The first, even though I run qemu as root:root for some reason I
+get Permission denied when trying to open the _VARS.fd file. The
+problem is, the upper directory misses execute permissions, which in
+combination with us dropping some capabilities result in EPERM.
+
+The next thing is, that if I switch SELinux to enforcing mode, I get
+another EPERM because the vars file is not labeled correctly. It is
+passed to qemu as disk and hence should be labelled as disk. QEMU may
+write to it eventually, so this is different to kernel or initrd.
+
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+(cherry picked from commit 37d8c75fad297891b80086b125046ed3990eaf59)
+---
+ libvirt.spec.in | 2 +-
+ src/security/security_selinux.c | 5 ++++-
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/libvirt.spec.in b/libvirt.spec.in
+index 935b8c8..3cd7b2e 100644
+--- a/libvirt.spec.in
++++ b/libvirt.spec.in
+@@ -1970,7 +1970,7 @@ exit 0
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/target/
+-%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/nvram/
++%dir %attr(0711, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/nvram/
+ %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/cache/libvirt/qemu/
+ %{_datadir}/augeas/lenses/libvirtd_qemu.aug
+ %{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
+diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
+index a409c19..b9efbc5 100644
+--- a/src/security/security_selinux.c
++++ b/src/security/security_selinux.c
+@@ -2298,8 +2298,11 @@ virSecuritySELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
+ mgr) < 0)
+ return -1;
+
++ /* This is different than kernel or initrd. The nvram store
++ * is really a disk, qemu can read and write to it. */
+ if (def->os.loader && def->os.loader->nvram &&
+- virSecuritySELinuxSetFilecon(def->os.loader->nvram, data->content_context) < 0)
++ secdef && secdef->imagelabel &&
++ virSecuritySELinuxSetFilecon(def->os.loader->nvram, secdef->imagelabel) < 0)
+ return -1;
+
+ if (def->os.kernel &&
diff --git a/0015-virDomainUndefineFlags-Allow-NVRAM-unlinking.patch b/0015-virDomainUndefineFlags-Allow-NVRAM-unlinking.patch
new file mode 100644
index 0000000..d9c9feb
--- /dev/null
+++ b/0015-virDomainUndefineFlags-Allow-NVRAM-unlinking.patch
@@ -0,0 +1,148 @@
+From 03c156e5d54b311291101ca21690b586222be276 Mon Sep 17 00:00:00 2001
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Thu, 11 Sep 2014 13:17:11 +0200
+Subject: [PATCH] virDomainUndefineFlags: Allow NVRAM unlinking
+
+When a domain is undefined, there are options to remove it's
+managed save state or snapshots. However, there's another file
+that libvirt creates per domain: the NVRAM variable store file.
+Make sure that the file is not left behind if the domain is
+undefined.
+
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+(cherry picked from commit 273b6581ca8dae11e6ff40e3d13813fdbb37d41b)
+---
+ include/libvirt/libvirt.h.in | 2 ++
+ src/qemu/qemu_driver.c | 20 +++++++++++++++++++-
+ tools/virsh-domain.c | 20 ++++++++++++++++----
+ tools/virsh.pod | 6 +++++-
+ 4 files changed, 42 insertions(+), 6 deletions(-)
+
+diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
+index a64f597..8996231 100644
+--- a/include/libvirt/libvirt.h.in
++++ b/include/libvirt/libvirt.h.in
+@@ -2257,6 +2257,8 @@ typedef enum {
+ VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA = (1 << 1), /* If last use of domain,
+ then also remove any
+ snapshot metadata */
++ VIR_DOMAIN_UNDEFINE_NVRAM = (1 << 2), /* Also remove any
++ nvram file */
+
+ /* Future undefine control flags should come here. */
+ } virDomainUndefineFlagsValues;
+diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
+index 239a300..588eba4 100644
+--- a/src/qemu/qemu_driver.c
++++ b/src/qemu/qemu_driver.c
+@@ -6402,7 +6402,8 @@ qemuDomainUndefineFlags(virDomainPtr dom,
+ virQEMUDriverConfigPtr cfg = NULL;
+
+ virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
+- VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
++ VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA |
++ VIR_DOMAIN_UNDEFINE_NVRAM, -1);
+
+ if (!(vm = qemuDomObjFromDomain(dom)))
+ return -1;
+@@ -6451,6 +6452,23 @@ qemuDomainUndefineFlags(virDomainPtr dom,
+ }
+ }
+
++ if (!virDomainObjIsActive(vm) &&
++ vm->def->os.loader && vm->def->os.loader->nvram &&
++ virFileExists(vm->def->os.loader->nvram)) {
++ if (!(flags & VIR_DOMAIN_UNDEFINE_NVRAM)) {
++ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
++ _("cannot delete inactive domain with nvram"));
++ goto cleanup;
++ }
++
++ if (unlink(vm->def->os.loader->nvram) < 0) {
++ virReportSystemError(errno,
++ _("failed to remove nvram: %s"),
++ vm->def->os.loader->nvram);
++ goto cleanup;
++ }
++ }
++
+ if (virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm) < 0)
+ goto cleanup;
+
+diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
+index c75cd73..d84db51 100644
+--- a/tools/virsh-domain.c
++++ b/tools/virsh-domain.c
+@@ -3038,6 +3038,10 @@ static const vshCmdOptDef opts_undefine[] = {
+ .type = VSH_OT_BOOL,
+ .help = N_("remove all domain snapshot metadata, if inactive")
+ },
++ {.name = "nvram",
++ .type = VSH_OT_BOOL,
++ .help = N_("remove nvram file, if inactive")
++ },
+ {.name = NULL}
+ };
+
+@@ -3060,6 +3064,7 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
+ bool snapshots_metadata = vshCommandOptBool(cmd, "snapshots-metadata");
+ bool wipe_storage = vshCommandOptBool(cmd, "wipe-storage");
+ bool remove_all_storage = vshCommandOptBool(cmd, "remove-all-storage");
++ bool nvram = vshCommandOptBool(cmd, "nvram");
+ /* Positive if these items exist. */
+ int has_managed_save = 0;
+ int has_snapshots_metadata = 0;
+@@ -3103,6 +3108,9 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
+ flags |= VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA;
+ snapshots_safe = true;
+ }
++ if (nvram) {
++ flags |= VIR_DOMAIN_UNDEFINE_NVRAM;
++ }
+
+ if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
+ return false;
+@@ -3293,11 +3301,15 @@ cmdUndefine(vshControl *ctl, const vshCmd *cmd)
+ * VIR_DOMAIN_UNDEFINE_MANAGED_SAVE in 0.9.4, the
+ * VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA flag was not present
+ * until 0.9.5; skip to piecewise emulation if we couldn't prove
+- * above that the new API is safe. */
+- if (managed_save_safe && snapshots_safe) {
++ * above that the new API is safe.
++ * Moreover, only the newer UndefineFlags() API understands
++ * the VIR_DOMAIN_UNDEFINE_NVRAM flag. So if user has
++ * specified --nvram we must use the Flags() API. */
++ if ((managed_save_safe && snapshots_safe) || nvram) {
+ rc = virDomainUndefineFlags(dom, flags);
+- if (rc == 0 || (last_error->code != VIR_ERR_NO_SUPPORT &&
+- last_error->code != VIR_ERR_INVALID_ARG))
++ if (rc == 0 || nvram ||
++ (last_error->code != VIR_ERR_NO_SUPPORT &&
++ last_error->code != VIR_ERR_INVALID_ARG))
+ goto out;
+ vshResetLibvirtError();
+ }
+diff --git a/tools/virsh.pod b/tools/virsh.pod
+index ea9267e..a9fad73 100644
+--- a/tools/virsh.pod
++++ b/tools/virsh.pod
+@@ -2058,7 +2058,7 @@ Output the device used for the TTY console of the domain. If the information
+ is not available the processes will provide an exit code of 1.
+
+ =item B<undefine> I<domain> [I<--managed-save>] [I<--snapshots-metadata>]
+-[ {I<--storage> B<volumes> | I<--remove-all-storage>} I<--wipe-storage>]
++[I<--nvram>] [ {I<--storage> B<volumes> | I<--remove-all-storage>} I<--wipe-storage>]
+
+ Undefine a domain. If the domain is running, this converts it to a
+ transient domain, without stopping it. If the domain is inactive,
+@@ -2074,6 +2074,10 @@ domain. Without the flag, attempts to undefine an inactive domain with
+ snapshot metadata will fail. If the domain is active, this flag is
+ ignored.
+
++The I<--nvram> flag ensures no nvram (/domain/os/nvram/) file is
++left behind. If the domain has an nvram file and the flag is
++omitted, the undefine will fail.
++
+ The I<--storage> flag takes a parameter B<volumes>, which is a comma separated
+ list of volume target names or source paths of storage volumes to be removed
+ along with the undefined domain. Volumes can be undefined and thus removed only
diff --git a/0016-formatdomain-Update-loader-example-to-match-the-rest.patch b/0016-formatdomain-Update-loader-example-to-match-the-rest.patch
new file mode 100644
index 0000000..6ed25e4
--- /dev/null
+++ b/0016-formatdomain-Update-loader-example-to-match-the-rest.patch
@@ -0,0 +1,32 @@
+From 2b30f114b796aee6f92eb13244f8cd42ef523bfe Mon Sep 17 00:00:00 2001
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Fri, 12 Sep 2014 13:18:32 +0200
+Subject: [PATCH] formatdomain: Update <loader/> example to match the rest
+
+At the beginning when I was inventing <loader/> attributes and
+<nvram/> I've introduced this @readonly attribute to the loader
+element. It accepted values 'on' and 'off'. However, later, during the
+review process, that has changed to 'yes' and 'no', but the example
+XML snippet wasn't updated, so while the description is correct, the
+example isn't.
+
+Reported-by: Laszlo Ersek <lersek at redhat.com>
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+(cherry picked from commit dcf7d0423c1ad79e45df4ddd1cb619603cf221e7)
+---
+ docs/formatdomain.html.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
+index a2ea758..5081be3 100644
+--- a/docs/formatdomain.html.in
++++ b/docs/formatdomain.html.in
+@@ -102,7 +102,7 @@
+ ...
+ <os>
+ <type>hvm</type>
+- <loader readonly='on' type='rom'>/usr/lib/xen/boot/hvmloader</loader>
++ <loader readonly='yes' type='rom'>/usr/lib/xen/boot/hvmloader</loader>
+ <nvram template='/usr/share/OVMF/OVMF_VARS.fd'>/var/lib/libvirt/nvram/guest_VARS.fd</nvram>
+ <boot dev='hd'/>
+ <boot dev='cdrom'/>
diff --git a/0017-domaincaps-Expose-UEFI-capability.patch b/0017-domaincaps-Expose-UEFI-capability.patch
new file mode 100644
index 0000000..98de34a
--- /dev/null
+++ b/0017-domaincaps-Expose-UEFI-capability.patch
@@ -0,0 +1,338 @@
+From 2c4e9da2b46d55fda49b20ae48dbdd4e63209565 Mon Sep 17 00:00:00 2001
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Tue, 16 Sep 2014 14:47:47 +0200
+Subject: [PATCH] domaincaps: Expose UEFI capability
+
+As of 542899168c38 we learned libvirt to use UEFI for domains.
+However, management applications may firstly query if libvirt
+supports it. And this is where virConnectGetDomainCapabilities()
+API comes handy.
+
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+(cherry picked from commit 4f76621c0edb895431a6fc30c026865dbf1c1316)
+---
+ docs/formatdomaincaps.html.in | 40 ++++++++++++++++++++++
+ docs/schemas/domaincaps.rng | 21 ++++++++++++
+ src/conf/domain_capabilities.c | 28 +++++++++++++++
+ src/conf/domain_capabilities.h | 16 +++++++++
+ src/qemu/qemu_capabilities.c | 38 ++++++++++++++++++++
+ tests/domaincapsschemadata/domaincaps-basic.xml | 1 +
+ tests/domaincapsschemadata/domaincaps-full.xml | 13 +++++++
+ .../domaincaps-qemu_1.6.50-1.xml | 12 +++++++
+ tests/domaincapstest.c | 8 +++++
+ 9 files changed, 177 insertions(+)
+
+diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in
+index 66b6017..34d746d 100644
+--- a/docs/formatdomaincaps.html.in
++++ b/docs/formatdomaincaps.html.in
+@@ -93,6 +93,46 @@
+ <dd>The maximum number of supported virtual CPUs</dd>
+ </dl>
+
++ <h3><a name="elementsOSBIOS">BIOS bootloader</a></h3>
++
++ <p>Sometimes users might want to tweak some BIOS knobs or use
++ UEFI. For cases like that, <a
++ href="formatdomain.html#elementsOSBIOS"><code>os</code></a>
++ element exposes what values can be passed to its children.</p>
++
++<pre>
++<domainCapabilities>
++ ...
++ <os supported='yes'>
++ <loader supported='yes'>
++ <enum name='type'>
++ <value>rom</value>
++ <value>pflash</value>
++ </enum>
++ <enum name='readonly'>
++ <value>yes</value>
++ <value>no</value>
++ </enum>
++ </loader>
++ </os>
++ ...
++<domainCapabilities>
++</pre>
++
++ <p>For the <code>loader</code> element, the following can occur:</p>
++
++ <dl>
++ <dt>type</dt>
++ <dd>Whether loader is a typical BIOS (<code>rom</code>) or
++ an UEFI binary (<code>pflash</code>). This refers to
++ <code>type</code> attribute of the <loader/>
++ element.</dd>
++
++ <dt>readonly</dt>
++ <dd>Options for the <code>readonly</code> attribute of the
++ <loader/> element.</dd>
++ </dl>
++
+ <h3><a name="elementsDevices">Devices</a></h3>
+
+ <p>
+diff --git a/docs/schemas/domaincaps.rng b/docs/schemas/domaincaps.rng
+index 627b699..ad8d966 100644
+--- a/docs/schemas/domaincaps.rng
++++ b/docs/schemas/domaincaps.rng
+@@ -26,6 +26,9 @@
+ <ref name='vcpu'/>
+ </optional>
+ <optional>
++ <ref name='os'/>
++ </optional>
++ <optional>
+ <ref name='devices'/>
+ </optional>
+ </interleave>
+@@ -41,6 +44,24 @@
+ </element>
+ </define>
+
++ <define name='loader'>
++ <element name='loader'>
++ <ref name='supported'/>
++ <ref name='enum'/>
++ </element>
++ </define>
++
++ <define name='os'>
++ <element name='os'>
++ <interleave>
++ <ref name='supported'/>
++ <optional>
++ <ref name='loader'/>
++ </optional>
++ </interleave>
++ </element>
++ </define>
++
+ <define name='devices'>
+ <element name='devices'>
+ <interleave>
+diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
+index df190eb..5a3c8e7 100644
+--- a/src/conf/domain_capabilities.c
++++ b/src/conf/domain_capabilities.c
+@@ -178,6 +178,32 @@ virDomainCapsEnumFormat(virBufferPtr buf,
+ #capsEnum, valToStr); \
+ } while (0)
+
++
++static void
++virDomainCapsLoaderFormat(virBufferPtr buf,
++ virDomainCapsLoaderPtr loader)
++{
++ FORMAT_PROLOGUE(loader);
++
++ ENUM_PROCESS(loader, type, virDomainLoaderTypeToString);
++ ENUM_PROCESS(loader, readonly, virTristateBoolTypeToString);
++
++ FORMAT_EPILOGUE(loader);
++}
++
++static void
++virDomainCapsOSFormat(virBufferPtr buf,
++ virDomainCapsOSPtr os)
++{
++ virDomainCapsLoaderPtr loader = &os->loader;
++
++ FORMAT_PROLOGUE(os);
++
++ virDomainCapsLoaderFormat(buf, loader);
++
++ FORMAT_EPILOGUE(os);
++}
++
+ static void
+ virDomainCapsDeviceDiskFormat(virBufferPtr buf,
+ virDomainCapsDeviceDiskPtr const disk)
+@@ -225,6 +251,8 @@ virDomainCapsFormatInternal(virBufferPtr buf,
+ if (caps->maxvcpus)
+ virBufferAsprintf(buf, "<vcpu max='%d'/>\n", caps->maxvcpus);
+
++ virDomainCapsOSFormat(buf, &caps->os);
++
+ virBufferAddLit(buf, "<devices>\n");
+ virBufferAdjustIndent(buf, 2);
+
+diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h
+index 731e66f..768646b 100644
+--- a/src/conf/domain_capabilities.h
++++ b/src/conf/domain_capabilities.h
+@@ -43,6 +43,21 @@ struct _virDomainCapsDevice {
+ bool supported; /* true if <devtype> is supported by hypervisor */
+ };
+
++typedef struct _virDomainCapsLoader virDomainCapsLoader;
++typedef virDomainCapsLoader *virDomainCapsLoaderPtr;
++struct _virDomainCapsLoader {
++ virDomainCapsDevice device;
++ virDomainCapsEnum type; /* Info about virDomainLoader */
++ virDomainCapsEnum readonly; /* Info about readonly:virTristateBool */
++};
++
++typedef struct _virDomainCapsOS virDomainCapsOS;
++typedef virDomainCapsOS *virDomainCapsOSPtr;
++struct _virDomainCapsOS {
++ virDomainCapsDevice device;
++ virDomainCapsLoader loader; /* Info about virDomainLoaderDef */
++};
++
+ typedef struct _virDomainCapsDeviceDisk virDomainCapsDeviceDisk;
+ typedef virDomainCapsDeviceDisk *virDomainCapsDeviceDiskPtr;
+ struct _virDomainCapsDeviceDisk {
+@@ -75,6 +90,7 @@ struct _virDomainCaps {
+ /* Some machine specific info */
+ int maxvcpus;
+
++ virDomainCapsOS os;
+ virDomainCapsDeviceDisk disk;
+ virDomainCapsDeviceHostdev hostdev;
+ /* add new domain devices here */
+diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
+index c70a1a8..c999ee4 100644
+--- a/src/qemu/qemu_capabilities.c
++++ b/src/qemu/qemu_capabilities.c
+@@ -3609,6 +3609,42 @@ virQEMUCapsGetDefaultMachine(virQEMUCapsPtr qemuCaps)
+
+
+ static void
++virQEMUCapsFillDomainLoaderCaps(virQEMUCapsPtr qemuCaps,
++ virDomainCapsLoaderPtr loader,
++ virArch arch)
++{
++ loader->device.supported = true;
++
++ VIR_DOMAIN_CAPS_ENUM_SET(loader->type,
++ VIR_DOMAIN_LOADER_TYPE_ROM);
++
++ if (arch == VIR_ARCH_X86_64 &&
++ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE) &&
++ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_FORMAT))
++ VIR_DOMAIN_CAPS_ENUM_SET(loader->type,
++ VIR_DOMAIN_LOADER_TYPE_PFLASH);
++
++
++ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_READONLY))
++ VIR_DOMAIN_CAPS_ENUM_SET(loader->readonly,
++ VIR_TRISTATE_BOOL_YES,
++ VIR_TRISTATE_BOOL_NO);
++}
++
++
++static void
++virQEMUCapsFillDomainOSCaps(virQEMUCapsPtr qemuCaps,
++ virDomainCapsOSPtr os,
++ virArch arch)
++{
++ virDomainCapsLoaderPtr loader = &os->loader;
++
++ os->device.supported = true;
++ virQEMUCapsFillDomainLoaderCaps(qemuCaps, loader, arch);
++}
++
++
++static void
+ virQEMUCapsFillDomainDeviceDiskCaps(virQEMUCapsPtr qemuCaps,
+ virDomainCapsDeviceDiskPtr disk)
+ {
+@@ -3686,12 +3722,14 @@ void
+ virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
+ virQEMUCapsPtr qemuCaps)
+ {
++ virDomainCapsOSPtr os = &domCaps->os;
+ virDomainCapsDeviceDiskPtr disk = &domCaps->disk;
+ virDomainCapsDeviceHostdevPtr hostdev = &domCaps->hostdev;
+ int maxvcpus = virQEMUCapsGetMachineMaxCpus(qemuCaps, domCaps->machine);
+
+ domCaps->maxvcpus = maxvcpus;
+
++ virQEMUCapsFillDomainOSCaps(qemuCaps, os, domCaps->arch);
+ virQEMUCapsFillDomainDeviceDiskCaps(qemuCaps, disk);
+ virQEMUCapsFillDomainDeviceHostdevCaps(qemuCaps, hostdev);
+ }
+diff --git a/tests/domaincapsschemadata/domaincaps-basic.xml b/tests/domaincapsschemadata/domaincaps-basic.xml
+index 9963519..6171393 100644
+--- a/tests/domaincapsschemadata/domaincaps-basic.xml
++++ b/tests/domaincapsschemadata/domaincaps-basic.xml
+@@ -3,6 +3,7 @@
+ <domain>uml</domain>
+ <machine>my-machine-type</machine>
+ <arch>x86_64</arch>
++ <os supported='no'/>
+ <devices>
+ <disk supported='no'/>
+ <hostdev supported='no'/>
+diff --git a/tests/domaincapsschemadata/domaincaps-full.xml b/tests/domaincapsschemadata/domaincaps-full.xml
+index 58dd4cb..9722772 100644
+--- a/tests/domaincapsschemadata/domaincaps-full.xml
++++ b/tests/domaincapsschemadata/domaincaps-full.xml
+@@ -4,6 +4,19 @@
+ <machine>my-machine-type</machine>
+ <arch>x86_64</arch>
+ <vcpu max='255'/>
++ <os supported='yes'>
++ <loader supported='yes'>
++ <enum name='type'>
++ <value>rom</value>
++ <value>pflash</value>
++ </enum>
++ <enum name='readonly'>
++ <value>default</value>
++ <value>yes</value>
++ <value>no</value>
++ </enum>
++ </loader>
++ </os>
+ <devices>
+ <disk supported='yes'>
+ <enum name='diskDevice'>
+diff --git a/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml b/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
+index 8b63993..568cecb 100644
+--- a/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
++++ b/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
+@@ -3,6 +3,18 @@
+ <domain>kvm</domain>
+ <machine>pc-1.2</machine>
+ <arch>x86_64</arch>
++ <os supported='yes'>
++ <loader supported='yes'>
++ <enum name='type'>
++ <value>rom</value>
++ <value>pflash</value>
++ </enum>
++ <enum name='readonly'>
++ <value>yes</value>
++ <value>no</value>
++ </enum>
++ </loader>
++ </os>
+ <devices>
+ <disk supported='yes'>
+ <enum name='diskDevice'>
+diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c
+index 78197e2..f240643 100644
+--- a/tests/domaincapstest.c
++++ b/tests/domaincapstest.c
+@@ -38,10 +38,18 @@ static void
+ fillAll(virDomainCapsPtr domCaps,
+ void *opaque ATTRIBUTE_UNUSED)
+ {
++ virDomainCapsOSPtr os = &domCaps->os;
++ virDomainCapsLoaderPtr loader = &os->loader;
+ virDomainCapsDeviceDiskPtr disk = &domCaps->disk;
+ virDomainCapsDeviceHostdevPtr hostdev = &domCaps->hostdev;
+ domCaps->maxvcpus = 255;
+
++ os->device.supported = true;
++
++ loader->device.supported = true;
++ SET_ALL_BITS(loader->type);
++ SET_ALL_BITS(loader->readonly);
++
+ disk->device.supported = true;
+ SET_ALL_BITS(disk->diskDevice);
+ SET_ALL_BITS(disk->bus);
diff --git a/0018-qemu_capabilities-Change-virQEMUCapsFillDomainCaps-s.patch b/0018-qemu_capabilities-Change-virQEMUCapsFillDomainCaps-s.patch
new file mode 100644
index 0000000..23ec2a5
--- /dev/null
+++ b/0018-qemu_capabilities-Change-virQEMUCapsFillDomainCaps-s.patch
@@ -0,0 +1,192 @@
+From 103a146b669a778238485425f4eb69a5a1f5c747 Mon Sep 17 00:00:00 2001
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Wed, 17 Sep 2014 11:33:35 +0200
+Subject: [PATCH] qemu_capabilities: Change virQEMUCapsFillDomainCaps signature
+
+Up till now the virQEMUCapsFillDomainCaps() was type of void as
+there was no way for it to fail. This is, however, going to
+change in the next commit.
+
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+(cherry picked from commit 2b2e4a7acff5574dd82bfbd61a638270f6be54ef)
+---
+ src/qemu/qemu_capabilities.c | 25 ++++++++++++++++---------
+ src/qemu/qemu_capabilities.h | 4 ++--
+ src/qemu/qemu_driver.c | 3 ++-
+ tests/domaincapstest.c | 19 ++++++++++++-------
+ 4 files changed, 32 insertions(+), 19 deletions(-)
+
+diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
+index c999ee4..d2e5f47 100644
+--- a/src/qemu/qemu_capabilities.c
++++ b/src/qemu/qemu_capabilities.c
+@@ -3608,7 +3608,7 @@ virQEMUCapsGetDefaultMachine(virQEMUCapsPtr qemuCaps)
+ }
+
+
+-static void
++static int
+ virQEMUCapsFillDomainLoaderCaps(virQEMUCapsPtr qemuCaps,
+ virDomainCapsLoaderPtr loader,
+ virArch arch)
+@@ -3629,10 +3629,11 @@ virQEMUCapsFillDomainLoaderCaps(virQEMUCapsPtr qemuCaps,
+ VIR_DOMAIN_CAPS_ENUM_SET(loader->readonly,
+ VIR_TRISTATE_BOOL_YES,
+ VIR_TRISTATE_BOOL_NO);
++ return 0;
+ }
+
+
+-static void
++static int
+ virQEMUCapsFillDomainOSCaps(virQEMUCapsPtr qemuCaps,
+ virDomainCapsOSPtr os,
+ virArch arch)
+@@ -3640,11 +3641,13 @@ virQEMUCapsFillDomainOSCaps(virQEMUCapsPtr qemuCaps,
+ virDomainCapsLoaderPtr loader = &os->loader;
+
+ os->device.supported = true;
+- virQEMUCapsFillDomainLoaderCaps(qemuCaps, loader, arch);
++ if (virQEMUCapsFillDomainLoaderCaps(qemuCaps, loader, arch) < 0)
++ return -1;
++ return 0;
+ }
+
+
+-static void
++static int
+ virQEMUCapsFillDomainDeviceDiskCaps(virQEMUCapsPtr qemuCaps,
+ virDomainCapsDeviceDiskPtr disk)
+ {
+@@ -3667,10 +3670,11 @@ virQEMUCapsFillDomainDeviceDiskCaps(virQEMUCapsPtr qemuCaps,
+
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_USB_STORAGE))
+ VIR_DOMAIN_CAPS_ENUM_SET(disk->bus, VIR_DOMAIN_DISK_BUS_USB);
++ return 0;
+ }
+
+
+-static void
++static int
+ virQEMUCapsFillDomainDeviceHostdevCaps(virQEMUCapsPtr qemuCaps,
+ virDomainCapsDeviceHostdevPtr hostdev)
+ {
+@@ -3715,10 +3719,11 @@ virQEMUCapsFillDomainDeviceHostdevCaps(virQEMUCapsPtr qemuCaps,
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT,
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM);
+ }
++ return 0;
+ }
+
+
+-void
++int
+ virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
+ virQEMUCapsPtr qemuCaps)
+ {
+@@ -3729,7 +3734,9 @@ virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
+
+ domCaps->maxvcpus = maxvcpus;
+
+- virQEMUCapsFillDomainOSCaps(qemuCaps, os, domCaps->arch);
+- virQEMUCapsFillDomainDeviceDiskCaps(qemuCaps, disk);
+- virQEMUCapsFillDomainDeviceHostdevCaps(qemuCaps, hostdev);
++ if (virQEMUCapsFillDomainOSCaps(qemuCaps, os, domCaps->arch) < 0 ||
++ virQEMUCapsFillDomainDeviceDiskCaps(qemuCaps, disk) < 0 ||
++ virQEMUCapsFillDomainDeviceHostdevCaps(qemuCaps, hostdev) < 0)
++ return -1;
++ return 0;
+ }
+diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
+index 0980c00..828bba3 100644
+--- a/src/qemu/qemu_capabilities.h
++++ b/src/qemu/qemu_capabilities.h
+@@ -324,7 +324,7 @@ int virQEMUCapsInitGuestFromBinary(virCapsPtr caps,
+ virQEMUCapsPtr kvmbinCaps,
+ virArch guestarch);
+
+-void virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
+- virQEMUCapsPtr qemuCaps);
++int virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
++ virQEMUCapsPtr qemuCaps);
+
+ #endif /* __QEMU_CAPABILITIES_H__*/
+diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
+index 588eba4..9c1644c 100644
+--- a/src/qemu/qemu_driver.c
++++ b/src/qemu/qemu_driver.c
+@@ -17205,7 +17205,8 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn,
+ if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype)))
+ goto cleanup;
+
+- virQEMUCapsFillDomainCaps(domCaps, qemuCaps);
++ if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps) < 0)
++ goto cleanup;
+
+ ret = virDomainCapsFormat(domCaps);
+ cleanup:
+diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c
+index f240643..0c4b09f 100644
+--- a/tests/domaincapstest.c
++++ b/tests/domaincapstest.c
+@@ -28,13 +28,13 @@
+
+ #define VIR_FROM_THIS VIR_FROM_NONE
+
+-typedef void (*virDomainCapsFill)(virDomainCapsPtr domCaps,
+- void *opaque);
++typedef int (*virDomainCapsFill)(virDomainCapsPtr domCaps,
++ void *opaque);
+
+ #define SET_ALL_BITS(x) \
+ memset(&(x.values), 0xff, sizeof(x.values))
+
+-static void
++static int
+ fillAll(virDomainCapsPtr domCaps,
+ void *opaque ATTRIBUTE_UNUSED)
+ {
+@@ -60,18 +60,20 @@ fillAll(virDomainCapsPtr domCaps,
+ SET_ALL_BITS(hostdev->subsysType);
+ SET_ALL_BITS(hostdev->capsType);
+ SET_ALL_BITS(hostdev->pciBackend);
++ return 0;
+ }
+
+
+ #ifdef WITH_QEMU
+ # include "testutilsqemu.h"
+-static void
++static int
+ fillQemuCaps(virDomainCapsPtr domCaps,
+ void *opaque)
+ {
+ virQEMUCapsPtr qemuCaps = (virQEMUCapsPtr) opaque;
+
+- virQEMUCapsFillDomainCaps(domCaps, qemuCaps);
++ if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps) < 0)
++ return -1;
+
+ /* The function above tries to query host's KVM & VFIO capabilities by
+ * calling qemuHostdevHostSupportsPassthroughLegacy() and
+@@ -82,6 +84,7 @@ fillQemuCaps(virDomainCapsPtr domCaps,
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT,
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM,
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO);
++ return 0;
+ }
+ #endif /* WITH_QEMU */
+
+@@ -99,8 +102,10 @@ buildVirDomainCaps(const char *emulatorbin,
+ if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, type)))
+ goto cleanup;
+
+- if (fillFunc)
+- fillFunc(domCaps, opaque);
++ if (fillFunc && fillFunc(domCaps, opaque) < 0) {
++ virObjectUnref(domCaps);
++ domCaps = NULL;
++ }
+
+ cleanup:
+ return domCaps;
diff --git a/0019-domaincaps-Expose-UEFI-binary-path-if-it-exists.patch b/0019-domaincaps-Expose-UEFI-binary-path-if-it-exists.patch
new file mode 100644
index 0000000..fb27137
--- /dev/null
+++ b/0019-domaincaps-Expose-UEFI-binary-path-if-it-exists.patch
@@ -0,0 +1,444 @@
+From 64041dc7d34d7af3fd611d194bf2ab56729a13fa Mon Sep 17 00:00:00 2001
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Tue, 16 Sep 2014 19:52:54 -0400
+Subject: [PATCH] domaincaps: Expose UEFI binary path, if it exists
+
+Check to see if the UEFI binary mentioned in qemu.conf actually
+exists, and if so expose it in domcapabilities like
+
+<loader ...>
+ <value>/path/to/ovmf</value>
+</loader>
+
+We introduce some generic domcaps infrastructure for handling
+a dynamic list of string values, it may be of use for future bits.
+
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+(cherry picked from commit f05b6a918e283929f5d837cd1668cdcdb3834b9a)
+---
+ docs/formatdomaincaps.html.in | 6 +++
+ docs/schemas/domaincaps.rng | 17 +++++---
+ src/conf/domain_capabilities.c | 29 +++++++++++++
+ src/conf/domain_capabilities.h | 8 ++++
+ src/qemu/qemu_capabilities.c | 32 +++++++++++---
+ src/qemu/qemu_capabilities.h | 7 +++-
+ src/qemu/qemu_driver.c | 6 ++-
+ tests/domaincapsschemadata/domaincaps-full.xml | 2 +
+ .../domaincaps-qemu_1.6.50-1.xml | 1 +
+ tests/domaincapstest.c | 49 +++++++++++++++++++---
+ 10 files changed, 140 insertions(+), 17 deletions(-)
+
+diff --git a/docs/formatdomaincaps.html.in b/docs/formatdomaincaps.html.in
+index 34d746d..6959dfe 100644
+--- a/docs/formatdomaincaps.html.in
++++ b/docs/formatdomaincaps.html.in
+@@ -105,6 +105,7 @@
+ ...
+ <os supported='yes'>
+ <loader supported='yes'>
++ <value>/usr/share/OVMF/OVMF_CODE.fd</value>
+ <enum name='type'>
+ <value>rom</value>
+ <value>pflash</value>
+@@ -122,6 +123,11 @@
+ <p>For the <code>loader</code> element, the following can occur:</p>
+
+ <dl>
++ <dt>value</dt>
++ <dd>List of known loader paths. Currently this is only used
++ to advertise known locations of OVMF binaries for qemu. Binaries
++ will only be listed if they actually exist on disk.</dd>
++
+ <dt>type</dt>
+ <dd>Whether loader is a typical BIOS (<code>rom</code>) or
+ an UEFI binary (<code>pflash</code>). This refers to
+diff --git a/docs/schemas/domaincaps.rng b/docs/schemas/domaincaps.rng
+index ad8d966..f4a555f 100644
+--- a/docs/schemas/domaincaps.rng
++++ b/docs/schemas/domaincaps.rng
+@@ -47,6 +47,9 @@
+ <define name='loader'>
+ <element name='loader'>
+ <ref name='supported'/>
++ <optional>
++ <ref name='value'/>
++ </optional>
+ <ref name='enum'/>
+ </element>
+ </define>
+@@ -85,6 +88,14 @@
+ </element>
+ </define>
+
++ <define name='value'>
++ <zeroOrMore>
++ <element name='value'>
++ <text/>
++ </element>
++ </zeroOrMore>
++ </define>
++
+ <define name='supported'>
+ <attribute name='supported'>
+ <choice>
+@@ -100,11 +111,7 @@
+ <attribute name='name'>
+ <text/>
+ </attribute>
+- <zeroOrMore>
+- <element name='value'>
+- <text/>
+- </element>
+- </zeroOrMore>
++ <ref name='value'/>
+ </element>
+ </zeroOrMore>
+ </define>
+diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
+index 5a3c8e7..7c59912 100644
+--- a/src/conf/domain_capabilities.c
++++ b/src/conf/domain_capabilities.c
+@@ -48,12 +48,28 @@ VIR_ONCE_GLOBAL_INIT(virDomainCaps)
+
+
+ static void
++virDomainCapsStringValuesFree(virDomainCapsStringValuesPtr values)
++{
++ size_t i;
++
++ if (!values || !values->values)
++ return;
++
++ for (i = 0; i < values->nvalues; i++)
++ VIR_FREE(values->values[i]);
++ VIR_FREE(values->values);
++}
++
++
++static void
+ virDomainCapsDispose(void *obj)
+ {
+ virDomainCapsPtr caps = obj;
+
+ VIR_FREE(caps->path);
+ VIR_FREE(caps->machine);
++
++ virDomainCapsStringValuesFree(&caps->os.loader.values);
+ }
+
+
+@@ -156,6 +172,18 @@ virDomainCapsEnumFormat(virBufferPtr buf,
+ return ret;
+ }
+
++
++static void
++virDomainCapsStringValuesFormat(virBufferPtr buf,
++ virDomainCapsStringValuesPtr values)
++{
++ size_t i;
++
++ for (i = 0; i < values->nvalues; i++)
++ virBufferEscapeString(buf, "<value>%s</value>\n", values->values[i]);
++}
++
++
+ #define FORMAT_PROLOGUE(item) \
+ do { \
+ virBufferAsprintf(buf, "<" #item " supported='%s'%s\n", \
+@@ -185,6 +213,7 @@ virDomainCapsLoaderFormat(virBufferPtr buf,
+ {
+ FORMAT_PROLOGUE(loader);
+
++ virDomainCapsStringValuesFormat(buf, &loader->values);
+ ENUM_PROCESS(loader, type, virDomainLoaderTypeToString);
+ ENUM_PROCESS(loader, readonly, virTristateBoolTypeToString);
+
+diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h
+index 768646b..597ac75 100644
+--- a/src/conf/domain_capabilities.h
++++ b/src/conf/domain_capabilities.h
+@@ -37,6 +37,13 @@ struct _virDomainCapsEnum {
+ unsigned int values; /* Bitmask of values supported in the corresponding enum */
+ };
+
++typedef struct _virDomainCapsStringValues virDomainCapsStringValues;
++typedef virDomainCapsStringValues *virDomainCapsStringValuesPtr;
++struct _virDomainCapsStringValues {
++ char **values; /* raw string values */
++ size_t nvalues; /* number of strings */
++};
++
+ typedef struct _virDomainCapsDevice virDomainCapsDevice;
+ typedef virDomainCapsDevice *virDomainCapsDevicePtr;
+ struct _virDomainCapsDevice {
+@@ -47,6 +54,7 @@ typedef struct _virDomainCapsLoader virDomainCapsLoader;
+ typedef virDomainCapsLoader *virDomainCapsLoaderPtr;
+ struct _virDomainCapsLoader {
+ virDomainCapsDevice device;
++ virDomainCapsStringValues values; /* Info about values for the element */
+ virDomainCapsEnum type; /* Info about virDomainLoader */
+ virDomainCapsEnum readonly; /* Info about readonly:virTristateBool */
+ };
+diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
+index d2e5f47..651bacd 100644
+--- a/src/qemu/qemu_capabilities.c
++++ b/src/qemu/qemu_capabilities.c
+@@ -3611,10 +3611,30 @@ virQEMUCapsGetDefaultMachine(virQEMUCapsPtr qemuCaps)
+ static int
+ virQEMUCapsFillDomainLoaderCaps(virQEMUCapsPtr qemuCaps,
+ virDomainCapsLoaderPtr loader,
+- virArch arch)
++ virArch arch,
++ virQEMUDriverConfigPtr cfg)
+ {
++ size_t i;
++
+ loader->device.supported = true;
+
++ if (VIR_ALLOC_N(loader->values.values, cfg->nloader) < 0)
++ return -1;
++
++ for (i = 0; i < cfg->nloader; i++) {
++ const char *filename = cfg->loader[i];
++
++ if (!virFileExists(filename)) {
++ VIR_DEBUG("loader filename=%s does not exist", filename);
++ continue;
++ }
++
++ if (VIR_STRDUP(loader->values.values[loader->values.nvalues],
++ filename) < 0)
++ return -1;
++ loader->values.nvalues++;
++ }
++
+ VIR_DOMAIN_CAPS_ENUM_SET(loader->type,
+ VIR_DOMAIN_LOADER_TYPE_ROM);
+
+@@ -3636,12 +3656,13 @@ virQEMUCapsFillDomainLoaderCaps(virQEMUCapsPtr qemuCaps,
+ static int
+ virQEMUCapsFillDomainOSCaps(virQEMUCapsPtr qemuCaps,
+ virDomainCapsOSPtr os,
+- virArch arch)
++ virArch arch,
++ virQEMUDriverConfigPtr cfg)
+ {
+ virDomainCapsLoaderPtr loader = &os->loader;
+
+ os->device.supported = true;
+- if (virQEMUCapsFillDomainLoaderCaps(qemuCaps, loader, arch) < 0)
++ if (virQEMUCapsFillDomainLoaderCaps(qemuCaps, loader, arch, cfg) < 0)
+ return -1;
+ return 0;
+ }
+@@ -3725,7 +3746,8 @@ virQEMUCapsFillDomainDeviceHostdevCaps(virQEMUCapsPtr qemuCaps,
+
+ int
+ virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
+- virQEMUCapsPtr qemuCaps)
++ virQEMUCapsPtr qemuCaps,
++ virQEMUDriverConfigPtr cfg)
+ {
+ virDomainCapsOSPtr os = &domCaps->os;
+ virDomainCapsDeviceDiskPtr disk = &domCaps->disk;
+@@ -3734,7 +3756,7 @@ virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
+
+ domCaps->maxvcpus = maxvcpus;
+
+- if (virQEMUCapsFillDomainOSCaps(qemuCaps, os, domCaps->arch) < 0 ||
++ if (virQEMUCapsFillDomainOSCaps(qemuCaps, os, domCaps->arch, cfg) < 0 ||
+ virQEMUCapsFillDomainDeviceDiskCaps(qemuCaps, disk) < 0 ||
+ virQEMUCapsFillDomainDeviceHostdevCaps(qemuCaps, hostdev) < 0)
+ return -1;
+diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
+index 828bba3..cf69e59 100644
+--- a/src/qemu/qemu_capabilities.h
++++ b/src/qemu/qemu_capabilities.h
+@@ -324,7 +324,12 @@ int virQEMUCapsInitGuestFromBinary(virCapsPtr caps,
+ virQEMUCapsPtr kvmbinCaps,
+ virArch guestarch);
+
++/* Forward declaration */
++typedef struct _virQEMUDriverConfig virQEMUDriverConfig;
++typedef virQEMUDriverConfig *virQEMUDriverConfigPtr;
++
+ int virQEMUCapsFillDomainCaps(virDomainCapsPtr domCaps,
+- virQEMUCapsPtr qemuCaps);
++ virQEMUCapsPtr qemuCaps,
++ virQEMUDriverConfigPtr cfg);
+
+ #endif /* __QEMU_CAPABILITIES_H__*/
+diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
+index 9c1644c..0d895c6 100644
+--- a/src/qemu/qemu_driver.c
++++ b/src/qemu/qemu_driver.c
+@@ -17133,12 +17133,15 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn,
+ int virttype; /* virDomainVirtType */
+ virDomainCapsPtr domCaps = NULL;
+ int arch = virArchFromHost(); /* virArch */
++ virQEMUDriverConfigPtr cfg = NULL;
+
+ virCheckFlags(0, ret);
+
+ if (virConnectGetDomainCapabilitiesEnsureACL(conn) < 0)
+ return ret;
+
++ cfg = virQEMUDriverGetConfig(driver);
++
+ if (qemuHostdevHostSupportsPassthroughLegacy())
+ virttype = VIR_DOMAIN_VIRT_KVM;
+ else
+@@ -17205,11 +17208,12 @@ qemuConnectGetDomainCapabilities(virConnectPtr conn,
+ if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype)))
+ goto cleanup;
+
+- if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps) < 0)
++ if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps, cfg) < 0)
+ goto cleanup;
+
+ ret = virDomainCapsFormat(domCaps);
+ cleanup:
++ virObjectUnref(cfg);
+ virObjectUnref(domCaps);
+ virObjectUnref(qemuCaps);
+ return ret;
+diff --git a/tests/domaincapsschemadata/domaincaps-full.xml b/tests/domaincapsschemadata/domaincaps-full.xml
+index 9722772..96202bc 100644
+--- a/tests/domaincapsschemadata/domaincaps-full.xml
++++ b/tests/domaincapsschemadata/domaincaps-full.xml
+@@ -6,6 +6,8 @@
+ <vcpu max='255'/>
+ <os supported='yes'>
+ <loader supported='yes'>
++ <value>/foo/bar</value>
++ <value>/tmp/my_path</value>
+ <enum name='type'>
+ <value>rom</value>
+ <value>pflash</value>
+diff --git a/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml b/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
+index 568cecb..346ef65 100644
+--- a/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
++++ b/tests/domaincapsschemadata/domaincaps-qemu_1.6.50-1.xml
+@@ -5,6 +5,7 @@
+ <arch>x86_64</arch>
+ <os supported='yes'>
+ <loader supported='yes'>
++ <value>/usr/share/OVMF/OVMF_CODE.fd</value>
+ <enum name='type'>
+ <value>rom</value>
+ <value>pflash</value>
+diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c
+index 0c4b09f..8543963 100644
+--- a/tests/domaincapstest.c
++++ b/tests/domaincapstest.c
+@@ -34,6 +34,27 @@ typedef int (*virDomainCapsFill)(virDomainCapsPtr domCaps,
+ #define SET_ALL_BITS(x) \
+ memset(&(x.values), 0xff, sizeof(x.values))
+
++static int ATTRIBUTE_SENTINEL
++fillStringValues(virDomainCapsStringValuesPtr values, ...)
++{
++ int ret = 0;
++ va_list list;
++ const char *str;
++
++ va_start(list, values);
++ while ((str = va_arg(list, const char *))) {
++ if (VIR_REALLOC_N(values->values, values->nvalues + 1) < 0 ||
++ VIR_STRDUP(values->values[values->nvalues], str) < 0) {
++ ret = -1;
++ break;
++ }
++ values->nvalues++;
++ }
++ va_end(list);
++
++ return ret;
++}
++
+ static int
+ fillAll(virDomainCapsPtr domCaps,
+ void *opaque ATTRIBUTE_UNUSED)
+@@ -49,6 +70,11 @@ fillAll(virDomainCapsPtr domCaps,
+ loader->device.supported = true;
+ SET_ALL_BITS(loader->type);
+ SET_ALL_BITS(loader->readonly);
++ if (fillStringValues(&loader->values,
++ "/foo/bar",
++ "/tmp/my_path",
++ NULL) < 0)
++ return -1;
+
+ disk->device.supported = true;
+ SET_ALL_BITS(disk->diskDevice);
+@@ -66,13 +92,21 @@ fillAll(virDomainCapsPtr domCaps,
+
+ #ifdef WITH_QEMU
+ # include "testutilsqemu.h"
++
++struct fillQemuCapsData {
++ virQEMUCapsPtr qemuCaps;
++ virQEMUDriverConfigPtr cfg;
++};
++
+ static int
+ fillQemuCaps(virDomainCapsPtr domCaps,
+ void *opaque)
+ {
+- virQEMUCapsPtr qemuCaps = (virQEMUCapsPtr) opaque;
++ struct fillQemuCapsData *data = (struct fillQemuCapsData *) opaque;
++ virQEMUCapsPtr qemuCaps = data->qemuCaps;
++ virQEMUDriverConfigPtr cfg = data->cfg;
+
+- if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps) < 0)
++ if (virQEMUCapsFillDomainCaps(domCaps, qemuCaps, cfg) < 0)
+ return -1;
+
+ /* The function above tries to query host's KVM & VFIO capabilities by
+@@ -97,7 +131,7 @@ buildVirDomainCaps(const char *emulatorbin,
+ virDomainCapsFill fillFunc,
+ void *opaque)
+ {
+- virDomainCapsPtr domCaps;
++ virDomainCapsPtr domCaps, ret = NULL;
+
+ if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, type)))
+ goto cleanup;
+@@ -107,8 +141,9 @@ buildVirDomainCaps(const char *emulatorbin,
+ domCaps = NULL;
+ }
+
++ ret = domCaps;
+ cleanup:
+- return domCaps;
++ return ret;
+ }
+
+ struct test_virDomainCapsFormatData {
+@@ -182,13 +217,16 @@ mymain(void)
+
+ #ifdef WITH_QEMU
+
++ virQEMUDriverConfigPtr cfg = virQEMUDriverConfigNew(false);
++
+ # define DO_TEST_QEMU(Filename, QemuCapsFile, Emulatorbin, Machine, Arch, Type, ...) \
+ do { \
+ const char *capsPath = abs_srcdir "/qemucapabilitiesdata/" QemuCapsFile ".caps"; \
+ virQEMUCapsPtr qemuCaps = qemuTestParseCapabilities(capsPath); \
++ struct fillQemuCapsData fillData = {.qemuCaps = qemuCaps, .cfg = cfg}; \
+ struct test_virDomainCapsFormatData data = {.filename = Filename, \
+ .emulatorbin = Emulatorbin, .machine = Machine, .arch = Arch, \
+- .type = Type, .fillFunc = fillQemuCaps, .opaque = qemuCaps}; \
++ .type = Type, .fillFunc = fillQemuCaps, .opaque = &fillData}; \
+ if (!qemuCaps) { \
+ fprintf(stderr, "Unable to build qemu caps from %s\n", capsPath); \
+ ret = -1; \
+@@ -199,6 +237,7 @@ mymain(void)
+ DO_TEST_QEMU("qemu_1.6.50-1", "caps_1.6.50-1", "/usr/bin/qemu-system-x86_64",
+ "pc-1.2", VIR_ARCH_X86_64, VIR_DOMAIN_VIRT_KVM);
+
++ virObjectUnref(cfg);
+ #endif /* WITH_QEMU */
+
+ return ret;
diff --git a/0020-domaincapstest-Run-cleanly-on-systems-missing-OVMF-f.patch b/0020-domaincapstest-Run-cleanly-on-systems-missing-OVMF-f.patch
new file mode 100644
index 0000000..9b1d453
--- /dev/null
+++ b/0020-domaincapstest-Run-cleanly-on-systems-missing-OVMF-f.patch
@@ -0,0 +1,40 @@
+From 6fcd1ae861279589172783c4937367685469f265 Mon Sep 17 00:00:00 2001
+From: Michal Privoznik <mprivozn at redhat.com>
+Date: Wed, 17 Sep 2014 17:17:03 +0200
+Subject: [PATCH] domaincapstest: Run cleanly on systems missing OVMF firmware
+
+As of f05b6a918e28 the test produces the list of paths that can
+be passed to <loader/> and libvirt knows about them. However,
+during the process of generating the list the paths are checked
+for their presence. This may produce different results on
+different systems. Therefore, the path - if missing - is
+added to pretend it's there.
+
+Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
+(cherry picked from commit b3f42da6b77644107bcbaf720d7ed9cef5c798a2)
+---
+ tests/domaincapstest.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c
+index 8543963..067ad4d 100644
+--- a/tests/domaincapstest.c
++++ b/tests/domaincapstest.c
+@@ -118,6 +118,17 @@ fillQemuCaps(virDomainCapsPtr domCaps,
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT,
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM,
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO);
++
++ /* Moreover, as of f05b6a918e28 we are expecting to see
++ * OVMF_CODE.fd file which may not exists everywhere. */
++ if (!domCaps->os.loader.values.nvalues) {
++ virDomainCapsLoaderPtr loader = &domCaps->os.loader;
++
++ if (fillStringValues(&loader->values,
++ "/usr/share/OVMF/OVMF_CODE.fd",
++ NULL) < 0)
++ return -1;
++ }
+ return 0;
+ }
+ #endif /* WITH_QEMU */
diff --git a/libvirt.spec b/libvirt.spec
index 6044558..ada2e30 100644
--- a/libvirt.spec
+++ b/libvirt.spec
@@ -366,7 +366,7 @@
Summary: Library providing a simple virtualization API
Name: libvirt
Version: 1.2.8
-Release: 3%{?dist}%{?extra_release}
+Release: 4%{?dist}%{?extra_release}
License: LGPLv2+
Group: Development/Libraries
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
@@ -382,7 +382,6 @@ Source: http://libvirt.org/sources/%{?mainturl}libvirt-%{version}.tar.gz
Patch0001: 0001-network-try-to-eliminate-default-network-conflict-du.patch
Patch0002: 0002-network-detect-conflicting-route-even-if-it-is-the-f.patch
# Fix directory creation at session daemon startup (bz #1139672)
-# (Patch 5 is posted but not in git as of 2014-09-15)
Patch0003: 0003-rpc-reformat-the-flow-to-make-a-bit-more-sense.patch
Patch0004: 0004-remove-redundant-pidfile-path-constructions.patch
Patch0005: 0005-util-fix-potential-leak-in-error-codepath.patch
@@ -393,6 +392,19 @@ Patch0007: 0007-rpc-make-daemon-spawning-a-bit-more-intelligent.patch
Patch0008: 0008-spec-Don-t-build-wireshark-on-f21-non-upstream.patch
# Fix preun script (bz #1142367)
Patch0009: 0009-spec-Fix-preun-script-for-daemon.patch
+# Don't mess up labelling of /dev/net/tun (bz #1141879)
+Patch0010: 0010-virSecuritySELinuxSetTapFDLabel-Temporarily-revert-t.patch
+# pflash/nvram support for UEFI/OVMF
+Patch0011: 0011-conf-Extend-loader-and-introduce-nvram.patch
+Patch0012: 0012-qemu-Implement-extended-loader-and-nvram.patch
+Patch0013: 0013-qemu-Automatically-create-NVRAM-store.patch
+Patch0014: 0014-nvram-Fix-permissions.patch
+Patch0015: 0015-virDomainUndefineFlags-Allow-NVRAM-unlinking.patch
+Patch0016: 0016-formatdomain-Update-loader-example-to-match-the-rest.patch
+Patch0017: 0017-domaincaps-Expose-UEFI-capability.patch
+Patch0018: 0018-qemu_capabilities-Change-virQEMUCapsFillDomainCaps-s.patch
+Patch0019: 0019-domaincaps-Expose-UEFI-binary-path-if-it-exists.patch
+Patch0020: 0020-domaincapstest-Run-cleanly-on-systems-missing-OVMF-f.patch
%if %{with_libvirtd}
Requires: libvirt-daemon = %{version}-%{release}
@@ -1223,7 +1235,6 @@ driver
%patch0001 -p1
%patch0002 -p1
# Fix directory creation at session daemon startup (bz #1139672)
-# (Patch 5 is posted but not in git as of 2014-09-15)
%patch0003 -p1
%patch0004 -p1
%patch0005 -p1
@@ -1234,6 +1245,19 @@ driver
%patch0008 -p1
# Fix preun script (bz #1142367)
%patch0009 -p1
+# Don't mess up labelling of /dev/net/tun (bz #1141879)
+%patch0010 -p1
+# pflash/nvram support for UEFI/OVMF
+%patch0011 -p1
+%patch0012 -p1
+%patch0013 -p1
+%patch0014 -p1
+%patch0015 -p1
+%patch0016 -p1
+%patch0017 -p1
+%patch0018 -p1
+%patch0019 -p1
+%patch0020 -p1
%build
%if ! %{with_xen}
@@ -2004,6 +2028,7 @@ exit 0
%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/
%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/
%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/target/
+%dir %attr(0711, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/nvram/
%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/cache/libvirt/qemu/
%{_datadir}/augeas/lenses/libvirtd_qemu.aug
%{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
@@ -2106,6 +2131,7 @@ exit 0
%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/
%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/
%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/channel/target/
+%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/nvram/
%dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/cache/libvirt/qemu/
%{_datadir}/augeas/lenses/libvirtd_qemu.aug
%{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
@@ -2309,6 +2335,10 @@ exit 0
%doc examples/systemtap
%changelog
+* Thu Sep 18 2014 Cole Robinson <crobinso at redhat.com> - 1.2.8-4
+- Don't mess up labelling of /dev/net/tun (bz #1141879)
+- pflash/nvram support for UEFI/OVMF
+
* Wed Sep 17 2014 Cole Robinson <crobinso at redhat.com> - 1.2.8-3
- Fix preun script (bz #1142367)
More information about the scm-commits
mailing list