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