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