From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.33) id 1Ca6Uu-0004U4-OK for mharc-grub-devel@gnu.org; Fri, 03 Dec 2004 01:00:52 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.33) id 1Ca6Us-0004Tn-MJ for grub-devel@gnu.org; Fri, 03 Dec 2004 01:00:50 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.33) id 1Ca6Ur-0004Tb-TH for grub-devel@gnu.org; Fri, 03 Dec 2004 01:00:50 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.33) id 1Ca6Uq-0004TY-Ts for grub-devel@gnu.org; Fri, 03 Dec 2004 01:00:49 -0500 Received: from [207.217.121.251] (helo=pop-a065d10.pas.sa.earthlink.net) by monty-python.gnu.org with esmtp (Exim 4.34) id 1Ca6LC-0001fg-2w for grub-devel@gnu.org; Fri, 03 Dec 2004 00:50:50 -0500 Received: from user-0vvde2s.cable.mindspring.com ([63.246.184.92] helo=miracle) by pop-a065d10.pas.sa.earthlink.net with esmtp (Exim 3.33 #1) id 1Ca6LA-00050e-00 for grub-devel@gnu.org; Thu, 02 Dec 2004 21:50:48 -0800 Received: from hollis by miracle with local (Exim 3.36 #1 (Debian)) id 1Ca67a-0005rc-00 for ; Thu, 02 Dec 2004 23:36:46 -0600 Date: Thu, 2 Dec 2004 23:36:46 -0600 To: grub-devel@gnu.org Message-ID: <20041203053646.GA22463@miracle> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.6+20040722i From: Hollis Blanchard Subject: [ppc patch] grub-mkimage X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GRUB 2 List-Id: The development of GRUB 2 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 03 Dec 2004 06:00:50 -0000 I'm going to be on vacation next week, so I wanted to get this out so others could continue progress on PPC module loading... this is not ready for inclusion, but it is functional. Comments are welcome. Open Firmware loads GRUB as an ELF file (rather than a binary image like x86 BIOS). So we can't just concatenate modules to the end of the grubof ELF file; we need to put them in an ELF LOAD segment. That's what this grub-mkimage does. Right now there's still a manual step or two involved. You must build a binary "note" segment (in the proper endianness). I *thought* we could get the toolchain to build this for us with the right combination of gcc/ld/objcopy options, but now I'm not so sure. Anyways, for now from a PPC host: gcc -c note.S objcopy -O binary note.o note Use the -n/--note switch to add the CHRP NOTE segment on CHRP platforms (e.g. briQ and Pegasos). NEVER use this switch on Power Macintosh. I guess that should be documented better in the help text, but anyways... The endian-swapping code in grub-mkimage has not been tested, but may work. Right now grub-mkimage arbitrarily loads the modules starting at 3MB, and grubof must look for them there at runtime. It's a bit awkward to tell the grubof runtime about where the modules are loaded, since we would need to parse the ELF file and edit it on disk (not as easy as just hacking a binary file at reserved offsets). That same difficulty makes it impossible right now to tell grubof runtime about the total size of the modules loaded. One possible solution there is to end the module area with a (0, 0) grub_module_header. It may be possible to place module variables into their own section containing nothing else, yet still in a LOAD segment. Then grub-mkimage could parse the *section* table (right now it only does segments) and overwrite the contents of this section to inform the runtime of the module location. I'm not convinced it's worth the effort. I'm firmly convinced that grub_load_modules(), currently in kern/main.c, will need to be changed to a more generic interface. For example, each arch could provide its own grub_module_start() and grub_module_end() functions. It is no longer a valid assumption that the modules begin immediately after grub_end_addr in memory. But for now I will leave that to someone (Marco?) doing the real module loading; grub-mkimage just needs to get it into memory (which I've verified it does). -Hollis P.S. -o is a mandatory switch for this grub-mkimage. ELF rewriting involves a lot of seeking, which you can't do with stdout... Index: boot/powerpc/ieee1275/crt0.S =================================================================== RCS file: /cvsroot/grub/grub2/boot/powerpc/ieee1275/crt0.S,v retrieving revision 1.3 diff -u -p -r1.3 crt0.S --- boot/powerpc/ieee1275/crt0.S 12 Oct 2004 03:56:10 -0000 1.3 +++ boot/powerpc/ieee1275/crt0.S 3 Dec 2004 05:26:48 -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.14 diff -u -p -r1.14 powerpc-ieee1275.rmk --- conf/powerpc-ieee1275.rmk 16 Nov 2004 23:34:44 -0000 1.14 +++ conf/powerpc-ieee1275.rmk 3 Dec 2004 05:26:49 -0000 @@ -17,9 +17,13 @@ kernel_syms.lst: $(addprefix include/gru # Utilities. sbin_UTILITIES = grubof -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/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 Dec 2004 05:26:49 -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: util/misc.c =================================================================== RCS file: /cvsroot/grub/grub2/util/misc.c,v retrieving revision 1.8 diff -u -p -r1.8 misc.c --- util/misc.c 4 Apr 2004 13:46:03 -0000 1.8 +++ util/misc.c 3 Dec 2004 05:26:49 -0000 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -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,6 +188,15 @@ grub_util_load_image (const char *path, } void +grub_util_write_image_at (const void *img, size_t size, off_t offset, FILE *out) +{ + grub_util_info ("writing 0x%x bytes at offset 0x%x", size, offset); + if (fseek (out, offset, SEEK_SET) == -1) + grub_util_error ("write failed"); + grub_util_write_image (img, size, out); +} + +void grub_util_write_image (const char *img, size_t size, FILE *out) { grub_util_info ("writing 0x%x bytes", size); --- /dev/null 2004-09-05 22:56:24.000000000 -0500 +++ util/powerpc/ieee1275/grub-mkimage.c 2004-12-02 23:06:42.309752560 -0600 @@ -0,0 +1,334 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#define ALIGN_UP(addr, align) ((long)((char *)addr + align - 1) & ~(align - 1)) + +#define MODULE_BASE 0x00300000 + +static char *kernel_path = "grubof"; +static char *note_path = "note"; + +void swap_ehdr (const Elf32_Ehdr *ehdr, Elf32_Ehdr *swapped) +{ + memcpy (swapped->e_ident, ehdr->e_ident, EI_NIDENT); + swapped->e_type = grub_cpu_to_be16 (ehdr->e_type); + swapped->e_machine = grub_cpu_to_be16 (ehdr->e_machine); + swapped->e_version = grub_cpu_to_be32 (ehdr->e_version); + swapped->e_entry = grub_cpu_to_be32 (ehdr->e_entry); + swapped->e_phoff = grub_cpu_to_be32 (ehdr->e_phoff); + swapped->e_shoff = grub_cpu_to_be32 (ehdr->e_shoff); + swapped->e_flags = grub_cpu_to_be32 (ehdr->e_flags); + swapped->e_ehsize = grub_cpu_to_be16 (ehdr->e_ehsize); + swapped->e_phentsize = grub_cpu_to_be16 (ehdr->e_phentsize); + swapped->e_phnum = grub_cpu_to_be16 (ehdr->e_phnum); + swapped->e_shentsize = grub_cpu_to_be16 (ehdr->e_shentsize); + swapped->e_shnum = grub_cpu_to_be16 (ehdr->e_shnum); + swapped->e_shstrndx = grub_cpu_to_be16 (ehdr->e_shstrndx); +} + +void swap_phdrs (Elf32_Phdr *phdr, Elf32_Phdr *swapped, int count) +{ + int i; + + for (i = 0; i < count; i++) + { + swapped->p_type = grub_cpu_to_be32 (phdr->p_type); + swapped->p_offset = grub_cpu_to_be32 (phdr->p_offset); + swapped->p_vaddr = grub_cpu_to_be32 (phdr->p_vaddr); + swapped->p_paddr = grub_cpu_to_be32 (phdr->p_paddr); + swapped->p_filesz = grub_cpu_to_be32 (phdr->p_filesz); + swapped->p_memsz = grub_cpu_to_be32 (phdr->p_memsz); + swapped->p_flags = grub_cpu_to_be32 (phdr->p_flags); + swapped->p_align = grub_cpu_to_be32 (phdr->p_align); + } +} + +#ifdef GRUB_CPU_WORDS_BIGENDIAN +#define grub_cpu_to_be_ehdr(x, y) +#define grub_be_to_cpu_ehdr(x, y) +#define grub_cpu_to_be_phdrs(x, y, z) +#define grub_be_to_cpu_phdrs(x, y, z) +#else /* ! WORDS_BIGENDIAN */ +#define grub_cpu_to_be_ehdr(x, y) swap_ehdr(x, y) +#define grub_be_to_cpu_ehdr(x, y) swap_ehdr(x, y) +#define grub_cpu_to_be_phdrs(x, y, z) swap_phdrs(x, y, z) +#define grub_be_to_cpu_phdrs(x, y, z) swap_phdrs(x, y, z) +#endif + +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; + size_t offset = 0; + size_t total_module_size; + + path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); + + total_module_size = 0; + 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); + + /* 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); + grub_be_to_cpu_ehdr (&ehdr, &ehdr); + + 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_be_to_cpu_phdrs (phdr, phdr, 1); + + 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_cpu_to_be_phdrs (phdrs, phdrs, ehdr.e_phnum); + grub_util_write_image_at (phdrs, ehdr.e_phentsize * ehdr.e_phnum, + phdroff, out); + + /* Write ELF header. */ + ehdr.e_phoff = phdroff; + grub_cpu_to_be_ehdr (&ehdr, &ehdr); + 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; +} --- /dev/null 2004-09-05 22:56:24.000000000 -0500 +++ note.S 2004-11-08 21:30:09.000000000 -0600 @@ -0,0 +1,17 @@ +/* PT_NOTE segment for IEEE1275 CHRP binding. + !!! NOT for use on Power Macs!!! + */ + +.note_section_header: + .long 8 + .long .note_end - .note_section_header + .long 0x1275 + .string "PowerPC" +.note_descriptor: + .long 0xffffffff /* real-mode */ + .long 0x00c00000 /* real-base */ + .long 0xffffffff /* real-size */ + .long 0xffffffff /* virt-base */ + .long 0xffffffff /* virt-size */ + .long 0x00004000 /* load-base */ +.note_end: