From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1Gjmuw-00006w-Ae for mharc-grub-devel@gnu.org; Mon, 13 Nov 2006 20:16:50 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Gjmuu-00006d-CO for grub-devel@gnu.org; Mon, 13 Nov 2006 20:16:48 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Gjmup-00005A-AB for grub-devel@gnu.org; Mon, 13 Nov 2006 20:16:47 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Gjmup-000057-3z for grub-devel@gnu.org; Mon, 13 Nov 2006 20:16:43 -0500 Received: from [32.97.182.144] (helo=e4.ny.us.ibm.com) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA:32) (Exim 4.52) id 1Gjmui-0002s8-5T for grub-devel@gnu.org; Mon, 13 Nov 2006 20:16:42 -0500 Received: from d01relay04.pok.ibm.com (d01relay04.pok.ibm.com [9.56.227.236]) by e4.ny.us.ibm.com (8.13.8/8.12.11) with ESMTP id kAE1GP6j011404 for ; Mon, 13 Nov 2006 20:16:25 -0500 Received: from d01av04.pok.ibm.com (d01av04.pok.ibm.com [9.56.224.64]) by d01relay04.pok.ibm.com (8.13.6/8.13.6/NCO v8.1.1) with ESMTP id kAE1GORj215566 for ; Mon, 13 Nov 2006 20:16:25 -0500 Received: from d01av04.pok.ibm.com (loopback [127.0.0.1]) by d01av04.pok.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id kAE1GOEw027129 for ; Mon, 13 Nov 2006 20:16:24 -0500 Received: from [9.53.41.42] (basalt.austin.ibm.com [9.53.41.42]) by d01av04.pok.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id kAE1GOTV027023 for ; Mon, 13 Nov 2006 20:16:24 -0500 From: Hollis Blanchard To: grub-devel Content-Type: multipart/mixed; boundary="=-Gf8puDyOim87E5IrhvE1" Date: Mon, 13 Nov 2006 19:16:20 -0600 Message-Id: <1163466980.1801.44.camel@basalt> Mime-Version: 1.0 X-Mailer: Evolution 2.8.1 Subject: [RFC] multiboot2 loader 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: Tue, 14 Nov 2006 01:16:48 -0000 --=-Gf8puDyOim87E5IrhvE1 Content-Type: text/plain Content-Transfer-Encoding: 7bit Hi, this is a first pass at a multiboot2 loader (and sample kernel). It is working on qemu/x86, so I figured I'd send it out now for comments. I've implemented the tags data structure described at http://grub.enbug.org/MultibootDraft . The new file layout is like this: conf/i386-pc.rmk | 4 conf/powerpc-ieee1275.rmk | 12 include/grub/i386/pc/loader.h | 7 include/grub/i386/pc/multiboot.h | 184 ----------- include/grub/misc.h | 2 include/grub/multiboot.h | 39 ++ include/multiboot.h | 136 ++++++++ kern/i386/pc/startup.S | 12 loader/i386/pc/multiboot.c | 437 +--------------------------- loader/i386/pc/multiboot_normal.c | 61 --- loader/multiboot.c | 466 ++++++++++++++++++++++++++++++ loader/multiboot_normal.c | 61 +++ loader/powerpc/ieee1275/multiboot.c | 54 +++ util/powerpc/ieee1275/grub-mkimage.c | 3 15 files changed, 805 insertions(+), 857 deletions(-) (Unfortunately CVS sucks, even with quilt, so this patch may have bits in it that don't make sense or apply.) Missing functionality: - all arch-specific tags (e.g. memory map descriptors on x86) - unloading - non-ELF multiboot executables - PowerPC support is untested I've placed a generic multiboot.h directly into include/ (not in the grub subdirectory), since it it suitable for using in kernels independently of GRUB. As for the license, I believe that include/multiboot.h should NOT be GPL, to allow it to be used directly for non-GPL operating systems like the BSDs. I've also included a multiboot "Hello world", suitable for testing the loader. (I believe this is far more valuable than the "hello" module, which we should remove.) It is based on the code scattered through the GRUB Legacy documentation. Actually, we probably want to leave the old x86-only multiboot loader around to allow people to boot multiboot1 kernels... how should we name the two? All comments welcome. -Hollis --=-Gf8puDyOim87E5IrhvE1 Content-Disposition: attachment; filename=multiboot2-helloworld Content-Type: text/x-patch; name=multiboot2-helloworld; charset=UTF-8 Content-Transfer-Encoding: 7bit Index: grub2-x86/multiboot/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ grub2-x86/multiboot/Makefile 2006-11-13 17:32:20.000000000 -0600 @@ -0,0 +1,13 @@ +CFLAGS := -nostdinc -I. +LDFLAGS := -nostdlib -Ttext=0x00100000 +ASFLAGS := -I. + +OBJS := boot.o kernel.o + +all: multiboot + +multiboot: $(OBJS) + $(CC) $(LDFLAGS) $^ -o $@ + +clean: + rm -f $(OBJS) multiboot Index: grub2-x86/multiboot/boot.S =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ grub2-x86/multiboot/boot.S 2006-11-13 18:56:52.000000000 -0600 @@ -0,0 +1,93 @@ +/* boot.S - bootstrap the kernel */ +/* Copyright (C) 1999, 2001 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. */ + +#define ASM_FILE 1 +#include "multiboot.h" + +/* XXX why does EXT_C exist? */ +#define EXT_C(sym) sym + +/* The size of our stack (16KB). */ +#define STACK_SIZE 0x4000 + +/* The flags for the Multiboot header. */ +#ifdef __ELF__ +# define MULTIBOOT_HEADER_FLAGS 0x00000003 +#else +# define MULTIBOOT_HEADER_FLAGS 0x00010003 +#endif + + .text + + .globl start, _start +start: +_start: + jmp multiboot_entry + + /* Align 32 bits boundary. */ + .align 4 + + /* Multiboot header. */ +multiboot_header: + /* magic */ + .long MULTIBOOT_HEADER_MAGIC + /* flags */ + .long MULTIBOOT_HEADER_FLAGS + /* checksum */ + .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) +#ifndef __ELF__ + /* header_addr */ + .long multiboot_header + /* load_addr */ + .long _start + /* load_end_addr */ + .long _edata + /* bss_end_addr */ + .long _end + /* entry_addr */ + .long multiboot_entry +#endif /* ! __ELF__ */ + +multiboot_entry: + /* Initialize the stack pointer. */ + movl $(stack + STACK_SIZE), %esp + + /* Reset EFLAGS. */ + pushl $0 + popf + + /* Push the pointer to the Multiboot information structure. */ + pushl %ebx + /* Push the magic value. */ + pushl %eax + + /* Now enter the C main function... */ + call EXT_C(cmain) + + /* Halt. */ + pushl $halt_message + call EXT_C(mb_printf) + +loop: hlt + jmp loop + +halt_message: + .asciz "Halted." + + /* Our stack area. */ + .comm stack, STACK_SIZE + Index: grub2-x86/multiboot/kernel.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ grub2-x86/multiboot/kernel.c 2006-11-13 18:56:40.000000000 -0600 @@ -0,0 +1,248 @@ +/* kernel.c - the C part of the kernel */ +/* Copyright (C) 1999 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 "multiboot.h" + +/* Macros. */ + +/* Check if the bit BIT in FLAGS is set. */ +#define CHECK_FLAG(flags,bit) ((flags) & (1 << (bit))) + +/* Some screen stuff. */ +/* The number of columns. */ +#define COLUMNS 80 +/* The number of lines. */ +#define LINES 24 +/* The attribute of an character. */ +#define ATTRIBUTE 7 +/* The video memory address. */ +#define VIDEO 0xB8000 + +/* Variables. */ +/* Save the X position. */ +static int xpos; +/* Save the Y position. */ +static int ypos; +/* Point to the video memory. */ +static volatile unsigned char *video = (volatile unsigned char *) VIDEO; + +/* Forward declarations. */ +void cmain (unsigned long magic, unsigned long addr); +static void cls (void); +static void itoa (char *buf, int base, int d); +static void mb_putchar (int c); +void mb_printf (const char *format, ...); + +/* Check if MAGIC is valid and print the Multiboot information structure + pointed by ADDR. */ +void +cmain (unsigned long magic, unsigned long addr) +{ + struct multiboot_tag_header *tag; + int tagno; + + /* Clear the screen. */ + cls (); + + /* Am I booted by a Multiboot-compliant boot loader? */ + if (magic != MULTIBOOT_BOOTLOADER_MAGIC) + { + mb_printf ("Invalid magic number: 0x%x\n", (unsigned) magic); + return; + } + + tag = (struct multiboot_tag_header *) addr; + if (tag->key != MULTIBOOT_TAG_START) + { + mb_printf ("First tag has invalid key: 0x%x\n", tag->key); + return; + } + + tagno = 0; + do + { + tag = (struct multiboot_tag_header *) ((char *) tag + tag->len); + tagno++; + switch (tag->key) + { + case MULTIBOOT_TAG_START: + mb_printf ("Tag %d is a duplicate START tag\n", tagno); + return; + case MULTIBOOT_TAG_CMDLINE: + { + struct multiboot_tag_cmdline *cmdline = + (struct multiboot_tag_cmdline *) tag; + mb_printf ("cmdline = %s\n", cmdline->cmdline); + } + break; + case MULTIBOOT_TAG_MODULE: + { + struct multiboot_tag_module *module = + (struct multiboot_tag_module *) tag; + mb_printf ("module: addr 0x%x, size 0x%x, cmdline %s\n", + (unsigned int) module->addr, (unsigned int) module->size, + module->cmdline); + } + break; + case MULTIBOOT_TAG_NAME: + { + struct multiboot_tag_name *name = + (struct multiboot_tag_name *) tag; + mb_printf ("bootloader name = %s\n", name->name); + } + break; + case MULTIBOOT_TAG_END: + mb_printf ("end\n"); + break; + default: + mb_printf ("Tag %d has invalid key: 0x%x\n", tagno, tag->key); + return; + } + } + while (tag->key != MULTIBOOT_TAG_END); +} + +/* Clear the screen and initialize VIDEO, XPOS and YPOS. */ +static void +cls (void) +{ + int i; + + video = (unsigned char *) VIDEO; + + for (i = 0; i < COLUMNS * LINES * 2; i++) + *(video + i) = 0; + + xpos = 0; + ypos = 0; +} + +/* Convert the integer D to a string and save the string in BUF. If + BASE is equal to 'd', interpret that D is decimal, and if BASE is + equal to 'x', interpret that D is hexadecimal. */ +static void +itoa (char *buf, int base, int d) +{ + char *p = buf; + char *p1, *p2; + unsigned long ud = d; + int divisor = 10; + + /* If %d is specified and D is minus, put `-' in the head. */ + if (base == 'd' && d < 0) + { + *p++ = '-'; + buf++; + ud = -d; + } + else if (base == 'x') + divisor = 16; + + /* Divide UD by DIVISOR until UD == 0. */ + do + { + int remainder = ud % divisor; + + *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10; + } + while (ud /= divisor); + + /* Terminate BUF. */ + *p = 0; + + /* Reverse BUF. */ + p1 = buf; + p2 = p - 1; + while (p1 < p2) + { + char tmp = *p1; + *p1 = *p2; + *p2 = tmp; + p1++; + p2--; + } +} + +/* Put the character C on the screen. */ +static void +mb_putchar (int c) +{ + if (c == '\n' || c == '\r') + { + newline: + xpos = 0; + ypos++; + if (ypos >= LINES) + ypos = 0; + return; + } + + *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF; + *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE; + + xpos++; + if (xpos >= COLUMNS) + goto newline; +} + +/* Format a string and print it on the screen, just like the libc + function mb_printf. */ +void +mb_printf (const char *format, ...) +{ + char **arg = (char **) &format; + int c; + char buf[20]; + + arg++; + + while ((c = *format++) != 0) + { + if (c != '%') + mb_putchar (c); + else + { + char *p; + + c = *format++; + switch (c) + { + case 'd': + case 'u': + case 'x': + itoa (buf, c, *((int *) arg++)); + p = buf; + goto string; + break; + + case 's': + p = *arg++; + if (! p) + p = "(null)"; + + string: + while (*p) + mb_putchar (*p++); + break; + + default: + mb_putchar (*((int *) arg++)); + break; + } + } + } +} Index: grub2-x86/multiboot/multiboot.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ grub2-x86/multiboot/multiboot.h 2006-11-13 18:44:57.000000000 -0600 @@ -0,0 +1,136 @@ +/* multiboot.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 MULTIBOOT_HEADER +#define MULTIBOOT_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 MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* This should be in %eax. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* The bits in the required part of flags field we don't support. */ +#define MULTIBOOT_UNSUPPORTED 0x0000fffc + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* + * Flags set in the 'flags' member of the multiboot header. + */ + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +#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 +{ + /* Must be MULTIBOOT_MAGIC - see above. */ + uint32_t magic; + + /* Feature flags. */ + uint32_t flags; + + /* The above fields plus this one must equal 0 mod 2^32. */ + uint32_t checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + uint32_t header_addr; + uint32_t load_addr; + uint32_t load_end_addr; + uint32_t bss_end_addr; + uint32_t entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + uint32_t mode_type; + uint32_t width; + uint32_t height; + uint32_t depth; +}; + +struct multiboot_tag_header +{ + uint32_t key; + uint32_t len; +}; + +#define MULTIBOOT_TAG_START 0 +struct multiboot_tag_start +{ + struct multiboot_tag_header header; + multiboot_word size; /* Total size of all multiboot tags. */ + multiboot_word num; /* Number of multiboot tags. */ +}; + +#define MULTIBOOT_TAG_CMDLINE 1 +struct multiboot_tag_cmdline +{ + struct multiboot_tag_header header; + char cmdline[1]; +}; + +#define MULTIBOOT_TAG_MODULE 2 +struct multiboot_tag_module +{ + struct multiboot_tag_header header; + multiboot_word addr; + multiboot_word size; + char cmdline[1]; +}; + +#define MULTIBOOT_TAG_NAME 4 +struct multiboot_tag_name +{ + struct multiboot_tag_header header; + char name[1]; +}; + +#define MULTIBOOT_TAG_END 0xffff +struct multiboot_tag_end +{ + struct multiboot_tag_header header; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT_HEADER */ Index: grub2-x86/multiboot/stdint.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ grub2-x86/multiboot/stdint.h 2006-11-13 18:55:54.000000000 -0600 @@ -0,0 +1,26 @@ +/* + * 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 MULTIBOOT_STDINT_H +#define MULTIBOOT_STDINT_H + +typedef unsigned int uint32_t; +typedef unsigned long uint64_t; + +#endif /* ! MULTIBOOT_STDINT_H */ --=-Gf8puDyOim87E5IrhvE1 Content-Disposition: attachment; filename=multiboot2 Content-Type: text/x-patch; name=multiboot2; charset=UTF-8 Content-Transfer-Encoding: 7bit Index: loader/powerpc/ieee1275/multiboot.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ loader/powerpc/ieee1275/multiboot.c 2006-11-13 18:59:21.000000000 -0600 @@ -0,0 +1,54 @@ +/* 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 +#include +#include +#include +#include + +typedef void (*kernel_entry_t) (unsigned long, void *, int (void *), + unsigned long, unsigned long); + +int grub_multiboot_arch_load32_hook (UNUSED Elf32_Phdr *phdr, + UNUSED grub_addr_t *addr) +{ + return 0; +} + +int grub_multiboot_arch_load64_hook (UNUSED Elf64_Phdr *phdr, + UNUSED grub_addr_t *addr) +{ + return 0; +} + +void +grub_multiboot_arch_boot (grub_addr_t entry_addr, void *tags) +{ + kernel_entry_t entry = (kernel_entry_t) entry_addr; + entry (GRUB_MB_MAGIC2, tags, grub_ieee1275_entry_fn, 0, 0); +} + +grub_err_t +grub_multiboot_tags_arch_create (int argc, char *argv[]) +{ + /* Nothing special. */ + return GRUB_ERR_NONE; +} Index: include/grub/multiboot.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ include/grub/multiboot.h 2006-11-13 18:57:24.000000000 -0600 @@ -0,0 +1,39 @@ +/* multiboot.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_MULTIBOOT_HEADER +#define GRUB_MULTIBOOT_HEADER 1 + +#include +#include +#include + +grub_err_t grub_mb_tag_alloc (grub_addr_t *addr, int key, grub_size_t len); +grub_err_t grub_mb_tags_arch_create (int argc, char *argv[]); + +void grub_mb_arch_boot (grub_addr_t entry, void *tags); +int grub_mb_arch_load32_hook (Elf32_Phdr *phdr, grub_addr_t *addr); +int grub_mb_arch_load64_hook (Elf64_Phdr *phdr, grub_addr_t *addr); + +/* Provided by the core to modules. */ +void grub_rescue_cmd_multiboot (int argc, char *argv[]); +void grub_rescue_cmd_module (int argc, char *argv[]); + +#endif /* ! GRUB_MULTIBOOT_HEADER */ Index: loader/multiboot.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ loader/multiboot.c 2006-11-13 18:57:24.000000000 -0600 @@ -0,0 +1,466 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static grub_dl_t my_mod; +static grub_addr_t entry; + +static char *grub_mb_tags; +static char *grub_mb_tags_pos; +static grub_size_t grub_mb_tags_len; +static int grub_mb_tags_count; + +static void +grub_mb_tags_free (void) +{ + grub_dprintf ("loader", "Freeing all tags...\n"); + grub_free (grub_mb_tags); + grub_mb_tags = 0; + grub_mb_tags_pos = 0; + grub_mb_tags_len = 0; + grub_mb_tags_count = 0; +} + +grub_err_t +grub_mb_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_mb_tags_pos - grub_mb_tags; + len = ALIGN_UP(len, sizeof (multiboot_word)); + + needed = used + len; + + if (needed > grub_mb_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_mb_tags, grub_mb_tags_len); + grub_free (grub_mb_tags); + + grub_mb_tags_len = newsize; + grub_mb_tags = newarea; + grub_mb_tags_pos = newarea + used; + } + + tag = (struct multiboot_tag_header *) grub_mb_tags_pos; + grub_mb_tags_pos += len; + + tag->key = key; + tag->len = len; + + if (addr) + *addr = (grub_addr_t) tag; + + grub_mb_tags_count++; + + grub_dprintf ("loader", "Allocated tag %u at %p.\n", grub_mb_tags_count, tag); + + return 0; +} + +static grub_err_t +grub_mb_tag_start_create (UNUSED int argc, UNUSED char *argv[]) +{ + return grub_mb_tag_alloc (0, MULTIBOOT_TAG_START, + sizeof (struct multiboot_tag_start)); +} + +static grub_err_t +grub_mb_tag_name_create (UNUSED int argc, UNUSED char *argv[]) +{ + struct multiboot_tag_name *name; + grub_addr_t name_addr; + grub_err_t err; + const char *grub_version = PACKAGE_STRING; + + err = grub_mb_tag_alloc (&name_addr, MULTIBOOT_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; +} + +static grub_err_t +grub_mb_tag_cmdline_create (int argc, char *argv[]) +{ + grub_addr_t cmdline_addr; + char *p; + grub_size_t len = 0; + grub_err_t err; + int i; + + for (i = 0; i < argc; i++) + len += grub_strlen (argv[i]) + 1; + + err = grub_mb_tag_alloc (&cmdline_addr, MULTIBOOT_TAG_CMDLINE, + sizeof (struct multiboot_tag_header) + len); + if (err) + return err; + + p = ((struct multiboot_tag_cmdline *) cmdline_addr)->cmdline; + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + *(--p) = '\0'; + + return GRUB_ERR_NONE; +} + +typedef grub_err_t (*tag_create_t) (int argc, char *argv[]); +static tag_create_t grub_mb_tag_creators[] = { + grub_mb_tag_start_create, + grub_mb_tag_name_create, + grub_mb_tag_cmdline_create, + grub_mb_tags_arch_create, + 0, +}; + +static grub_err_t +grub_mb_tags_create (int argc, char *argv[]) +{ + tag_create_t *creator; + grub_err_t err; + + for (creator = grub_mb_tag_creators; *creator != 0; creator++) + { + err = (*creator) (argc, argv); + if (err) + goto error; + } + + return GRUB_ERR_NONE; + +error: + grub_error_push (); + grub_mb_tags_free (); + grub_error_pop (); + return err; +} + +static grub_err_t +grub_mb_tags_finish (void) +{ + struct multiboot_tag_start *start; + grub_err_t err; + + err = grub_mb_tag_alloc (0, MULTIBOOT_TAG_END, sizeof (struct multiboot_tag_end)); + if (err) + goto error; + + /* We created the `start' tag first. */ + start = (struct multiboot_tag_start *) grub_mb_tags; + start->num = grub_mb_tags_count; + start->size = grub_mb_tags_pos - grub_mb_tags; + return GRUB_ERR_NONE; + +error: + grub_error_push (); + grub_mb_tags_free (); + grub_error_pop (); + return err; +} + +static grub_err_t +grub_mb_boot (void) +{ + grub_mb_tags_finish (); + + grub_dprintf ("loader", "Tags at %p\n", grub_mb_tags); + grub_mb_arch_boot (entry, grub_mb_tags); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_mb_unload (void) +{ +#if 0 + if (mbi) + { + unsigned int i; + for (i = 0; i < mbi->mods_count; i++) + { + grub_free ((void *) + ((struct grub_mod_list *) mbi->mods_addr)[i].mod_start); + grub_free ((void *) + ((struct grub_mod_list *) mbi->mods_addr)[i].cmdline); + } + grub_free ((void *) mbi->mods_addr); + grub_free ((void *) mbi->cmdline); + grub_free (mbi); + } + + + mbi = 0; + grub_dl_unref (my_mod); +#endif + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_mb_load_other (UNUSED grub_file_t file, UNUSED void *buffer) +{ + return grub_error (GRUB_ERR_UNKNOWN_OS, "currently only ELF is supported"); +} + +/* Load ELF32 or ELF64. */ +static grub_err_t +grub_mb_load_elf (grub_elf_t elf) +{ + grub_err_t err; + + if (grub_elf_is_elf32 (elf)) + { + entry = elf->ehdr.ehdr32.e_entry; + err = grub_elf32_load (elf, grub_mb_arch_load32_hook); + } + else if (grub_elf_is_elf64 (elf)) + { + entry = elf->ehdr.ehdr64.e_entry; + err = grub_elf64_load (elf, grub_mb_arch_load64_hook); + } + else + err = grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class"); + + grub_dprintf ("loader", "Entry point is 0x%lx.\n", (unsigned long) entry); + + return err; +} + +void +grub_rescue_cmd_multiboot (int argc, char *argv[]) +{ + char buffer[MULTIBOOT_HEADER_SEARCH]; + grub_file_t file = 0; + grub_elf_t elf = 0; + grub_ssize_t len; + grub_err_t err; + struct multiboot_header *header; + int header_found = 0; + char *p; + + 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; + } + + 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 == MULTIBOOT_HEADER_MAGIC + && header->magic + header->flags + header->checksum == 0) + { + header_found = 1; + break; + } + } + + if (! header_found) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "No multiboot header found"); + goto fail; + } + + grub_dprintf ("loader", "Multiboot flags: 0x%x\n", header->flags); + + if (header->flags & MULTIBOOT_UNSUPPORTED) + { + grub_error (GRUB_ERR_UNKNOWN_OS, + "Unsupported flag: 0x%x", header->flags); + goto fail; + } + + elf = grub_elf_file (file); + if (elf) + { + grub_dprintf ("loader", "Loading ELF multiboot file.\n"); + err = grub_mb_load_elf (elf); + } + else + { + grub_dprintf ("loader", "Loading non-ELF multiboot file.\n"); + err = grub_mb_load_other (file, header); + } + if (err) + goto fail; + + grub_dprintf ("loader", "Creating multiboot tags\n"); + grub_mb_tags_create (argc, argv); + + grub_loader_set (grub_mb_boot, grub_mb_unload, 1); + + fail: + if (elf) + grub_elf_close (elf); + else if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + { + grub_dl_unref (my_mod); + } +} + + +void +grub_rescue_cmd_module (int argc, char *argv[]) +{ + struct multiboot_tag_module *module; + grub_file_t file = 0; + grub_ssize_t modsize, argslen = 0; + grub_err_t err; + char *data = 0; + char *p; + grub_addr_t module_addr; + int i; + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); + goto fail; + } + + if (entry == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, + "You need to load the multiboot kernel first"); + goto fail; + } + + /* Load module data into the heap. */ + file = grub_gzfile_open (argv[0], 1); + if (! file) + goto fail; + + modsize = grub_file_size (file); + data = grub_memalign (MULTIBOOT_MOD_ALIGN, modsize); + if (! data) + goto fail; + + if (grub_file_read (file, data, modsize) != modsize) + { + grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); + goto fail; + } + + /* Create the tag containing the command line and the address of the data. */ + for (i = 0; i < argc; i++) + argslen += grub_strlen (argv[i]) + 1; + + err = grub_mb_tag_alloc (&module_addr, MULTIBOOT_TAG_MODULE, + sizeof (struct multiboot_tag_module) + argslen); + if (err) + goto fail; + + module = (struct multiboot_tag_module *) module_addr; + module->addr = (grub_addr_t) data; + module->size = modsize; + + p = module->cmdline; + for (i = 0; i < argc; i++) + { + p = grub_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + *(--p) = '\0'; + + fail: + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + grub_free (data); +} + + +GRUB_MOD_INIT(multiboot) +{ + grub_rescue_register_command ("multiboot", grub_rescue_cmd_multiboot, + "load a multiboot kernel"); + grub_rescue_register_command ("module", grub_rescue_cmd_module, + "load a multiboot module"); + my_mod = mod; +} + +GRUB_MOD_FINI(multiboot) +{ + grub_rescue_unregister_command ("multiboot"); + grub_rescue_unregister_command ("module"); +} Index: loader/i386/pc/multiboot.c =================================================================== --- loader/i386/pc/multiboot.c 2006-11-13 18:57:22.000000000 -0600 +++ loader/i386/pc/multiboot.c 2006-11-13 18:57:24.000000000 -0600 @@ -1,7 +1,7 @@ /* multiboot.c - boot a multiboot OS image. */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + * 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 @@ -18,436 +18,43 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* - * FIXME: The following features from the Multiboot specification still - * need to be implemented: - * - VBE support - * - a.out support - * - boot device - * - symbol table - * - memory map - * - drives table - * - ROM configuration table - * - APM table - */ - -#include -#include -#include -#include +#include #include -#include #include -#include -#include -#include -#include -#include - -static grub_dl_t my_mod; -static struct grub_multiboot_info *mbi; -static grub_addr_t entry; - -static grub_err_t -grub_multiboot_boot (void) -{ - grub_multiboot_real_boot (entry, mbi); - - /* Not reached. */ - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_multiboot_unload (void) -{ - if (mbi) - { - unsigned int i; - for (i = 0; i < mbi->mods_count; i++) - { - grub_free ((void *) - ((struct grub_mod_list *) mbi->mods_addr)[i].mod_start); - grub_free ((void *) - ((struct grub_mod_list *) mbi->mods_addr)[i].cmdline); - } - grub_free ((void *) mbi->mods_addr); - grub_free ((void *) mbi->cmdline); - grub_free (mbi); - } - - - mbi = 0; - grub_dl_unref (my_mod); - - return GRUB_ERR_NONE; -} - -/* Check if BUFFER contains ELF32. */ -static int -grub_multiboot_is_elf32 (void *buffer) -{ - Elf32_Ehdr *ehdr = (Elf32_Ehdr *) buffer; - - return ehdr->e_ident[EI_CLASS] == ELFCLASS32; -} - -static grub_err_t -grub_multiboot_load_elf32 (grub_file_t file, void *buffer) -{ - Elf32_Ehdr *ehdr = (Elf32_Ehdr *) buffer; - Elf32_Phdr *phdr; - int i; - - if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) - return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class"); - - if (grub_dl_check_header (ehdr, sizeof(Elf32_Ehdr))) - return grub_error (GRUB_ERR_UNKNOWN_OS, "no valid ELF header found"); - - if (ehdr->e_type != ET_EXEC) - return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type"); - - /* FIXME: Should we support program headers at strange locations? */ - if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > GRUB_MB_SEARCH) - return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset"); - - entry = ehdr->e_entry; - - /* Load every loadable segment in memory. */ - for (i = 0; i < ehdr->e_phnum; i++) - { - phdr = (Elf32_Phdr *) ((char *) buffer + ehdr->e_phoff - + i * ehdr->e_phentsize); - if (phdr->p_type == PT_LOAD) - { - /* The segment should fit in the area reserved for the OS. */ - if ((phdr->p_paddr < grub_os_area_addr) - || (phdr->p_paddr + phdr->p_memsz - > grub_os_area_addr + grub_os_area_size)) - return grub_error (GRUB_ERR_BAD_OS, - "segment doesn't fit in memory reserved for the OS"); - - if (grub_file_seek (file, (grub_off_t) phdr->p_offset) - == (grub_off_t) -1) - return grub_error (GRUB_ERR_BAD_OS, - "invalid offset in program header"); - - if (grub_file_read (file, (void *) phdr->p_paddr, phdr->p_filesz) - != (grub_ssize_t) phdr->p_filesz) - return grub_error (GRUB_ERR_BAD_OS, - "couldn't read segment from file"); - - if (phdr->p_filesz < phdr->p_memsz) - grub_memset ((char *) phdr->p_paddr + phdr->p_filesz, 0, - phdr->p_memsz - phdr->p_filesz); - } - } - - return grub_errno; -} - -/* Check if BUFFER contains ELF64. */ -static int -grub_multiboot_is_elf64 (void *buffer) -{ - Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer; - - return ehdr->e_ident[EI_CLASS] == ELFCLASS64; -} +#include -static grub_err_t -grub_multiboot_load_elf64 (grub_file_t file, void *buffer) +int grub_mb_arch_load32_hook (Elf32_Phdr *phdr, + UNUSED grub_addr_t *addr) { - Elf64_Ehdr *ehdr = (Elf64_Ehdr *) buffer; - Elf64_Phdr *phdr; - int i; - - if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) - return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF class"); - - if (ehdr->e_ident[EI_MAG0] != ELFMAG0 - || ehdr->e_ident[EI_MAG1] != ELFMAG1 - || ehdr->e_ident[EI_MAG2] != ELFMAG2 - || ehdr->e_ident[EI_MAG3] != ELFMAG3 - || ehdr->e_version != EV_CURRENT - || ehdr->e_ident[EI_DATA] != ELFDATA2LSB - || ehdr->e_machine != EM_X86_64) - return grub_error(GRUB_ERR_UNKNOWN_OS, "no valid ELF header found"); - - if (ehdr->e_type != ET_EXEC) - return grub_error (GRUB_ERR_UNKNOWN_OS, "invalid ELF file type"); - - /* FIXME: Should we support program headers at strange locations? */ - if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > GRUB_MB_SEARCH) - return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset"); + Elf32_Addr paddr = phdr->p_paddr; - /* We still in 32-bit mode */ - if (ehdr->e_entry > 0xffffffff) - return grub_error (GRUB_ERR_BAD_OS, "invalid entry point for ELF64"); + if ((paddr < grub_os_area_addr) + || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)) + return 1; - entry = ehdr->e_entry; - - /* Load every loadable segment in memory. */ - for (i = 0; i < ehdr->e_phnum; i++) - { - phdr = (Elf64_Phdr *) ((char *) buffer + ehdr->e_phoff - + i * ehdr->e_phentsize); - if (phdr->p_type == PT_LOAD) - { - /* The segment should fit in the area reserved for the OS. */ - if ((phdr->p_paddr < (grub_uint64_t) grub_os_area_addr) - || (phdr->p_paddr + phdr->p_memsz - > ((grub_uint64_t) grub_os_area_addr - + (grub_uint64_t) grub_os_area_size))) - return grub_error (GRUB_ERR_BAD_OS, - "segment doesn't fit in memory reserved for the OS"); - - if (grub_file_seek (file, (grub_off_t) phdr->p_offset) - == (grub_off_t) -1) - return grub_error (GRUB_ERR_BAD_OS, - "invalid offset in program header"); - - if (grub_file_read (file, (void *) ((grub_uint32_t) phdr->p_paddr), - phdr->p_filesz) - != (grub_ssize_t) phdr->p_filesz) - return grub_error (GRUB_ERR_BAD_OS, - "couldn't read segment from file"); - - if (phdr->p_filesz < phdr->p_memsz) - grub_memset (((char *) ((grub_uint32_t) phdr->p_paddr) - + phdr->p_filesz), - 0, - phdr->p_memsz - phdr->p_filesz); - } - } - - return grub_errno; + return 0; } -/* Load ELF32 or ELF64. */ -static grub_err_t -grub_multiboot_load_elf (grub_file_t file, void *buffer) +int grub_mb_arch_load64_hook (Elf64_Phdr *phdr, + UNUSED grub_addr_t *addr) { - if (grub_multiboot_is_elf32 (buffer)) - return grub_multiboot_load_elf32 (file, buffer); - else if (grub_multiboot_is_elf64 (buffer)) - return grub_multiboot_load_elf64 (file, buffer); - - return grub_error (GRUB_ERR_UNKNOWN_OS, "unknown ELF class"); -} - -void -grub_rescue_cmd_multiboot (int argc, char *argv[]) -{ - grub_file_t file = 0; - char buffer[GRUB_MB_SEARCH], *cmdline = 0, *p; - struct grub_multiboot_header *header; - grub_ssize_t len; - int i; - - 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; - } - - len = grub_file_read (file, buffer, GRUB_MB_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 (header = (struct grub_multiboot_header *) buffer; - ((char *) header <= buffer + len - 12) || (header = 0); - header = (struct grub_multiboot_header *) ((char *) header + 4)) - { - if (header->magic == GRUB_MB_MAGIC - && !(header->magic + header->flags + header->checksum)) - break; - } - - if (header == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No multiboot header found"); - goto fail; - } - - if (header->flags & GRUB_MB_UNSUPPORTED) - { - grub_error (GRUB_ERR_UNKNOWN_OS, - "Unsupported flag: 0x%x", header->flags); - goto fail; - } - - if (grub_multiboot_load_elf (file, buffer) != GRUB_ERR_NONE) - goto fail; - - mbi = grub_malloc (sizeof (struct grub_multiboot_info)); - if (! mbi) - goto fail; - - mbi->flags = GRUB_MB_INFO_MEMORY; - - /* Convert from bytes to kilobytes. */ - mbi->mem_lower = grub_lower_mem / 1024; - mbi->mem_upper = grub_upper_mem / 1024; - - for (i = 0, len = 0; i < argc; i++) - len += grub_strlen (argv[i]) + 1; - - cmdline = p = grub_malloc (len); - if (! cmdline) - goto fail; - - for (i = 0; i < argc; i++) - { - p = grub_stpcpy (p, argv[i]); - *(p++) = ' '; - } - - /* Remove the space after the last word. */ - *(--p) = '\0'; - - mbi->flags |= GRUB_MB_INFO_CMDLINE; - mbi->cmdline = (grub_uint32_t) cmdline; - - mbi->flags |= GRUB_MB_INFO_BOOT_LOADER_NAME; - mbi->boot_loader_name = (grub_uint32_t) grub_strdup (PACKAGE_STRING); + Elf64_Addr paddr = phdr->p_paddr; - grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 1); + if ((paddr < grub_os_area_addr) + || (paddr + phdr->p_memsz > grub_os_area_addr + grub_os_area_size)) + return 1; - fail: - if (file) - grub_file_close (file); - - if (grub_errno != GRUB_ERR_NONE) - { - grub_free (cmdline); - grub_free (mbi); - grub_dl_unref (my_mod); - } + return 0; } - void -grub_rescue_cmd_module (int argc, char *argv[]) -{ - grub_file_t file = 0; - grub_ssize_t size, len = 0; - char *module = 0, *cmdline = 0, *p; - int i; - - if (argc == 0) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); - goto fail; - } - - if (!mbi) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, - "You need to load the multiboot kernel first"); - goto fail; - } - - file = grub_gzfile_open (argv[0], 1); - if (! file) - goto fail; - - size = grub_file_size (file); - module = grub_memalign (GRUB_MB_MOD_ALIGN, size); - if (! module) - goto fail; - - if (grub_file_read (file, module, size) != size) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); - goto fail; - } - - for (i = 0; i < argc; i++) - len += grub_strlen (argv[i]) + 1; - - cmdline = p = grub_malloc (len); - if (! cmdline) - goto fail; - - for (i = 0; i < argc; i++) - { - p = grub_stpcpy (p, argv[i]); - *(p++) = ' '; - } - - /* Remove the space after the last word. */ - *(--p) = '\0'; - - if (mbi->flags & GRUB_MB_INFO_MODS) - { - struct grub_mod_list *modlist = (struct grub_mod_list *) mbi->mods_addr; - - modlist = grub_realloc (modlist, (mbi->mods_count + 1) - * sizeof (struct grub_mod_list)); - if (! modlist) - goto fail; - mbi->mods_addr = (grub_uint32_t) modlist; - modlist += mbi->mods_count; - modlist->mod_start = (grub_uint32_t) module; - modlist->mod_end = (grub_uint32_t) module + size; - modlist->cmdline = (grub_uint32_t) cmdline; - modlist->pad = 0; - mbi->mods_count++; - } - else - { - struct grub_mod_list *modlist = grub_malloc (sizeof (struct grub_mod_list)); - if (! modlist) - goto fail; - modlist->mod_start = (grub_uint32_t) module; - modlist->mod_end = (grub_uint32_t) module + size; - modlist->cmdline = (grub_uint32_t) cmdline; - modlist->pad = 0; - mbi->mods_count = 1; - mbi->mods_addr = (grub_uint32_t) modlist; - mbi->flags |= GRUB_MB_INFO_MODS; - } - - fail: - if (file) - grub_file_close (file); - - if (grub_errno != GRUB_ERR_NONE) - { - grub_free (module); - grub_free (cmdline); - } -} - - -GRUB_MOD_INIT(multiboot) +grub_mb_arch_boot (grub_addr_t entry, void *tags) { - grub_rescue_register_command ("multiboot", grub_rescue_cmd_multiboot, - "load a multiboot kernel"); - grub_rescue_register_command ("module", grub_rescue_cmd_module, - "load a multiboot module"); - my_mod = mod; + grub_multiboot_real_boot (entry, tags); } -GRUB_MOD_FINI(multiboot) +grub_err_t +grub_mb_tags_arch_create (int argc, char *argv[]) { - grub_rescue_unregister_command ("multiboot"); - grub_rescue_unregister_command ("module"); + return GRUB_ERR_NONE; } Index: include/grub/misc.h =================================================================== --- include/grub/misc.h 2006-11-13 18:57:22.000000000 -0600 +++ include/grub/misc.h 2006-11-13 18:57:24.000000000 -0600 @@ -26,6 +26,8 @@ #include #include +#define ALIGN_UP(addr, align) ((long)((char *)addr + align - 1) & ~(align - 1)) + #define grub_dprintf(condition, fmt, args...) grub_real_dprintf(__FILE__, __LINE__, condition, fmt, ## args); /* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */ #define grub_memcpy(d,s,n) grub_memmove ((d), (s), (n)) Index: util/powerpc/ieee1275/grub-mkimage.c =================================================================== --- util/powerpc/ieee1275/grub-mkimage.c 2006-11-13 18:57:22.000000000 -0600 +++ util/powerpc/ieee1275/grub-mkimage.c 2006-11-13 18:57:24.000000000 -0600 @@ -27,13 +27,12 @@ #include #include #include +#include #include #include #include #include -#define ALIGN_UP(addr, align) ((long)((char *)addr + align - 1) & ~(align - 1)) - #define GRUB_IEEE1275_NOTE_NAME "PowerPC" #define GRUB_IEEE1275_NOTE_TYPE 0x1275 Index: loader/i386/pc/multiboot_normal.c =================================================================== --- loader/i386/pc/multiboot_normal.c 2006-11-13 18:57:22.000000000 -0600 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -/* 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 -#include -#include -#include - -static grub_err_t -grub_normal_cmd_multiboot (struct grub_arg_list *state __attribute__ ((unused)), - int argc, char **args) -{ - grub_rescue_cmd_multiboot (argc, args); - return grub_errno; -} - - -static grub_err_t -grub_normal_cmd_module (struct grub_arg_list *state __attribute__ ((unused)), - int argc, char **args) -{ - grub_rescue_cmd_module (argc, args); - return grub_errno; -} - -GRUB_MOD_INIT(multiboot_normal) -{ - (void) mod; /* To stop warning. */ - grub_register_command ("multiboot", grub_normal_cmd_multiboot, - 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_module, - 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 ("multiboot"); - grub_unregister_command ("module"); -} Index: loader/multiboot_normal.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ loader/multiboot_normal.c 2006-11-13 18:57:24.000000000 -0600 @@ -0,0 +1,61 @@ +/* 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 +#include +#include +#include + +static grub_err_t +grub_normal_cmd_multiboot (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + grub_rescue_cmd_multiboot (argc, args); + return grub_errno; +} + + +static grub_err_t +grub_normal_cmd_module (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + grub_rescue_cmd_module (argc, args); + return grub_errno; +} + +GRUB_MOD_INIT(multiboot_normal) +{ + (void) mod; /* To stop warning. */ + grub_register_command ("multiboot", grub_normal_cmd_multiboot, + 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_module, + 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 ("multiboot"); + grub_unregister_command ("module"); +} Index: conf/i386-pc.rmk =================================================================== --- conf/i386-pc.rmk 2006-11-13 18:57:22.000000000 -0600 +++ conf/i386-pc.rmk 2006-11-13 18:57:24.000000000 -0600 @@ -164,12 +164,12 @@ serial_mod_CFLAGS = $(COMMON_CFLAGS) serial_mod_LDFLAGS = $(COMMON_LDFLAGS) # For _multiboot.mod. -_multiboot_mod_SOURCES = loader/i386/pc/multiboot.c +_multiboot_mod_SOURCES = loader/multiboot.c loader/i386/pc/multiboot.c _multiboot_mod_CFLAGS = $(COMMON_CFLAGS) _multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) # For multiboot.mod. -multiboot_mod_SOURCES = loader/i386/pc/multiboot_normal.c +multiboot_mod_SOURCES = loader/multiboot_normal.c multiboot_mod_CFLAGS = $(COMMON_CFLAGS) multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) Index: conf/powerpc-ieee1275.rmk =================================================================== --- conf/powerpc-ieee1275.rmk 2006-11-13 18:57:22.000000000 -0600 +++ conf/powerpc-ieee1275.rmk 2006-11-13 18:57:24.000000000 -0600 @@ -84,6 +84,8 @@ grub_install_SOURCES = util/powerpc/ieee pkgdata_MODULES = halt.mod \ _linux.mod \ linux.mod \ + _multiboot.mod \ + multiboot.mod \ normal.mod \ reboot.mod \ suspend.mod @@ -98,6 +100,16 @@ linux_mod_SOURCES = loader/powerpc/ieee1 linux_mod_CFLAGS = $(COMMON_CFLAGS) linux_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For _multiboot.mod. +_multiboot_mod_SOURCES = loader/multiboot.c loader/powerpc/ieee1275/multiboot.c +_multiboot_mod_CFLAGS = $(COMMON_CFLAGS) +_multiboot_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For multiboot.mod. +multiboot_mod_SOURCES = loader/multiboot_normal.c +multiboot_mod_CFLAGS = $(COMMON_CFLAGS) +multiboot_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: include/grub/i386/pc/loader.h =================================================================== --- include/grub/i386/pc/loader.h 2006-11-13 18:57:22.000000000 -0600 +++ include/grub/i386/pc/loader.h 2006-11-13 18:57:24.000000000 -0600 @@ -22,11 +22,13 @@ #include #include -#include +#include extern grub_uint32_t EXPORT_VAR(grub_linux_prot_size); extern char *EXPORT_VAR(grub_linux_tmp_addr); extern char *EXPORT_VAR(grub_linux_real_addr); +extern grub_addr_t EXPORT_VAR(grub_os_area_addr); +extern grub_size_t EXPORT_VAR(grub_os_area_size); void EXPORT_FUNC(grub_linux_boot_zimage) (void) __attribute__ ((noreturn)); void EXPORT_FUNC(grub_linux_boot_bzimage) (void) __attribute__ ((noreturn)); @@ -35,8 +37,7 @@ void EXPORT_FUNC(grub_linux_boot_bzimage void EXPORT_FUNC(grub_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn)); /* The asm part of the multiboot loader. */ -void EXPORT_FUNC(grub_multiboot_real_boot) (grub_addr_t entry, - struct grub_multiboot_info *mbi) +void EXPORT_FUNC(grub_multiboot_real_boot) (grub_addr_t entry, void *tags) __attribute__ ((noreturn)); /* It is necessary to export these functions, because normal mode commands Index: include/grub/i386/pc/multiboot.h =================================================================== --- include/grub/i386/pc/multiboot.h 2006-11-13 18:57:22.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 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 - -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: kern/i386/pc/startup.S =================================================================== --- kern/i386/pc/startup.S 2006-11-13 18:57:22.000000000 -0600 +++ kern/i386/pc/startup.S 2006-11-13 18:57:24.000000000 -0600 @@ -50,8 +50,8 @@ #include #include #include -#include - +#include + #define ABS(x) ((x) - EXT_C(start) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200) .file "startup.S" @@ -803,18 +803,18 @@ linux_setup_seg: FUNCTION(grub_multiboot_real_boot) /* Push the entry address on the stack. */ pushl %eax - /* Move the address of the multiboot information structure to ebx. */ + /* Move the address of the multiboot tags to ebx. */ movl %edx,%ebx - + /* Unload all modules and stop the floppy driver. */ call EXT_C(grub_dl_unload_all) call EXT_C(grub_stop_floppy) /* Interrupts should be disabled. */ cli - + /* Move the magic value into eax and jump to the kernel. */ - movl $GRUB_MB_MAGIC2,%eax + movl $MULTIBOOT_BOOTLOADER_MAGIC,%eax popl %ecx jmp *%ecx Index: include/multiboot.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ include/multiboot.h 2006-11-13 18:57:24.000000000 -0600 @@ -0,0 +1,136 @@ +/* multiboot.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 MULTIBOOT_HEADER +#define MULTIBOOT_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 MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* This should be in %eax. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* The bits in the required part of flags field we don't support. */ +#define MULTIBOOT_UNSUPPORTED 0x0000fffc + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* + * Flags set in the 'flags' member of the multiboot header. + */ + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +#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 +{ + /* Must be MULTIBOOT_MAGIC - see above. */ + uint32_t magic; + + /* Feature flags. */ + uint32_t flags; + + /* The above fields plus this one must equal 0 mod 2^32. */ + uint32_t checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + uint32_t header_addr; + uint32_t load_addr; + uint32_t load_end_addr; + uint32_t bss_end_addr; + uint32_t entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + uint32_t mode_type; + uint32_t width; + uint32_t height; + uint32_t depth; +}; + +struct multiboot_tag_header +{ + uint32_t key; + uint32_t len; +}; + +#define MULTIBOOT_TAG_START 0 +struct multiboot_tag_start +{ + struct multiboot_tag_header header; + multiboot_word size; /* Total size of all multiboot tags. */ + multiboot_word num; /* Number of multiboot tags. */ +}; + +#define MULTIBOOT_TAG_CMDLINE 1 +struct multiboot_tag_cmdline +{ + struct multiboot_tag_header header; + char cmdline[1]; +}; + +#define MULTIBOOT_TAG_MODULE 2 +struct multiboot_tag_module +{ + struct multiboot_tag_header header; + multiboot_word addr; + multiboot_word size; + char cmdline[1]; +}; + +#define MULTIBOOT_TAG_NAME 4 +struct multiboot_tag_name +{ + struct multiboot_tag_header header; + char name[1]; +}; + +#define MULTIBOOT_TAG_END 0xffff +struct multiboot_tag_end +{ + struct multiboot_tag_header header; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT_HEADER */ --=-Gf8puDyOim87E5IrhvE1--