9119d9
From 51566a10c2f7cdbfb04b8be8a163f496a3792b29 Mon Sep 17 00:00:00 2001
9119d9
Message-Id: <51566a10c2f7cdbfb04b8be8a163f496a3792b29@dist-git>
9119d9
From: Michal Privoznik <mprivozn@redhat.com>
9119d9
Date: Wed, 10 Sep 2014 10:11:44 +0200
9119d9
Subject: [PATCH] qemu: Implement extended loader and nvram
9119d9
9119d9
https://bugzilla.redhat.com/show_bug.cgi?id=1112257
9119d9
9119d9
QEMU now supports UEFI with the following command line:
9119d9
9119d9
  -drive file=/usr/share/OVMF/OVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on \
9119d9
  -drive file=/usr/share/OVMF/OVMF_VARS.fd,if=pflash,format=raw,unit=1 \
9119d9
9119d9
where the first line reflects <loader> and the second one <nvram>.
9119d9
Moreover, these two lines obsolete the -bios argument.
9119d9
9119d9
Note that UEFI is unusable without ACPI. This is handled properly now.
9119d9
Among with this extension, the variable file is expected to be
9119d9
writable and hence we need security drivers to label it.
9119d9
9119d9
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
9119d9
Acked-by: Laszlo Ersek <lersek@redhat.com>
9119d9
(cherry picked from commit 542899168c382610dbad9a597d27ef3d7c699f68)
9119d9
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
9119d9
---
9119d9
 src/qemu/qemu_command.c                            | 94 +++++++++++++++++++++-
9119d9
 src/security/security_dac.c                        |  8 ++
9119d9
 src/security/security_selinux.c                    |  8 ++
9119d9
 .../qemuxml2argvdata/qemuxml2argv-bios-nvram.args  | 10 +++
9119d9
 tests/qemuxml2argvtest.c                           |  2 +
9119d9
 5 files changed, 118 insertions(+), 4 deletions(-)
9119d9
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.args
9119d9
9119d9
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
9119d9
index 3cb2e0b..718533b 100644
9119d9
--- a/src/qemu/qemu_command.c
9119d9
+++ b/src/qemu/qemu_command.c
9119d9
@@ -7370,6 +7370,94 @@ qemuBuildChrDeviceCommandLine(virCommandPtr cmd,
9119d9
     return 0;
9119d9
 }
9119d9
 
9119d9
+static int
9119d9
+qemuBuildDomainLoaderCommandLine(virCommandPtr cmd,
9119d9
+                                 virDomainDefPtr def,
9119d9
+                                 virQEMUCapsPtr qemuCaps)
9119d9
+{
9119d9
+    int ret = -1;
9119d9
+    virDomainLoaderDefPtr loader = def->os.loader;
9119d9
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
9119d9
+    int unit = 0;
9119d9
+
9119d9
+    if (!loader)
9119d9
+        return 0;
9119d9
+
9119d9
+    switch ((virDomainLoader) loader->type) {
9119d9
+    case VIR_DOMAIN_LOADER_TYPE_ROM:
9119d9
+        virCommandAddArg(cmd, "-bios");
9119d9
+        virCommandAddArg(cmd, loader->path);
9119d9
+        break;
9119d9
+
9119d9
+    case VIR_DOMAIN_LOADER_TYPE_PFLASH:
9119d9
+        /* UEFI is supported only for x86_64 currently */
9119d9
+        if (def->os.arch != VIR_ARCH_X86_64) {
9119d9
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
9119d9
+                           _("pflash is not supported for %s guest architecture"),
9119d9
+                           virArchToString(def->os.arch));
9119d9
+            goto cleanup;
9119d9
+        }
9119d9
+
9119d9
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE)) {
9119d9
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
9119d9
+                           _("this QEMU binary doesn't support -drive"));
9119d9
+            goto cleanup;
9119d9
+        }
9119d9
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_FORMAT)) {
9119d9
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
9119d9
+                           _("this QEMU binary doesn't support passing "
9119d9
+                             "drive format"));
9119d9
+            goto cleanup;
9119d9
+        }
9119d9
+        if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_NO_ACPI) &&
9119d9
+            def->features[VIR_DOMAIN_FEATURE_ACPI] != VIR_TRISTATE_SWITCH_ON) {
9119d9
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
9119d9
+                           _("ACPI must be enabled in order to use UEFI"));
9119d9
+            goto cleanup;
9119d9
+        }
9119d9
+
9119d9
+        virBufferAsprintf(&buf,
9119d9
+                          "file=%s,if=pflash,format=raw,unit=%d",
9119d9
+                          loader->path, unit);
9119d9
+        unit++;
9119d9
+
9119d9
+        if (loader->readonly) {
9119d9
+            if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DRIVE_READONLY)) {
9119d9
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
9119d9
+                               _("this qemu doesn't support passing "
9119d9
+                                 "readonly attribute"));
9119d9
+                goto cleanup;
9119d9
+            }
9119d9
+
9119d9
+            virBufferAsprintf(&buf, ",readonly=%s",
9119d9
+                              virTristateSwitchTypeToString(loader->readonly));
9119d9
+        }
9119d9
+
9119d9
+        virCommandAddArg(cmd, "-drive");
9119d9
+        virCommandAddArgBuffer(cmd, &buf;;
9119d9
+
9119d9
+        if (loader->nvram) {
9119d9
+            virBufferFreeAndReset(&buf;;
9119d9
+            virBufferAsprintf(&buf,
9119d9
+                              "file=%s,if=pflash,format=raw,unit=%d",
9119d9
+                              loader->nvram, unit);
9119d9
+
9119d9
+            virCommandAddArg(cmd, "-drive");
9119d9
+            virCommandAddArgBuffer(cmd, &buf;;
9119d9
+        }
9119d9
+        break;
9119d9
+
9119d9
+    case VIR_DOMAIN_LOADER_TYPE_LAST:
9119d9
+        /* nada */
9119d9
+        break;
9119d9
+    }
9119d9
+
9119d9
+    ret = 0;
9119d9
+ cleanup:
9119d9
+    virBufferFreeAndReset(&buf;;
9119d9
+    return ret;
9119d9
+}
9119d9
+
9119d9
 qemuBuildCommandLineCallbacks buildCommandLineCallbacks = {
9119d9
     .qemuGetSCSIDeviceSgName = virSCSIDeviceGetSgName,
9119d9
 };
9119d9
@@ -7525,10 +7613,8 @@ qemuBuildCommandLine(virConnectPtr conn,
9119d9
             virCommandAddArg(cmd, "-enable-nesting");
9119d9
     }
9119d9
 
9119d9
-    if (def->os.loader) {
9119d9
-        virCommandAddArg(cmd, "-bios");
9119d9
-        virCommandAddArg(cmd, def->os.loader->path);
9119d9
-    }
9119d9
+    if (qemuBuildDomainLoaderCommandLine(cmd, def, qemuCaps) < 0)
9119d9
+        goto error;
9119d9
 
9119d9
     /* Set '-m MB' based on maxmem, because the lower 'memory' limit
9119d9
      * is set post-startup using the balloon driver. If balloon driver
9119d9
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
9119d9
index e62828e..e398d2c 100644
9119d9
--- a/src/security/security_dac.c
9119d9
+++ b/src/security/security_dac.c
9119d9
@@ -960,6 +960,10 @@ virSecurityDACRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
9119d9
             rc = -1;
9119d9
     }
9119d9
 
9119d9
+    if (def->os.loader && def->os.loader->nvram &&
9119d9
+        virSecurityDACRestoreSecurityFileLabel(def->os.loader->nvram) < 0)
9119d9
+        rc = -1;
9119d9
+
9119d9
     if (def->os.kernel &&
9119d9
         virSecurityDACRestoreSecurityFileLabel(def->os.kernel) < 0)
9119d9
         rc = -1;
9119d9
@@ -1036,6 +1040,10 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
9119d9
     if (virSecurityDACGetImageIds(secdef, priv, &user, &group))
9119d9
         return -1;
9119d9
 
9119d9
+    if (def->os.loader && def->os.loader->nvram &&
9119d9
+        virSecurityDACSetOwnership(def->os.loader->nvram, user, group) < 0)
9119d9
+        return -1;
9119d9
+
9119d9
     if (def->os.kernel &&
9119d9
         virSecurityDACSetOwnership(def->os.kernel, user, group) < 0)
9119d9
         return -1;
9119d9
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
9119d9
index e8c13db..65f0d64 100644
9119d9
--- a/src/security/security_selinux.c
9119d9
+++ b/src/security/security_selinux.c
9119d9
@@ -1911,6 +1911,10 @@ virSecuritySELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
9119d9
                                      mgr) < 0)
9119d9
         rc = -1;
9119d9
 
9119d9
+    if (def->os.loader && def->os.loader->nvram &&
9119d9
+        virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.loader->nvram) < 0)
9119d9
+        rc = -1;
9119d9
+
9119d9
     if (def->os.kernel &&
9119d9
         virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.kernel) < 0)
9119d9
         rc = -1;
9119d9
@@ -2294,6 +2298,10 @@ virSecuritySELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
9119d9
                                      mgr) < 0)
9119d9
         return -1;
9119d9
 
9119d9
+    if (def->os.loader && def->os.loader->nvram &&
9119d9
+        virSecuritySELinuxSetFilecon(def->os.loader->nvram, data->content_context) < 0)
9119d9
+        return -1;
9119d9
+
9119d9
     if (def->os.kernel &&
9119d9
         virSecuritySELinuxSetFilecon(def->os.kernel, data->content_context) < 0)
9119d9
         return -1;
9119d9
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.args b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.args
9119d9
new file mode 100644
9119d9
index 0000000..b51e8f3
9119d9
--- /dev/null
9119d9
+++ b/tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.args
9119d9
@@ -0,0 +1,10 @@
9119d9
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test QEMU_AUDIO_DRV=none \
9119d9
+/usr/bin/qemu -S -M pc \
9119d9
+-drive file=/usr/share/OVMF/OVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on \
9119d9
+-drive file=/usr/share/OVMF/OVMF_VARS.fd,if=pflash,format=raw,unit=1 \
9119d9
+-m 1024 -smp 1 -nographic -nodefaults \
9119d9
+-monitor unix:/tmp/test-monitor,server,nowait -boot c -usb \
9119d9
+-drive file=/dev/HostVG/QEMUGuest1,if=none,id=drive-ide0-0-0,format=raw \
9119d9
+-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
9119d9
+-serial pty -device usb-tablet,id=input0 \
9119d9
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
9119d9
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
9119d9
index 3feb2fe..5c28253 100644
9119d9
--- a/tests/qemuxml2argvtest.c
9119d9
+++ b/tests/qemuxml2argvtest.c
9119d9
@@ -642,6 +642,8 @@ mymain(void)
9119d9
     DO_TEST_FAILURE("reboot-timeout-enabled", NONE);
9119d9
 
9119d9
     DO_TEST("bios", QEMU_CAPS_DEVICE, QEMU_CAPS_SGA);
9119d9
+    DO_TEST("bios-nvram", QEMU_CAPS_DEVICE, QEMU_CAPS_DRIVE,
9119d9
+            QEMU_CAPS_DRIVE_FORMAT, QEMU_CAPS_DRIVE_READONLY);
9119d9
     DO_TEST("clock-utc", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE);
9119d9
     DO_TEST("clock-localtime", NONE);
9119d9
     DO_TEST("clock-localtime-basis-localtime", QEMU_CAPS_RTC);
9119d9
-- 
9119d9
2.1.0
9119d9