diff -urN ../grub2.multiboot/conf/i386-pc.mk ./conf/i386-pc.mk --- ../grub2.multiboot/conf/i386-pc.mk 2007-06-17 18:58:52.000000000 +0700 +++ ./conf/i386-pc.mk 2007-06-18 12:52:15.000000000 +0700 @@ -833,7 +833,8 @@ pkgdata_MODULES = _chain.mod _linux.mod linux.mod normal.mod \ _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \ vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ - videotest.mod play.mod bitmap.mod tga.mod cpuid.mod + videotest.mod play.mod bitmap.mod tga.mod cpuid.mod \ + _elbp.mod elbp.mod # For _chain.mod. _chain_mod_SOURCES = loader/i386/pc/chainloader.c @@ -2075,4 +2076,108 @@ cpuid_mod_CFLAGS = $(COMMON_CFLAGS) cpuid_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For _elbp.mod. +_elbp_mod_SOURCES = loader/i386/pc/elbp.c +CLEANFILES += _elbp.mod mod-_elbp.o mod-_elbp.c pre-_elbp.o _elbp_mod-loader_i386_pc_elbp.o und-_elbp.lst +ifneq ($(_elbp_mod_EXPORTS),no) +CLEANFILES += def-_elbp.lst +DEFSYMFILES += def-_elbp.lst +endif +MOSTLYCLEANFILES += _elbp_mod-loader_i386_pc_elbp.d +UNDSYMFILES += und-_elbp.lst + +_elbp.mod: pre-_elbp.o mod-_elbp.o + -rm -f $@ + $(TARGET_CC) $(_elbp_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ $^ + $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@ + +pre-_elbp.o: $(_elbp_mod_DEPENDENCIES) _elbp_mod-loader_i386_pc_elbp.o + -rm -f $@ + $(TARGET_CC) $(_elbp_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ _elbp_mod-loader_i386_pc_elbp.o + +mod-_elbp.o: mod-_elbp.c + $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(_elbp_mod_CFLAGS) -c -o $@ $< + +mod-_elbp.c: moddep.lst genmodsrc.sh + sh $(srcdir)/genmodsrc.sh '_elbp' $< > $@ || (rm -f $@; exit 1) + +ifneq ($(_elbp_mod_EXPORTS),no) +def-_elbp.lst: pre-_elbp.o + $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 _elbp/' > $@ +endif + +und-_elbp.lst: pre-_elbp.o + echo '_elbp' > $@ + $(NM) -u -P -p $< | cut -f1 -d' ' >> $@ + +_elbp_mod-loader_i386_pc_elbp.o: loader/i386/pc/elbp.c + $(TARGET_CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(_elbp_mod_CFLAGS) -MD -c -o $@ $< +-include _elbp_mod-loader_i386_pc_elbp.d + +CLEANFILES += cmd-_elbp_mod-loader_i386_pc_elbp.lst fs-_elbp_mod-loader_i386_pc_elbp.lst +COMMANDFILES += cmd-_elbp_mod-loader_i386_pc_elbp.lst +FSFILES += fs-_elbp_mod-loader_i386_pc_elbp.lst + +cmd-_elbp_mod-loader_i386_pc_elbp.lst: loader/i386/pc/elbp.c gencmdlist.sh + set -e; $(TARGET_CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(_elbp_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh _elbp > $@ || (rm -f $@; exit 1) + +fs-_elbp_mod-loader_i386_pc_elbp.lst: loader/i386/pc/elbp.c genfslist.sh + set -e; $(TARGET_CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(_elbp_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh _elbp > $@ || (rm -f $@; exit 1) + + +_elbp_mod_CFLAGS = $(COMMON_CFLAGS) +_elbp_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For elbp.mod. +elbp_mod_SOURCES = loader/i386/pc/elbp_normal.c +CLEANFILES += elbp.mod mod-elbp.o mod-elbp.c pre-elbp.o elbp_mod-loader_i386_pc_elbp_normal.o und-elbp.lst +ifneq ($(elbp_mod_EXPORTS),no) +CLEANFILES += def-elbp.lst +DEFSYMFILES += def-elbp.lst +endif +MOSTLYCLEANFILES += elbp_mod-loader_i386_pc_elbp_normal.d +UNDSYMFILES += und-elbp.lst + +elbp.mod: pre-elbp.o mod-elbp.o + -rm -f $@ + $(TARGET_CC) $(elbp_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ $^ + $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@ + +pre-elbp.o: $(elbp_mod_DEPENDENCIES) elbp_mod-loader_i386_pc_elbp_normal.o + -rm -f $@ + $(TARGET_CC) $(elbp_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ elbp_mod-loader_i386_pc_elbp_normal.o + +mod-elbp.o: mod-elbp.c + $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(elbp_mod_CFLAGS) -c -o $@ $< + +mod-elbp.c: moddep.lst genmodsrc.sh + sh $(srcdir)/genmodsrc.sh 'elbp' $< > $@ || (rm -f $@; exit 1) + +ifneq ($(elbp_mod_EXPORTS),no) +def-elbp.lst: pre-elbp.o + $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 elbp/' > $@ +endif + +und-elbp.lst: pre-elbp.o + echo 'elbp' > $@ + $(NM) -u -P -p $< | cut -f1 -d' ' >> $@ + +elbp_mod-loader_i386_pc_elbp_normal.o: loader/i386/pc/elbp_normal.c + $(TARGET_CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(elbp_mod_CFLAGS) -MD -c -o $@ $< +-include elbp_mod-loader_i386_pc_elbp_normal.d + +CLEANFILES += cmd-elbp_mod-loader_i386_pc_elbp_normal.lst fs-elbp_mod-loader_i386_pc_elbp_normal.lst +COMMANDFILES += cmd-elbp_mod-loader_i386_pc_elbp_normal.lst +FSFILES += fs-elbp_mod-loader_i386_pc_elbp_normal.lst + +cmd-elbp_mod-loader_i386_pc_elbp_normal.lst: loader/i386/pc/elbp_normal.c gencmdlist.sh + set -e; $(TARGET_CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(elbp_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh elbp > $@ || (rm -f $@; exit 1) + +fs-elbp_mod-loader_i386_pc_elbp_normal.lst: loader/i386/pc/elbp_normal.c genfslist.sh + set -e; $(TARGET_CC) -Iloader/i386/pc -I$(srcdir)/loader/i386/pc $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(elbp_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh elbp > $@ || (rm -f $@; exit 1) + + +elbp_mod_CFLAGS = $(COMMON_CFLAGS) +elbp_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff -urN ../grub2.multiboot/conf/i386-pc.rmk ./conf/i386-pc.rmk --- ../grub2.multiboot/conf/i386-pc.rmk 2007-06-11 13:26:18.000000000 +0700 +++ ./conf/i386-pc.rmk 2007-06-18 12:49:19.000000000 +0700 @@ -131,7 +131,8 @@ pkgdata_MODULES = _chain.mod _linux.mod linux.mod normal.mod \ _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \ vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ - videotest.mod play.mod bitmap.mod tga.mod cpuid.mod + videotest.mod play.mod bitmap.mod tga.mod cpuid.mod \ + _elbp.mod elbp.mod # For _chain.mod. _chain_mod_SOURCES = loader/i386/pc/chainloader.c @@ -240,4 +241,14 @@ cpuid_mod_CFLAGS = $(COMMON_CFLAGS) cpuid_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For _elbp.mod. +_elbp_mod_SOURCES = loader/i386/pc/elbp.c +_elbp_mod_CFLAGS = $(COMMON_CFLAGS) +_elbp_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For elbp.mod. +elbp_mod_SOURCES = loader/i386/pc/elbp_normal.c +elbp_mod_CFLAGS = $(COMMON_CFLAGS) +elbp_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/common.mk diff -urN ../grub2.multiboot/DISTLIST ./DISTLIST --- ../grub2.multiboot/DISTLIST 2007-05-20 16:10:05.000000000 +0700 +++ ./DISTLIST 2007-06-20 12:27:19.000000000 +0700 @@ -105,6 +105,7 @@ include/grub/lvm.h include/grub/misc.h include/grub/mm.h +include/grub/elbp.h include/grub/net.h include/grub/normal.h include/grub/parser.h @@ -137,6 +138,7 @@ include/grub/i386/pc/boot.h include/grub/i386/pc/chainloader.h include/grub/i386/pc/console.h +include/grub/i386/pc/elbp.h include/grub/i386/pc/init.h include/grub/i386/pc/kernel.h include/grub/i386/pc/loader.h @@ -216,6 +218,8 @@ loader/i386/efi/linux_normal.c loader/i386/pc/chainloader.c loader/i386/pc/chainloader_normal.c +loader/i386/pc/elbp.c +loader/i386/pc/elbp_normal.c loader/i386/pc/linux.c loader/i386/pc/linux_normal.c loader/i386/pc/multiboot.c diff -urN ../grub2.multiboot/include/grub/elbp.h ./include/grub/elbp.h --- ../grub2.multiboot/include/grub/elbp.h 1970-01-01 06:00:00.000000000 +0600 +++ ./include/grub/elbp.h 2007-06-20 12:47:14.000000000 +0700 @@ -0,0 +1,217 @@ +/* elbp.h - ELBP header file. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007 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_ELBP_HEADER +#define GRUB_ELBP_HEADER 1 + +/* Magic values for big- and little-endian headers. */ +#define GRUB_ELBP_HDR_MAGIC_BE "ELBPHDRB" +#define GRUB_ELBP_HDR_MAGIC_LE "ELBPHDRL" + +/* Magic value passed to OS. */ +#define GRUB_ELBP_INFO_MAGIC 0x454C4250 + +/* + * Each of generic, image, platform, and machine interfaces (format and + * interpretation of corresponding _header and _info structures) has a + * version. Only versions with same major numbers are comparable. + * Version X.Z MUST be backward compatible with version X.Y if Z>Y. + * 'Size' field determines size in qwords of _header or _info structure + * (depending on context). It's just a packing hack, not a version part. + */ + +/* Construct version from fields. */ +#define GRUB_ELBP_VERSION(major,minor,size) \ + ((((major) & 0xFFF) << 20) | (((minor) & 0xFFF) << 8) | ((size) & 0xFF)) + +/* Extract fields from version. */ +#define GRUB_ELBP_VERSION_MAJOR(v) (((v) >> 20) & 0xFFF) +#define GRUB_ELBP_VERSION_MINOR(v) (((v) >> 8) & 0xFFF) +#define GRUB_ELBP_VERSION_SIZE(v) ((v) & 0xFF) + +/* Special invalid version. */ +#define GRUB_ELBP_VERSION_NONE 0xFFFFFF00 + +/* Image formats. */ +#define GRUB_ELBP_IMAGE_RAW 1 +#define GRUB_ELBP_IMAGE_AOUT 2 +#define GRUB_ELBP_IMAGE_ELF 3 + +/* Architectures. */ +#define GRUB_ELBP_ARCH_I386 1 +#define GRUB_ELBP_ARCH_X86_64 2 +#define GRUB_ELBP_ARCH_PPC 3 +#define GRUB_ELBP_ARCH_PPC64 4 + +/* Platforms. */ +#define GRUB_ELBP_PLATFORM_PC 1 +#define GRUB_ELBP_PLATFORM_EFI 2 +#define GRUB_ELBP_PLATFORM_IEEE1275 3 + +#ifndef ASM_FILE + +#include + +struct grub_elbp_header +{ + /* 'ELBPHDR[L|B]' */ + grub_uint8_t magic[8]; + + /* ELBP version. */ + grub_uint32_t version; + + /* Image format. */ + grub_uint8_t image; + + /* Architecture. */ + grub_uint8_t arch; + + /* Platform. */ + grub_uint8_t platform; + + /* Pad, must be zero. */ + grub_uint8_t pad; + + /* Supported major versions count. */ + grub_uint16_t image_vers_count; + grub_uint16_t platform_vers_count; + grub_uint16_t machine_vers_count; + + /* Align modules on 2^mod_align boundary. */ + grub_uint8_t mod_align; + + /* Header must sum to 0 mod 2^8 as a byte array. */ + grub_uint8_t chksum; +} __attribute__ ((packed)); + +static inline grub_uint8_t +grub_elbp_header_chksum (const struct grub_elbp_header *hdr) +{ + grub_uint8_t chksum = 0; + unsigned int i; + + for (i = 0; i < sizeof (struct grub_elbp_header); ++i) + chksum += ((grub_uint8_t *) hdr)[i]; + + return chksum; +} + +struct grub_elbp32_raw_v0_header +{ + /* Code offset from header. */ + grub_uint64_t load_offset; + + /* Entry point offset from header. */ + grub_uint64_t entry_offset; + + /* Load code and data area to this address. */ + grub_uint32_t load_addr; + + /* Size of code and data area. If zero, load rest of the file. */ + grub_uint32_t load_size; + + /* BSS size. */ + grub_uint32_t bss_size; + + /* Pad, must be zero. */ + grub_uint32_t pad; +}; + +struct grub_elbp64_raw_v0_header +{ + /* Code offset from header. */ + grub_uint64_t load_offset; + + /* Entry point offset from header. */ + grub_uint64_t entry_offset; + + /* Load code and data area to this address. */ + grub_uint64_t load_addr; + + /* Size of code and data area. If zero, load rest of the file. */ + grub_uint64_t load_size; + + /* BSS size. */ + grub_uint64_t bss_size; +}; + +struct grub_elbp32_info +{ + /* Info version. */ + grub_uint32_t version; + + /* Available versions. */ + grub_uint32_t image_info_ver; + grub_uint32_t platform_info_ver; + grub_uint32_t machine_info_ver; + + /* Command line. */ + grub_uint32_t cmdline; + + /* List of modules infos. */ + grub_uint32_t mod_info; +}; + +struct grub_elbp64_info +{ + /* Info version. */ + grub_uint32_t version; + + /* Available versions. */ + grub_uint32_t image_info_ver; + grub_uint32_t platform_info_ver; + grub_uint32_t machine_info_ver; + + /* Command line. */ + grub_uint64_t cmdline; + + /* List of modules infos. */ + grub_uint64_t mod_info; +}; + +struct grub_elbp32_mod_info +{ + /* Address and size of occupied memory. */ + grub_uint32_t addr; + grub_uint32_t size; + + /* Module command line. */ + grub_uint32_t cmdline; + + /* Next module info or 0. */ + grub_uint32_t next; +}; + +struct grub_elbp64_mod_info +{ + /* Address and size of occupied memory. */ + grub_uint64_t addr; + grub_uint64_t size; + + /* Module command line. */ + grub_uint64_t cmdline; + + /* Next module info or 0. */ + grub_uint64_t next; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! GRUB_ELBP_HEADER */ diff -urN ../grub2.multiboot/include/grub/i386/pc/elbp.h ./include/grub/i386/pc/elbp.h --- ../grub2.multiboot/include/grub/i386/pc/elbp.h 1970-01-01 06:00:00.000000000 +0600 +++ ./include/grub/i386/pc/elbp.h 2007-06-18 16:08:44.000000000 +0700 @@ -0,0 +1,70 @@ +/* elbp.h - ELBP header file. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007 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_ELBP_MACHINE_HEADER +#define GRUB_ELBP_MACHINE_HEADER 1 + +#define GRUB_ELBP_PC_FLAG_MMAP 1 +#define GRUB_ELBP_PC_FLAG_BOOT_DEVICE 2 + +#ifndef ASM_FILE + +#include + +struct grub_elbp_pc_v0_header +{ + /* Requested information. */ + grub_uint32_t flags; + + /* Pad, must be zero. */ + grub_uint32_t pad; +}; + +struct grub_elbp32_pc_v0_info +{ + /* Provided information. */ + grub_uint32_t flags; + + /* Memory regions infos list. */ + grub_uint32_t mem_region_info; + + /* Boot device. */ + grub_uint32_t boot_device; + + /* Pad, must be zero. */ + grub_uint32_t pad; +}; + +struct grub_elbp32_pc_mem_region_info +{ + /* Memory region boundaries. */ + grub_uint64_t addr; + grub_uint64_t size; + + /* Region type. */ + grub_uint32_t type; + + /* Next memory region info or 0. */ + grub_uint32_t next; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! GRUB_ELBP_MACHINE_HEADER */ diff -urN ../grub2.multiboot/include/grub/i386/pc/kernel.h ./include/grub/i386/pc/kernel.h --- ../grub2.multiboot/include/grub/i386/pc/kernel.h 2005-09-29 06:04:26.000000000 +0700 +++ ./include/grub/i386/pc/kernel.h 2007-06-19 17:38:58.000000000 +0700 @@ -39,7 +39,7 @@ #define GRUB_KERNEL_MACHINE_PREFIX 0x1c /* The size of the first region which won't be compressed. */ -#define GRUB_KERNEL_MACHINE_RAW_SIZE 0x4A0 +#define GRUB_KERNEL_MACHINE_RAW_SIZE 0x520 #ifndef ASM_FILE diff -urN ../grub2.multiboot/include/grub/i386/pc/loader.h ./include/grub/i386/pc/loader.h --- ../grub2.multiboot/include/grub/i386/pc/loader.h 2007-06-17 18:31:53.000000000 +0700 +++ ./include/grub/i386/pc/loader.h 2007-06-18 16:35:37.000000000 +0700 @@ -22,17 +22,25 @@ #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); -/* Multiboot loader needs to know boot device. */ +/* Multiboot and ELBP loaders need to know boot device. */ extern grub_uint32_t EXPORT_VAR(grub_boot_drive); extern grub_int32_t EXPORT_VAR(grub_install_dos_part); extern grub_int32_t EXPORT_VAR(grub_install_bsd_part); +/* Multiboot and ELBP loaders need to know memory map. */ +struct grub_machine_mmap_entry; +grub_uint32_t EXPORT_FUNC(grub_get_mmap_entry) ( + struct grub_machine_mmap_entry *entry, + grub_uint32_t cont); +grub_uint32_t EXPORT_FUNC(grub_get_eisa_mmap) (void); + void EXPORT_FUNC(grub_linux_boot_zimage) (void) __attribute__ ((noreturn)); void EXPORT_FUNC(grub_linux_boot_bzimage) (void) __attribute__ ((noreturn)); @@ -40,9 +48,9 @@ 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) +/* The asm part of the multiboot and ELBP loaders. */ +void EXPORT_FUNC(grub_multiboot_real_boot) (grub_addr_t entry, + grub_uint32_t magic, void *info) __attribute__ ((noreturn)); /* It is necessary to export these functions, because normal mode commands @@ -51,5 +59,7 @@ void grub_rescue_cmd_initrd (int argc, char *argv[]); void grub_rescue_cmd_multiboot (int argc, char *argv[]); void grub_rescue_cmd_module (int argc, char *argv[]); +void grub_rescue_cmd_elbp (int argc, char *argv[]); +void grub_rescue_cmd_elbp_append (int argc, char *argv[]); #endif /* ! GRUB_LOADER_MACHINE_HEADER */ diff -urN ../grub2.multiboot/kern/i386/pc/startup.S ./kern/i386/pc/startup.S --- ../grub2.multiboot/kern/i386/pc/startup.S 2006-05-15 04:16:19.000000000 +0700 +++ ./kern/i386/pc/startup.S 2007-06-20 12:51:47.000000000 +0700 @@ -45,7 +45,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -127,11 +129,89 @@ /* entry addr */ .long multiboot_entry - _start + 0x100000 + 0x200 +/* + * Support for booting GRUB from a ELBP boot loader (e.g. GRUB itself). + */ +elbp_header: + /* magic */ + .ascii GRUB_ELBP_HDR_MAGIC_LE + /* version 0.0 */ + .long 0x00000000 + /* raw image */ + .byte GRUB_ELBP_IMAGE_RAW + /* i386 architecture */ + .byte GRUB_ELBP_ARCH_I386 + /* PC platform */ + .byte GRUB_ELBP_PLATFORM_PC + /* pad */ + .byte 0 + /* one image version */ + .word 1 + /* one platform version */ + .word 1 + /* no machine versions */ + .word 0 + /* do not align modules */ + .byte 0 + /* checksum */ + .byte 0xAE + /* raw image header version 0.0 */ + .long 0x00000004 + .long 0 + /* load offset */ + .quad _start - 0x200 - elbp_header + /* entry point offset */ + .quad multiboot_entry - elbp_header + /* load address */ + .long 0x100000 + /* load whole file */ + .long 0 + /* no bss */ + .long 0 + /* pad */ + .long 0 + /* PC platform header version 0.0 */ + .long 0x00000001 + .long 0 + /* flags: want to know boot device. */ + .long GRUB_ELBP_PC_FLAG_BOOT_DEVICE + /* pad */ + .long 0 + multiboot_entry: .code32 - /* obtain the boot device */ + cmpl $GRUB_MB_MAGIC2, %eax + je 1f + cmpl $GRUB_ELBP_INFO_MAGIC, %eax + je 2f + jmp 3f +1: + /* Multiboot version. */ + /* Obtain the boot device. */ movl 12(%ebx), %edx - + jmp 4f +2: + /* ELBP version. */ + /* Save ELBP info size in EAX. */ + xorl %eax, %eax + movb 0(%ebx), %al + shll $3, %eax + /* Save raw image info size in EDX. */ + xorl %edx, %edx + movb 4(%ebx), %dl + shll $3, %edx + /* Move EBX to PC info start. */ + addl %eax, %ebx + addl %edx, %ebx + /* Make sure BOOT_DEVICE is provided. */ + testl $GRUB_ELBP_PC_FLAG_BOOT_DEVICE, 0(%ebx) + jz 3f + /* Obtain the boot device. */ + movl 8(%ebx), %edx + jmp 4f +3: + /* FIXME: insert error handling here. */ +4: /* relocate the code */ movl $(GRUB_KERNEL_MACHINE_RAW_SIZE + 0x200), %ecx addl EXT_C(grub_compressed_size) - _start + 0x100000 + 0x200, %ecx @@ -797,14 +877,16 @@ /* - * This starts the multiboot kernel. + * This starts the multiboot or ELBP kernel. */ FUNCTION(grub_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 + /* Push magic value on the stack. */ + pushl %edx + /* Move the address of the information structure to ebx. */ + movl %ecx,%ebx /* Unload all modules and stop the floppy driver. */ call EXT_C(grub_dl_unload_all) @@ -813,8 +895,8 @@ /* Interrupts should be disabled. */ cli - /* Move the magic value into eax and jump to the kernel. */ - movl $GRUB_MB_MAGIC2,%eax + /* Pop the magic value into eax and jump to the kernel. */ + popl %eax popl %ecx jmp *%ecx diff -urN ../grub2.multiboot/loader/i386/pc/elbp.c ./loader/i386/pc/elbp.c --- ../grub2.multiboot/loader/i386/pc/elbp.c 1970-01-01 06:00:00.000000000 +0600 +++ ./loader/i386/pc/elbp.c 2007-06-20 14:04:42.000000000 +0700 @@ -0,0 +1,894 @@ +/* elbp.c - boot a ELBP OS image. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007 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 +#include +#include + +static grub_dl_t my_mod; +static struct grub_elbp32_info *info; +static struct grub_elbp32_pc_v0_info *pc_info; +static grub_size_t mod_align; +static grub_addr_t entry; + +static grub_err_t +grub_elbp_boot (void) +{ + grub_multiboot_real_boot (entry, GRUB_ELBP_INFO_MAGIC, info); + + /* Not reached. */ + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_elbp_unload (void) +{ + if (info) + { + struct grub_elbp32_mod_info *mod_info + = (struct grub_elbp32_mod_info *) info->mod_info; + + while (mod_info) + { + void *tmp = (void *) mod_info; + grub_free ((void *) mod_info->addr); + mod_info = (struct grub_elbp32_mod_info *) mod_info->next; + grub_free (tmp); + } + + if (pc_info) + { + struct grub_elbp32_pc_mem_region_info *reg_info + = (struct grub_elbp32_pc_mem_region_info *) + pc_info->mem_region_info; + + while (reg_info) + { + void *tmp = (void *) reg_info; + reg_info + = (struct grub_elbp32_pc_mem_region_info *) reg_info->next; + grub_free (tmp); + } + } + + grub_free (info); + } + + info = 0; + grub_dl_unref (my_mod); + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_elbp_load_elf32 (grub_file_t file) +{ + grub_off_t file_size = grub_file_size (file); + Elf32_Ehdr ehdr; + Elf32_Phdr phdr; + Elf32_Half i; + + if (sizeof (ehdr) > file_size) + return grub_error (GRUB_ERR_BAD_OS, "No valid ELF header found"); + + if (grub_file_seek (file, 0) == (grub_off_t) -1 + || grub_file_read (file, (char *) &ehdr, sizeof (ehdr)) != sizeof (ehdr)) + return grub_error (GRUB_ERR_READ_ERROR, "Cannot read ELF header"); + + if (grub_dl_check_header (&ehdr, sizeof (ehdr))) + return grub_error (GRUB_ERR_BAD_OS, "No valid ELF header found"); + + if (ehdr.e_type != ET_EXEC) + return grub_error (GRUB_ERR_BAD_OS, "Not an executable ELF"); + + entry = ehdr.e_entry; + + if (ehdr.e_phoff < sizeof (ehdr) + || (ehdr.e_phnum > 0 && -ehdr.e_phoff <= sizeof (phdr))) + return grub_error (GRUB_ERR_BAD_OS, "Invalid program header offset"); + + /* Load every loadable segment in memory. */ + for (i = 0; i < ehdr.e_phnum; i++) + { + Elf32_Off phent_offset = (Elf32_Off) i * ehdr.e_phentsize; + + if (-(ehdr.e_phoff + sizeof (phdr)) <= phent_offset + || ehdr.e_phoff + sizeof (phdr) + phent_offset > file_size) + return grub_error (GRUB_ERR_BAD_OS, "Invalid program header offset"); + + if (grub_file_seek (file, ehdr.e_phoff + phent_offset) + == (grub_off_t) -1 + || grub_file_read (file, (char *) &phdr, sizeof (phdr)) + != sizeof (phdr)) + return grub_error (GRUB_ERR_READ_ERROR, "Cannot read program header"); + + if (phdr.p_type == PT_LOAD) + { + if (phdr.p_filesz > phdr.p_memsz) + return grub_error (GRUB_ERR_BAD_OS, "Invalid program header"); + + if (phdr.p_memsz == 0) + continue; + + if (phdr.p_offset < sizeof (ehdr)) + return grub_error (GRUB_ERR_BAD_OS, "Invalid segment offset"); + + if (-phdr.p_offset <= phdr.p_filesz + || (phdr.p_offset + phdr.p_filesz) > file_size) + return grub_error (GRUB_ERR_BAD_OS, "Segment goes out of file"); + + if (phdr.p_paddr < grub_os_area_addr + || -phdr.p_memsz <= phdr.p_paddr + || (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, phdr.p_offset) == (grub_off_t) -1 + || grub_file_read (file, (char *) phdr.p_paddr, phdr.p_filesz) + != (grub_ssize_t) phdr.p_filesz) + return grub_error (GRUB_ERR_READ_ERROR, "Cannot read segment"); + + 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; +} + +static grub_err_t +grub_elbp_load_elf64 (grub_file_t file) +{ + grub_off_t file_size = grub_file_size (file); + Elf64_Ehdr ehdr; + Elf64_Phdr phdr; + Elf64_Half i; + + if (sizeof (ehdr) > file_size) + return grub_error (GRUB_ERR_BAD_OS, "No valid ELF header found"); + + if (grub_file_seek (file, 0) == (grub_off_t) -1 + || grub_file_read (file, (char *) &ehdr, sizeof (ehdr)) != sizeof (ehdr)) + return grub_error (GRUB_ERR_READ_ERROR, "Cannot read ELF header"); + + 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_BAD_OS, "No valid ELF header found"); + + if (ehdr.e_type != ET_EXEC) + return grub_error (GRUB_ERR_BAD_OS, "Not an executable ELF"); + + /* We still in 32-bit mode. */ + if (ehdr.e_entry > 0xffffffff) + return grub_error (GRUB_ERR_BAD_OS, "Invalid entry point for ELF64"); + + entry = ehdr.e_entry; + + if (ehdr.e_phoff < sizeof (ehdr) + || (ehdr.e_phnum > 0 && -ehdr.e_phoff <= sizeof (phdr))) + return grub_error (GRUB_ERR_BAD_OS, "Invalid program header offset"); + + /* Load every loadable segment in memory. */ + for (i = 0; i < ehdr.e_phnum; i++) + { + Elf64_Off phent_offset = (Elf32_Off) i * ehdr.e_phentsize; + + if (-(ehdr.e_phoff + sizeof (phdr)) <= phent_offset + || ehdr.e_phoff + sizeof (phdr) + phent_offset > file_size) + return grub_error (GRUB_ERR_BAD_OS, "Invalid program header offset"); + + if (grub_file_seek (file, ehdr.e_phoff + phent_offset) + == (grub_off_t) -1 + || grub_file_read (file, (char *) &phdr, sizeof (phdr)) + != sizeof (phdr)) + return grub_error (GRUB_ERR_READ_ERROR, "Cannot read program header"); + + if (phdr.p_type == PT_LOAD) + { + if (phdr.p_filesz > phdr.p_memsz) + return grub_error (GRUB_ERR_BAD_OS, "Invalid program header"); + + if (phdr.p_memsz == 0) + continue; + + if (phdr.p_offset < sizeof (ehdr)) + return grub_error (GRUB_ERR_BAD_OS, "Invalid segment offset"); + + if (-phdr.p_offset <= phdr.p_filesz + || (phdr.p_offset + phdr.p_filesz) > file_size) + return grub_error (GRUB_ERR_BAD_OS, "Segment goes out of file"); + + if (phdr.p_paddr < grub_os_area_addr + || -phdr.p_memsz <= phdr.p_paddr + || (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, phdr.p_offset) == (grub_off_t) -1 + || grub_file_read (file, (char *) phdr.p_paddr, phdr.p_filesz) + != (grub_ssize_t) phdr.p_filesz) + return grub_error (GRUB_ERR_READ_ERROR, "Cannot read segment"); + + 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; +} + +/* Load ELF32 or ELF64. */ +static grub_err_t +grub_elbp_load_elf (grub_file_t file) +{ + unsigned char e_ident[EI_NIDENT]; + + if (grub_file_seek (file, 0) == (grub_off_t) -1 + || grub_file_read (file, (char *) e_ident, EI_NIDENT) != EI_NIDENT) + return grub_error (GRUB_ERR_BAD_OS, "Cannot read ELF header"); + + if (e_ident[EI_CLASS] == ELFCLASS32) + return grub_elbp_load_elf32 (file); + else if (e_ident[EI_CLASS] == ELFCLASS64) + return grub_elbp_load_elf64 (file); + + return grub_error (GRUB_ERR_BAD_OS, "Unknown ELF class"); +} + +/* Load raw image. */ +static grub_err_t +grub_elbp_load_raw (grub_file_t file, grub_off_t hdr_offset, + const struct grub_elbp32_raw_v0_header *raw_hdr) +{ + grub_off_t file_size = grub_file_size (file); + grub_off_t load_offset = hdr_offset + raw_hdr->load_offset; + grub_off_t entry_offset = hdr_offset + raw_hdr->entry_offset; + grub_uint32_t total_size, load_size = raw_hdr->load_size; + + if (load_size == 0) + { + if (load_offset > file_size) + return grub_error (GRUB_ERR_BAD_OS, "Code and data go out of file"); + if (file_size - load_offset > 0xFFFFFFFF) + return grub_error (GRUB_ERR_BAD_OS, "Code and data size is too big"); + load_size = (grub_uint32_t) (file_size - load_offset); + } + + if (-(grub_off_t) load_size <= load_offset + || load_offset + load_size > file_size) + return grub_error (GRUB_ERR_BAD_OS, "Code and data go out of file"); + + if (entry_offset < load_offset + || entry_offset >= load_offset + load_size) + return grub_error (GRUB_ERR_BAD_OS, + "Entry point is outside of code and data area"); + + total_size = load_size + raw_hdr->bss_size; + + if (-load_size <= raw_hdr->bss_size + || raw_hdr->load_addr < grub_os_area_addr + || -total_size <= raw_hdr->load_addr + || (raw_hdr->load_addr + total_size) + > (grub_os_area_addr + grub_os_area_size)) + return grub_error (GRUB_ERR_BAD_OS, + "Kernel doesn't fit in memory reserved for the OS"); + + if (grub_file_seek (file, load_offset) == (grub_off_t) -1 + || grub_file_read (file, (char *) raw_hdr->load_addr, load_size) + != (grub_ssize_t) load_size) + return grub_error (GRUB_ERR_READ_ERROR, "Cannot read code and data"); + + grub_memset ((char *) raw_hdr->load_addr + load_size, 0, raw_hdr->bss_size); + + entry = raw_hdr->load_addr + (entry_offset - load_offset); + + return GRUB_ERR_NONE; +} + +/* Add memory region to PC info memory map. */ +static grub_err_t +add_mem_region (grub_uint64_t addr, grub_uint64_t size, grub_uint32_t type) +{ + struct grub_elbp32_pc_mem_region_info *mem_region_info, *prev; + + if (-size <= addr) + return GRUB_ERR_TEST_FAILURE; + + for (mem_region_info = + (struct grub_elbp32_pc_mem_region_info *) pc_info->mem_region_info, + prev = 0; + mem_region_info; + prev = mem_region_info, + mem_region_info = + (struct grub_elbp32_pc_mem_region_info *) mem_region_info->next) + { + if (addr < mem_region_info->addr) + { + if (addr + size > mem_region_info->addr) + return GRUB_ERR_TEST_FAILURE; + break; + } + + if (addr < mem_region_info->addr + mem_region_info->size) + return GRUB_ERR_TEST_FAILURE; + } + + mem_region_info + = grub_malloc (sizeof (struct grub_elbp32_pc_mem_region_info)); + + if (!mem_region_info) + return grub_errno; + + mem_region_info->addr = addr; + mem_region_info->size = size; + mem_region_info->type = type; + + if (!prev) + { + mem_region_info->next = pc_info->mem_region_info; + pc_info->mem_region_info = (grub_uint32_t) mem_region_info; + } + else + { + mem_region_info->next = prev->next; + prev->next = (grub_uint32_t) mem_region_info; + } + + return GRUB_ERR_NONE; +} + +void +grub_rescue_cmd_elbp (int argc, char *argv[]) +{ + grub_file_t file = 0; + char *cmdline = 0, *p; + struct grub_elbp_header hdr; + struct grub_elbp32_raw_v0_header raw_hdr; + struct grub_elbp_pc_v0_header pc_hdr; + grub_uint32_t version; + grub_off_t pos, hdr_offset, file_size; + grub_size_t len, info_size; + grub_err_t error; + int i, found_p; + grub_uint32_t image_ver = GRUB_ELBP_VERSION_NONE; + grub_uint32_t platform_ver = GRUB_ELBP_VERSION_NONE; + + 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) + goto fail; + + file_size = grub_file_size (file); + + /* Find appropriate ELBP header. */ + + for (pos = 0; pos <= file_size - sizeof (hdr); pos += 8) + { + grub_uint8_t buf[8]; + + if (grub_file_seek (file, pos) == (grub_off_t) -1 + || grub_file_read (file, (char *) &buf, 8) != 8) + { + grub_error (GRUB_ERR_READ_ERROR, "Cannot read file"); + goto fail; + } + + if (grub_memcmp (GRUB_ELBP_HDR_MAGIC_LE, buf, 8) != 0) + continue; + + if (grub_file_read (file, (char *) &version, 4) != 4) + { + grub_error (GRUB_ERR_READ_ERROR, "Cannot read file"); + goto fail; + } + + if (GRUB_ELBP_VERSION_MAJOR (version) != 0 + || GRUB_ELBP_VERSION_MINOR (version) != 0) + continue; + + if (grub_file_seek (file, pos) == (grub_off_t) -1 + || grub_file_read (file, (char *) &hdr, sizeof (hdr)) != sizeof (hdr)) + { + grub_error (GRUB_ERR_READ_ERROR, "Cannot read file"); + goto fail; + } + + if (grub_elbp_header_chksum (&hdr) != 0) + continue; + + if (hdr.arch == GRUB_ELBP_ARCH_I386 + && hdr.platform == GRUB_ELBP_PLATFORM_PC) + break; + } + + if (pos > file_size - sizeof (hdr)) + { + grub_error (GRUB_ERR_UNKNOWN_OS, "ELBP interface negotiation failed"); + goto fail; + } + + if (hdr.image != GRUB_ELBP_IMAGE_RAW + && hdr.image != GRUB_ELBP_IMAGE_ELF) + { + grub_error (GRUB_ERR_UNKNOWN_OS, "Unsupported image format"); + goto fail; + } + + if (hdr.mod_align > 28) + { + grub_error (GRUB_ERR_BAD_OS, "Module align boundary is too big"); + goto fail; + } + + hdr_offset = pos; + pos += sizeof (hdr); + + /* Negotiate image interface. */ + + found_p = (hdr.image_vers_count == 0 && hdr.image != GRUB_ELBP_IMAGE_RAW); + + for (i = 0; i < hdr.image_vers_count; + ++i, pos += (1 + GRUB_ELBP_VERSION_SIZE (version)) * 8) + { + if (pos > file_size - 8) + { + grub_error (GRUB_ERR_BAD_OS, "ELBP header goes out of file"); + goto fail; + } + + if (grub_file_seek (file, pos) == (grub_off_t) -1 + || grub_file_read (file, (char *) &version, 4) != 4) + { + grub_error (GRUB_ERR_READ_ERROR, "Cannot read ELBP image version"); + goto fail; + } + + if (found_p) + continue; + + if (version == GRUB_ELBP_VERSION_NONE) + { + if (hdr.image == GRUB_ELBP_IMAGE_RAW) + continue; + found_p = 1; + } + else if (hdr.image == GRUB_ELBP_IMAGE_RAW + && GRUB_ELBP_VERSION_MAJOR (version) == 0 + && GRUB_ELBP_VERSION_MINOR (version) == 0 + && (GRUB_ELBP_VERSION_SIZE (version) * 8) == sizeof (raw_hdr)) + { + if (pos + 8 + sizeof (raw_hdr) > file_size) + { + grub_error (GRUB_ERR_BAD_OS, "ELBP header goes out of file"); + goto fail; + } + + if (grub_file_seek (file, pos + 8) == (grub_off_t) -1 + || grub_file_read (file, (char *) &raw_hdr, sizeof (raw_hdr)) + != sizeof (raw_hdr)) + { + grub_error (GRUB_ERR_READ_ERROR, "Cannot read ELBP image header"); + goto fail; + } + + image_ver = version; + found_p = 1; + } + } + + if (!found_p) + { + grub_error (GRUB_ERR_UNKNOWN_OS, "Image interface negotiation failed"); + goto fail; + } + + /* Negotiate platform interface. */ + + found_p = (hdr.platform_vers_count == 0); + + for (i = 0; i < hdr.platform_vers_count; + ++i, pos += (1 + GRUB_ELBP_VERSION_SIZE (version)) * 8) + { + if (pos > file_size - 8) + { + grub_error (GRUB_ERR_BAD_OS, "ELBP header goes out of file "); + goto fail; + } + + if (grub_file_seek (file, pos) == (grub_off_t) -1 + || grub_file_read (file, (char *) &version, 4) != 4) + { + grub_error (GRUB_ERR_READ_ERROR, "Cannot read ELBP platform version"); + goto fail; + } + + if (found_p) + continue; + + if (version == GRUB_ELBP_VERSION_NONE) + found_p = 1; + else if (GRUB_ELBP_VERSION_MAJOR (version) == 0 + && GRUB_ELBP_VERSION_MINOR (version) == 0 + && (GRUB_ELBP_VERSION_SIZE (version) * 8) == sizeof (pc_hdr)) + { + if (pos + 8 + sizeof (pc_hdr) > file_size) + { + grub_error (GRUB_ERR_BAD_OS, "ELBP header goes out of file"); + goto fail; + } + + if (grub_file_seek (file, pos + 8) == (grub_off_t) -1 + || grub_file_read (file, (char *) &pc_hdr, sizeof (pc_hdr)) + != sizeof (pc_hdr)) + { + grub_error (GRUB_ERR_READ_ERROR, + "Cannot read ELBP platform header"); + goto fail; + } + + platform_ver = version; + found_p = 1; + } + } + + if (!found_p) + { + grub_error (GRUB_ERR_UNKNOWN_OS, "Platform interface negotiation failed"); + goto fail; + } + + /* Negotiate machine interface. */ + + found_p = (hdr.machine_vers_count == 0); + + for (i = 0; i < hdr.machine_vers_count; + ++i, pos += (1 + GRUB_ELBP_VERSION_SIZE (version)) * 8) + { + if (pos > file_size - 8) + { + grub_error (GRUB_ERR_BAD_OS, "ELBP header goes out of file"); + goto fail; + } + + if (grub_file_seek (file, pos) == (grub_off_t) -1 + || grub_file_read (file, (char *) &version, 4) != 4) + { + grub_error (GRUB_ERR_READ_ERROR, "Cannot read ELBP machine header"); + goto fail; + } + + if (found_p) + continue; + + if (version == GRUB_ELBP_VERSION_NONE) + found_p = 1; + } + + if (!found_p) + { + grub_error (GRUB_ERR_UNKNOWN_OS, "Machine interface negotiation failed"); + goto fail; + } + + if (hdr.image == GRUB_ELBP_IMAGE_RAW) + error = grub_elbp_load_raw (file, hdr_offset, &raw_hdr); + else + error = grub_elbp_load_elf (file); + + if (error != GRUB_ERR_NONE) + goto fail; + + mod_align = (grub_size_t) 1 << hdr.mod_align; + + info_size = sizeof (struct grub_elbp32_info); + + if (GRUB_ELBP_VERSION_MAJOR (platform_ver) == 0) + info_size += sizeof (struct grub_elbp32_pc_v0_info); + + info = grub_malloc (info_size); + + if (!info) + goto fail; + + grub_memset (info, 0, info_size); + + info->version + = GRUB_ELBP_VERSION (0, 0, sizeof (struct grub_elbp32_info) / 8); + + if (hdr.image == GRUB_ELBP_IMAGE_RAW) + info->image_info_ver = GRUB_ELBP_VERSION (0, 0, 0); + else + info->image_info_ver = GRUB_ELBP_VERSION_NONE; + + if (GRUB_ELBP_VERSION_MAJOR (platform_ver) == 0) + { + pc_info + = (struct grub_elbp32_pc_v0_info *) + ((char *) info + sizeof (struct grub_elbp32_info)); + info->platform_info_ver + = GRUB_ELBP_VERSION (0, 0, sizeof (struct grub_elbp32_pc_v0_info) / 8); + } + else + { + pc_info = 0; + info->platform_info_ver = GRUB_ELBP_VERSION_NONE; + } + + info->machine_info_ver = GRUB_ELBP_VERSION_NONE; + + 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'; + + info->cmdline = (grub_uint32_t) cmdline; + + if (pc_info && pc_hdr.flags & GRUB_ELBP_PC_FLAG_MMAP) + { + struct grub_machine_mmap_entry *e + = (struct grub_machine_mmap_entry *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; + grub_uint32_t cont = grub_get_mmap_entry (e, 0); + + if (e->size) + { + while (1) + { + error = add_mem_region (e->addr, e->len, e->type); + + if (error == GRUB_ERR_TEST_FAILURE) + break; + if (error != GRUB_ERR_NONE) + goto fail; + + if (cont == 0) + { + pc_info->flags |= GRUB_ELBP_PC_FLAG_MMAP; + break; + } + + cont = grub_get_mmap_entry (e, cont); + + if (e->size == 0) + { + pc_info->flags |= GRUB_ELBP_PC_FLAG_MMAP; + break; + } + } + } + else + { + grub_uint32_t eisa_mmap = grub_get_eisa_mmap (); + + if (eisa_mmap) + { + pc_info->flags |= GRUB_ELBP_PC_FLAG_MMAP; + + if ((eisa_mmap & 0xFFFF) == 0x3C00) + { + if (add_mem_region (0x100000, + (eisa_mmap << 16) + 0x100000 * 15, 1) + != GRUB_ERR_NONE) + goto fail; + } + else + { + if (add_mem_region (0x100000, (eisa_mmap & 0xFFFF) << 10, 1) + != GRUB_ERR_NONE + || add_mem_region (0x1000000, eisa_mmap << 16, 1) + != GRUB_ERR_NONE) + goto fail; + } + } + } + } + + if (pc_info && pc_hdr.flags & GRUB_ELBP_PC_FLAG_BOOT_DEVICE) + { + pc_info->flags |= GRUB_ELBP_PC_FLAG_BOOT_DEVICE; + pc_info->boot_device = grub_boot_drive << 24; + if (grub_install_dos_part > 0) + pc_info->boot_device |= 0x00FFFF | grub_install_dos_part << 16; + else if (grub_install_bsd_part > 0) + pc_info->boot_device |= 0xFF00FF | (grub_install_bsd_part << 8); + else + pc_info->boot_device |= 0xFFFFFF; + } + + grub_loader_set (grub_elbp_boot, grub_elbp_unload, 1); + +fail: + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + { + if (pc_info) + { + struct grub_elbp32_pc_mem_region_info *reg_info + = (struct grub_elbp32_pc_mem_region_info *) + pc_info->mem_region_info; + + while (reg_info) + { + void *tmp = reg_info; + reg_info + = (struct grub_elbp32_pc_mem_region_info *) reg_info->next; + grub_free (tmp); + } + } + + grub_free (cmdline); + grub_free (info); + grub_dl_unref (my_mod); + } +} + + +void +grub_rescue_cmd_elbp_append (int argc, char *argv[]) +{ + grub_file_t file = 0; + grub_off_t file_size; + grub_size_t len; + struct grub_elbp32_mod_info *prev, *mod_info = 0; + char *module = 0, *cmdline = 0, *p; + int i; + + if (argc == 0) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "No module specified"); + goto fail; + } + + if (!info) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, + "You need to load the ELBP kernel first"); + goto fail; + } + + file = grub_gzfile_open (argv[0], 1); + + if (!file) + goto fail; + + file_size = grub_file_size (file); + + if (file_size > 0x7FFFFFFF) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "File is too big"); + goto fail; + } + + module = grub_memalign (mod_align, (grub_size_t) file_size); + + if (!module) + goto fail; + + if (grub_file_read (file, module, file_size) != (grub_ssize_t) file_size) + { + grub_error (GRUB_ERR_FILE_READ_ERROR, "Cannot read file"); + goto fail; + } + + 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'; + + mod_info = grub_malloc (sizeof (struct grub_elbp32_mod_info)); + + if (!mod_info) + goto fail; + + mod_info->addr = (grub_uint32_t) module; + mod_info->size = (grub_uint32_t) file_size; + mod_info->cmdline = (grub_uint32_t) cmdline; + mod_info->next = 0; + + if (info->mod_info == 0) + info->mod_info = (grub_uint32_t) mod_info; + else + { + for (prev = (struct grub_elbp32_mod_info *) info->mod_info; + prev->next != 0; prev = (struct grub_elbp32_mod_info *) prev->next); + prev->next = (grub_uint32_t) mod_info; + } + +fail: + if (file) + grub_file_close (file); + + if (grub_errno != GRUB_ERR_NONE) + { + grub_free (module); + grub_free (mod_info); + grub_free (cmdline); + } +} + + +GRUB_MOD_INIT(elbp) +{ + grub_rescue_register_command ("elbp", grub_rescue_cmd_elbp, + "load an ELBP kernel"); + grub_rescue_register_command ( + "elbp-append", grub_rescue_cmd_elbp_append, + "load an ELBP module and append it to the modules list"); + my_mod = mod; +} + +GRUB_MOD_FINI(elbp) +{ + grub_rescue_unregister_command ("elbp"); + grub_rescue_unregister_command ("elbp-append"); +} diff -urN ../grub2.multiboot/loader/i386/pc/elbp_normal.c ./loader/i386/pc/elbp_normal.c --- ../grub2.multiboot/loader/i386/pc/elbp_normal.c 1970-01-01 06:00:00.000000000 +0600 +++ ./loader/i386/pc/elbp_normal.c 2007-06-19 17:59:42.000000000 +0700 @@ -0,0 +1,65 @@ +/* elbp_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_elbp (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + grub_rescue_cmd_elbp (argc, args); + return grub_errno; +} + + +static grub_err_t +grub_normal_cmd_elbp_append ( + struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + grub_rescue_cmd_elbp_append (argc, args); + return grub_errno; +} + +GRUB_MOD_INIT(elbp_normal) +{ + (void) mod; /* To stop warning. */ + + grub_register_command ( + "elbp", grub_normal_cmd_elbp, + GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_NO_ARG_PARSE, + "elbp FILE [ARGS...]", + "Load an ELBP kernel.", 0); + + grub_register_command ( + "elbp-append", grub_normal_cmd_elbp_append, + GRUB_COMMAND_FLAG_BOTH | GRUB_COMMAND_FLAG_NO_ARG_PARSE, + "elbp-append FILE [ARGS...]", + "Load an ELBP module and append it to the modules list.", 0); +} + +GRUB_MOD_FINI(elbp_normal) +{ + grub_unregister_command ("elbp"); + grub_unregister_command ("elbp-append"); +} diff -urN ../grub2.multiboot/loader/i386/pc/multiboot.c ./loader/i386/pc/multiboot.c --- ../grub2.multiboot/loader/i386/pc/multiboot.c 2007-06-17 19:02:10.000000000 +0700 +++ ./loader/i386/pc/multiboot.c 2007-06-18 12:50:44.000000000 +0700 @@ -49,7 +49,7 @@ static grub_err_t grub_multiboot_boot (void) { - grub_multiboot_real_boot (entry, mbi); + grub_multiboot_real_boot (entry, GRUB_MB_MAGIC2, mbi); /* Not reached. */ return GRUB_ERR_NONE;