grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Multiboot overhaul


From: Mikhail Vorozhtsov
Subject: Multiboot overhaul
Date: Wed, 20 Jun 2007 14:34:21 +0700
User-agent: Mozilla-Thunderbird 2.0.0.0 (X11/20070601)

Hi.

I'm working on a microkernel for x86_64 (with looking forward to ppc64
and sparc64 ports). As you know, microkernels are quite useless without
user-space servers that provide "classic" OS services. But microkernels
are so useless that they even cannot load servers from disk :). That's
why bootloader need to load servers images directly into memory in
addition to image of microkernel itself. For i386-pc we have multiboot
and it "just works". But it's really too i386-pc-specific. We also have draft of next multiboot version, but I think it still lacks flexibility (e.g. single 'flags' field for all image format, platform, and machine related features requests, no versioning). So I've implemented new loader (patch attached) focused on exensibility and versioning.

Design in few words:

Interface - format and interpretation of corresponding header and info structures. Each interface has a version (X.Y, X - major number, Y - minor number, both are 12-bits wide). Version X.Z MUST be backward compatible with version X.Y if Z>Y.

Interface negotiation - bootloader procedure which selects version and header from given list of (version, header) pairs. Bootloader MUST provide info compatible with selected version with respect to the selected header.

Header consists of the following parts:
1) Generic header. Defines container version and parameters and modules alignment.
2) List of image format related (version, header) pairs*.
3) List of platform related (version, header) pairs*.
4) List of machine related (version, header) pairs*.
* - In order of preference. Special version GRUB_ELBP_VERSION_NONE means that it's ok to omit header (and provide no info) of this type.

Given this header, bootloader negotiates interfaces and constructs info structure.

Info consists of the following parts:
1) Generic info. Provides modules list and command lines.
2) Image format related info.
3) Platform related info.
4) Machine related info.

You can find more details in the code, I've tried to comment things :).
Opinions are appreciated.

P.S. Some parts of the patch haven't been well tested (e.g. ELF loading) and I haven't implemented a.out loading yet. But grub boots itself fine.
P.P.S. Patch depends on self-multiboot patch I posted few days ago.
P.P.P.S. ELBP stands for Extensible Loading and Booting Protocol :)
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 <grub/types.h>
+
+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 <grub/types.h>
+
+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 <grub/types.h>
 #include <grub/symbol.h>
+#include <grub/elbp.h>
 #include <grub/machine/multiboot.h>
 
 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 <config.h>
 #include <grub/symbol.h>
 #include <grub/boot.h>
+#include <grub/elbp.h>
 #include <grub/machine/boot.h>
+#include <grub/machine/elbp.h>
 #include <grub/machine/memory.h>
 #include <grub/machine/console.h>
 #include <grub/cpu/linux.h>
@@ -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 <grub/loader.h>
+#include <grub/elbp.h>
+#include <grub/machine/loader.h>
+#include <grub/machine/elbp.h>
+#include <grub/machine/init.h>
+#include <grub/machine/memory.h>
+#include <grub/elf.h>
+#include <grub/file.h>
+#include <grub/err.h>
+#include <grub/rescue.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/gzio.h>
+
+static grub_dl_t my_mod;
+static 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 <grub/machine/loader.h>
+#include <grub/err.h>
+#include <grub/normal.h>
+#include <grub/dl.h>
+
+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;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]