218e99
From a49a3e6984fdb8562003cff96a82b2ac7d9bcc0d Mon Sep 17 00:00:00 2001
218e99
Message-Id: <a49a3e6984fdb8562003cff96a82b2ac7d9bcc0d.1383564115.git.minovotn@redhat.com>
218e99
In-Reply-To: <5575e0aec51f40ebec46e98ec085cda053283aba.1383564115.git.minovotn@redhat.com>
218e99
References: <5575e0aec51f40ebec46e98ec085cda053283aba.1383564115.git.minovotn@redhat.com>
218e99
From: Markus Armbruster <armbru@redhat.com>
218e99
Date: Fri, 27 Sep 2013 13:31:13 +0200
218e99
Subject: [PATCH 03/14] vl: Fix -boot order and once regressions, and related
218e99
 bugs
218e99
218e99
RH-Author: Markus Armbruster <armbru@redhat.com>
218e99
Message-id: <1380288680-26645-4-git-send-email-armbru@redhat.com>
218e99
Patchwork-id: 54567
218e99
O-Subject: [PATCH 7.0 qemu-kvm 03/10] vl: Fix -boot order and once regressions, and related bugs
218e99
Bugzilla: 997817
218e99
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
218e99
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
218e99
RH-Acked-by: Luiz Capitulino <lcapitulino@redhat.com>
218e99
218e99
From: Markus Armbruster <armbru@redhat.com>
218e99
218e99
Option "once" sets up a different boot order just for the initial
218e99
boot.  Boot order reverts back to normal on reset.  Option "order"
218e99
changes the normal boot order.
218e99
218e99
The reversal is implemented by reset handler restore_boot_devices(),
218e99
which takes the boot order to revert to as argument.
218e99
restore_boot_devices() does nothing on its first call, because that
218e99
must be the initial machine reset.  On its second call, it changes the
218e99
boot order back, and unregisters itself.
218e99
218e99
Because we register the handler right when -boot gets parsed, we can
218e99
revert to an incorrect normal boot order, and multiple -boot can
218e99
interact in funny ways.
218e99
218e99
Here's how things work without -boot once or order:
218e99
218e99
* boot_devices is "".
218e99
218e99
* main() passes machine->boot_order to to machine->init(), because
218e99
  boot_devices is "".  machine->init() configures firmware
218e99
  accordingly.  For PC machines, machine->boot_order is "cad", and
218e99
  pc_cmos_init() writes it to RTC CMOS, where SeaBIOS picks it up.
218e99
218e99
Now consider -boot order=:
218e99
218e99
* boot_devices is "".
218e99
218e99
* -boot order= sets boot_devices to "" (no change).
218e99
218e99
* main() passes machine->boot_order to to machine->init(), because
218e99
  boot_devices is "", as above.
218e99
218e99
  Bug: -boot order= has no effect.  Broken in commit e4ada29e.
218e99
218e99
Next, consider -boot once=a:
218e99
218e99
* boot_devices is "".
218e99
218e99
* -boot once=a registers restore_boot_devices() with argument "", and
218e99
  sets boot_devices to "a".
218e99
218e99
* main() passes boot_devices "a" to machine->init(), which configures
218e99
  firmware accordingly.  For PC machines, pc_cmos_init() writes the
218e99
  boot order to RTC CMOS.
218e99
218e99
* main() calls qemu_system_reset().  This runs reset handlers.
218e99
218e99
  - restore_boot_devices() gets called with argument "".  Does
218e99
    nothing, because it's the first call.
218e99
218e99
* Machine boots, boot order is "a".
218e99
218e99
* Machine resets (e.g. monitor command).  Reset handlers run.
218e99
218e99
  - restore_boot_devices() gets called with argument "".  Calls
218e99
    qemu_boot_set("") to reconfigure firmware.  For PC machines,
218e99
    pc_boot_set() writes it into RTC CMOS.  Reset handler
218e99
    unregistered.
218e99
218e99
    Bug: boot order reverts to "" instead of machine->boot_order.  The
218e99
    actual boot order depends on how firmware interprets "".  Broken
218e99
    in commit e4ada29e.
218e99
218e99
Next, consider -boot once=a -boot order=c:
218e99
218e99
* boot_devices is "".
218e99
218e99
* -boot once=a registers restore_boot_devices() with argument "", and
218e99
  sets boot_devices to "a".
218e99
218e99
* -boot order=c sets boot_devices to "c".
218e99
218e99
* main() passes boot_devices "c" to machine->init(), which configures
218e99
  firmware accordingly.  For PC machines, pc_cmos_init() writes the
218e99
  boot order to RTC CMOS.
218e99
218e99
* main() calls qemu_system_reset().  This runs reset handlers.
218e99
218e99
  - restore_boot_devices() gets called with argument "".  Does
218e99
    nothing, because it's the first call.
218e99
218e99
* Machine boots, boot order is "c".
218e99
218e99
  Bug: it should be "a".  I figure this has always been broken.
218e99
218e99
* Machine resets (e.g. monitor command).  Reset handlers run.
218e99
218e99
  - restore_boot_devices() gets called with argument "".  Calls
218e99
    qemu_boot_set("") to reconfigure firmware.  For PC machines,
218e99
    pc_boot_set() writes it into RTC CMOS.  Reset handler
218e99
    unregistered.
218e99
218e99
    Bug: boot order reverts to "" instead of "c".  I figure this has
218e99
    always been broken, just differently broken before commit
218e99
    e4ada29e.
218e99
218e99
Next, consider -boot once=a -boot once=b -boot once=c:
218e99
218e99
* boot_devices is "".
218e99
218e99
* -boot once=a registers restore_boot_devices() with argument "", and
218e99
  sets boot_devices to "a".
218e99
218e99
* -boot once=b registers restore_boot_devices() with argument "a", and
218e99
  sets boot_devices to "b".
218e99
218e99
* -boot once=c registers restore_boot_devices() with argument "b", and
218e99
  sets boot_devices to "c".
218e99
218e99
* main() passes boot_devices "c" to machine->init(), which configures
218e99
  firmware accordingly.  For PC machines, pc_cmos_init() writes the
218e99
  boot order to RTC CMOS.
218e99
218e99
* main() calls qemu_system_reset().  This runs reset handlers.
218e99
218e99
  - restore_boot_devices() gets called with argument "".  Does
218e99
    nothing, because it's the first call.
218e99
218e99
  - restore_boot_devices() gets called with argument "a".  Calls
218e99
    qemu_boot_set("a") to reconfigure firmware.  For PC machines,
218e99
    pc_boot_set() writes it into RTC CMOS.  Reset handler
218e99
    unregistered.
218e99
218e99
  - restore_boot_devices() gets called with argument "b".  Calls
218e99
    qemu_boot_set("b") to reconfigure firmware.  For PC machines,
218e99
    pc_boot_set() writes it into RTC CMOS.  Reset handler
218e99
    unregistered.
218e99
218e99
* Machine boots, boot order is "b".
218e99
218e99
  Bug: should really be "c", because that came last, and for all other
218e99
  -boot options, the last one wins.  I figure this was broken some
218e99
  time before commit 37905d6a, and fixed there only for a single
218e99
  occurence of "once".
218e99
218e99
* Machine resets (e.g. monitor command).  Reset handlers run.
218e99
218e99
  - restore_boot_devices() gets called with argument "".  Calls
218e99
    qemu_boot_set("") to reconfigure firmware.  For PC machines,
218e99
    pc_boot_set() writes it into RTC CMOS.  Reset handler
218e99
    unregistered.
218e99
218e99
    Same bug as above: boot order reverts to "" instead of
218e99
    machine->boot_order.
218e99
218e99
Fix by acting upon -boot options order, once and menu only after
218e99
option parsing is complete, and the machine is known.  This is how the
218e99
other -boot options work already.
218e99
218e99
Signed-off-by: Markus Armbruster <armbru@redhat.com>
218e99
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
218e99
Message-id: 1371208516-7857-4-git-send-email-armbru@redhat.com
218e99
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
218e99
(cherry picked from commit 8281abd548d840d84223e66812491918c713e56c)
218e99
---
218e99
 vl.c | 59 ++++++++++++++++++++++++++++++-----------------------------
218e99
 1 file changed, 30 insertions(+), 29 deletions(-)
218e99
218e99
Signed-off-by: Michal Novotny <minovotn@redhat.com>
218e99
---
218e99
 vl.c | 59 ++++++++++++++++++++++++++++++-----------------------------
218e99
 1 file changed, 30 insertions(+), 29 deletions(-)
218e99
218e99
diff --git a/vl.c b/vl.c
218e99
index a5663ad..1c3236c 100644
218e99
--- a/vl.c
218e99
+++ b/vl.c
218e99
@@ -2795,7 +2795,7 @@ int main(int argc, char **argv, char **envp)
218e99
     const char *icount_option = NULL;
218e99
     const char *initrd_filename;
218e99
     const char *kernel_filename, *kernel_cmdline;
218e99
-    char boot_devices[33] = "";
218e99
+    const char *boot_order = NULL;
218e99
     DisplayState *ds;
218e99
     int cyls, heads, secs, translation;
218e99
     QemuOpts *hda_opts = NULL, *opts, *machine_opts;
218e99
@@ -3086,31 +3086,9 @@ int main(int argc, char **argv, char **envp)
218e99
                 drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
218e99
                 break;
218e99
             case QEMU_OPTION_boot:
218e99
-                {
218e99
-                    char *standard_boot_devices;
218e99
-                    const char *order, *once;
218e99
-
218e99
-                    opts = qemu_opts_parse(qemu_find_opts("boot-opts"),
218e99
-                                           optarg, 1);
218e99
-                    if (!opts) {
218e99
-                        exit(1);
218e99
-                    }
218e99
-
218e99
-                    order = qemu_opt_get(opts, "order");
218e99
-                    if (order) {
218e99
-                        validate_bootdevices(order);
218e99
-                        pstrcpy(boot_devices, sizeof(boot_devices), order);
218e99
-                    }
218e99
-
218e99
-                    once = qemu_opt_get(opts, "once");
218e99
-                    if (once) {
218e99
-                        validate_bootdevices(once);
218e99
-                        standard_boot_devices = g_strdup(boot_devices);
218e99
-                        pstrcpy(boot_devices, sizeof(boot_devices), once);
218e99
-                        qemu_register_reset(restore_boot_devices,
218e99
-                                            standard_boot_devices);
218e99
-                    }
218e99
-                    boot_menu = qemu_opt_get_bool(opts, "menu", boot_menu);
218e99
+                opts = qemu_opts_parse(qemu_find_opts("boot-opts"), optarg, 1);
218e99
+                if (!opts) {
218e99
+                    exit(1);
218e99
                 }
218e99
                 break;
218e99
             case QEMU_OPTION_fda:
218e99
@@ -4049,6 +4027,31 @@ int main(int argc, char **argv, char **envp)
218e99
     initrd_filename = qemu_opt_get(machine_opts, "initrd");
218e99
     kernel_cmdline = qemu_opt_get(machine_opts, "append");
218e99
 
218e99
+    if (!boot_order) {
218e99
+        boot_order = machine->boot_order;
218e99
+    }
218e99
+    opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL);
218e99
+    if (opts) {
218e99
+        char *normal_boot_order;
218e99
+        const char *order, *once;
218e99
+
218e99
+        order = qemu_opt_get(opts, "order");
218e99
+        if (order) {
218e99
+            validate_bootdevices(order);
218e99
+            boot_order = order;
218e99
+        }
218e99
+
218e99
+        once = qemu_opt_get(opts, "once");
218e99
+        if (once) {
218e99
+            validate_bootdevices(once);
218e99
+            normal_boot_order = g_strdup(boot_order);
218e99
+            boot_order = once;
218e99
+            qemu_register_reset(restore_boot_devices, normal_boot_order);
218e99
+        }
218e99
+
218e99
+        boot_menu = qemu_opt_get_bool(opts, "menu", boot_menu);
218e99
+    }
218e99
+
218e99
     if (!kernel_cmdline) {
218e99
         kernel_cmdline = "";
218e99
     }
218e99
@@ -4213,9 +4216,7 @@ int main(int argc, char **argv, char **envp)
218e99
     qdev_machine_init();
218e99
 
218e99
     QEMUMachineInitArgs args = { .ram_size = ram_size,
218e99
-                                 .boot_device = (boot_devices[0] == '\0') ?
218e99
-                                                machine->boot_order :
218e99
-                                                boot_devices,
218e99
+                                 .boot_device = boot_order,
218e99
                                  .kernel_filename = kernel_filename,
218e99
                                  .kernel_cmdline = kernel_cmdline,
218e99
                                  .initrd_filename = initrd_filename,
218e99
-- 
218e99
1.7.11.7
218e99