]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: Implement extended loader and nvram
authorMichal Privoznik <mprivozn@redhat.com>
Thu, 7 Aug 2014 11:50:00 +0000 (13:50 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Wed, 10 Sep 2014 07:38:07 +0000 (09:38 +0200)
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@redhat.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
src/qemu/qemu_command.c
src/security/security_dac.c
src/security/security_selinux.c
tests/qemuxml2argvdata/qemuxml2argv-bios-nvram.args [new file with mode: 0644]
tests/qemuxml2argvtest.c

index c67b3ad368868e63d30bc4b5e242c6a73767c99e..5856fe7b7a396324ee60b3b95967329721ef5f84 100644 (file)
@@ -7371,6 +7371,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,
 };
@@ -7526,10 +7614,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
index e62828ef12a5fb56d803ff01fe785b6cebcd8ff5..e398d2ce77f94b615d45a6bd419b23f976cf43a0 100644 (file)
@@ -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;
index c21e4fe65961e11da67a7bc3ce541366bff7da6b..7064158e337ced5a2fde8e59de49839f2efd9836 100644 (file)
@@ -1913,6 +1913,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;
@@ -2296,6 +2300,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 (file)
index 0000000..b51e8f3
--- /dev/null
@@ -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
index 3feb2fe2594306090923ebf2c6767c83d6fe0e07..5c2825329e53b0cb46c15f41c06968bcb6cc3a1a 100644 (file)
@@ -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);