From 9a5c1adeaa8f9733e8f1651a44414c97d9189582 Mon Sep 17 00:00:00 2001 From: jeroen Date: Sun, 16 Nov 2003 16:36:39 +0000 Subject: [PATCH] 2003-11-16 Jeroen Dekkers * conf/i386-pc.rmk (pkgdata_MODULES): Add _multiboot.mod. (_multiboot_mod_SOURCES): New variable. (_multiboot_mod_CFLAGS): Likewise. * loader/i386/pc/multiboot.c: New file. * include/pupa/i386/pc/multiboot.h: Likewise. * kern/i386/pc/startup.S: Include pupa/machine/multiboot.h. (pupa_multiboot_real_boot): New function. * include/pupa/i386/pc/loader.h: Include pupa/machine/multiboot.h. (pupa_multiboot_real_boot): New prototype. (pupa_rescue_cmd_multiboot): Likewise (pupa_rescue_cmd_module): Likewise. * kern/loader.c (pupa_loader_set): Continue when pupa_loader_unload_func() fails. (pupa_loader_unset): New function. * include/pupa/loader.h (pupa_loader_unset): New prototype. * kern/misc.c (pupa_stpcpy): New function. * include/pupa/misc.h (pupa_stpcpy): New prototype. --- ChangeLog | 22 ++ conf/i386-pc.mk | 41 +++- conf/i386-pc.rmk | 6 +- include/grub/i386/pc/loader.h | 9 + include/grub/i386/pc/multiboot.h | 184 ++++++++++++++++ include/grub/loader.h | 2 + include/grub/misc.h | 1 + kern/i386/pc/startup.S | 25 +++ kern/loader.c | 16 +- kern/misc.c | 13 ++ loader/i386/pc/multiboot.c | 357 +++++++++++++++++++++++++++++++ 11 files changed, 672 insertions(+), 4 deletions(-) create mode 100644 include/grub/i386/pc/multiboot.h create mode 100644 loader/i386/pc/multiboot.c diff --git a/ChangeLog b/ChangeLog index c004f04e2..daee77777 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2003-11-16 Jeroen Dekkers + + * conf/i386-pc.rmk (pkgdata_MODULES): Add _multiboot.mod. + (_multiboot_mod_SOURCES): New variable. + (_multiboot_mod_CFLAGS): Likewise. + * loader/i386/pc/multiboot.c: New file. + * include/pupa/i386/pc/multiboot.h: Likewise. + * kern/i386/pc/startup.S: Include pupa/machine/multiboot.h. + (pupa_multiboot_real_boot): New function. + * include/pupa/i386/pc/loader.h: Include pupa/machine/multiboot.h. + (pupa_multiboot_real_boot): New prototype. + (pupa_rescue_cmd_multiboot): Likewise + (pupa_rescue_cmd_module): Likewise. + + * kern/loader.c (pupa_loader_set): Continue when + pupa_loader_unload_func() fails. + (pupa_loader_unset): New function. + * include/pupa/loader.h (pupa_loader_unset): New prototype. + + * kern/misc.c (pupa_stpcpy): New function. + * include/pupa/misc.h (pupa_stpcpy): New prototype. + 2003-11-12 Marco Gerards * disk/i386/pc/biosdisk.c (pupa_biosdisk_open): Correctly check diff --git a/conf/i386-pc.mk b/conf/i386-pc.mk index 77b7f5443..c62bb1100 100644 --- a/conf/i386-pc.mk +++ b/conf/i386-pc.mk @@ -403,7 +403,7 @@ genmoddep-util_genmoddep.d: util/genmoddep.c # Modules. pkgdata_MODULES = _chain.mod _linux.mod fat.mod ext2.mod normal.mod hello.mod \ - vga.mod font.mod + vga.mod font.mod _multiboot.mod # For _chain.mod. _chain_mod_SOURCES = loader/i386/pc/chainloader.c @@ -750,6 +750,45 @@ font_mod-font_manager.d: font/manager.c -include font_mod-font_manager.d font_mod_CFLAGS = $(COMMON_CFLAGS) + +# For _multiboot.mod. +_multiboot_mod_SOURCES = loader/i386/pc/multiboot.c +CLEANFILES += _multiboot.mod mod-_multiboot.o mod-_multiboot.c pre-_multiboot.o _multiboot_mod-loader_i386_pc_multiboot.o def-_multiboot.lst und-_multiboot.lst +MOSTLYCLEANFILES += _multiboot_mod-loader_i386_pc_multiboot.d +DEFSYMFILES += def-_multiboot.lst +UNDSYMFILES += und-_multiboot.lst + +_multiboot.mod: pre-_multiboot.o mod-_multiboot.o + -rm -f $@ + $(LD) -r -o $@ $^ + $(STRIP) --strip-unneeded -K pupa_mod_init -K pupa_mod_fini -R .note -R .comment $@ + +pre-_multiboot.o: _multiboot_mod-loader_i386_pc_multiboot.o + -rm -f $@ + $(LD) -r -o $@ $^ + +mod-_multiboot.o: mod-_multiboot.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(_multiboot_mod_CFLAGS) -c -o $@ $< + +mod-_multiboot.c: moddep.lst genmodsrc.sh + sh $(srcdir)/genmodsrc.sh '_multiboot' $< > $@ || (rm -f $@; exit 1) + +def-_multiboot.lst: pre-_multiboot.o + $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 _multiboot/' > $@ + +und-_multiboot.lst: pre-_multiboot.o + echo '_multiboot' > $@ + $(NM) -u -P -p $< | cut -f1 -d' ' >> $@ + +_multiboot_mod-loader_i386_pc_multiboot.o: loader/i386/pc/multiboot.c + $(CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(CPPFLAGS) $(CFLAGS) $(_multiboot_mod_CFLAGS) -c -o $@ $< + +_multiboot_mod-loader_i386_pc_multiboot.d: loader/i386/pc/multiboot.c + set -e; $(CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(CPPFLAGS) $(CFLAGS) $(_multiboot_mod_CFLAGS) -M $< | sed 's,multiboot\.o[ :]*,_multiboot_mod-loader_i386_pc_multiboot.o $@ : ,g' > $@; [ -s $@ ] || rm -f $@ + +-include _multiboot_mod-loader_i386_pc_multiboot.d + +_multiboot_mod_CFLAGS = $(COMMON_CFLAGS) CLEANFILES += moddep.lst pkgdata_DATA += moddep.lst moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index d913f8d4f..1bdc23bd9 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -62,7 +62,7 @@ genmoddep_SOURCES = util/genmoddep.c # Modules. pkgdata_MODULES = _chain.mod _linux.mod fat.mod ext2.mod normal.mod hello.mod \ - vga.mod font.mod + vga.mod font.mod _multiboot.mod # For _chain.mod. _chain_mod_SOURCES = loader/i386/pc/chainloader.c @@ -97,3 +97,7 @@ vga_mod_CFLAGS = $(COMMON_CFLAGS) # For font.mod. font_mod_SOURCES = font/manager.c font_mod_CFLAGS = $(COMMON_CFLAGS) + +# For _multiboot.mod. +_multiboot_mod_SOURCES = loader/i386/pc/multiboot.c +_multiboot_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/include/grub/i386/pc/loader.h b/include/grub/i386/pc/loader.h index dad25513d..53c0268d4 100644 --- a/include/grub/i386/pc/loader.h +++ b/include/grub/i386/pc/loader.h @@ -1,6 +1,7 @@ /* * PUPA -- Preliminary Universal Programming Architecture for GRUB * Copyright (C) 2002 Yoshinori K. Okuji + * Copyright (C) 2003 Jeroen Dekkers * * 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 @@ -22,6 +23,7 @@ #include #include +#include extern pupa_uint32_t EXPORT_VAR(pupa_linux_prot_size); extern char *EXPORT_VAR(pupa_linux_tmp_addr); @@ -33,10 +35,17 @@ void EXPORT_FUNC(pupa_linux_boot_bzimage) (void) __attribute__ ((noreturn)); /* This is an asm part of the chainloader. */ void EXPORT_FUNC(pupa_chainloader_real_boot) (int drive, void *part_addr) __attribute__ ((noreturn)); +/* The asm part of the multiboot loader. */ +void EXPORT_FUNC(pupa_multiboot_real_boot) (pupa_addr_t entry, + struct pupa_multiboot_info *mbi) + __attribute__ ((noreturn)); + /* It is necessary to export these functions, because normal mode commands reuse rescue mode commands. */ void pupa_rescue_cmd_chainloader (int argc, char *argv[]); void pupa_rescue_cmd_linux (int argc, char *argv[]); void pupa_rescue_cmd_initrd (int argc, char *argv[]); +void pupa_rescue_cmd_multiboot (int argc, char *argv[]); +void pupa_rescue_cmd_module (int argc, char *argv[]); #endif /* ! PUPA_LOADER_MACHINE_HEADER */ diff --git a/include/grub/i386/pc/multiboot.h b/include/grub/i386/pc/multiboot.h new file mode 100644 index 000000000..ec5805bd7 --- /dev/null +++ b/include/grub/i386/pc/multiboot.h @@ -0,0 +1,184 @@ +/* multiboot.h - multiboot header file. */ +/* + * PUPA -- Preliminary Universal Programming Architecture for GRUB + * Copyright (C) 2003 Jeroen Dekkers + * + * 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 PUPA_MULTIBOOT_MACHINE_HEADER +#define PUPA_MULTIBOOT_MACHINE_HEADER 1 + +/* How many bytes from the start of the file we search for the header. */ +#define PUPA_MB_SEARCH 8192 + +/* The magic field should contain this. */ +#define PUPA_MB_MAGIC 0x1BADB002 + +/* This should be in %eax. */ +#define PUPA_MB_MAGIC2 0x2BADB002 + +/* The bits in the required part of flags field we don't support. */ +#define PUPA_MB_UNSUPPORTED 0x0000fffc + +/* Alignment of multiboot modules. */ +#define PUPA_MB_MOD_ALIGN 0x00001000 + +/* + * Flags set in the 'flags' member of the multiboot header. + */ + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define PUPA_MB_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define PUPA_MB_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define PUPA_MB_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define PUPA_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 PUPA_MB_INFO_MEMORY 0x00000001 +/* is there a boot device set? */ +#define PUPA_MB_INFO_BOOTDEV 0x00000002 +/* is the command-line defined? */ +#define PUPA_MB_INFO_CMDLINE 0x00000004 +/* are there modules to do something with? */ +#define PUPA_MB_INFO_MODS 0x00000008 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define PUPA_MB_INFO_AOUT_SYMS 0x00000010 +/* is there an ELF section header table? */ +#define PUPA_MB_INFO_ELF_SHDR 0x00000020 + +/* is there a full memory map? */ +#define PUPA_MB_INFO_MEM_MAP 0x00000040 + +/* Is there drive info? */ +#define PUPA_MB_INFO_DRIVE_INFO 0x00000080 + +/* Is there a config table? */ +#define PUPA_MB_INFO_CONFIG_TABLE 0x00000100 + +/* Is there a boot loader name? */ +#define PUPA_MB_INFO_BOOT_LOADER_NAME 0x00000200 + +/* Is there a APM table? */ +#define PUPA_MB_INFO_APM_TABLE 0x00000400 + +/* Is there video information? */ +#define PUPA_MB_INFO_VIDEO_INFO 0x00000800 + +#ifndef ASM_FILE + +#include + +struct pupa_multiboot_header +{ + /* Must be PUPA_MB_MAGIC - see above. */ + pupa_uint32_t magic; + + /* Feature flags. */ + pupa_uint32_t flags; + + /* The above fields plus this one must equal 0 mod 2^32. */ + pupa_uint32_t checksum; + + /* These are only valid if PUPA_MB_AOUT_KLUDGE is set. */ + pupa_uint32_t header_addr; + pupa_uint32_t load_addr; + pupa_uint32_t load_end_addr; + pupa_uint32_t bss_end_addr; + pupa_uint32_t entry_addr; + + /* These are only valid if PUPA_MB_VIDEO_MODE is set. */ + pupa_uint32_t mode_type; + pupa_uint32_t width; + pupa_uint32_t height; + pupa_uint32_t depth; +}; + +struct pupa_multiboot_info +{ + /* MultiBoot info version number */ + pupa_uint32_t flags; + + /* Available memory from BIOS */ + pupa_uint32_t mem_lower; + pupa_uint32_t mem_upper; + + /* "root" partition */ + pupa_uint32_t boot_device; + + /* Kernel command line */ + pupa_uint32_t cmdline; + + /* Boot-Module list */ + pupa_uint32_t mods_count; + pupa_uint32_t mods_addr; + + pupa_uint32_t syms[4]; + + /* Memory Mapping buffer */ + pupa_uint32_t mmap_length; + pupa_uint32_t mmap_addr; + + /* Drive Info buffer */ + pupa_uint32_t drives_length; + pupa_uint32_t drives_addr; + + /* ROM configuration table */ + pupa_uint32_t config_table; + + /* Boot Loader Name */ + pupa_uint32_t boot_loader_name; + + /* APM table */ + pupa_uint32_t apm_table; + + /* Video */ + pupa_uint32_t vbe_control_info; + pupa_uint32_t vbe_mode_info; + pupa_uint16_t vbe_mode; + pupa_uint16_t vbe_interface_seg; + pupa_uint16_t vbe_interface_off; + pupa_uint16_t vbe_interface_len; +}; + +struct pupa_mod_list +{ + /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ + pupa_uint32_t mod_start; + pupa_uint32_t mod_end; + + /* Module command line */ + pupa_uint32_t cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + pupa_uint32_t pad; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! PUPA_MULTIBOOT_MACHINE_HEADER */ diff --git a/include/grub/loader.h b/include/grub/loader.h index 7d190406d..bb3a57085 100644 --- a/include/grub/loader.h +++ b/include/grub/loader.h @@ -2,6 +2,7 @@ /* * PUPA -- Preliminary Universal Programming Architecture for GRUB * Copyright (C) 2002 Yoshinori K. Okuji + * Copyright (C) 2003 Jeroen Dekkers * * 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 @@ -31,6 +32,7 @@ extern pupa_size_t EXPORT_VAR(pupa_os_area_size); void EXPORT_FUNC(pupa_loader_set) (pupa_err_t (*boot) (void), pupa_err_t (*unload) (void)); +void EXPORT_FUNC(pupa_loader_unset) (void); pupa_err_t EXPORT_FUNC(pupa_loader_boot) (void); diff --git a/include/grub/misc.h b/include/grub/misc.h index 909d47f05..8bc3fd95b 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h @@ -32,6 +32,7 @@ void *EXPORT_FUNC(pupa_memmove) (void *dest, const void *src, pupa_size_t n); char *EXPORT_FUNC(pupa_strcpy) (char *dest, const char *src); char *EXPORT_FUNC(pupa_strncpy) (char *dest, const char *src, int c); +char *EXPORT_FUNC(pupa_stpcpy) (char *dest, const char *src); char *EXPORT_FUNC(pupa_strcat) (char *dest, const char *src); diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S index 885a89033..ff60fe6b5 100644 --- a/kern/i386/pc/startup.S +++ b/kern/i386/pc/startup.S @@ -3,6 +3,7 @@ * Copyright (C) 1999,2000,2001,2002 Free Software Foundation, Inc. * Copyright (C) 2002,2003 Yoshinori K. Okuji * Copyright (C) 2003 Marco Gerards + * Copyright (C) 2003 Jeroen Dekkers * * 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 @@ -52,6 +53,7 @@ #include #include #include +#include #define ABS(x) ((x) - EXT_C(start) + PUPA_BOOT_MACHINE_KERNEL_ADDR + 0x200) @@ -621,6 +623,29 @@ linux_setup_seg: .code32 +/* + * This starts the multiboot kernel. + */ + +FUNCTION(pupa_multiboot_real_boot) + /* Push the entry address on the stack. */ + pushl %eax + /* Move the address of the multiboot information structure to ebx. */ + movl %edx,%ebx + + /* Unload all modules and stop the floppy driver. */ + call EXT_C(pupa_dl_unload_all) + call EXT_C(pupa_stop_floppy) + + /* Interrupts should be disabled. */ + cli + + /* Move the magic value into eax and jump to the kernel. */ + movl $PUPA_MB_MAGIC2,%eax + popl %ecx + jmp *%ecx + + /* * int pupa_biosdisk_rw_int13_extensions (int ah, int drive, void *dap) * diff --git a/kern/loader.c b/kern/loader.c index 65ee654bf..b34118b68 100644 --- a/kern/loader.c +++ b/kern/loader.c @@ -1,6 +1,7 @@ /* * PUPA -- Preliminary Universal Programming Architecture for GRUB * Copyright (C) 2002 Yoshinori K. Okuji + * Copyright (C) 2003 Jeroen Dekkers * * PUPA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,8 +33,7 @@ pupa_loader_set (pupa_err_t (*boot) (void), pupa_err_t (*unload) (void)) { if (pupa_loader_loaded && pupa_loader_unload_func) - if (pupa_loader_unload_func () != PUPA_ERR_NONE) - return; + pupa_loader_unload_func (); pupa_loader_boot_func = boot; pupa_loader_unload_func = unload; @@ -41,6 +41,18 @@ pupa_loader_set (pupa_err_t (*boot) (void), pupa_loader_loaded = 1; } +void +pupa_loader_unset(void) +{ + if (pupa_loader_loaded && pupa_loader_unload_func) + pupa_loader_unload_func (); + + pupa_loader_boot_func = 0; + pupa_loader_unload_func = 0; + + pupa_loader_loaded = 0; +} + pupa_err_t pupa_loader_boot (void) { diff --git a/kern/misc.c b/kern/misc.c index a3a55778c..53fc59ecc 100644 --- a/kern/misc.c +++ b/kern/misc.c @@ -70,6 +70,19 @@ pupa_strncpy (char *dest, const char *src, int c) return dest; } +char * +pupa_stpcpy (char *dest, const char *src) +{ + char *d = dest; + const char *s = src; + + do + *d++ = *s; + while (*s++ != '\0'); + + return d - 1; +} + char * pupa_strcat (char *dest, const char *src) { diff --git a/loader/i386/pc/multiboot.c b/loader/i386/pc/multiboot.c new file mode 100644 index 000000000..390c0cfa1 --- /dev/null +++ b/loader/i386/pc/multiboot.c @@ -0,0 +1,357 @@ +/* multiboot.c - boot a multiboot OS image. */ +/* + * PUPA -- Preliminary Universal Programming Architecture for GRUB + * Copyright (C) 2003 Jeroen Dekkers + * + * 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. + */ + +/* + * 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 + +static pupa_dl_t my_mod; +static struct pupa_multiboot_info *mbi; +static pupa_addr_t entry; + +static pupa_err_t +pupa_multiboot_boot (void) +{ + pupa_multiboot_real_boot (entry, mbi); + + /* Not reached. */ + return PUPA_ERR_NONE; +} + +static pupa_err_t +pupa_multiboot_unload (void) +{ + if (mbi) + { + int i; + for (i = 0; i < mbi->mods_count; i++) + { + pupa_free ((void *) + ((struct pupa_mod_list *) mbi->mods_addr)[i].mod_start); + pupa_free ((void *) + ((struct pupa_mod_list *) mbi->mods_addr)[i].cmdline); + } + pupa_free ((void *) mbi->mods_addr); + pupa_free ((void *) mbi->cmdline); + pupa_free (mbi); + } + + + mbi = 0; + pupa_dl_unref (my_mod); + + return PUPA_ERR_NONE; +} + +void +pupa_rescue_cmd_multiboot (int argc, char *argv[]) +{ + pupa_file_t file = 0; + char buffer[PUPA_MB_SEARCH], *cmdline = 0, *p; + struct pupa_multiboot_header *header; + pupa_ssize_t len; + int i; + Elf32_Ehdr *ehdr; + + pupa_dl_ref (my_mod); + + pupa_loader_unset(); + + if (argc == 0) + { + pupa_error (PUPA_ERR_BAD_ARGUMENT, "No kernel specified"); + goto fail; + } + + file = pupa_file_open (argv[0]); + if (!file) + { + pupa_error (PUPA_ERR_BAD_ARGUMENT, "Couldn't open file"); + goto fail; + } + + len = pupa_file_read (file, buffer, PUPA_MB_SEARCH); + if (len < 32) + { + pupa_error (PUPA_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 pupa_multiboot_header *) buffer; + ((char *) header <= buffer + len - 12) || (header = 0); + (char *)header += 4) + { + if (header->magic == PUPA_MB_MAGIC + && !(header->magic + header->flags + header->checksum)) + break; + } + + if (header == 0) + { + pupa_error (PUPA_ERR_BAD_ARGUMENT, "No multiboot header found"); + goto fail; + } + + if (header->flags & PUPA_MB_UNSUPPORTED) + { + pupa_error (PUPA_ERR_UNKNOWN_OS, "Unsupported flag: 0x%x", header->flags); + goto fail; + } + + ehdr = (Elf32_Ehdr *) buffer; + + 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_ident[EI_CLASS] == ELFCLASS32) + && (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + && (ehdr->e_ident[EI_VERSION] == EV_CURRENT) + && (ehdr->e_type == ET_EXEC) && (ehdr->e_machine == EM_386) + && (ehdr->e_version == EV_CURRENT))) + { + pupa_error (PUPA_ERR_UNKNOWN_OS, "No valid ELF header found"); + goto fail; + } + + /* FIXME: Should we support program headers at strange locations? */ + if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > PUPA_MB_SEARCH) + { + pupa_error (PUPA_ERR_UNKNOWN_OS, "Program header at a too high offset"); + goto fail; + } + + entry = ehdr->e_entry; + + /* Load every loadable segment in memory. */ + for (i = 0; i < ehdr->e_phnum; i++) + { + Elf32_Phdr *phdr; + phdr = (Elf32_Phdr *) (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 < pupa_os_area_addr) + || (phdr->p_paddr + phdr->p_memsz + > pupa_os_area_addr + pupa_os_area_size)) + { + pupa_error (PUPA_ERR_BAD_OS, + "Segment doesn't fit in memory reserved for the OS"); + goto fail; + } + + if (pupa_file_seek (file, phdr->p_offset) == -1) + { + pupa_error (PUPA_ERR_BAD_OS, "Invalid offset in program header"); + goto fail; + } + + if (pupa_file_read (file, (void *) phdr->p_paddr, phdr->p_filesz) + != (pupa_ssize_t) phdr->p_filesz) + { + pupa_error (PUPA_ERR_BAD_OS, "Couldn't read segment from file"); + goto fail; + } + + if (phdr->p_filesz < phdr->p_memsz) + pupa_memset ((char *) phdr->p_paddr + phdr->p_filesz, 0, + phdr->p_memsz - phdr->p_filesz); + } + } + + mbi = pupa_malloc (sizeof (struct pupa_multiboot_info)); + if (!mbi) + goto fail; + + mbi->flags = PUPA_MB_INFO_MEMORY; + + /* Convert from bytes to kilobytes. */ + mbi->mem_lower = pupa_lower_mem / 1024; + mbi->mem_upper = pupa_upper_mem / 1024; + + for (i = 0, len = 0; i < argc; i++) + len += pupa_strlen (argv[i]) + 1; + + cmdline = p = pupa_malloc (len); + if (!cmdline) + goto fail; + + for (i = 0; i < argc; i++) + { + p = pupa_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + *(--p) = '\0'; + + mbi->flags |= PUPA_MB_INFO_CMDLINE; + mbi->cmdline = (pupa_uint32_t) cmdline; + + mbi->flags |= PUPA_MB_INFO_BOOT_LOADER_NAME; + mbi->boot_loader_name = (pupa_uint32_t) pupa_strdup (PACKAGE_STRING); + + pupa_loader_set (pupa_multiboot_boot, pupa_multiboot_unload); + + fail: + if (file) + pupa_file_close (file); + + if (pupa_errno != PUPA_ERR_NONE) + { + pupa_free (cmdline); + pupa_free (mbi); + pupa_dl_unref (my_mod); + } +} + + +void +pupa_rescue_cmd_module (int argc, char *argv[]) +{ + pupa_file_t file = 0; + pupa_ssize_t size, len = 0; + char *module = 0, *cmdline = 0, *p; + int i; + + if (argc == 0) + { + pupa_error (PUPA_ERR_BAD_ARGUMENT, "No module specified"); + goto fail; + } + + if (!mbi) + { + pupa_error (PUPA_ERR_BAD_ARGUMENT, + "You need to load the multiboot kernel first"); + goto fail; + } + + file = pupa_file_open (argv[0]); + if (!file) + goto fail; + + size = pupa_file_size (file); + module = pupa_memalign (PUPA_MB_MOD_ALIGN, size); + if (!module) + goto fail; + + if (pupa_file_read (file, module, size) != size) + { + pupa_error (PUPA_ERR_FILE_READ_ERROR, "Couldn't read file"); + goto fail; + } + + for (i = 0; i < argc; i++) + len += pupa_strlen (argv[i]) + 1; + + cmdline = p = pupa_malloc (len); + if (!cmdline) + goto fail; + + for (i = 0; i < argc; i++) + { + p = pupa_stpcpy (p, argv[i]); + *(p++) = ' '; + } + + /* Remove the space after the last word. */ + *(--p) = '\0'; + + if (mbi->flags & PUPA_MB_INFO_MODS) + { + struct pupa_mod_list *modlist = (struct pupa_mod_list *) mbi->mods_addr; + + modlist = pupa_realloc (modlist, (mbi->mods_count + 1) + * sizeof (struct pupa_mod_list)); + if (!modlist) + goto fail; + mbi->mods_addr = (pupa_uint32_t) modlist; + modlist += mbi->mods_count; + modlist->mod_start = (pupa_uint32_t) module; + modlist->mod_end = (pupa_uint32_t) module + size; + modlist->cmdline = (pupa_uint32_t) cmdline; + modlist->pad = 0; + mbi->mods_count++; + } + else + { + struct pupa_mod_list *modlist = pupa_malloc (sizeof (struct pupa_mod_list)); + if (!modlist) + goto fail; + modlist->mod_start = (pupa_uint32_t) module; + modlist->mod_end = (pupa_uint32_t) module + size; + modlist->cmdline = (pupa_uint32_t) cmdline; + modlist->pad = 0; + mbi->mods_count = 1; + mbi->mods_addr = (pupa_uint32_t) modlist; + mbi->flags |= PUPA_MB_INFO_MODS; + } + + fail: + if (file) + pupa_file_close (file); + + if (pupa_errno != PUPA_ERR_NONE) + { + pupa_free (module); + pupa_free (cmdline); + } +} + + +PUPA_MOD_INIT +{ + pupa_rescue_register_command ("multiboot", pupa_rescue_cmd_multiboot, + "load a multiboot kernel"); + pupa_rescue_register_command ("module", pupa_rescue_cmd_module, + "load a multiboot module"); + my_mod = mod; +} + +PUPA_MOD_FINI +{ + pupa_rescue_unregister_command ("multiboot"); + pupa_rescue_unregister_command ("module"); +}