nalika / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone
d9d99f
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
d9d99f
From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
d9d99f
Date: Thu, 20 Sep 2012 18:07:39 -0300
d9d99f
Subject: [PATCH] IBM client architecture (CAS) reboot support
d9d99f
d9d99f
This is an implementation of IBM client architecture (CAS) reboot for GRUB.
d9d99f
d9d99f
There are cases where the POWER firmware must reboot in order to support
d9d99f
specific features requested by a kernel. The kernel calls
d9d99f
ibm,client-architecture-support and it may either return or reboot with the new
d9d99f
feature set. eg:
d9d99f
d9d99f
Calling ibm,client-architecture-support.../
d9d99f
Elapsed time since release of system processors: 70959 mins 50 secs
d9d99f
Welcome to GRUB!
d9d99f
d9d99f
Instead of return to the GRUB menu, it will check if the flag for CAS reboot is
d9d99f
set. If so, grub will automatically boot the last booted kernel using the same
d9d99f
parameters
d9d99f
---
d9d99f
 grub-core/kern/ieee1275/openfw.c | 63 ++++++++++++++++++++++++++++++++++++++++
d9d99f
 grub-core/normal/main.c          | 19 ++++++++++++
d9d99f
 grub-core/script/execute.c       |  7 +++++
d9d99f
 include/grub/ieee1275/ieee1275.h |  2 ++
d9d99f
 4 files changed, 91 insertions(+)
d9d99f
d9d99f
diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c
b71686
index 62929d983..2d53c0e86 100644
d9d99f
--- a/grub-core/kern/ieee1275/openfw.c
d9d99f
+++ b/grub-core/kern/ieee1275/openfw.c
d9d99f
@@ -588,3 +588,66 @@ grub_ieee1275_get_boot_dev (void)
d9d99f
 
d9d99f
   return bootpath;
d9d99f
 }
d9d99f
+
d9d99f
+/* Check if it's a CAS reboot. If so, set the script to be executed.  */
d9d99f
+int
d9d99f
+grub_ieee1275_cas_reboot (char *script)
d9d99f
+{
d9d99f
+  grub_uint32_t ibm_ca_support_reboot;
d9d99f
+  grub_uint32_t ibm_fw_nbr_reboots;
d9d99f
+  char property_value[10];
d9d99f
+  grub_ssize_t actual;
d9d99f
+  grub_ieee1275_ihandle_t options;
d9d99f
+
d9d99f
+  if (grub_ieee1275_finddevice ("/options", &options) < 0)
d9d99f
+    return -1;
d9d99f
+
d9d99f
+  /* Check two properties, one is enough to get cas reboot value */
d9d99f
+  ibm_ca_support_reboot = 0;
d9d99f
+  if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen,
d9d99f
+                                          "ibm,client-architecture-support-reboot",
d9d99f
+                                          &ibm_ca_support_reboot,
d9d99f
+                                          sizeof (ibm_ca_support_reboot),
d9d99f
+                                          &actual) >= 0)
d9d99f
+    grub_dprintf("ieee1275", "ibm,client-architecture-support-reboot: %u\n",
d9d99f
+                 ibm_ca_support_reboot);
d9d99f
+
d9d99f
+  ibm_fw_nbr_reboots = 0;
d9d99f
+  if (grub_ieee1275_get_property (options, "ibm,fw-nbr-reboots",
d9d99f
+                                  property_value, sizeof (property_value),
d9d99f
+                                  &actual) >= 0)
d9d99f
+    {
d9d99f
+      property_value[sizeof (property_value) - 1] = 0;
d9d99f
+      ibm_fw_nbr_reboots = (grub_uint8_t) grub_strtoul (property_value, 0, 10);
d9d99f
+      grub_dprintf("ieee1275", "ibm,fw-nbr-reboots: %u\n", ibm_fw_nbr_reboots);
d9d99f
+    }
d9d99f
+
d9d99f
+  if (ibm_ca_support_reboot || ibm_fw_nbr_reboots)
d9d99f
+    {
d9d99f
+      if (! grub_ieee1275_get_property_length (options, "boot-last-label", &actual))
d9d99f
+        {
d9d99f
+          if (actual > 1024)
d9d99f
+            script = grub_realloc (script, actual + 1);
d9d99f
+          grub_ieee1275_get_property (options, "boot-last-label", script, actual,
d9d99f
+                                      &actual);
d9d99f
+          return 0;
d9d99f
+        }
d9d99f
+    }
d9d99f
+
d9d99f
+  grub_ieee1275_set_boot_last_label ("");
d9d99f
+
d9d99f
+  return -1;
d9d99f
+}
d9d99f
+
d9d99f
+int grub_ieee1275_set_boot_last_label (const char *text)
d9d99f
+{
d9d99f
+  grub_ieee1275_ihandle_t options;
d9d99f
+  grub_ssize_t actual;
d9d99f
+
d9d99f
+  grub_dprintf("ieee1275", "set boot_last_label (size: %u)\n", grub_strlen(text));
d9d99f
+  if (! grub_ieee1275_finddevice ("/options", &options) &&
d9d99f
+      options != (grub_ieee1275_ihandle_t) -1)
d9d99f
+    grub_ieee1275_set_property (options, "boot-last-label", text,
d9d99f
+                                grub_strlen (text), &actual);
d9d99f
+  return 0;
d9d99f
+}
d9d99f
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
b71686
index 78a70a8bf..249e19bc7 100644
d9d99f
--- a/grub-core/normal/main.c
d9d99f
+++ b/grub-core/normal/main.c
d9d99f
@@ -33,6 +33,9 @@
d9d99f
 #include <grub/charset.h>
d9d99f
 #include <grub/script_sh.h>
d9d99f
 #include <grub/bufio.h>
d9d99f
+#ifdef GRUB_MACHINE_IEEE1275
d9d99f
+#include <grub/ieee1275/ieee1275.h>
d9d99f
+#endif
d9d99f
 
d9d99f
 GRUB_MOD_LICENSE ("GPLv3+");
d9d99f
 
d9d99f
@@ -275,6 +278,22 @@ grub_normal_execute (const char *config, int nested, int batch)
d9d99f
     {
d9d99f
       menu = read_config_file (config);
d9d99f
 
d9d99f
+#ifdef GRUB_MACHINE_IEEE1275
d9d99f
+      int boot;
d9d99f
+      boot = 0;
d9d99f
+      char *script;
d9d99f
+      script = grub_malloc (1024);
d9d99f
+      if (! grub_ieee1275_cas_reboot (script))
d9d99f
+        {
d9d99f
+          char *dummy[1] = { NULL };
d9d99f
+          if (! grub_script_execute_sourcecode (script))
d9d99f
+            boot = 1;
d9d99f
+        }
d9d99f
+      grub_free (script);
d9d99f
+      if (boot)
d9d99f
+        grub_command_execute ("boot", 0, 0);
d9d99f
+#endif
d9d99f
+
d9d99f
       /* Ignore any error.  */
d9d99f
       grub_errno = GRUB_ERR_NONE;
d9d99f
     }
d9d99f
diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
b71686
index a8502d907..ab78ca87f 100644
d9d99f
--- a/grub-core/script/execute.c
d9d99f
+++ b/grub-core/script/execute.c
d9d99f
@@ -27,6 +27,9 @@
d9d99f
 #include <grub/normal.h>
d9d99f
 #include <grub/extcmd.h>
d9d99f
 #include <grub/i18n.h>
d9d99f
+#ifdef GRUB_MACHINE_IEEE1275
d9d99f
+#include <grub/ieee1275/ieee1275.h>
d9d99f
+#endif
d9d99f
 
d9d99f
 /* Max digits for a char is 3 (0xFF is 255), similarly for an int it
d9d99f
    is sizeof (int) * 3, and one extra for a possible -ve sign.  */
d9d99f
@@ -877,6 +880,10 @@ grub_script_execute_sourcecode (const char *source)
d9d99f
   grub_err_t ret = 0;
d9d99f
   struct grub_script *parsed_script;
d9d99f
 
d9d99f
+#ifdef GRUB_MACHINE_IEEE1275
d9d99f
+  grub_ieee1275_set_boot_last_label (source);
d9d99f
+#endif
d9d99f
+
d9d99f
   while (source)
d9d99f
     {
d9d99f
       char *line;
d9d99f
diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
b71686
index 8868f3a75..2310f33db 100644
d9d99f
--- a/include/grub/ieee1275/ieee1275.h
d9d99f
+++ b/include/grub/ieee1275/ieee1275.h
d9d99f
@@ -252,6 +252,8 @@ int EXPORT_FUNC(grub_ieee1275_devalias_next) (struct grub_ieee1275_devalias *ali
d9d99f
 void EXPORT_FUNC(grub_ieee1275_children_peer) (struct grub_ieee1275_devalias *alias);
d9d99f
 void EXPORT_FUNC(grub_ieee1275_children_first) (const char *devpath,
d9d99f
 						struct grub_ieee1275_devalias *alias);
d9d99f
+int EXPORT_FUNC(grub_ieee1275_cas_reboot) (char *script);
d9d99f
+int EXPORT_FUNC(grub_ieee1275_set_boot_last_label) (const char *text);
d9d99f
 
d9d99f
 char *EXPORT_FUNC(grub_ieee1275_get_boot_dev) (void);
d9d99f