This patch implements multiboot2 loading, as described at http://grub.enbug.org/MultibootDraft . I have included the architecture-independent infrastructure as well as the PowerPC-specific code. I have tested it by booting PowerPC Xen (with modifications to parse the multiboot tag list).
Right now I have implemented it as a completely separate command from the old i386 "multiboot" command. I was thinking it would be better to merge them into a single "multiboot" command that choose a loader based on the magic number found in the kernel header, but I'm not sure what the best interface is for the inter-module calls. I will not be checking it in until I come up with a solution. I implemented the "module type" field we discussed on this list as a fixed 36-char field, and I'm using that in Xen to find the dom0 kernel. I think the GRUB commandline interface could be more friendly though. Most of the work is in loader/multiboot2.c and loader/powerpc/ieee1275/multiboot.c . Comments and suggestions welcome. Index: grub2-cvs/conf/powerpc-ieee1275.rmk =================================================================== --- grub2-cvs.orig/conf/powerpc-ieee1275.rmk 2007-02-21 16:52:29.000000000 -0600 +++ grub2-cvs/conf/powerpc-ieee1275.rmk 2007-02-21 17:00:17.000000000 -0600 @@ -86,6 +86,8 @@ grub_install_SOURCES = util/powerpc/ieee pkgdata_MODULES = halt.mod \ _linux.mod \ linux.mod \ + _multiboot2.mod \ + multiboot2.mod \ normal.mod \ reboot.mod \ suspend.mod @@ -100,6 +102,17 @@ linux_mod_SOURCES = loader/powerpc/ieee1 linux_mod_CFLAGS = $(COMMON_CFLAGS) linux_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For _multiboot2.mod. +_multiboot2_mod_SOURCES = loader/multiboot2.c \ + loader/powerpc/ieee1275/multiboot2.c +_multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) +_multiboot2_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For multiboot2.mod. +multiboot2_mod_SOURCES = loader/multiboot2_normal.c +multiboot2_mod_CFLAGS = $(COMMON_CFLAGS) +multiboot2_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For normal.mod. normal_mod_DEPENDENCIES = grub_script.tab.c grub_script.tab.h normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ Index: grub2-cvs/include/grub/powerpc/ieee1275/multiboot.h =================================================================== --- grub2-cvs.orig/include/grub/powerpc/ieee1275/multiboot.h 2007-02-21 16:51:47.000000000 -0600 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,184 +0,0 @@ -/* multiboot.h - multiboot header file. */ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003, 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. - */ - -#ifndef GRUB_MULTIBOOT_MACHINE_HEADER -#define GRUB_MULTIBOOT_MACHINE_HEADER 1 - -/* How many bytes from the start of the file we search for the header. */ -#define GRUB_MB_SEARCH 8192 - -/* The magic field should contain this. */ -#define GRUB_MB_MAGIC 0x1BADB002 - -/* This should be in %eax. */ -#define GRUB_MB_MAGIC2 0x2BADB002 - -/* The bits in the required part of flags field we don't support. */ -#define GRUB_MB_UNSUPPORTED 0x0000fffc - -/* Alignment of multiboot modules. */ -#define GRUB_MB_MOD_ALIGN 0x00001000 - -/* - * Flags set in the 'flags' member of the multiboot header. - */ - -/* Align all boot modules on i386 page (4KB) boundaries. */ -#define GRUB_MB_PAGE_ALIGN 0x00000001 - -/* Must pass memory information to OS. */ -#define GRUB_MB_MEMORY_INFO 0x00000002 - -/* Must pass video information to OS. */ -#define GRUB_MB_VIDEO_MODE 0x00000004 - -/* This flag indicates the use of the address fields in the header. */ -#define GRUB_MB_AOUT_KLUDGE 0x00010000 - -/* - * Flags to be set in the 'flags' member of the multiboot info structure. - */ - -/* is there basic lower/upper memory information? */ -#define GRUB_MB_INFO_MEMORY 0x00000001 -/* is there a boot device set? */ -#define GRUB_MB_INFO_BOOTDEV 0x00000002 -/* is the command-line defined? */ -#define GRUB_MB_INFO_CMDLINE 0x00000004 -/* are there modules to do something with? */ -#define GRUB_MB_INFO_MODS 0x00000008 - -/* These next two are mutually exclusive */ - -/* is there a symbol table loaded? */ -#define GRUB_MB_INFO_AOUT_SYMS 0x00000010 -/* is there an ELF section header table? */ -#define GRUB_MB_INFO_ELF_SHDR 0x00000020 - -/* is there a full memory map? */ -#define GRUB_MB_INFO_MEM_MAP 0x00000040 - -/* Is there drive info? */ -#define GRUB_MB_INFO_DRIVE_INFO 0x00000080 - -/* Is there a config table? */ -#define GRUB_MB_INFO_CONFIG_TABLE 0x00000100 - -/* Is there a boot loader name? */ -#define GRUB_MB_INFO_BOOT_LOADER_NAME 0x00000200 - -/* Is there a APM table? */ -#define GRUB_MB_INFO_APM_TABLE 0x00000400 - -/* Is there video information? */ -#define GRUB_MB_INFO_VIDEO_INFO 0x00000800 - -#ifndef ASM_FILE - -#include <grub/types.h> - -struct grub_multiboot_header -{ - /* Must be GRUB_MB_MAGIC - see above. */ - grub_uint32_t magic; - - /* Feature flags. */ - grub_uint32_t flags; - - /* The above fields plus this one must equal 0 mod 2^32. */ - grub_uint32_t checksum; - - /* These are only valid if GRUB_MB_AOUT_KLUDGE is set. */ - grub_uint32_t header_addr; - grub_uint32_t load_addr; - grub_uint32_t load_end_addr; - grub_uint32_t bss_end_addr; - grub_uint32_t entry_addr; - - /* These are only valid if GRUB_MB_VIDEO_MODE is set. */ - grub_uint32_t mode_type; - grub_uint32_t width; - grub_uint32_t height; - grub_uint32_t depth; -}; - -struct grub_multiboot_info -{ - /* MultiBoot info version number */ - grub_uint32_t flags; - - /* Available memory from BIOS */ - grub_uint32_t mem_lower; - grub_uint32_t mem_upper; - - /* "root" partition */ - grub_uint32_t boot_device; - - /* Kernel command line */ - grub_uint32_t cmdline; - - /* Boot-Module list */ - grub_uint32_t mods_count; - grub_uint32_t mods_addr; - - grub_uint32_t syms[4]; - - /* Memory Mapping buffer */ - grub_uint32_t mmap_length; - grub_uint32_t mmap_addr; - - /* Drive Info buffer */ - grub_uint32_t drives_length; - grub_uint32_t drives_addr; - - /* ROM configuration table */ - grub_uint32_t config_table; - - /* Boot Loader Name */ - grub_uint32_t boot_loader_name; - - /* APM table */ - grub_uint32_t apm_table; - - /* Video */ - grub_uint32_t vbe_control_info; - grub_uint32_t vbe_mode_info; - grub_uint16_t vbe_mode; - grub_uint16_t vbe_interface_seg; - grub_uint16_t vbe_interface_off; - grub_uint16_t vbe_interface_len; -}; - -struct grub_mod_list -{ - /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ - grub_uint32_t mod_start; - grub_uint32_t mod_end; - - /* Module command line */ - grub_uint32_t cmdline; - - /* padding to take it to 16 bytes (must be zero) */ - grub_uint32_t pad; -}; - -#endif /* ! ASM_FILE */ - -#endif /* ! GRUB_MULTIBOOT_MACHINE_HEADER */ Index: grub2-cvs/include/multiboot2.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ grub2-cvs/include/multiboot2.h 2007-02-21 17:00:17.000000000 -0600 @@ -0,0 +1,108 @@ +/* multiboot2.h - multiboot header file. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006 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 MULTIBOOT2_HEADER +#define MULTIBOOT2_HEADER 1 + +/* How many bytes from the start of the file we search for the header. */ +#define MULTIBOOT_HEADER_SEARCH 8192 + +/* The magic field should contain this. */ +#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 + +/* Passed from the bootloader to the kernel. */ +#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289 + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +#ifndef ASM_FILE + +#include "stdint.h" + +/* XXX not portable? */ +#if __WORDSIZE == 64 +typedef uint64_t multiboot_word; +#else +typedef uint32_t multiboot_word; +#endif + +struct multiboot_header +{ + uint32_t magic; +}; + +struct multiboot_tag_header +{ + uint32_t key; + uint32_t len; +}; + +#define MULTIBOOT2_TAG_RESERVED1 0 +#define MULTIBOOT2_TAG_RESERVED2 (~0) + +#define MULTIBOOT2_TAG_START 1 +struct multiboot_tag_start +{ + struct multiboot_tag_header header; + multiboot_word size; /* Total size of all multiboot tags. */ +}; + +#define MULTIBOOT2_TAG_NAME 2 +struct multiboot_tag_name +{ + struct multiboot_tag_header header; + char name[1]; +}; + +#define MULTIBOOT2_TAG_MODULE 3 +struct multiboot_tag_module +{ + struct multiboot_tag_header header; + multiboot_word addr; + multiboot_word size; + unsigned char type[36]; + unsigned char cmdline[1]; +}; + +#define MULTIBOOT2_TAG_MEMORY 4 +struct multiboot_tag_memory +{ + struct multiboot_tag_header header; + multiboot_word addr; + multiboot_word size; + multiboot_word type; +}; + +#define MULTIBOOT2_TAG_UNUSED 5 +struct multiboot_tag_unused +{ + struct multiboot_tag_header header; +}; + +#define MULTIBOOT2_TAG_END 0xffff +struct multiboot_tag_end +{ + struct multiboot_tag_header header; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT2_HEADER */ Index: grub2-cvs/include/grub/multiboot2.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ grub2-cvs/include/grub/multiboot2.h 2007-02-21 17:00:17.000000000 -0600 @@ -0,0 +1,51 @@ +/* multiboot2.h - multiboot header file. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006 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_MULTIBOOT2_HEADER +#define GRUB_MULTIBOOT2_HEADER 1 + +#include <grub/types.h> +#include <grub/err.h> +#include <grub/elf.h> + +struct multiboot_tag_header; + +grub_err_t grub_mb2_tag_alloc (grub_addr_t *addr, int key, grub_size_t len); + +grub_err_t grub_mb2_tags_arch_create (void); +void grub_mb2_arch_boot (grub_addr_t entry, void *tags); +void grub_mb2_arch_unload (struct multiboot_tag_header *tags); + +grub_err_t grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, grub_addr_t *addr); +grub_err_t grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, grub_addr_t *addr); + +grub_err_t grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr); +grub_err_t grub_mb2_arch_module_free (grub_addr_t addr, grub_size_t size); + +/* Provided by the core ("rescue mode"). */ +void grub_rescue_cmd_multiboot2 (int argc, char *argv[]); +void grub_rescue_cmd_module2 (int argc, char *argv[]); + +#define for_each_tag(tag, tags) \ + for (tag = tags; \ + tag && tag->key != MULTIBOOT2_TAG_END; \ + tag = (struct multiboot_tag_header *)((char *)tag + tag->len)) + +#endif /* ! GRUB_MULTIBOOT2_HEADER */ Index: grub2-cvs/loader/multiboot2.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ grub2-cvs/loader/multiboot2.c 2007-02-21 17:08:07.000000000 -0600 @@ -0,0 +1,481 @@ +/* multiboot.c - boot a multiboot OS image. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003, 2004, 2005, 2006 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 <multiboot2.h> +#include <grub/loader.h> +#include <grub/machine/loader.h> +#include <grub/multiboot2.h> +#include <grub/elfload.h> +#include <grub/file.h> +#include <grub/err.h> +#include <grub/rescue.h> +#include <grub/dl.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/gzio.h> + +static grub_dl_t my_mod; +static grub_addr_t entry; + +static char *grub_mb2_tags; +static char *grub_mb2_tags_pos; +static grub_size_t grub_mb2_tags_len; +static int grub_mb2_tags_count; + +static void +grub_mb2_tags_free (void) +{ + grub_dprintf ("loader", "Freeing all tags...\n"); + grub_free (grub_mb2_tags); + grub_mb2_tags = 0; + grub_mb2_tags_pos = 0; + grub_mb2_tags_len = 0; + grub_mb2_tags_count = 0; +} + +grub_err_t +grub_mb2_tag_alloc (grub_addr_t *addr, int key, grub_size_t len) +{ + struct multiboot_tag_header *tag; + grub_size_t used; + grub_size_t needed; + + grub_dprintf ("loader", "Allocating tag: key 0x%x, size 0x%lx.\n", + key, (unsigned long) len); + + used = grub_mb2_tags_pos - grub_mb2_tags; + len = ALIGN_UP (len, sizeof (multiboot_word)); + + needed = used + len; + + if (needed > grub_mb2_tags_len) + { + /* Allocate new buffer. */ + grub_size_t newsize = needed * 2; + char *newarea; + + grub_dprintf ("loader", "Reallocating tag buffer (new size 0x%lx).\n", + (unsigned long) newsize); + + newarea = grub_malloc (newsize); + if (! newarea) + return grub_errno; + grub_memcpy (newarea, grub_mb2_tags, grub_mb2_tags_len); + grub_free (grub_mb2_tags); + + grub_mb2_tags_len = newsize; + grub_mb2_tags = newarea; + grub_mb2_tags_pos = newarea + used; + } + + tag = (struct multiboot_tag_header *) grub_mb2_tags_pos; + grub_mb2_tags_pos += len; + + tag->key = key; + tag->len = len; + + if (addr) + *addr = (grub_addr_t) tag; + + grub_mb2_tags_count++; + + grub_dprintf ("loader", "Allocated tag %u at %p.\n", grub_mb2_tags_count, tag); + + return 0; +} + +static grub_err_t +grub_mb2_tag_start_create (void) +{ + return grub_mb2_tag_alloc (0, MULTIBOOT2_TAG_START, + sizeof (struct multiboot_tag_start)); +} + +static grub_err_t +grub_mb2_tag_name_create (void) +{ + struct multiboot_tag_name *name; + grub_addr_t name_addr; + grub_err_t err; + const char *grub_version = PACKAGE_STRING; + + err = grub_mb2_tag_alloc (&name_addr, MULTIBOOT2_TAG_NAME, + sizeof (struct multiboot_tag_name) + + sizeof (grub_version) + 1); + if (err) + return err; + + name = (struct multiboot_tag_name *) name_addr; + grub_strcpy (name->name, grub_version); + + return GRUB_ERR_NONE; +} + +typedef grub_err_t (*tag_create_t) (void); +static tag_create_t grub_mb2_tag_creators[] = { + grub_mb2_tag_start_create, + grub_mb2_tag_name_create, + grub_mb2_tags_arch_create, + 0, +}; + +static grub_err_t +grub_mb2_tags_create (void) +{ + tag_create_t *creator; + grub_err_t err; + + for (creator = grub_mb2_tag_creators; *creator != 0; creator++) + { + err = (*creator) (); + if (err) + goto error; + } + + return GRUB_ERR_NONE; + +error: + grub_error_push (); + grub_mb2_tags_free (); + grub_error_pop (); + return err; +} + +static grub_err_t +grub_mb2_tags_finish (void) +{ + struct multiboot_tag_start *start; + grub_err_t err; + + /* Create the `end' tag. */ + err = grub_mb2_tag_alloc (0, MULTIBOOT2_TAG_END, + sizeof (struct multiboot_tag_end)); + if (err) + goto error; + + /* We created the `start' tag first. Update it now. */ + start = (struct multiboot_tag_start *) grub_mb2_tags; + start->size = grub_mb2_tags_pos - grub_mb2_tags; + return GRUB_ERR_NONE; + +error: + grub_error_push (); + grub_mb2_tags_free (); + grub_error_pop (); + return err; +} + +static grub_err_t +grub_mb2_boot (void) +{ + grub_mb2_tags_finish (); + + grub_dprintf ("loader", "Tags at %p\n", grub_mb2_tags); + grub_mb2_arch_boot (entry, grub_mb2_tags); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_mb2_unload (void) +{ + struct multiboot_tag_header *tag; + struct multiboot_tag_header *tags = + (struct multiboot_tag_header *) grub_mb2_tags; + + /* Free all module memory in the tag list. */ + for_each_tag (tag, tags) + { + if (tag->key == MULTIBOOT2_TAG_MODULE) + { + struct multiboot_tag_module *module = + (struct multiboot_tag_module *) tag; + grub_free ((void *) module->addr); + } + } + + /* Allow architecture to un-reserve memory. */ + grub_mb2_arch_unload (tags); + + /* Free the tags themselves. */ + grub_mb2_tags_free (); + + grub_dl_unref (my_mod); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_mb2_load_other (UNUSED grub_file_t file, UNUSED void *buffer) +{ + /* XXX Create module tag here. */ + return grub_error (GRUB_ERR_UNKNOWN_OS, "currently only ELF is supported"); +} + +/* Create the tag containing the cmdline and the address of the module data. */ +static grub_err_t +grub_mb2_tag_module_create (grub_addr_t modaddr, grub_size_t modsize, + char *type, int key, int argc, char *argv[]) +{ + struct multiboot_tag_module *module; + grub_ssize_t argslen = 0; + grub_err_t err; + char *p; + grub_addr_t module_addr; + int i; + + /* Allocate enough space for the arguments and spaces between them. */ + for (i = 0; i < argc; i++) + argslen += grub_strlen (argv[i]) + 1; + + /* Note: includes implicit 1-byte cmdline. */ + err = grub_mb2_tag_alloc (&module_addr, key, + sizeof (struct multiboot_tag_module) + argslen); + if (err) + return grub_errno; + + module = (struct multiboot_tag_module *) module_addr; + module->addr = modaddr; + module->size = modsize; + grub_strcpy(module->type, type); + + /* Fill in the command line. */ + p = module->cmdline; + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *p++ = ' '; + } + module->cmdline[argslen] = '\0'; + + for (i=0; i < argslen+8; i++) + grub_printf(" %x", module->cmdline[i]); + grub_printf("\n"); + + return GRUB_ERR_NONE; +} + +/* Load ELF32 or ELF64. */ +static grub_err_t +grub_mb2_load_elf (grub_elf_t elf, int argc, char *argv[]) +{ + grub_addr_t kern_base; + grub_size_t kern_size; + grub_err_t err; + + if (grub_elf_is_elf32 (elf)) + { + entry = elf->ehdr.ehdr32.e_entry; + err = grub_elf32_load (elf, grub_mb2_arch_elf32_hook, &kern_base, + &kern_size); + } + else if (grub_elf_is_elf64 (elf)) + { + entry = elf->ehdr.ehdr64.e_entry; + err = grub_elf64_load (elf, grub_mb2_arch_elf64_hook, &kern_base, + &kern_size); + } + else + err = grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class"); + + if (err) + goto fail; + + grub_dprintf ("loader", "Entry point is 0x%lx.\n", (unsigned long) entry); + + grub_mb2_tag_module_create (kern_base, kern_size, "kernel", + MULTIBOOT2_TAG_MODULE, argc, argv); + +fail: + return err; +} + +void +grub_rescue_cmd_multiboot2 (int argc, char *argv[]) +{ + char *buffer; + grub_file_t file = 0; + grub_elf_t elf = 0; + struct multiboot_header *header = 0; + char *p; + grub_ssize_t len; + grub_err_t err; + int header_found = 0; + + grub_dl_ref (my_mod); + + grub_loader_unset (); + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "No kernel specified"); + goto fail; + } + + file = grub_gzfile_open (argv[0], 1); + if (! file) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file"); + goto fail; + } + + buffer = grub_malloc (MULTIBOOT_HEADER_SEARCH); + if (! buffer) + return; + + len = grub_file_read (file, buffer, MULTIBOOT_HEADER_SEARCH); + if (len < 32) + { + grub_error (GRUB_ERR_BAD_OS, "File too small"); + goto fail; + } + + /* Look for the multiboot header in the buffer. The header should + be at least 12 bytes and aligned on a 4-byte boundary. */ + for (p = buffer; p <= buffer + len - 12; p += 4) + { + header = (struct multiboot_header *) p; + if (header->magic == MULTIBOOT2_HEADER_MAGIC) + { + header_found = 1; + break; + } + } + + if (! header_found) + grub_dprintf ("loader", "No multiboot header found.\n"); + + /* Create the basic tags. */ + grub_dprintf ("loader", "Creating multiboot tags\n"); + grub_mb2_tags_create (); + + /* Load the kernel and create its tag. */ + elf = grub_elf_file (file); + if (elf) + { + grub_dprintf ("loader", "Loading ELF multiboot file.\n"); + err = grub_mb2_load_elf (elf, argc-1, &argv[1]); + grub_elf_close (elf); + } + else + { + grub_dprintf ("loader", "Loading non-ELF multiboot file.\n"); + + if (header) + err = grub_mb2_load_other (file, header); + else + err = grub_error (GRUB_ERR_BAD_OS, + "Need multiboot header to load non-ELF files."); + grub_file_close (file); + } + + grub_free (buffer); + + if (err) + goto fail; + + /* Good to go. */ + grub_loader_set (grub_mb2_boot, grub_mb2_unload, 1); + return; + +fail: + grub_mb2_tags_free (); + grub_dl_unref (my_mod); +} + +void +grub_rescue_cmd_module2 (int argc, char *argv[]) +{ + grub_file_t file; + grub_addr_t modaddr = 0; + grub_ssize_t modsize = 0; + grub_err_t err; + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); + return; + } + + if (argc == 1) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "No module type specified"); + return; + } + + if (entry == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, + "You need to load the multiboot kernel first"); + return; + } + + /* Load module data. */ + file = grub_gzfile_open (argv[0], 1); + if (! file) + goto out; + + modsize = grub_file_size (file); + err = grub_mb2_arch_module_alloc (modsize, &modaddr); + if (err) + goto out; + + grub_dprintf ("loader", "Loading module at 0x%x - 0x%x\n", modaddr, + modaddr + modsize); + if (grub_file_read (file, (char *) modaddr, modsize) != modsize) + { + grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + goto out; + } + + /* Create the module tag. */ + err = grub_mb2_tag_module_create (modaddr, modsize, + argv[1], MULTIBOOT2_TAG_MODULE, + argc-2, &argv[2]); + if (err) + goto out; + +out: + grub_error_push (); + + if (file) + grub_file_close (file); + + if (modaddr) + grub_mb2_arch_module_free (modaddr, modsize); + + grub_error_pop (); +} + +GRUB_MOD_INIT(multiboot2) +{ + grub_rescue_register_command ("multiboot2", grub_rescue_cmd_multiboot2, + "load a multiboot kernel"); + grub_rescue_register_command ("module2", grub_rescue_cmd_module2, + "load a multiboot module"); + my_mod = mod; +} + +GRUB_MOD_FINI(multiboot2) +{ + grub_rescue_unregister_command ("multiboot2"); + grub_rescue_unregister_command ("module2"); +} Index: grub2-cvs/loader/powerpc/ieee1275/multiboot2.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ grub2-cvs/loader/powerpc/ieee1275/multiboot2.c 2007-02-21 17:00:17.000000000 -0600 @@ -0,0 +1,120 @@ +/* multiboot.c - boot a multiboot OS image. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003, 2004, 2005, 2006 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 <multiboot2.h> +#include <grub/loader.h> +#include <grub/ieee1275/ieee1275.h> +#include <grub/multiboot2.h> +#include <grub/err.h> +#include <grub/elf.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/machine/kernel.h> + +typedef void (*kernel_entry_t) (unsigned long, void *, int (void *), + unsigned long, unsigned long); + +/* Claim the memory occupied by the multiboot kernel. */ +grub_err_t +grub_mb2_arch_elf32_hook (Elf32_Phdr *phdr, UNUSED grub_addr_t *addr) +{ + int rc; + + rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz); + if (rc) + return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim %x - %x", + phdr->p_paddr, phdr->p_paddr + phdr->p_memsz); + + grub_dprintf ("loader", "Loading segment at 0x%x - 0x%x\n", phdr->p_paddr, + phdr->p_paddr + phdr->p_memsz); + + return GRUB_ERR_NONE; +} + +/* Claim the memory occupied by the multiboot kernel. */ +grub_err_t +grub_mb2_arch_elf64_hook (Elf64_Phdr *phdr, UNUSED grub_addr_t *addr) +{ + int rc; + + rc = grub_claimmap (phdr->p_paddr, phdr->p_memsz); + if (rc) + return grub_error(GRUB_ERR_OUT_OF_MEMORY, "Couldn't claim 0x%lx - 0x%lx", + phdr->p_paddr, phdr->p_paddr + phdr->p_memsz); + + grub_dprintf ("loader", "Loading segment at 0x%lx - 0x%lx\n", + (unsigned long) phdr->p_paddr, + (unsigned long) (phdr->p_paddr + phdr->p_memsz)); + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_mb2_arch_module_alloc (grub_size_t size, grub_addr_t *addr) +{ + int rc; + + /* XXX Will need to map on some firmwares. */ + rc = grub_ieee1275_claim (0, size, MULTIBOOT_MOD_ALIGN, addr); + if (rc) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "Firmware couldn't allocate memory (size 0x%lx)", size); + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_mb2_arch_module_free (grub_addr_t addr, grub_size_t size) +{ + grub_ieee1275_release (addr, size); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_mb2_tags_arch_create (void) +{ + /* Nothing special. */ + return GRUB_ERR_NONE; +} + +/* Release the memory we claimed from Open Firmware above. */ +void +grub_mb2_arch_unload (struct multiboot_tag_header *tags) +{ + struct multiboot_tag_header *tag; + + /* Free all module memory in the tag list. */ + for_each_tag (tag, tags) + { + if (tag->key == MULTIBOOT2_TAG_MODULE) + { + struct multiboot_tag_module *module = + (struct multiboot_tag_module *) tag; + grub_ieee1275_release (module->addr, module->size); + } + } +} + +void +grub_mb2_arch_boot (grub_addr_t entry_addr, void *tags) +{ + kernel_entry_t entry = (kernel_entry_t) entry_addr; + entry (MULTIBOOT2_BOOTLOADER_MAGIC, tags, grub_ieee1275_entry_fn, 0, 0); +} Index: grub2-cvs/loader/multiboot2_normal.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ grub2-cvs/loader/multiboot2_normal.c 2007-02-21 17:00:17.000000000 -0600 @@ -0,0 +1,63 @@ +/* multiboot_normal.c - boot another boot loader */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2004,2005 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 <grub/multiboot2.h> +#include <grub/err.h> +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/machine/loader.h> + +static grub_err_t +grub_normal_cmd_multiboot2 (UNUSED struct grub_arg_list *state, + int argc, char **args) +{ + grub_rescue_cmd_multiboot2 (argc, args); + return grub_errno; +} + +static grub_err_t +grub_normal_cmd_module2 (UNUSED struct grub_arg_list *state, + int argc, char **args) +{ + grub_rescue_cmd_module2 (argc, args); + return grub_errno; +} + +GRUB_MOD_INIT(multiboot2_normal) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("multiboot", grub_normal_cmd_multiboot2, + GRUB_COMMAND_FLAG_BOTH + | GRUB_COMMAND_FLAG_NO_ARG_PARSE, + "multiboot FILE [ARGS...]", + "Load a Multiboot kernel.", 0); + + grub_register_command ("module", grub_normal_cmd_module2, + GRUB_COMMAND_FLAG_BOTH + | GRUB_COMMAND_FLAG_NO_ARG_PARSE, + "module FILE [ARGS...]", + "Load a Multiboot module.", 0); +} + +GRUB_MOD_FINI(multiboot_normal) +{ + grub_unregister_command ("multiboot2"); + grub_unregister_command ("module2"); +} -- Hollis Blanchard IBM Linux Technology Center _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel