[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: grub-mkimage and module loading
From: |
Hollis Blanchard |
Subject: |
Re: grub-mkimage and module loading |
Date: |
Sun, 2 Jan 2005 13:02:04 -0600 |
User-agent: |
Mutt/1.5.6+20040907i |
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
- Re: grub-mkimage and module loading,
Hollis Blanchard <=
- Re: grub-mkimage and module loading, Marco Gerards, 2005/01/02
- Re: grub-mkimage and module loading, Hollis Blanchard, 2005/01/02
- Re: grub-mkimage and module loading, Marco Gerards, 2005/01/02
- Re: Pentium II boot failure, Hollis Blanchard, 2005/01/02
- Re: Pentium II boot failure, Marco Gerards, 2005/01/03
- Re: Pentium II boot failure, Vincent Pelletier, 2005/01/03
- Re: Pentium II boot failure, Hollis Blanchard, 2005/01/03