f2e5630
From 4613775aee8b413ba89bfb7233d49a4288e13390 Mon Sep 17 00:00:00 2001
f2e5630
From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
f2e5630
Date: Mon, 15 Oct 2012 17:21:01 -0300
f2e5630
Subject: [PATCH] for ppc, include all modules in the core image
f2e5630
f2e5630
This patch implements the solution suggested by Gustavo Luiz Duarte
f2e5630
<gustavold@linux.vnet.ibm.com>:
f2e5630
f2e5630
Adding more modules to be built-in to the grub core ELF is easy. It is a
f2e5630
parameter passed by grub2-install to grub2-mkimage. However, there is a downside
f2e5630
on adding many modules to the core ELF: they are fully initialized in the grub's
f2e5630
first stage. It means you could hit a bug on a module you don't need and end up
f2e5630
with a non-bootable system.
f2e5630
f2e5630
Another downside is that you wouldn't get updates for these built-in modules, as
f2e5630
updating the grub2 package only updates the modules residing in /boot and not
f2e5630
the grub core ELF in the PReP partition.
f2e5630
f2e5630
A proper solution would be to add to grub the ability of having built-in
f2e5630
*inactive* modules which would be loaded and initialized only on demand (i.e.
f2e5630
explicitly calling the insmod command).
f2e5630
f2e5630
This patch fix this bugzilla:
f2e5630
https://bugzilla.redhat.com/show_bug.cgi?id=866559
f2e5630
---
f2e5630
 grub-core/kern/corecmd.c    |    3 ++
f2e5630
 grub-core/kern/dl.c         |   67 ++++++++++++++++++++++++++++++++++++++++---
f2e5630
 include/grub/dl.h           |    1 +
f2e5630
 include/grub/kernel.h       |    1 +
f2e5630
 include/grub/util/resolve.h |    5 ++++
f2e5630
 util/grub-mkimage.c         |   37 +++++++++++++++++++++++-
f2e5630
 util/resolve.c              |   57 ++++++++++++++++++++++++++++++++++++
f2e5630
 7 files changed, 166 insertions(+), 5 deletions(-)
f2e5630
f2e5630
diff --git a/grub-core/kern/corecmd.c b/grub-core/kern/corecmd.c
f2e5630
index 16c03df..8684139 100644
f2e5630
--- a/grub-core/kern/corecmd.c
f2e5630
+++ b/grub-core/kern/corecmd.c
f2e5630
@@ -100,6 +100,9 @@ grub_core_cmd_insmod (struct grub_command *cmd __attribute__ ((unused)),
f2e5630
   else
f2e5630
     mod = grub_dl_load (argv[0]);
f2e5630
 
f2e5630
+  if (!mod)
f2e5630
+    grub_dl_load_core_by_name (argv[0]);
f2e5630
+
f2e5630
   if (mod)
f2e5630
     grub_dl_ref (mod);
f2e5630
 
f2e5630
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
f2e5630
index 5b0aa65..a498682 100644
f2e5630
--- a/grub-core/kern/dl.c
f2e5630
+++ b/grub-core/kern/dl.c
f2e5630
@@ -32,6 +32,7 @@
f2e5630
 #include <grub/env.h>
f2e5630
 #include <grub/cache.h>
f2e5630
 #include <grub/i18n.h>
f2e5630
+#include <grub/kernel.h>
f2e5630
 
f2e5630
 /* Platforms where modules are in a readonly area of memory.  */
f2e5630
 #if defined(GRUB_MACHINE_QEMU)
f2e5630
@@ -47,6 +48,7 @@
f2e5630
 #pragma GCC diagnostic ignored "-Wcast-align"
f2e5630
 
f2e5630
 grub_dl_t grub_dl_head = 0;
f2e5630
+char grub_use_stale_modules = 0;
f2e5630
 
f2e5630
 grub_err_t
f2e5630
 grub_dl_add (grub_dl_t mod);
f2e5630
@@ -659,6 +661,57 @@ grub_dl_load_core (void *addr, grub_size_t size)
f2e5630
   return mod;
f2e5630
 }
f2e5630
 
f2e5630
+/* Load a module from core using a symbolic name.  */
f2e5630
+grub_dl_t
f2e5630
+grub_dl_load_core_by_name (const char *name)
f2e5630
+{
f2e5630
+  struct grub_module_header *header;
f2e5630
+  grub_dl_t mod;
f2e5630
+  char *module_addr;
f2e5630
+
f2e5630
+  mod = (grub_dl_t) grub_zalloc (sizeof (*mod));
f2e5630
+  if (! mod)
f2e5630
+    return 0;
f2e5630
+
f2e5630
+  grub_use_stale_modules = 1;
f2e5630
+
f2e5630
+  FOR_MODULES (header)
f2e5630
+    {
f2e5630
+      /* Not an ELF module, skip.  */
f2e5630
+      if ((header->type != OBJ_TYPE_ELF) &&
f2e5630
+          (header->type != OBJ_TYPE_ELF_STALE))
f2e5630
+        continue;
f2e5630
+
f2e5630
+      module_addr = (char *) header + sizeof (struct grub_module_header);
f2e5630
+      grub_dl_resolve_name (mod, (Elf_Ehdr *) module_addr);
f2e5630
+
f2e5630
+      if (grub_strcmp(name, mod->name) == 0)
f2e5630
+        {
f2e5630
+          grub_printf ("WARNING: You are using the built-in '%s' module!\n", name);
f2e5630
+
f2e5630
+          mod = grub_dl_load_core ((char *) header + sizeof (struct grub_module_header),
f2e5630
+                                   (header->size - sizeof (struct grub_module_header)));
f2e5630
+
f2e5630
+          break;
f2e5630
+        }
f2e5630
+      else
f2e5630
+        mod = 0;
f2e5630
+    }
f2e5630
+
f2e5630
+  if (! mod)
f2e5630
+    return 0;
f2e5630
+  else
f2e5630
+    {
f2e5630
+      if (grub_errno == GRUB_ERR_IO)
f2e5630
+        grub_errno = GRUB_ERR_NONE;
f2e5630
+    }
f2e5630
+
f2e5630
+  if (grub_strcmp (mod->name, name) != 0)
f2e5630
+    grub_error (GRUB_ERR_BAD_MODULE, "mismatched names");
f2e5630
+
f2e5630
+  return mod;
f2e5630
+}
f2e5630
+
f2e5630
 /* Load a module from the file FILENAME.  */
f2e5630
 grub_dl_t
f2e5630
 grub_dl_load_file (const char *filename)
f2e5630
@@ -718,13 +771,19 @@ grub_dl_load (const char *name)
f2e5630
     return 0;
f2e5630
   }
f2e5630
 
f2e5630
+  /* First, try to load module from the grub directory */
f2e5630
   filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM "/%s.mod",
f2e5630
 			     grub_dl_dir, name);
f2e5630
-  if (! filename)
f2e5630
-    return 0;
f2e5630
+  if (filename)
f2e5630
+    {
f2e5630
+      mod = grub_dl_load_file (filename);
f2e5630
+      grub_free (filename);
f2e5630
+    }
f2e5630
 
f2e5630
-  mod = grub_dl_load_file (filename);
f2e5630
-  grub_free (filename);
f2e5630
+  /* If the module isn't loaded, check if there is a stale module available and
f2e5630
+   * use it*/
f2e5630
+  if (! mod && grub_use_stale_modules)
f2e5630
+      mod = grub_dl_load_core_by_name (name);
f2e5630
 
f2e5630
   if (! mod)
f2e5630
     return 0;
f2e5630
diff --git a/include/grub/dl.h b/include/grub/dl.h
f2e5630
index 3119978..30f12f9 100644
f2e5630
--- a/include/grub/dl.h
f2e5630
+++ b/include/grub/dl.h
f2e5630
@@ -181,6 +181,7 @@ typedef struct grub_dl *grub_dl_t;
f2e5630
 grub_dl_t grub_dl_load_file (const char *filename);
f2e5630
 grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name);
f2e5630
 grub_dl_t grub_dl_load_core (void *addr, grub_size_t size);
f2e5630
+grub_dl_t grub_dl_load_core_by_name (const char *name);
f2e5630
 int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod);
f2e5630
 void grub_dl_unload_unneeded (void);
f2e5630
 int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod);
f2e5630
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
f2e5630
index eef4c3f..4cd2cb0 100644
f2e5630
--- a/include/grub/kernel.h
f2e5630
+++ b/include/grub/kernel.h
f2e5630
@@ -25,6 +25,7 @@
f2e5630
 enum
f2e5630
 {
f2e5630
   OBJ_TYPE_ELF,
f2e5630
+  OBJ_TYPE_ELF_STALE,
f2e5630
   OBJ_TYPE_MEMDISK,
f2e5630
   OBJ_TYPE_CONFIG,
f2e5630
   OBJ_TYPE_PREFIX
f2e5630
diff --git a/include/grub/util/resolve.h b/include/grub/util/resolve.h
f2e5630
index f42df32..1d0252c 100644
f2e5630
--- a/include/grub/util/resolve.h
f2e5630
+++ b/include/grub/util/resolve.h
f2e5630
@@ -32,4 +32,9 @@ grub_util_resolve_dependencies (const char *prefix,
f2e5630
 				const char *dep_list_file,
f2e5630
 				char *modules[]);
f2e5630
 
f2e5630
+struct grub_util_path_list *
f2e5630
+grub_util_create_complementary_module_list (const char *prefix,
f2e5630
+				const char *dep_list_file,
f2e5630
+				struct grub_util_path_list *path_list);
f2e5630
+
f2e5630
 #endif /* ! GRUB_UTIL_RESOLVE_HEADER */
f2e5630
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
f2e5630
index a551bbb..b06f37a 100644
f2e5630
--- a/util/grub-mkimage.c
f2e5630
+++ b/util/grub-mkimage.c
f2e5630
@@ -711,7 +711,7 @@ generate_image (const char *dir, const char *prefix,
f2e5630
   size_t prefix_size = 0;
f2e5630
   char *kernel_path;
f2e5630
   size_t offset;
f2e5630
-  struct grub_util_path_list *path_list, *p, *next;
f2e5630
+  struct grub_util_path_list *path_list, *path_list_comp = 0, *p, *next;
f2e5630
   grub_size_t bss_size;
f2e5630
   grub_uint64_t start_address;
f2e5630
   void *rel_section = 0;
f2e5630
@@ -727,6 +727,10 @@ generate_image (const char *dir, const char *prefix,
f2e5630
 
f2e5630
   path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
f2e5630
 
f2e5630
+  if (image_target->id == IMAGE_PPC)
f2e5630
+    path_list_comp = grub_util_create_complementary_module_list (dir,
f2e5630
+                                              "moddep.lst", path_list);
f2e5630
+
f2e5630
   kernel_path = grub_util_get_path (dir, "kernel.img");
f2e5630
 
f2e5630
   if (image_target->voidp_sizeof == 8)
f2e5630
@@ -761,6 +765,10 @@ generate_image (const char *dir, const char *prefix,
f2e5630
     total_module_size += (ALIGN_ADDR (grub_util_get_image_size (p->name))
f2e5630
 			  + sizeof (struct grub_module_header));
f2e5630
 
f2e5630
+  for (p = path_list_comp; p; p = p->next)
f2e5630
+    total_module_size += (ALIGN_ADDR (grub_util_get_image_size (p->name))
f2e5630
+			  + sizeof (struct grub_module_header));
f2e5630
+
f2e5630
   grub_util_info ("the total module size is 0x%llx",
f2e5630
 		  (unsigned long long) total_module_size);
f2e5630
 
f2e5630
@@ -835,6 +843,25 @@ generate_image (const char *dir, const char *prefix,
f2e5630
       offset += mod_size;
f2e5630
     }
f2e5630
 
f2e5630
+  for (p = path_list_comp; p; p = p->next)
f2e5630
+    {
f2e5630
+      struct grub_module_header *header;
f2e5630
+      size_t mod_size, orig_size;
f2e5630
+
f2e5630
+      orig_size = grub_util_get_image_size (p->name);
f2e5630
+      mod_size = ALIGN_ADDR (orig_size);
f2e5630
+
f2e5630
+      header = (struct grub_module_header *) (kernel_img + offset);
f2e5630
+      memset (header, 0, sizeof (struct grub_module_header));
f2e5630
+      header->type = grub_host_to_target32 (OBJ_TYPE_ELF_STALE);
f2e5630
+      header->size = grub_host_to_target32 (mod_size + sizeof (*header));
f2e5630
+      offset += sizeof (*header);
f2e5630
+      memset (kernel_img + offset + orig_size, 0, mod_size - orig_size);
f2e5630
+
f2e5630
+      grub_util_load_image (p->name, kernel_img + offset);
f2e5630
+      offset += mod_size;
f2e5630
+    }
f2e5630
+
f2e5630
   if (memdisk_path)
f2e5630
     {
f2e5630
       struct grub_module_header *header;
f2e5630
@@ -1639,6 +1666,14 @@ generate_image (const char *dir, const char *prefix,
f2e5630
       free (path_list);
f2e5630
       path_list = next;
f2e5630
     }
f2e5630
+
f2e5630
+  while (path_list_comp)
f2e5630
+    {
f2e5630
+      next = path_list_comp->next;
f2e5630
+      free ((void *) path_list_comp->name);
f2e5630
+      free (path_list_comp);
f2e5630
+      path_list_comp = next;
f2e5630
+    }
f2e5630
 }
f2e5630
 
f2e5630
 
f2e5630
diff --git a/util/resolve.c b/util/resolve.c
f2e5630
index 1af24e6..997db99 100644
f2e5630
--- a/util/resolve.c
f2e5630
+++ b/util/resolve.c
f2e5630
@@ -271,3 +271,60 @@ grub_util_resolve_dependencies (const char *prefix,
f2e5630
     return prev;
f2e5630
   }
f2e5630
 }
f2e5630
+
f2e5630
+struct grub_util_path_list *
f2e5630
+grub_util_create_complementary_module_list (const char *prefix,
f2e5630
+				const char *dep_list_file,
f2e5630
+				struct grub_util_path_list *path_list)
f2e5630
+{
f2e5630
+  char *path;
f2e5630
+  FILE *fp;
f2e5630
+  struct grub_util_path_list *path_list_comp = 0;
f2e5630
+  struct grub_util_path_list *new_path;
f2e5630
+  char skip;
f2e5630
+
f2e5630
+  path = grub_util_get_path (prefix, dep_list_file);
f2e5630
+  fp = fopen (path, "r");
f2e5630
+  if (! fp)
f2e5630
+    grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
f2e5630
+
f2e5630
+  while (fgets (buf, sizeof (buf), fp))
f2e5630
+    {
f2e5630
+      char *p;
f2e5630
+      struct grub_util_path_list *pl;
f2e5630
+
f2e5630
+      skip = 0;
f2e5630
+
f2e5630
+      /* Get the target name.  */
f2e5630
+      p = strchr (buf, ':');
f2e5630
+      if (! p)
f2e5630
+	grub_util_error (_("invalid line format: %s"), buf);
f2e5630
+
f2e5630
+      *p++ = '\0';
f2e5630
+
f2e5630
+      /* kernel is not a module */
f2e5630
+      if (strcmp(buf, "kernel") == 0)
f2e5630
+        continue;
f2e5630
+
f2e5630
+      /* Check if the module is already in the core. */
f2e5630
+      for (pl = path_list; pl; pl = pl->next)
f2e5630
+        {
f2e5630
+          if (strcmp(buf, get_module_name(pl->name)) == 0)
f2e5630
+            {
f2e5630
+              skip = 1;
f2e5630
+              break;
f2e5630
+            }
f2e5630
+        }
f2e5630
+
f2e5630
+      if (skip)
f2e5630
+          continue;
f2e5630
+
f2e5630
+      /* Add the new path.  */
f2e5630
+      new_path = (struct grub_util_path_list *) xmalloc (sizeof (*new_path));
f2e5630
+      new_path->name = get_module_path (prefix, buf);
f2e5630
+      new_path->next = path_list_comp;
f2e5630
+      path_list_comp = new_path;
f2e5630
+    }
f2e5630
+
f2e5630
+  return path_list_comp;
f2e5630
+}
f2e5630
-- 
f2e5630
1.7.10.4
f2e5630