All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: grub-mkimage and module loading
@ 2005-01-02 19:02 Hollis Blanchard
  2005-01-02 21:05 ` Marco Gerards
  0 siblings, 1 reply; 12+ messages in thread
From: Hollis Blanchard @ 2005-01-02 19:02 UTC (permalink / raw)
  To: grub-devel

This is a more complete patch for PPC grub-mkimage that I posted a while
back. Important points:
- move grub_load_modules() into i386/pc as grub_arch_load_modules()
- implement PPC's grub_arch_load_modules() using an in-memory structure
  telling us how many modules to expect
- the structure contains a version field to avoid grub-mkimage/grub
  binary layout mismatches
- util/powerpc/ieee1275/grub-mkimage.c is a fair amount of code, but
  it's used almost exactly like the i386 version
- added a couple helper functions to the util/misc.c code

I think there is still some PC cleanup needed, e.g. grub_end_addr and
grub_add_unused_region() should also be moved into i386 code, but my
patch is already fairly large, and I'd prefer a PC person were involved
in this additional cleanup anyways.

This patch has been tested and is needed to load modules on PPC. Please
comment soon so we can get PPC modules working in the main tree...

-Hollis

Index: boot/powerpc/ieee1275/crt0.S
===================================================================
RCS file: /cvsroot/grub/grub2/boot/powerpc/ieee1275/crt0.S,v
retrieving revision 1.4
diff -u -p -r1.4 crt0.S
--- boot/powerpc/ieee1275/crt0.S	28 Dec 2004 22:43:37 -0000	1.4
+++ boot/powerpc/ieee1275/crt0.S	2 Jan 2005 19:01:50 -0000
@@ -18,21 +18,6 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-	.section ".note"
-	.align	2
-.note_section_header:
-	.long	8
-	.long	24
-	.long	0x1275
-	.string	"PowerPC"
-.note_descriptor:
-	.long   0x0             /* real-mode */
-	.long   0xffffffff      /* real-base */
-	.long   0xffffffff      /* real-size */
-	.long   0xffffffff      /* virt-base */
-	.long   0xffffffff      /* virt-size */
-	.long   0x00030000      /* load-base */
-
 .extern __bss_start
 .extern _end
 
Index: conf/powerpc-ieee1275.rmk
===================================================================
RCS file: /cvsroot/grub/grub2/conf/powerpc-ieee1275.rmk,v
retrieving revision 1.18
diff -u -p -r1.18 powerpc-ieee1275.rmk
--- conf/powerpc-ieee1275.rmk	28 Dec 2004 22:43:37 -0000	1.18
+++ conf/powerpc-ieee1275.rmk	2 Jan 2005 19:01:53 -0000
@@ -24,9 +24,13 @@ kernel_syms.lst: $(addprefix include/gru
 pkgdata_PROGRAMS = grubof
 
 # Utilities.
-bin_UTILITIES = grub-emu
+bin_UTILITIES = grub-emu grub-mkimage
 noinst_UTILITIES = genmoddep
 
+# For grub-mkimage.
+grub_mkimage_SOURCES = util/powerpc/ieee1275/grub-mkimage.c util/misc.c \
+        util/resolve.c 
+
 # For grub-emu
 grub_emu_SOURCES = kern/main.c kern/device.c				\
 	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c		\
Index: include/grub/kernel.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/kernel.h,v
retrieving revision 1.4
diff -u -p -r1.4 kernel.h
--- include/grub/kernel.h	4 Apr 2004 13:46:00 -0000	1.4
+++ include/grub/kernel.h	2 Jan 2005 19:01:53 -0000
@@ -31,8 +31,14 @@ struct grub_module_header
   grub_size_t size;
 };
 
-/* The start address of the kernel.  */
-extern grub_addr_t grub_start_addr;
+#define MODINFO_VERSION 1
+struct grub_module_info {
+  grub_uint32_t version;
+  grub_uint32_t num_modules;
+  struct grub_module_header module_data[0];
+};
+
+extern void grub_arch_load_modules (void);
 
 /* The end address of the kernel.  */
 extern grub_addr_t grub_end_addr;
@@ -49,9 +55,6 @@ void grub_main (void);
 /* The machine-specific initialization. This must initialize memory.  */
 void grub_machine_init (void);
 
-/* Return the end address of the core image.  */
-grub_addr_t grub_get_end_addr (void);
-
 /* Register all the exported symbols. This is automatically generated.  */
 void grub_register_exported_symbols (void);
 
Index: include/grub/util/misc.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/util/misc.h,v
retrieving revision 1.5
diff -u -p -r1.5 misc.h
--- include/grub/util/misc.h	4 Apr 2004 13:46:01 -0000	1.5
+++ include/grub/util/misc.h	2 Jan 2005 19:01:53 -0000
@@ -34,9 +34,13 @@ void *xrealloc (void *ptr, size_t size);
 char *xstrdup (const char *str);
 
 char *grub_util_get_path (const char *dir, const char *file);
+size_t grub_util_get_fp_size (FILE *fp);
 size_t grub_util_get_image_size (const char *path);
+void grub_util_read_at (void *img, size_t len, off_t offset, FILE *fp);
 char *grub_util_read_image (const char *path);
 void grub_util_load_image (const char *path, char *buf);
 void grub_util_write_image (const char *img, size_t size, FILE *out);
+void grub_util_write_image_at (const void *img, size_t size, off_t offset,
+			       FILE *out);
 
 #endif /* ! GRUB_UTIL_MISC_HEADER */
Index: kern/main.c
===================================================================
RCS file: /cvsroot/grub/grub2/kern/main.c,v
retrieving revision 1.8
diff -u -p -r1.8 main.c
--- kern/main.c	4 Apr 2004 13:46:01 -0000	1.8
+++ kern/main.c	2 Jan 2005 19:01:53 -0000
@@ -29,29 +29,6 @@
 #include <grub/device.h>
 #include <grub/env.h>
 
-/* Return the end of the core image.  */
-grub_addr_t
-grub_get_end_addr (void)
-{
-  return grub_total_module_size + grub_end_addr;
-}
-
-/* Load all modules in core.  */
-static void
-grub_load_modules (void)
-{
-  struct grub_module_header *header;
-
-  for (header = (struct grub_module_header *) grub_end_addr;
-       header < (struct grub_module_header *) grub_get_end_addr ();
-       header = (struct grub_module_header *) ((char *) header + header->size))
-    {
-      if (! grub_dl_load_core ((char *) header + header->offset,
-			       (header->size - header->offset)))
-	grub_fatal ("%s", grub_errmsg);
-    }
-}
-
 /* Add the region where modules reside into dynamic memory.  */
 static void
 grub_add_unused_region (void)
@@ -110,7 +87,7 @@ grub_main (void)
 
   /* Load pre-loaded modules and free the space.  */
   grub_register_exported_symbols ();
-  grub_load_modules ();
+  grub_arch_load_modules ();
   grub_add_unused_region ();
 
   /* Load the normal mode module.  */
Index: kern/i386/pc/init.c
===================================================================
RCS file: /cvsroot/grub/grub2/kern/i386/pc/init.c,v
retrieving revision 1.9
diff -u -p -r1.9 init.c
--- kern/i386/pc/init.c	27 Dec 2004 13:46:20 -0000	1.9
+++ kern/i386/pc/init.c	2 Jan 2005 19:01:53 -0000
@@ -233,3 +233,26 @@ grub_machine_init (void)
   /* Initialize the prefix.  */
   grub_env_set ("prefix", make_install_device ());
 }
+
+/* Return the end of the core image.  */
+static grub_addr_t
+grub_get_end_addr (void)
+{
+  return grub_total_module_size + grub_end_addr;
+}
+
+/* Load all modules in core.  */
+void
+grub_arch_load_modules (void)
+{
+  struct grub_module_header *header;
+
+  for (header = (struct grub_module_header *) grub_end_addr;
+       header < (struct grub_module_header *) grub_get_end_addr ();
+       header = (struct grub_module_header *) ((char *) header + header->size))
+    {
+      if (! grub_dl_load_core ((char *) header + header->offset,
+			       (header->size - header->offset)))
+	grub_fatal ("%s", grub_errmsg);
+    }
+}
Index: kern/powerpc/ieee1275/init.c
===================================================================
RCS file: /cvsroot/grub/grub2/kern/powerpc/ieee1275/init.c,v
retrieving revision 1.11
diff -u -p -r1.11 init.c
--- kern/powerpc/ieee1275/init.c	27 Dec 2004 13:46:20 -0000	1.11
+++ kern/powerpc/ieee1275/init.c	2 Jan 2005 19:01:53 -0000
@@ -31,6 +31,7 @@
 #include <grub/misc.h>
 #include <grub/machine/init.h>
 #include <grub/machine/time.h>
+#include <grub/machine/kernel.h>
 
 /* XXX: Modules are not yet supported.  */
 grub_addr_t grub_end_addr = -1;
@@ -84,3 +85,25 @@ grub_get_rtc (void)
 {
   return 0;
 }
+
+/* Load all modules in core.  */
+void
+grub_arch_load_modules (void)
+{
+  struct grub_module_info *base = (struct grub_module_info *) MODULE_BASE;
+  struct grub_module_header *header = base->module_data;
+  unsigned int i;
+
+  if (base->version != MODINFO_VERSION)
+    grub_fatal ("module version mismatch: wanted %d; found %d\n",
+		MODINFO_VERSION, base->version);
+
+  for (i = 0; i < base->num_modules; i++)
+  {
+    if (! grub_dl_load_core ((char *) header + header->offset,
+	  (header->size - header->offset)))
+      grub_fatal ("%s", grub_errmsg);
+    header = (struct grub_module_header *) ((char *) header + header->size);
+  }
+}
+
Index: util/misc.c
===================================================================
RCS file: /cvsroot/grub/grub2/util/misc.c,v
retrieving revision 1.9
diff -u -p -r1.9 misc.c
--- util/misc.c	27 Dec 2004 13:46:20 -0000	1.9
+++ util/misc.c	2 Jan 2005 19:01:53 -0000
@@ -25,6 +25,7 @@
 #include <sys/stat.h>
 #include <sys/times.h>
 #include <malloc.h>
+#include <unistd.h>
 
 #include <grub/util/misc.h>
 #include <grub/mm.h>
@@ -107,6 +108,20 @@ grub_util_get_path (const char *dir, con
 }
 
 size_t
+grub_util_get_fp_size (FILE *fp)
+{
+  struct stat st;
+  
+  if (fflush (fp) == EOF)
+    grub_util_error ("fflush failed");
+
+  if (fstat (fileno (fp), &st) == -1)
+    grub_util_error ("fstat failed");
+  
+  return st.st_size;
+}
+
+size_t
 grub_util_get_image_size (const char *path)
 {
   struct stat st;
@@ -119,6 +134,16 @@ grub_util_get_image_size (const char *pa
   return st.st_size;
 }
 
+void
+grub_util_read_at (void *img, size_t size, off_t offset, FILE *fp)
+{
+  if (fseek (fp, offset, SEEK_SET) == -1)
+    grub_util_error ("fseek failed");
+
+  if (fread (img, 1, size, fp) != size)
+    grub_util_error ("read failed");
+}
+
 char *
 grub_util_read_image (const char *path)
 {
@@ -134,9 +159,8 @@ grub_util_read_image (const char *path)
   fp = fopen (path, "rb");
   if (! fp)
     grub_util_error ("cannot open %s", path);
-  
-  if (fread (img, 1, size, fp) != size)
-    grub_util_error ("cannot read %s", path);
+
+  grub_util_read_at (img, size, 0, fp);
 
   fclose (fp);
   
@@ -164,13 +188,21 @@ grub_util_load_image (const char *path, 
 }
 
 void
-grub_util_write_image (const char *img, size_t size, FILE *out)
+grub_util_write_image_at (const void *img, size_t size, off_t offset, FILE *out)
 {
-  grub_util_info ("writing 0x%x bytes", size);
+  grub_util_info ("writing 0x%x bytes at offset 0x%x", size, offset);
+  if (fseek (out, offset, SEEK_SET) == -1)
+    grub_util_error ("seek failed");
   if (fwrite (img, 1, size, out) != size)
     grub_util_error ("write failed");
 }
 
+void
+grub_util_write_image (const char *img, size_t size, FILE *out)
+{
+  grub_util_write_image_at (img, size, 0, out);
+}
+
 void *
 grub_malloc (unsigned size)
 {
Index: util/powerpc/ieee1275/grub-mkimage.c
===================================================================
RCS file: util/powerpc/ieee1275/grub-mkimage.c
diff -N util/powerpc/ieee1275/grub-mkimage.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ util/powerpc/ieee1275/grub-mkimage.c	2 Jan 2005 19:05:06 -0000
@@ -0,0 +1,296 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2004  Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* TODO: endianness */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <grub/elf.h>
+#include <grub/util/misc.h>
+#include <grub/util/resolve.h>
+#include <grub/kernel.h>
+#include <grub/machine/kernel.h>
+
+#define ALIGN_UP(addr, align) ((long)((char *)addr + align - 1) & ~(align - 1))
+
+static char *kernel_path = "grubof";
+static char *note_path = "note";
+
+
+void load_note (Elf32_Phdr *phdr, const char *dir, FILE *out)
+{
+  char *note_img;
+  char *path;
+  int note_size;
+
+  grub_util_info ("adding CHRP NOTE segment");
+
+  path = grub_util_get_path (dir, note_path);
+  note_size = grub_util_get_image_size (path);
+  note_img = xmalloc (note_size);
+  grub_util_load_image (path, note_img);
+  free (path);
+
+  /* Write the note data to the new segment.  */
+  grub_util_write_image_at (note_img, note_size, phdr->p_offset, out);
+
+  /* Fill in the rest of the segment header.  */
+  phdr->p_type = PT_NOTE;
+  phdr->p_flags = PF_R;
+  phdr->p_align = sizeof (long);
+  phdr->p_vaddr = 0;
+  phdr->p_paddr = 0;
+  phdr->p_filesz = note_size;
+  phdr->p_memsz = 0;
+}
+
+void load_modules (Elf32_Phdr *phdr, const char *dir, char *mods[], FILE *out)
+{
+  char *module_img;
+  struct grub_util_path_list *path_list, *p;
+  struct grub_module_info *modinfo;
+  size_t offset;
+  size_t total_module_size;
+  int num_modules = 0;
+
+  path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
+
+  offset = sizeof (struct grub_module_info);
+  total_module_size = sizeof (struct grub_module_info);
+  for (p = path_list; p; p = p->next)
+    {
+      total_module_size += (grub_util_get_image_size (p->name)
+	  + sizeof (struct grub_module_header));
+      num_modules++;
+    }
+
+  grub_util_info ("the total module size is 0x%x", total_module_size);
+
+  module_img = xmalloc (total_module_size);
+  modinfo = (struct grub_module_info *) module_img;
+  modinfo->version = MODINFO_VERSION;
+  modinfo->num_modules = num_modules;
+
+  /* Load all the modules, with headers, into module_img.  */
+  for (p = path_list; p; p = p->next)
+    {
+      struct grub_module_header *header;
+      size_t mod_size;
+
+      grub_util_info ("adding module %s", p->name);
+
+      mod_size = grub_util_get_image_size (p->name);
+
+      header = (struct grub_module_header *) (module_img + offset);
+      header->offset = grub_cpu_to_be32 (sizeof (*header));
+      header->size = grub_cpu_to_be32 (mod_size + sizeof (*header));
+
+      grub_util_load_image (p->name, module_img + offset + sizeof (*header));
+
+      offset += sizeof (*header) + mod_size;
+    }
+
+  /* Write the module data to the new segment.  */
+  grub_util_write_image_at (module_img, total_module_size, phdr->p_offset, out);
+
+  /* Fill in the rest of the segment header.  */
+  phdr->p_type = PT_LOAD;
+  phdr->p_flags = PF_R | PF_W | PF_X;
+  phdr->p_align = sizeof (long);
+  phdr->p_vaddr = MODULE_BASE;
+  phdr->p_paddr = MODULE_BASE;
+  phdr->p_filesz = total_module_size;
+  phdr->p_memsz = total_module_size;
+}
+
+void add_segments (char *dir, FILE *out, int chrp, char *mods[])
+{
+  Elf32_Ehdr ehdr;
+  Elf32_Phdr *phdrs = NULL;
+  Elf32_Phdr *phdr;
+  FILE *in;
+  off_t phdroff;
+  int i;
+
+  /* Read ELF header.  */
+  in = fopen (kernel_path, "rb");
+  if (! in)
+    grub_util_error ("cannot open %s", kernel_path);
+  grub_util_read_at (&ehdr, sizeof (ehdr), 0, in);
+
+  phdrs = xmalloc (ehdr.e_phentsize * (ehdr.e_phnum + 2));
+
+  /* Copy all existing segments.  */
+  for (i = 0; i < ehdr.e_phnum; i++)
+    {
+      char *segment_img;
+
+      phdr = phdrs + i;
+
+      /* Read segment header.  */
+      grub_util_read_at (phdr, sizeof (Elf32_Phdr), ehdr.e_phoff
+			 + (i * ehdr.e_phentsize), in);
+      grub_util_info ("copying segment %d, type %d", i, phdr->p_type);
+
+      /* Read segment data and write it to new file.  */
+      segment_img = xmalloc (phdr->p_filesz);
+      grub_util_read_at (segment_img, phdr->p_filesz, phdr->p_offset, in);
+      grub_util_write_image_at (segment_img, phdr->p_filesz, phdr->p_offset, out);
+
+      free (segment_img);
+    }
+
+  if (mods[0] != NULL)
+    {
+      /* Construct new segment header for modules.  */
+      phdr = phdrs + ehdr.e_phnum;
+      ehdr.e_phnum++;
+
+      /* Fill in p_offset so the callees know where to write.  */
+      phdr->p_offset = ALIGN_UP (grub_util_get_fp_size (out), sizeof (long));
+
+      load_modules (phdr, dir, mods, out);
+    }
+
+  if (chrp)
+    {
+      /* Construct new segment header for the CHRP note.  */
+      phdr = phdrs + ehdr.e_phnum;
+      ehdr.e_phnum++;
+
+      /* Fill in p_offset so the callees know where to write.  */
+      phdr->p_offset = ALIGN_UP (grub_util_get_fp_size (out), sizeof (long));
+
+      load_note (phdr, dir, out);
+    }
+
+  /* Don't bother preserving the section headers.  */
+  ehdr.e_shoff = 0;
+  ehdr.e_shnum = 0;
+  ehdr.e_shstrndx = 0;
+
+  /* Append entire segment table to the file.  */
+  phdroff = ALIGN_UP (grub_util_get_fp_size (out), sizeof (long));
+  grub_util_write_image_at (phdrs, ehdr.e_phentsize * ehdr.e_phnum, phdroff,
+			    out);
+
+  /* Write ELF header.  */
+  ehdr.e_phoff = phdroff;
+  grub_util_write_image_at (&ehdr, sizeof (ehdr), 0, out);
+
+  free (phdrs);
+}
+
+static struct option options[] =
+  {
+    {"directory", required_argument, 0, 'd'},
+    {"output", required_argument, 0, 'o'},
+    {"help", no_argument, 0, 'h'},
+    {"note", no_argument, 0, 'n'},
+    {"version", no_argument, 0, 'V'},
+    {"verbose", no_argument, 0, 'v'},
+    { 0, 0, 0, 0 },
+  };
+
+static void
+usage (int status)
+{
+  if (status)
+    fprintf (stderr, "Try ``grub-mkimage --help'' for more information.\n");
+  else
+    printf ("\
+Usage: grub-mkimage -o FILE [OPTION]... [MODULES]\n\
+\n\
+Make a bootable image of GRUB.\n\
+\n\
+-d, --directory=DIR     use images and modules under DIR [default=%s]\n\
+-o, --output=FILE       output a generated image to FILE\n\
+-h, --help              display this message and exit\n\
+-n, --note              add NOTE segment for CHRP Open Firmware\n\
+-V, --version           print version information and exit\n\
+-v, --verbose           print verbose messages\n\
+\n\
+Report bugs to <%s>.\n\
+", GRUB_DATADIR, PACKAGE_BUGREPORT);
+
+  exit (status);
+}
+
+int main (int argc, char *argv[])
+{
+  FILE *fp;
+  char *output = NULL;
+  char *dir = NULL;
+  int chrp = 0;
+
+  progname = "grub-mkimage";
+
+  while (1)
+    {
+      int c = getopt_long (argc, argv, "d:o:hVvn", options, 0);
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	  case 'd':
+	    if (dir)
+	      free (dir);
+	    dir = xstrdup (optarg);
+	    break;
+	  case 'h':
+	    usage (0);
+	    break;
+	  case 'n':
+	    chrp = 1;
+	    break;
+	  case 'o':
+	    if (output)
+	      free (output);
+	    output = xstrdup (optarg);
+	    break;
+	  case 'V':
+	    printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+	    return 0;
+	  case 'v':
+	    verbosity++;
+	    break;
+	  default:
+	    usage (1);
+	    break;
+	}
+  }
+
+  if (!output)
+    usage (1);
+
+  fp = fopen (output, "wb");
+  if (! fp)
+    grub_util_error ("cannot open %s", output);
+
+  add_segments (dir ? : GRUB_DATADIR, fp, chrp, argv + optind);
+
+  fclose (fp);
+
+  return 0;
+}
Index: include/grub/powerpc/ieee1275/kernel.h
===================================================================
RCS file: include/grub/powerpc/ieee1275/kernel.h
diff -N include/grub/powerpc/ieee1275/kernel.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ include/grub/powerpc/ieee1275/kernel.h	2 Jan 2005 19:06:04 -0000
@@ -0,0 +1,26 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002  Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GRUB_KERNEL_MACHINE_HEADER
+#define GRUB_KERNEL_MACHINE_HEADER	1
+
+/* Where grub-mkimage places the core modules in memory.  */
+#define MODULE_BASE 0x00300000
+
+#endif



^ permalink raw reply	[flat|nested] 12+ messages in thread
* Re: grub-mkimage and module loading
@ 2005-01-03  3:12 Hollis Blanchard
  2005-01-03 13:10 ` Marco Gerards
  0 siblings, 1 reply; 12+ messages in thread
From: Hollis Blanchard @ 2005-01-03  3:12 UTC (permalink / raw)
  To: grub-devel

This is the updated version of the mkimage patch for PPC. It has been
tested on PowerPC, but only compile-tested on x86.

The interesting parts are in grub_load_modules(), where we no longer use
grub_end_addr and grub_get_end_addr() as the bounds of our modules.
Instead we call an arch-specific grub_arch_modules_addr(), and at that
location we find a struct grub_module_info, telling us the size of the
in-memory modules.

Note that now, grub_load_modules() is the only code that knows how large
the modules are. There were two other users of that information:
grub_add_unused_region() and i386/pc grub_machine_init(), and both are doing
the same thing: adding the module memory to the heap allocator.
grub_add_unused_region() was easily folded into grub_load_modules().
I believe the grub_machine_init use is unnecessary because the memory is
now given to the heap in grub_load_modules(). I have not confirmed this.

I know the common grub_load_modules() code works, but the corresponding i386
grub-mkimage additions need testing.

-Hollis

2004-01-02  Hollis Blanchard  <hollis@penguinppc.org>
	* TODO: Add note about endianness in grub-mkimage.
	* boot/powerpc/ieee1275/crt0.S (note): Remove unused .note
	section.
	* conf/powerpc-ieee1275.rmk (bin_UTILITIES): Add grub-mkimage.
	(grub_mkimage_SOURCES): New target.
	* include/grub/kernel.h (grub_start_addr): Remove variable.
	(grub_end_addr): Likewise.
	(grub_total_module_size): Likewise.
	(grub_kernel_image_size): Likewise.
	(GRUB_MODULE_MAGIC): New constant.
	(grub_module_info): New structure.
	(grub_arch_modules_addr): New prototype.
	(grub_get_end_addr): Remove prototype.
	* include/grub/i386/pc/kernel.h (grub_end_addr): New prototype.
	* include/grub/powerpc/ieee1275/kernel.h: New file.
	* include/grub/util/misc.h (grub_util_get_fp_size): New
	prototype.
	(grub_util_read_at): Likewise.
	(grub_util_write_image_at): Likewise.
	* kern/main.c (grub_get_end_addr): Remove function.
	(grub_load_modules): Call grub_arch_modules_addr instead of
	using grub_end_addr. Look for a grub_module_info struct in
	memory. Use the grub_module_info fields instead of calling
	grub_get_end_addr as loop conditions. Move
	grub_add_unused_region code here.
	(grub_add_unused_region): Remove function.
	* kern/i386/pc/init.c: Include grub/cache.h.
	(grub_machine_init): Remove call to grub_get_end_addr. Remove
	one call to add_mem_region.
	(grub_arch_modules_addr): New function.
	* kern/powerpc/ieee1275/init.c (grub_end_addr): Remove variable.
	(grub_total_module_size): Likewise.
	Include grub/machine/kernel.h.
	(grub_arch_modules_addr): New function.
	* util/grub-emu.c (grub_end_addr): Remove variable.
	(grub_total_module_size): Likewise.
	(grub_arch_modules_addr): New function.
	* util/misc.c: Include unistd.h.
	(grub_util_get_fp_size): New function.
	(grub_util_read_at): Likewise.
	(grub_util_write_image_at): Likewise.
	(grub_util_read_image): Call grub_util_read_at.
	(grub_util_write_image): Call grub_util_write_image_at.
	* util/i386/pc/grub-mkimage.c (generate_image): Allocate
	additional memory in kernel_img for a struct grub_module_info.
	Fill in that grub_module_info.
	* util/powerpc/ieee1275/grub-mkimage.c: New file.

Index: TODO
===================================================================
RCS file: /cvsroot/grub/grub2/TODO,v
retrieving revision 1.7
diff -u -p -r1.7 TODO
--- TODO	1 Aug 2004 13:19:38 -0000	1.7
+++ TODO	3 Jan 2005 02:56:55 -0000
@@ -39,3 +39,5 @@ Priorities:
 * Add a fancy menu interface which utilizes the graphics mode
   extensively with many eye-candies. This is important to beat
   GRUB legacy. :)
+
+* Audit util/powerpc/ieee1275/grub-mkimage.c for endianness fixes.
Index: boot/powerpc/ieee1275/crt0.S
===================================================================
RCS file: /cvsroot/grub/grub2/boot/powerpc/ieee1275/crt0.S,v
retrieving revision 1.4
diff -u -p -r1.4 crt0.S
--- boot/powerpc/ieee1275/crt0.S	28 Dec 2004 22:43:37 -0000	1.4
+++ boot/powerpc/ieee1275/crt0.S	3 Jan 2005 02:56:55 -0000
@@ -18,21 +18,6 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-	.section ".note"
-	.align	2
-.note_section_header:
-	.long	8
-	.long	24
-	.long	0x1275
-	.string	"PowerPC"
-.note_descriptor:
-	.long   0x0             /* real-mode */
-	.long   0xffffffff      /* real-base */
-	.long   0xffffffff      /* real-size */
-	.long   0xffffffff      /* virt-base */
-	.long   0xffffffff      /* virt-size */
-	.long   0x00030000      /* load-base */
-
 .extern __bss_start
 .extern _end
 
Index: conf/powerpc-ieee1275.rmk
===================================================================
RCS file: /cvsroot/grub/grub2/conf/powerpc-ieee1275.rmk,v
retrieving revision 1.18
diff -u -p -r1.18 powerpc-ieee1275.rmk
--- conf/powerpc-ieee1275.rmk	28 Dec 2004 22:43:37 -0000	1.18
+++ conf/powerpc-ieee1275.rmk	3 Jan 2005 02:56:57 -0000
@@ -24,9 +24,13 @@ kernel_syms.lst: $(addprefix include/gru
 pkgdata_PROGRAMS = grubof
 
 # Utilities.
-bin_UTILITIES = grub-emu
+bin_UTILITIES = grub-emu grub-mkimage
 noinst_UTILITIES = genmoddep
 
+# For grub-mkimage.
+grub_mkimage_SOURCES = util/powerpc/ieee1275/grub-mkimage.c util/misc.c \
+        util/resolve.c 
+
 # For grub-emu
 grub_emu_SOURCES = kern/main.c kern/device.c				\
 	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c		\
Index: include/grub/kernel.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/kernel.h,v
retrieving revision 1.4
diff -u -p -r1.4 kernel.h
--- include/grub/kernel.h	4 Apr 2004 13:46:00 -0000	1.4
+++ include/grub/kernel.h	3 Jan 2005 02:56:57 -0000
@@ -31,17 +31,18 @@ struct grub_module_header
   grub_size_t size;
 };
 
-/* The start address of the kernel.  */
-extern grub_addr_t grub_start_addr;
+#define GRUB_MODULE_MAGIC 0x676d696d /* "gmim" (GRUB Module Info Magic).  */
 
-/* The end address of the kernel.  */
-extern grub_addr_t grub_end_addr;
+struct grub_module_info {
+  /* Magic number so we know we have modules present.  */
+  grub_uint32_t magic;
+  /* The offset of the modules.  */
+  grub_off_t offset;
+  /* The size of all modules plus this header.  */
+  grub_size_t size;
+};
 
-/* The total size of modules including their headers.  */
-extern grub_size_t grub_total_module_size;
-
-/* The size of the kernel image.  */
-extern grub_size_t grub_kernel_image_size;
+extern grub_addr_t grub_arch_modules_addr (void);
 
 /* The start point of the C code.  */
 void grub_main (void);
@@ -49,9 +50,6 @@ void grub_main (void);
 /* The machine-specific initialization. This must initialize memory.  */
 void grub_machine_init (void);
 
-/* Return the end address of the core image.  */
-grub_addr_t grub_get_end_addr (void);
-
 /* Register all the exported symbols. This is automatically generated.  */
 void grub_register_exported_symbols (void);
 
Index: include/grub/i386/pc/kernel.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/i386/pc/kernel.h,v
retrieving revision 1.5
diff -u -p -r1.5 kernel.h
--- include/grub/i386/pc/kernel.h	4 Apr 2004 13:46:01 -0000	1.5
+++ include/grub/i386/pc/kernel.h	3 Jan 2005 02:56:57 -0000
@@ -58,6 +58,9 @@ extern char grub_prefix[];
 /* The boot BIOS drive number.  */
 extern grub_int32_t grub_boot_drive;
 
+/* The end address of the kernel.  */
+extern grub_addr_t grub_end_addr;
+
 #endif /* ! ASM_FILE */
 
 #endif /* ! KERNEL_MACHINE_HEADER */
Index: include/grub/powerpc/ieee1275/kernel.h
===================================================================
RCS file: include/grub/powerpc/ieee1275/kernel.h
diff -N include/grub/powerpc/ieee1275/kernel.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ include/grub/powerpc/ieee1275/kernel.h	3 Jan 2005 02:56:57 -0000
@@ -0,0 +1,26 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002  Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GRUB_KERNEL_MACHINE_HEADER
+#define GRUB_KERNEL_MACHINE_HEADER	1
+
+/* Where grub-mkimage places the core modules in memory.  */
+#define MODULE_BASE 0x00300000
+
+#endif
Index: include/grub/util/misc.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/util/misc.h,v
retrieving revision 1.5
diff -u -p -r1.5 misc.h
--- include/grub/util/misc.h	4 Apr 2004 13:46:01 -0000	1.5
+++ include/grub/util/misc.h	3 Jan 2005 02:56:57 -0000
@@ -34,9 +34,13 @@ void *xrealloc (void *ptr, size_t size);
 char *xstrdup (const char *str);
 
 char *grub_util_get_path (const char *dir, const char *file);
+size_t grub_util_get_fp_size (FILE *fp);
 size_t grub_util_get_image_size (const char *path);
+void grub_util_read_at (void *img, size_t len, off_t offset, FILE *fp);
 char *grub_util_read_image (const char *path);
 void grub_util_load_image (const char *path, char *buf);
 void grub_util_write_image (const char *img, size_t size, FILE *out);
+void grub_util_write_image_at (const void *img, size_t size, off_t offset,
+			       FILE *out);
 
 #endif /* ! GRUB_UTIL_MISC_HEADER */
Index: kern/main.c
===================================================================
RCS file: /cvsroot/grub/grub2/kern/main.c,v
retrieving revision 1.8
diff -u -p -r1.8 main.c
--- kern/main.c	4 Apr 2004 13:46:01 -0000	1.8
+++ kern/main.c	3 Jan 2005 02:56:57 -0000
@@ -29,35 +29,31 @@
 #include <grub/device.h>
 #include <grub/env.h>
 
-/* Return the end of the core image.  */
-grub_addr_t
-grub_get_end_addr (void)
-{
-  return grub_total_module_size + grub_end_addr;
-}
-
 /* Load all modules in core.  */
 static void
 grub_load_modules (void)
 {
+  struct grub_module_info *modinfo;
   struct grub_module_header *header;
+  grub_addr_t modbase;
+
+  modbase = grub_arch_modules_addr ();
+  modinfo = (struct grub_module_info *) modbase;
+  if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC)
+    /* No modules.  */
+    return;
 
-  for (header = (struct grub_module_header *) grub_end_addr;
-       header < (struct grub_module_header *) grub_get_end_addr ();
+  for (header = (struct grub_module_header *) (modbase + modinfo->offset);
+       header < (struct grub_module_header *) (modbase + modinfo->size);
        header = (struct grub_module_header *) ((char *) header + header->size))
     {
       if (! grub_dl_load_core ((char *) header + header->offset,
 			       (header->size - header->offset)))
 	grub_fatal ("%s", grub_errmsg);
     }
-}
 
-/* Add the region where modules reside into dynamic memory.  */
-static void
-grub_add_unused_region (void)
-{
-  if (grub_total_module_size)
-    grub_mm_init_region ((void *) grub_end_addr, grub_total_module_size);
+  /* Add the region where modules reside into dynamic memory.  */
+  grub_mm_init_region ((void *) modinfo, modinfo->size);
 }
 
 /* Set the root device according to the dl prefix.  */
@@ -111,7 +107,6 @@ grub_main (void)
   /* Load pre-loaded modules and free the space.  */
   grub_register_exported_symbols ();
   grub_load_modules ();
-  grub_add_unused_region ();
 
   /* Load the normal mode module.  */
   grub_load_normal_mode ();
Index: kern/i386/pc/init.c
===================================================================
RCS file: /cvsroot/grub/grub2/kern/i386/pc/init.c,v
retrieving revision 1.9
diff -u -p -r1.9 init.c
--- kern/i386/pc/init.c	27 Dec 2004 13:46:20 -0000	1.9
+++ kern/i386/pc/init.c	3 Jan 2005 02:56:57 -0000
@@ -30,6 +30,7 @@
 #include <grub/misc.h>
 #include <grub/loader.h>
 #include <grub/env.h>
+#include <grub/cache.h>
 
 struct mem_region
 {
@@ -126,7 +127,6 @@ grub_machine_init (void)
   grub_uint32_t cont;
   struct grub_machine_mmap_entry *entry
     = (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
-  grub_addr_t end_addr = grub_get_end_addr ();
   int i;
   
   /* Initialize the console as early as possible.  */
@@ -148,8 +148,6 @@ grub_machine_init (void)
     add_mem_region (GRUB_MEMORY_MACHINE_RESERVED_END,
 		    grub_lower_mem - GRUB_MEMORY_MACHINE_RESERVED_END);
   
-  add_mem_region (end_addr, GRUB_MEMORY_MACHINE_RESERVED_START - end_addr);
-
   /* Check if grub_get_mmap_entry works.  */
   cont = grub_get_mmap_entry (entry, 0);
 
@@ -233,3 +231,10 @@ grub_machine_init (void)
   /* Initialize the prefix.  */
   grub_env_set ("prefix", make_install_device ());
 }
+
+/* Return the end of the core image.  */
+grub_addr_t
+grub_arch_modules_addr (void)
+{
+  return grub_end_addr;
+}
Index: kern/powerpc/ieee1275/init.c
===================================================================
RCS file: /cvsroot/grub/grub2/kern/powerpc/ieee1275/init.c,v
retrieving revision 1.11
diff -u -p -r1.11 init.c
--- kern/powerpc/ieee1275/init.c	27 Dec 2004 13:46:20 -0000	1.11
+++ kern/powerpc/ieee1275/init.c	3 Jan 2005 02:56:57 -0000
@@ -31,10 +31,7 @@
 #include <grub/misc.h>
 #include <grub/machine/init.h>
 #include <grub/machine/time.h>
-
-/* XXX: Modules are not yet supported.  */
-grub_addr_t grub_end_addr = -1;
-grub_addr_t grub_total_module_size = 0;
+#include <grub/machine/kernel.h>
 
 void
 abort (void)
@@ -84,3 +81,9 @@ grub_get_rtc (void)
 {
   return 0;
 }
+
+grub_addr_t
+grub_arch_modules_addr (void)
+{
+  return MODULE_BASE;
+}
Index: util/grub-emu.c
===================================================================
RCS file: /cvsroot/grub/grub2/util/grub-emu.c,v
retrieving revision 1.9
diff -u -p -r1.9 grub-emu.c
--- util/grub-emu.c	4 Dec 2004 18:45:45 -0000	1.9
+++ util/grub-emu.c	3 Jan 2005 02:56:58 -0000
@@ -45,9 +45,11 @@
 
 #define DEFAULT_DEVICE_MAP	DEFAULT_DIRECTORY "/device.map"
 
-/* XXX.  */
-grub_addr_t grub_end_addr = -1;
-grub_addr_t grub_total_module_size = 0;
+grub_addr_t
+grub_arch_modules_addr (void)
+{
+  return 0;
+}
 
 int
 grub_arch_dl_check_header (void *ehdr, grub_size_t size)
Index: util/misc.c
===================================================================
RCS file: /cvsroot/grub/grub2/util/misc.c,v
retrieving revision 1.9
diff -u -p -r1.9 misc.c
--- util/misc.c	27 Dec 2004 13:46:20 -0000	1.9
+++ util/misc.c	3 Jan 2005 02:56:58 -0000
@@ -25,6 +25,7 @@
 #include <sys/stat.h>
 #include <sys/times.h>
 #include <malloc.h>
+#include <unistd.h>
 
 #include <grub/util/misc.h>
 #include <grub/mm.h>
@@ -107,6 +108,20 @@ grub_util_get_path (const char *dir, con
 }
 
 size_t
+grub_util_get_fp_size (FILE *fp)
+{
+  struct stat st;
+  
+  if (fflush (fp) == EOF)
+    grub_util_error ("fflush failed");
+
+  if (fstat (fileno (fp), &st) == -1)
+    grub_util_error ("fstat failed");
+  
+  return st.st_size;
+}
+
+size_t
 grub_util_get_image_size (const char *path)
 {
   struct stat st;
@@ -119,6 +134,16 @@ grub_util_get_image_size (const char *pa
   return st.st_size;
 }
 
+void
+grub_util_read_at (void *img, size_t size, off_t offset, FILE *fp)
+{
+  if (fseek (fp, offset, SEEK_SET) == -1)
+    grub_util_error ("fseek failed");
+
+  if (fread (img, 1, size, fp) != size)
+    grub_util_error ("read failed");
+}
+
 char *
 grub_util_read_image (const char *path)
 {
@@ -134,9 +159,8 @@ grub_util_read_image (const char *path)
   fp = fopen (path, "rb");
   if (! fp)
     grub_util_error ("cannot open %s", path);
-  
-  if (fread (img, 1, size, fp) != size)
-    grub_util_error ("cannot read %s", path);
+
+  grub_util_read_at (img, size, 0, fp);
 
   fclose (fp);
   
@@ -164,13 +188,21 @@ grub_util_load_image (const char *path, 
 }
 
 void
-grub_util_write_image (const char *img, size_t size, FILE *out)
+grub_util_write_image_at (const void *img, size_t size, off_t offset, FILE *out)
 {
-  grub_util_info ("writing 0x%x bytes", size);
+  grub_util_info ("writing 0x%x bytes at offset 0x%x", size, offset);
+  if (fseek (out, offset, SEEK_SET) == -1)
+    grub_util_error ("seek failed");
   if (fwrite (img, 1, size, out) != size)
     grub_util_error ("write failed");
 }
 
+void
+grub_util_write_image (const char *img, size_t size, FILE *out)
+{
+  grub_util_write_image_at (img, size, 0, out);
+}
+
 void *
 grub_malloc (unsigned size)
 {
Index: util/i386/pc/grub-mkimage.c
===================================================================
RCS file: /cvsroot/grub/grub2/util/i386/pc/grub-mkimage.c,v
retrieving revision 1.6
diff -u -p -r1.6 grub-mkimage.c
--- util/i386/pc/grub-mkimage.c	4 Apr 2004 13:46:03 -0000	1.6
+++ util/i386/pc/grub-mkimage.c	3 Jan 2005 02:56:58 -0000
@@ -79,13 +79,14 @@ generate_image (const char *dir, FILE *o
   unsigned num;
   size_t offset;
   struct grub_util_path_list *path_list, *p, *next;
+  struct grub_module_info *modinfo;
 
   path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
 
   kernel_path = grub_util_get_path (dir, "kernel.img");
   kernel_size = grub_util_get_image_size (kernel_path);
 
-  total_module_size = 0;
+  total_module_size = sizeof (struct grub_module_info);
   for (p = path_list; p; p = p->next)
     total_module_size += (grub_util_get_image_size (p->name)
 			  + sizeof (struct grub_module_header));
@@ -94,7 +95,14 @@ generate_image (const char *dir, FILE *o
 
   kernel_img = xmalloc (kernel_size + total_module_size);
   grub_util_load_image (kernel_path, kernel_img);
-  offset = kernel_size;
+
+  /* Fill in the grub_module_info structure.  */
+  modinfo = (struct grub_module_info *) (kernel_img + kernel_size);
+  modinfo->magic = GRUB_MODULE_MAGIC;
+  modinfo->offset = sizeof (struct grub_module_info);
+  modinfo->size = total_module_size;
+
+  offset = kernel_size + sizeof (struct grub_module_info);
   for (p = path_list; p; p = p->next)
     {
       struct grub_module_header *header;
Index: util/powerpc/ieee1275/grub-mkimage.c
===================================================================
RCS file: util/powerpc/ieee1275/grub-mkimage.c
diff -N util/powerpc/ieee1275/grub-mkimage.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ util/powerpc/ieee1275/grub-mkimage.c	3 Jan 2005 02:56:58 -0000
@@ -0,0 +1,298 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2004  Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <grub/elf.h>
+#include <grub/util/misc.h>
+#include <grub/util/resolve.h>
+#include <grub/kernel.h>
+#include <grub/machine/kernel.h>
+
+#define ALIGN_UP(addr, align) ((long)((char *)addr + align - 1) & ~(align - 1))
+
+static char *kernel_path = "grubof";
+static char *note_path = "note";
+
+
+void
+load_note (Elf32_Phdr *phdr, const char *dir, FILE *out)
+{
+  char *note_img;
+  char *path;
+  int note_size;
+
+  grub_util_info ("adding CHRP NOTE segment");
+
+  path = grub_util_get_path (dir, note_path);
+  note_size = grub_util_get_image_size (path);
+  note_img = xmalloc (note_size);
+  grub_util_load_image (path, note_img);
+  free (path);
+
+  /* Write the note data to the new segment.  */
+  grub_util_write_image_at (note_img, note_size, phdr->p_offset, out);
+
+  /* Fill in the rest of the segment header.  */
+  phdr->p_type = PT_NOTE;
+  phdr->p_flags = PF_R;
+  phdr->p_align = sizeof (long);
+  phdr->p_vaddr = 0;
+  phdr->p_paddr = 0;
+  phdr->p_filesz = note_size;
+  phdr->p_memsz = 0;
+}
+
+void
+load_modules (Elf32_Phdr *phdr, const char *dir, char *mods[], FILE *out)
+{
+  char *module_img;
+  struct grub_util_path_list *path_list;
+  struct grub_util_path_list *p;
+  struct grub_module_info *modinfo;
+  size_t offset;
+  size_t total_module_size;
+
+  path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
+
+  offset = sizeof (struct grub_module_info);
+  total_module_size = sizeof (struct grub_module_info);
+  for (p = path_list; p; p = p->next)
+    {
+      total_module_size += (grub_util_get_image_size (p->name)
+	  + sizeof (struct grub_module_header));
+    }
+
+  grub_util_info ("the total module size is 0x%x", total_module_size);
+
+  module_img = xmalloc (total_module_size);
+  modinfo = (struct grub_module_info *) module_img;
+  modinfo->magic = GRUB_MODULE_MAGIC;
+  modinfo->offset = sizeof (struct grub_module_info);
+  modinfo->size = total_module_size;
+
+  /* Load all the modules, with headers, into module_img.  */
+  for (p = path_list; p; p = p->next)
+    {
+      struct grub_module_header *header;
+      size_t mod_size;
+
+      grub_util_info ("adding module %s", p->name);
+
+      mod_size = grub_util_get_image_size (p->name);
+
+      header = (struct grub_module_header *) (module_img + offset);
+      header->offset = grub_cpu_to_be32 (sizeof (*header));
+      header->size = grub_cpu_to_be32 (mod_size + sizeof (*header));
+
+      grub_util_load_image (p->name, module_img + offset + sizeof (*header));
+
+      offset += sizeof (*header) + mod_size;
+    }
+
+  /* Write the module data to the new segment.  */
+  grub_util_write_image_at (module_img, total_module_size, phdr->p_offset, out);
+
+  /* Fill in the rest of the segment header.  */
+  phdr->p_type = PT_LOAD;
+  phdr->p_flags = PF_R | PF_W | PF_X;
+  phdr->p_align = sizeof (long);
+  phdr->p_vaddr = MODULE_BASE;
+  phdr->p_paddr = MODULE_BASE;
+  phdr->p_filesz = total_module_size;
+  phdr->p_memsz = total_module_size;
+}
+
+void
+add_segments (char *dir, FILE *out, int chrp, char *mods[])
+{
+  Elf32_Ehdr ehdr;
+  Elf32_Phdr *phdrs = NULL;
+  Elf32_Phdr *phdr;
+  FILE *in;
+  off_t phdroff;
+  int i;
+
+  /* Read ELF header.  */
+  in = fopen (kernel_path, "rb");
+  if (! in)
+    grub_util_error ("cannot open %s", kernel_path);
+  grub_util_read_at (&ehdr, sizeof (ehdr), 0, in);
+
+  phdrs = xmalloc (ehdr.e_phentsize * (ehdr.e_phnum + 2));
+
+  /* Copy all existing segments.  */
+  for (i = 0; i < ehdr.e_phnum; i++)
+    {
+      char *segment_img;
+
+      phdr = phdrs + i;
+
+      /* Read segment header.  */
+      grub_util_read_at (phdr, sizeof (Elf32_Phdr), ehdr.e_phoff
+			 + (i * ehdr.e_phentsize), in);
+      grub_util_info ("copying segment %d, type %d", i, phdr->p_type);
+
+      /* Read segment data and write it to new file.  */
+      segment_img = xmalloc (phdr->p_filesz);
+      grub_util_read_at (segment_img, phdr->p_filesz, phdr->p_offset, in);
+      grub_util_write_image_at (segment_img, phdr->p_filesz, phdr->p_offset, out);
+
+      free (segment_img);
+    }
+
+  if (mods[0] != NULL)
+    {
+      /* Construct new segment header for modules.  */
+      phdr = phdrs + ehdr.e_phnum;
+      ehdr.e_phnum++;
+
+      /* Fill in p_offset so the callees know where to write.  */
+      phdr->p_offset = ALIGN_UP (grub_util_get_fp_size (out), sizeof (long));
+
+      load_modules (phdr, dir, mods, out);
+    }
+
+  if (chrp)
+    {
+      /* Construct new segment header for the CHRP note.  */
+      phdr = phdrs + ehdr.e_phnum;
+      ehdr.e_phnum++;
+
+      /* Fill in p_offset so the callees know where to write.  */
+      phdr->p_offset = ALIGN_UP (grub_util_get_fp_size (out), sizeof (long));
+
+      load_note (phdr, dir, out);
+    }
+
+  /* Don't bother preserving the section headers.  */
+  ehdr.e_shoff = 0;
+  ehdr.e_shnum = 0;
+  ehdr.e_shstrndx = 0;
+
+  /* Append entire segment table to the file.  */
+  phdroff = ALIGN_UP (grub_util_get_fp_size (out), sizeof (long));
+  grub_util_write_image_at (phdrs, ehdr.e_phentsize * ehdr.e_phnum, phdroff,
+			    out);
+
+  /* Write ELF header.  */
+  ehdr.e_phoff = phdroff;
+  grub_util_write_image_at (&ehdr, sizeof (ehdr), 0, out);
+
+  free (phdrs);
+}
+
+static struct option options[] =
+  {
+    {"directory", required_argument, 0, 'd'},
+    {"output", required_argument, 0, 'o'},
+    {"help", no_argument, 0, 'h'},
+    {"note", no_argument, 0, 'n'},
+    {"version", no_argument, 0, 'V'},
+    {"verbose", no_argument, 0, 'v'},
+    { 0, 0, 0, 0 },
+  };
+
+static void
+usage (int status)
+{
+  if (status)
+    fprintf (stderr, "Try ``grub-mkimage --help'' for more information.\n");
+  else
+    printf ("\
+Usage: grub-mkimage -o FILE [OPTION]... [MODULES]\n\
+\n\
+Make a bootable image of GRUB.\n\
+\n\
+-d, --directory=DIR     use images and modules under DIR [default=%s]\n\
+-o, --output=FILE       output a generated image to FILE\n\
+-h, --help              display this message and exit\n\
+-n, --note              add NOTE segment for CHRP Open Firmware\n\
+-V, --version           print version information and exit\n\
+-v, --verbose           print verbose messages\n\
+\n\
+Report bugs to <%s>.\n\
+", GRUB_DATADIR, PACKAGE_BUGREPORT);
+
+  exit (status);
+}
+
+int
+main (int argc, char *argv[])
+{
+  FILE *fp;
+  char *output = NULL;
+  char *dir = NULL;
+  int chrp = 0;
+
+  progname = "grub-mkimage";
+
+  while (1)
+    {
+      int c = getopt_long (argc, argv, "d:o:hVvn", options, 0);
+      if (c == -1)
+	break;
+
+      switch (c)
+	{
+	  case 'd':
+	    if (dir)
+	      free (dir);
+	    dir = xstrdup (optarg);
+	    break;
+	  case 'h':
+	    usage (0);
+	    break;
+	  case 'n':
+	    chrp = 1;
+	    break;
+	  case 'o':
+	    if (output)
+	      free (output);
+	    output = xstrdup (optarg);
+	    break;
+	  case 'V':
+	    printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+	    return 0;
+	  case 'v':
+	    verbosity++;
+	    break;
+	  default:
+	    usage (1);
+	    break;
+	}
+  }
+
+  if (!output)
+    usage (1);
+
+  fp = fopen (output, "wb");
+  if (! fp)
+    grub_util_error ("cannot open %s", output);
+
+  add_segments (dir ? : GRUB_DATADIR, fp, chrp, argv + optind);
+
+  fclose (fp);
+
+  return 0;
+}



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2005-01-05 13:52 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-01-02 19:02 grub-mkimage and module loading Hollis Blanchard
2005-01-02 21:05 ` Marco Gerards
2005-01-02 22:23   ` Hollis Blanchard
2005-01-02 22:45     ` Marco Gerards
2005-01-03  2:49       ` Pentium II boot failure Hollis Blanchard
2005-01-03 12:53         ` Marco Gerards
2005-01-03 13:17           ` Vincent Pelletier
2005-01-03 18:06             ` Hollis Blanchard
  -- strict thread matches above, loose matches on Subject: below --
2005-01-03  3:12 grub-mkimage and module loading Hollis Blanchard
2005-01-03 13:10 ` Marco Gerards
2005-01-04 14:09   ` Marco Gerards
2005-01-05 13:36   ` Marco Gerards

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.