[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 @@
+   ...
+   &lt;os&gt;
+     &lt;type&gt;hvm&lt;/type&gt;
+-    &lt;loader&gt;/usr/lib/xen/boot/hvmloader&lt;/loader&gt;
++    &lt;loader readonly='on' type='rom'&gt;/usr/lib/xen/boot/hvmloader&lt;/loader&gt;
++    &lt;nvram&gt;/var/lib/libvirt/nvram/guest_VARS.fd&lt;/nvram&gt;
+     &lt;boot dev='hd'/&gt;
+     &lt;boot dev='cdrom'/&gt;
+     &lt;bootmenu enable='yes' timeout='3000'/&gt;
+@@ -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&amp;test</loader>
++    <loader type='rom'>/usr/lib/xen/boot/hvmloader&amp;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 @@
+   &lt;os&gt;
+     &lt;type&gt;hvm&lt;/type&gt;
+     &lt;loader readonly='on' type='rom'&gt;/usr/lib/xen/boot/hvmloader&lt;/loader&gt;
+-    &lt;nvram&gt;/var/lib/libvirt/nvram/guest_VARS.fd&lt;/nvram&gt;
++    &lt;nvram template='/usr/share/OVMF/OVMF_VARS.fd'&gt;/var/lib/libvirt/nvram/guest_VARS.fd&lt;/nvram&gt;
+     &lt;boot dev='hd'/&gt;
+     &lt;boot dev='cdrom'/&gt;
+     &lt;bootmenu enable='yes' timeout='3000'/&gt;
+@@ -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 @@
+   ...
+   &lt;os&gt;
+     &lt;type&gt;hvm&lt;/type&gt;
+-    &lt;loader readonly='on' type='rom'&gt;/usr/lib/xen/boot/hvmloader&lt;/loader&gt;
++    &lt;loader readonly='yes' type='rom'&gt;/usr/lib/xen/boot/hvmloader&lt;/loader&gt;
+     &lt;nvram template='/usr/share/OVMF/OVMF_VARS.fd'&gt;/var/lib/libvirt/nvram/guest_VARS.fd&lt;/nvram&gt;
+     &lt;boot dev='hd'/&gt;
+     &lt;boot dev='cdrom'/&gt;
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>
++&lt;domainCapabilities&gt;
++  ...
++  &lt;os supported='yes'&gt;
++    &lt;loader supported='yes'&gt;
++      &lt;enum name='type'&gt;
++        &lt;value&gt;rom&lt;/value&gt;
++        &lt;value&gt;pflash&lt;/value&gt;
++      &lt;/enum&gt;
++      &lt;enum name='readonly'&gt;
++        &lt;value&gt;yes&lt;/value&gt;
++        &lt;value&gt;no&lt;/value&gt;
++      &lt;/enum&gt;
++    &lt;/loader&gt;
++  &lt;/os&gt;
++  ...
++&lt;domainCapabilities&gt;
++</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 &lt;loader/&gt;
++      element.</dd>
++
++      <dt>readonly</dt>
++      <dd>Options for the <code>readonly</code> attribute of the
++      &lt;loader/&gt; 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 @@
+   ...
+   &lt;os supported='yes'&gt;
+     &lt;loader supported='yes'&gt;
++      &lt;value&gt;/usr/share/OVMF/OVMF_CODE.fd&lt;/value&gt;
+       &lt;enum name='type'&gt;
+         &lt;value&gt;rom&lt;/value&gt;
+         &lt;value&gt;pflash&lt;/value&gt;
+@@ -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