* [RFC][PATCH] multiboot2 loader
@ 2007-02-21 23:44 Hollis Blanchard
0 siblings, 0 replies; only message in thread
From: Hollis Blanchard @ 2007-02-21 23:44 UTC (permalink / raw)
To: The development of GRUB 2
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
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2007-02-21 23:45 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-02-21 23:44 [RFC][PATCH] multiboot2 loader Hollis Blanchard
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.