]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
2006-04-30 Yoshinori K. Okuji <okuji@enbug.org>
authorokuji <okuji@localhost>
Sun, 30 Apr 2006 21:09:37 +0000 (21:09 +0000)
committerokuji <okuji@localhost>
Sun, 30 Apr 2006 21:09:37 +0000 (21:09 +0000)
        Extend the loader so that GRUB can accept a loader which comes
        back to GRUB when a loaded image exits. Also, this change adds
        support for a chainloader on EFI.

        * term/efi/console.c: Include grub/misc.h.
        (grub_console_checkkey): Display a scan code on the top for
        debugging. This will be removed once the EFI port gets stable.
        Correct the scan code mapping.

        * kern/efi/mm.c (sort_memory_map): Sort in a descending order to
        allocate memory from larger regions, in order to reduce the number
        of allocated regions. Otherwise, the MacOSX loader panics.
        (filter_memory_map): Avoid less than 1MB for compatibility with
        other loaders.
        (add_memory_regions): Allocate from the tail of a region, if
        possible, to avoid allocating a region near to 1MB, for the MacOSX
        loader.

        * kern/efi/init.c (grub_efi_set_prefix): Specify
        GRUB_EFI_IMAGE_HANDLE to grub_efi_get_loaded_image.

        * kern/efi/efi.c (grub_efi_get_loaded_image): Accept a new
        argument IMAGE_HANDLE and specify it to get a loaded image.
        (grub_arch_modules_addr): Specify GRUB_EFI_IMAGE_HANDLE to
        grub_efi_get_loaded_image.
        (grub_efi_get_filename): Divide the legnth by the size of
        grub_efi_char16_t.
        (grub_efi_get_device_path): New function.
        (grub_efi_print_device_path): Print End Device Path nodes. Divide
        the length by the size of grub_efi_char16_t for a file path device
        path node.

        * kern/loader.c (grub_loader_noreturn): New variable.
        (grub_loader_set): Accept a new argument NORETURN. Set
        GRUB_LOADER_NORETURN to NORETURN.
        All callers changed.
        (grub_loader_boot): If GRUB_LOADER_NORETURN is false, do not call
        grub_machine_fini.

        * include/grub/efi/efi.h (grub_efi_get_device_path): New
        prototype.
        (grub_efi_get_loaded_image): Take an argument to specify an image
        handle.

        * include/grub/loader.h (grub_loader_set): Added one more argument
        NORETURN.

        * disk/efi/efidisk.c (make_devices): Use grub_efi_get_device_path
        instead of grub_efi_open_protocol.
        (grub_efidisk_get_device_name): Likewise.
        (grub_efidisk_close): Print a newline.
        (grub_efidisk_get_device_handle): Fixed to use
        GRUB_EFI_DEVICE_PATH_SUBTYPE instead of
        GRUB_EFI_DEVICE_PATH_TYPE.

        * disk/efi/efidisk.c (device_path_guid): Moved to ...
        * kern/efi/efi.c (device_path_guid): ... here.

        * conf/i386-efi.rmk (pkgdata_MODULES): Added _chain.mod and
        chain.mod.
        (kernel_mod_HEADERS): Added efi/disk.h.
        (_chain_mod_SOURCES): New variable.
        (_chain_mod_CFLAGS): Likewise.
        (_chain_mod_LDFLAGS): Likewise.
        (chain_mod_SOURCES): Likewise.
        (chain_mod_CFLAGS): Likewise.
        (chain_mod_LDFLAGS): Likewise.

        * DISTLIST: Added include/grub/efi/chainloader.h,
        loader/efi/chainloader.c and loader/efi/chainloader_normal.c.

        * include/grub/efi/chainloader.h: New file.
        * loader/efi/chainloader.c: Likewise.
        * loader/efi/chainloader_normal.c: Likewise.

19 files changed:
ChangeLog
DISTLIST
conf/i386-efi.mk
conf/i386-efi.rmk
disk/efi/efidisk.c
include/grub/efi/chainloader.h [new file with mode: 0644]
include/grub/efi/efi.h
include/grub/loader.h
kern/efi/efi.c
kern/efi/init.c
kern/efi/mm.c
kern/loader.c
loader/efi/chainloader.c [new file with mode: 0644]
loader/efi/chainloader_normal.c [new file with mode: 0644]
loader/i386/pc/chainloader.c
loader/i386/pc/linux.c
loader/i386/pc/multiboot.c
loader/powerpc/ieee1275/linux.c
term/efi/console.c

index 2dc1b5e4d6ee1dedbcd70eb729932a7e36d5d9c7..7e157220b85605854e5ca3381c1e2d2e6b45c47a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,80 @@
+2006-04-30  Yoshinori K. Okuji  <okuji@enbug.org>
+
+       Extend the loader so that GRUB can accept a loader which comes
+       back to GRUB when a loaded image exits. Also, this change adds
+       support for a chainloader on EFI.
+       
+       * term/efi/console.c: Include grub/misc.h.
+       (grub_console_checkkey): Display a scan code on the top for
+       debugging. This will be removed once the EFI port gets stable.
+       Correct the scan code mapping.
+
+       * kern/efi/mm.c (sort_memory_map): Sort in a descending order to
+       allocate memory from larger regions, in order to reduce the number
+       of allocated regions. Otherwise, the MacOSX loader panics.
+       (filter_memory_map): Avoid less than 1MB for compatibility with
+       other loaders.
+       (add_memory_regions): Allocate from the tail of a region, if
+       possible, to avoid allocating a region near to 1MB, for the MacOSX
+       loader.
+
+       * kern/efi/init.c (grub_efi_set_prefix): Specify
+       GRUB_EFI_IMAGE_HANDLE to grub_efi_get_loaded_image.
+
+       * kern/efi/efi.c (grub_efi_get_loaded_image): Accept a new
+       argument IMAGE_HANDLE and specify it to get a loaded image.
+       (grub_arch_modules_addr): Specify GRUB_EFI_IMAGE_HANDLE to
+       grub_efi_get_loaded_image.
+       (grub_efi_get_filename): Divide the legnth by the size of
+       grub_efi_char16_t.
+       (grub_efi_get_device_path): New function.
+       (grub_efi_print_device_path): Print End Device Path nodes. Divide
+       the length by the size of grub_efi_char16_t for a file path device
+       path node.
+
+       * kern/loader.c (grub_loader_noreturn): New variable.
+       (grub_loader_set): Accept a new argument NORETURN. Set
+       GRUB_LOADER_NORETURN to NORETURN.
+       All callers changed.
+       (grub_loader_boot): If GRUB_LOADER_NORETURN is false, do not call
+       grub_machine_fini.
+
+       * include/grub/efi/efi.h (grub_efi_get_device_path): New
+       prototype.
+       (grub_efi_get_loaded_image): Take an argument to specify an image
+       handle.
+
+       * include/grub/loader.h (grub_loader_set): Added one more argument
+       NORETURN.
+
+       * disk/efi/efidisk.c (make_devices): Use grub_efi_get_device_path
+       instead of grub_efi_open_protocol.
+       (grub_efidisk_get_device_name): Likewise.
+       (grub_efidisk_close): Print a newline.
+       (grub_efidisk_get_device_handle): Fixed to use
+       GRUB_EFI_DEVICE_PATH_SUBTYPE instead of
+       GRUB_EFI_DEVICE_PATH_TYPE.
+
+       * disk/efi/efidisk.c (device_path_guid): Moved to ...
+       * kern/efi/efi.c (device_path_guid): ... here.
+
+       * conf/i386-efi.rmk (pkgdata_MODULES): Added _chain.mod and
+       chain.mod.
+       (kernel_mod_HEADERS): Added efi/disk.h.
+       (_chain_mod_SOURCES): New variable.
+       (_chain_mod_CFLAGS): Likewise.
+       (_chain_mod_LDFLAGS): Likewise.
+       (chain_mod_SOURCES): Likewise.
+       (chain_mod_CFLAGS): Likewise.
+       (chain_mod_LDFLAGS): Likewise.
+
+       * DISTLIST: Added include/grub/efi/chainloader.h,
+       loader/efi/chainloader.c and loader/efi/chainloader_normal.c.
+
+       * include/grub/efi/chainloader.h: New file.
+       * loader/efi/chainloader.c: Likewise.
+       * loader/efi/chainloader_normal.c: Likewise.
+
 2006-04-30  Marco Gerards  <marco@gnu.org>
 
        * commands/configfile.c (grub_cmd_source): New function.
index 16899fc3ac00553014431e939d0e1d562e6f6b17..3aeccc781c3728ddd98d6f6be57a69effe4a7ba6 100644 (file)
--- a/DISTLIST
+++ b/DISTLIST
@@ -113,6 +113,7 @@ include/grub/tparm.h
 include/grub/types.h
 include/grub/video.h
 include/grub/efi/api.h
+include/grub/efi/chainloader.h
 include/grub/efi/console.h
 include/grub/efi/console_control.h
 include/grub/efi/disk.h
@@ -198,6 +199,8 @@ kern/sparc64/cache.S
 kern/sparc64/dl.c
 kern/sparc64/ieee1275/init.c
 kern/sparc64/ieee1275/openfw.c
+loader/efi/chainloader.c
+loader/efi/chainloader_normal.c
 loader/i386/pc/chainloader.c
 loader/i386/pc/chainloader_normal.c
 loader/i386/pc/linux.c
index e4393a6e3600318f8354ed1d3b1f40e2a3fed78f..29bf011d07305716a5738062beda3ef375e0810b 100644 (file)
@@ -111,7 +111,7 @@ genmoddep-util_genmoddep.d: util/genmoddep.c
 #grub_install_SOURCES = util/efi/pc/grub-install.in
 
 # Modules.
-pkgdata_MODULES = kernel.mod normal.mod
+pkgdata_MODULES = kernel.mod normal.mod _chain.mod chain.mod
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -612,7 +612,7 @@ fs-kernel_mod-disk_efi_efidisk.lst: disk/efi/efidisk.c genfslist.sh
 kernel_mod_HEADERS = arg.h boot.h device.h disk.h dl.h elf.h env.h err.h \
        file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h partition.h \
        pc_partition.h rescue.h symbol.h term.h types.h \
-       i386/efi/time.h efi/efi.h efi/time.h
+       i386/efi/time.h efi/efi.h efi/time.h efi/disk.h
 kernel_mod_CFLAGS = $(COMMON_CFLAGS)
 kernel_mod_ASFLAGS = $(COMMON_ASFLAGS)
 kernel_mod_LDFLAGS = $(COMMON_LDFLAGS)
@@ -954,4 +954,116 @@ normal_mod_CFLAGS = $(COMMON_CFLAGS)
 normal_mod_ASFLAGS = $(COMMON_ASFLAGS)
 normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For _chain.mod.
+_chain_mod_SOURCES = loader/efi/chainloader.c
+CLEANFILES += _chain.mod mod-_chain.o mod-_chain.c pre-_chain.o _chain_mod-loader_efi_chainloader.o und-_chain.lst
+ifneq ($(_chain_mod_EXPORTS),no)
+CLEANFILES += def-_chain.lst
+DEFSYMFILES += def-_chain.lst
+endif
+MOSTLYCLEANFILES += _chain_mod-loader_efi_chainloader.d
+UNDSYMFILES += und-_chain.lst
+
+_chain.mod: pre-_chain.o mod-_chain.o
+       -rm -f $@
+       $(CC) $(_chain_mod_LDFLAGS) $(LDFLAGS) -Wl,-r,-d -o $@ $^
+       $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@
+
+pre-_chain.o: _chain_mod-loader_efi_chainloader.o
+       -rm -f $@
+       $(CC) $(_chain_mod_LDFLAGS) $(LDFLAGS) -Wl,-r,-d -o $@ $^
+
+mod-_chain.o: mod-_chain.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(_chain_mod_CFLAGS) -c -o $@ $<
+
+mod-_chain.c: moddep.lst genmodsrc.sh
+       sh $(srcdir)/genmodsrc.sh '_chain' $< > $@ || (rm -f $@; exit 1)
+
+ifneq ($(_chain_mod_EXPORTS),no)
+def-_chain.lst: pre-_chain.o
+       $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 _chain/' > $@
+endif
+
+und-_chain.lst: pre-_chain.o
+       echo '_chain' > $@
+       $(NM) -u -P -p $< | cut -f1 -d' ' >> $@
+
+_chain_mod-loader_efi_chainloader.o: loader/efi/chainloader.c
+       $(CC) -Iloader/efi -I$(srcdir)/loader/efi $(CPPFLAGS) $(CFLAGS) $(_chain_mod_CFLAGS) -c -o $@ $<
+
+_chain_mod-loader_efi_chainloader.d: loader/efi/chainloader.c
+       set -e;           $(CC) -Iloader/efi -I$(srcdir)/loader/efi $(CPPFLAGS) $(CFLAGS) $(_chain_mod_CFLAGS) -M $<      | sed 's,chainloader\.o[ :]*,_chain_mod-loader_efi_chainloader.o $@ : ,g' > $@;         [ -s $@ ] || rm -f $@
+
+-include _chain_mod-loader_efi_chainloader.d
+
+CLEANFILES += cmd-_chain_mod-loader_efi_chainloader.lst fs-_chain_mod-loader_efi_chainloader.lst
+COMMANDFILES += cmd-_chain_mod-loader_efi_chainloader.lst
+FSFILES += fs-_chain_mod-loader_efi_chainloader.lst
+
+cmd-_chain_mod-loader_efi_chainloader.lst: loader/efi/chainloader.c gencmdlist.sh
+       set -e;           $(CC) -Iloader/efi -I$(srcdir)/loader/efi $(CPPFLAGS) $(CFLAGS) $(_chain_mod_CFLAGS) -E $<      | sh $(srcdir)/gencmdlist.sh _chain > $@ || (rm -f $@; exit 1)
+
+fs-_chain_mod-loader_efi_chainloader.lst: loader/efi/chainloader.c genfslist.sh
+       set -e;           $(CC) -Iloader/efi -I$(srcdir)/loader/efi $(CPPFLAGS) $(CFLAGS) $(_chain_mod_CFLAGS) -E $<      | sh $(srcdir)/genfslist.sh _chain > $@ || (rm -f $@; exit 1)
+
+
+_chain_mod_CFLAGS = $(COMMON_CFLAGS)
+_chain_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For chain.mod.
+chain_mod_SOURCES = loader/efi/chainloader_normal.c
+CLEANFILES += chain.mod mod-chain.o mod-chain.c pre-chain.o chain_mod-loader_efi_chainloader_normal.o und-chain.lst
+ifneq ($(chain_mod_EXPORTS),no)
+CLEANFILES += def-chain.lst
+DEFSYMFILES += def-chain.lst
+endif
+MOSTLYCLEANFILES += chain_mod-loader_efi_chainloader_normal.d
+UNDSYMFILES += und-chain.lst
+
+chain.mod: pre-chain.o mod-chain.o
+       -rm -f $@
+       $(CC) $(chain_mod_LDFLAGS) $(LDFLAGS) -Wl,-r,-d -o $@ $^
+       $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@
+
+pre-chain.o: chain_mod-loader_efi_chainloader_normal.o
+       -rm -f $@
+       $(CC) $(chain_mod_LDFLAGS) $(LDFLAGS) -Wl,-r,-d -o $@ $^
+
+mod-chain.o: mod-chain.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(chain_mod_CFLAGS) -c -o $@ $<
+
+mod-chain.c: moddep.lst genmodsrc.sh
+       sh $(srcdir)/genmodsrc.sh 'chain' $< > $@ || (rm -f $@; exit 1)
+
+ifneq ($(chain_mod_EXPORTS),no)
+def-chain.lst: pre-chain.o
+       $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 chain/' > $@
+endif
+
+und-chain.lst: pre-chain.o
+       echo 'chain' > $@
+       $(NM) -u -P -p $< | cut -f1 -d' ' >> $@
+
+chain_mod-loader_efi_chainloader_normal.o: loader/efi/chainloader_normal.c
+       $(CC) -Iloader/efi -I$(srcdir)/loader/efi $(CPPFLAGS) $(CFLAGS) $(chain_mod_CFLAGS) -c -o $@ $<
+
+chain_mod-loader_efi_chainloader_normal.d: loader/efi/chainloader_normal.c
+       set -e;           $(CC) -Iloader/efi -I$(srcdir)/loader/efi $(CPPFLAGS) $(CFLAGS) $(chain_mod_CFLAGS) -M $<       | sed 's,chainloader_normal\.o[ :]*,chain_mod-loader_efi_chainloader_normal.o $@ : ,g' > $@;    [ -s $@ ] || rm -f $@
+
+-include chain_mod-loader_efi_chainloader_normal.d
+
+CLEANFILES += cmd-chain_mod-loader_efi_chainloader_normal.lst fs-chain_mod-loader_efi_chainloader_normal.lst
+COMMANDFILES += cmd-chain_mod-loader_efi_chainloader_normal.lst
+FSFILES += fs-chain_mod-loader_efi_chainloader_normal.lst
+
+cmd-chain_mod-loader_efi_chainloader_normal.lst: loader/efi/chainloader_normal.c gencmdlist.sh
+       set -e;           $(CC) -Iloader/efi -I$(srcdir)/loader/efi $(CPPFLAGS) $(CFLAGS) $(chain_mod_CFLAGS) -E $<       | sh $(srcdir)/gencmdlist.sh chain > $@ || (rm -f $@; exit 1)
+
+fs-chain_mod-loader_efi_chainloader_normal.lst: loader/efi/chainloader_normal.c genfslist.sh
+       set -e;           $(CC) -Iloader/efi -I$(srcdir)/loader/efi $(CPPFLAGS) $(CFLAGS) $(chain_mod_CFLAGS) -E $<       | sh $(srcdir)/genfslist.sh chain > $@ || (rm -f $@; exit 1)
+
+
+chain_mod_CFLAGS = $(COMMON_CFLAGS)
+chain_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 include $(srcdir)/conf/common.mk
index f42fb6ea4223592a111243f14bc4429e0d1de399..b1d342f36acc05bffddb9f4fefddbac14236c2ca 100644 (file)
@@ -67,7 +67,7 @@ genmoddep_SOURCES = util/genmoddep.c
 #grub_install_SOURCES = util/efi/pc/grub-install.in
 
 # Modules.
-pkgdata_MODULES = kernel.mod normal.mod
+pkgdata_MODULES = kernel.mod normal.mod _chain.mod chain.mod
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -80,7 +80,7 @@ kernel_mod_SOURCES = kern/i386/efi/startup.S kern/main.c kern/device.c \
 kernel_mod_HEADERS = arg.h boot.h device.h disk.h dl.h elf.h env.h err.h \
        file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h partition.h \
        pc_partition.h rescue.h symbol.h term.h types.h \
-       i386/efi/time.h efi/efi.h efi/time.h
+       i386/efi/time.h efi/efi.h efi/time.h efi/disk.h
 kernel_mod_CFLAGS = $(COMMON_CFLAGS)
 kernel_mod_ASFLAGS = $(COMMON_ASFLAGS)
 kernel_mod_LDFLAGS = $(COMMON_LDFLAGS)
@@ -105,4 +105,14 @@ normal_mod_CFLAGS = $(COMMON_CFLAGS)
 normal_mod_ASFLAGS = $(COMMON_ASFLAGS)
 normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For _chain.mod.
+_chain_mod_SOURCES = loader/efi/chainloader.c
+_chain_mod_CFLAGS = $(COMMON_CFLAGS)
+_chain_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For chain.mod.
+chain_mod_SOURCES = loader/efi/chainloader_normal.c
+chain_mod_CFLAGS = $(COMMON_CFLAGS)
+chain_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 include $(srcdir)/conf/common.mk
index 2daf3d39f29d8db27ec064db379d26254a3a675c..8b8b9fa8de1b38c8664f42546e593a7f840758c8 100644 (file)
@@ -41,7 +41,6 @@ struct grub_efidisk_data
 /* GUIDs.  */
 static grub_efi_guid_t disk_io_guid = GRUB_EFI_DISK_IO_GUID;
 static grub_efi_guid_t block_io_guid = GRUB_EFI_BLOCK_IO_GUID;
-static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
 
 static struct grub_efidisk_data *fd_devices;
 static struct grub_efidisk_data *hd_devices;
@@ -159,8 +158,7 @@ make_devices (void)
       grub_efi_block_io_t *bio;
       grub_efi_disk_io_t *dio;
       
-      dp = grub_efi_open_protocol (*handle, &device_path_guid,
-                                  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+      dp = grub_efi_get_device_path (*handle);
       if (! dp)
        continue;
 
@@ -556,7 +554,7 @@ static void
 grub_efidisk_close (struct grub_disk *disk __attribute__ ((unused)))
 {
   /* EFI disks do not allocate extra memory, so nothing to do here.  */
-  grub_dprintf ("efidisk", "closing %s", disk->name);
+  grub_dprintf ("efidisk", "closing %s\n", disk->name);
 }
 
 static grub_err_t
@@ -683,7 +681,7 @@ grub_efidisk_get_device_handle (grub_disk_t disk)
            
            if ((GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path)
                 == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
-               && (GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path)
+               && (GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path)
                    == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)
                && (grub_partition_get_start (disk->partition)
                    == hd.partition_start)
@@ -718,8 +716,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
 {
   grub_efi_device_path_t *dp, *ldp;
 
-  dp = grub_efi_open_protocol (handle, &device_path_guid,
-                              GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+  dp = grub_efi_get_device_path (handle);
   if (! dp)
     return 0;
 
diff --git a/include/grub/efi/chainloader.h b/include/grub/efi/chainloader.h
new file mode 100644 (file)
index 0000000..6cdb205
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006  Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GRUB_EFI_CHAINLOADER_HEADER
+#define GRUB_EFI_CHAINLOADER_HEADER    1
+
+void grub_chainloader_cmd (const char *filename);
+
+#endif /* ! GRUB_EFI_CHAINLOADER_HEADER */
index 17778fb661bdc434e9eef872289ab04f1ccad3df..f28e39241ff0d09c5219f381b8f38db4c4434535 100644 (file)
@@ -49,9 +49,11 @@ EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size,
                                      grub_efi_uintn_t *map_key,
                                      grub_efi_uintn_t *descriptor_size,
                                      grub_efi_uint32_t *descriptor_version);
-grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (void);
+grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle);
 void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp);
 char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp);
+grub_efi_device_path_t *
+EXPORT_FUNC(grub_efi_get_device_path) (grub_efi_handle_t handle);
 
 void grub_efi_mm_init (void);
 void grub_efi_mm_fini (void);
index fee758a42e14b77ff087439668edad8b2501857e..54622f52069f2bfcd8c2e479bad6a40fd310e0fb 100644 (file)
@@ -1,7 +1,7 @@
 /* loader.h - OS loaders */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2002,2003,2004  Free Software Foundation, Inc.
+ *  Copyright (C) 2002,2003,2004,2006  Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #include <grub/err.h>
 #include <grub/types.h>
 
+/* Check if a loader is loaded.  */
 int EXPORT_FUNC(grub_loader_is_loaded) (void);
+
+/* Set loader functions. NORETURN must be set to true, if BOOT won't return
+   to the original state.  */
 void EXPORT_FUNC(grub_loader_set) (grub_err_t (*boot) (void),
-                                  grub_err_t (*unload) (void));
+                                  grub_err_t (*unload) (void),
+                                  int noreturn);
+
+/* Unset current loader, if any.  */
 void EXPORT_FUNC(grub_loader_unset) (void);
 
+/* Call the boot hook in current loader. This may or may not return,
+   depending on the setting by grub_loader_set.  */
 grub_err_t EXPORT_FUNC(grub_loader_boot) (void);
 
 #endif /* ! GRUB_LOADER_HEADER */
index d41b67b47b5d82a2e1b4b5e989ff293b51733aa0..12ecc9f129bd65c37d84e2442637f8614818ed2f 100644 (file)
@@ -36,6 +36,7 @@ grub_efi_system_table_t *grub_efi_system_table;
 
 static grub_efi_guid_t console_control_guid = GRUB_EFI_CONSOLE_CONTROL_GUID;
 static grub_efi_guid_t loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID;
+static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
 
 void *
 grub_efi_locate_protocol (grub_efi_guid_t *protocol, void *registration)
@@ -144,9 +145,9 @@ grub_efi_stall (grub_efi_uintn_t microseconds)
 }
 
 grub_efi_loaded_image_t *
-grub_efi_get_loaded_image (void)
+grub_efi_get_loaded_image (grub_efi_handle_t image_handle)
 {
-  return grub_efi_open_protocol (grub_efi_image_handle,
+  return grub_efi_open_protocol (image_handle,
                                 &loaded_image_guid,
                                 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
 }
@@ -189,7 +190,7 @@ grub_arch_modules_addr (void)
   struct grub_module_info *info;
   grub_uint16_t i;
   
-  image = grub_efi_get_loaded_image ();
+  image = grub_efi_get_loaded_image (grub_efi_image_handle);
   if (! image)
     return 0;
 
@@ -248,7 +249,8 @@ grub_efi_get_filename (grub_efi_device_path_t *dp)
          else
            size = 0;
          
-         len = GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4;
+         len = ((GRUB_EFI_DEVICE_PATH_LENGTH (dp) - 4)
+                / sizeof (grub_efi_char16_t));
          p = grub_realloc (name, size + len * 4 + 1);
          if (! p)
            {
@@ -278,6 +280,13 @@ grub_efi_get_filename (grub_efi_device_path_t *dp)
   return name;
 }
 
+grub_efi_device_path_t *
+grub_efi_get_device_path (grub_efi_handle_t handle)
+{
+  return grub_efi_open_protocol (handle, &device_path_guid,
+                                GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+}
+
 /* Print the chain of Device Path nodes. This is mainly for debugging. */
 void
 grub_efi_print_device_path (grub_efi_device_path_t *dp)
@@ -294,12 +303,12 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
          switch (subtype)
            {
            case GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE:
-             /* grub_printf ("/EndEntire\n"); */
-             grub_putchar ('\n');
+             grub_printf ("/EndEntire\n");
+             //grub_putchar ('\n');
              break;
            case GRUB_EFI_END_THIS_DEVICE_PATH_SUBTYPE:
-             /* grub_printf ("/EndThis\n"); */
-             grub_putchar ('\n');
+             grub_printf ("/EndThis\n");
+             //grub_putchar ('\n');
              break;
            default:
              grub_printf ("/EndUnknown(%x)\n", (unsigned) subtype);
@@ -633,9 +642,11 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
            case GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE:
              {
                grub_efi_file_path_device_path_t *fp;
-               grub_uint8_t buf[(len - 4) * 4 + 1];
+               grub_uint8_t buf[(len - 4) * 2 + 1];
                fp = (grub_efi_file_path_device_path_t *) dp;
-               *grub_utf16_to_utf8 (buf, fp->path_name, len - 4) = '\0';
+               *grub_utf16_to_utf8 (buf, fp->path_name,
+                                    (len - 4) / sizeof (grub_efi_char16_t))
+                 = '\0';
                grub_printf ("/File(%s)", buf);
              }
              break;
index 23ca144a0bef524e88248b666f96cfbad48283dd..c74213d33d6ce117ef169a227a4ee24cdaa36c55 100644 (file)
@@ -46,7 +46,7 @@ grub_efi_set_prefix (void)
 {
   grub_efi_loaded_image_t *image;
   
-  image = grub_efi_get_loaded_image ();
+  image = grub_efi_get_loaded_image (grub_efi_image_handle);
   if (image)
     {
       char *device;
index 534432c4e7e13ce4f81e405925d646db04bf9702..2715efef489214060902b66b20fbd8e8639b4aa0 100644 (file)
@@ -184,23 +184,23 @@ sort_memory_map (grub_efi_memory_descriptor_t *memory_map,
        d1 < memory_map_end;
        d1 = NEXT_MEMORY_DESCRIPTOR (d1, desc_size))
     {
-      grub_efi_memory_descriptor_t *min_desc = d1;
+      grub_efi_memory_descriptor_t *max_desc = d1;
       
       for (d2 = NEXT_MEMORY_DESCRIPTOR (d1, desc_size);
           d2 < memory_map_end;
           d2 = NEXT_MEMORY_DESCRIPTOR (d2, desc_size))
        {
-         if (min_desc->num_pages > d2->num_pages)
-           min_desc = d2;
+         if (max_desc->num_pages < d2->num_pages)
+           max_desc = d2;
        }
 
-      if (min_desc != d1)
+      if (max_desc != d1)
        {
          grub_efi_memory_descriptor_t tmp;
 
          tmp = *d1;
-         *d1 = *min_desc;
-         *min_desc = tmp;
+         *d1 = *max_desc;
+         *max_desc = tmp;
        }
     }
 }
@@ -223,16 +223,17 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
 #if GRUB_HOST_SIZEOF_VOID_P < 8
          && desc->physical_start <= 0xffffffff
 #endif
+         && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000
          && desc->num_pages != 0)
        {
          grub_memcpy (filtered_desc, desc, desc_size);
          
-         /* Avoid the page at the address zero, because this is really
-            confusing for C programs.  */
-         if (filtered_desc->physical_start == 0)
+         /* Avoid less than 1MB, because some loaders seem to be confused.  */
+         if (desc->physical_start < 0x100000)
            {
-             filtered_desc->physical_start = 0x1000;
-             filtered_desc->num_pages--;
+             desc->num_pages -= BYTES_TO_PAGES (0x100000
+                                                - desc->physical_start);
+             desc->physical_start = 0x100000;
            }
          
 #if GRUB_HOST_SIZEOF_VOID_P < 8
@@ -285,16 +286,21 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
        desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
     {
       grub_efi_uint64_t pages;
+      grub_efi_physical_address_t start;
       void *addr;
-      
+
+      start = desc->physical_start;
       pages = desc->num_pages;
       if (pages > required_pages)
-       pages = required_pages;
+       {
+         start += PAGES_TO_BYTES (pages - required_pages);
+         pages = required_pages;
+       }
 
-      addr = grub_efi_allocate_pages (desc->physical_start, pages);
+      addr = grub_efi_allocate_pages (start, pages);
       if (! addr)
        grub_fatal ("cannot allocate conventional memory %p with %u pages",
-                   (void *) ((grub_addr_t) desc->physical_start),
+                   (void *) ((grub_addr_t) start),
                    (unsigned) pages);
 
       grub_mm_init_region (addr, PAGES_TO_BYTES (pages));
@@ -308,6 +314,27 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
     grub_fatal ("too little memory");
 }
 
+#if 0
+/* Print the memory map.  */
+static void
+print_memory_map (grub_efi_memory_descriptor_t *memory_map,
+                 grub_efi_uintn_t desc_size,
+                 grub_efi_memory_descriptor_t *memory_map_end)
+{
+  grub_efi_memory_descriptor_t *desc;
+  int i;
+  
+  for (desc = memory_map, i = 0;
+       desc < memory_map_end;
+       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size), i++)
+    {
+      grub_printf ("MD: t=%x, p=%llx, v=%llx, n=%llx, a=%llx\n",
+                  desc->type, desc->physical_start, desc->virtual_start,
+                  desc->num_pages, desc->attribute);
+    }
+}
+#endif
+
 void
 grub_efi_mm_init (void)
 {
@@ -363,6 +390,19 @@ grub_efi_mm_init (void)
   /* Allocate memory regions for GRUB's memory management.  */
   add_memory_regions (filtered_memory_map, desc_size,
                      filtered_memory_map_end, required_pages);
+
+#if 0
+  /* For debug.  */
+  map_size = MEMORY_MAP_SIZE;
+
+  if (grub_efi_get_memory_map (&map_size, memory_map, 0, &desc_size, 0) < 0)
+    grub_fatal ("cannot get memory map");
+
+  grub_printf ("printing memory map\n");
+  print_memory_map (memory_map, desc_size,
+                   NEXT_MEMORY_DESCRIPTOR (memory_map, map_size));
+  grub_abort ();
+#endif
   
   /* Release the memory maps.  */
   grub_efi_free_pages ((grub_addr_t) memory_map,
index 772ca66b99d9830c842f3243cb73a608beb6e577..b799c8bcd47d8973ce3f77f7c9fbc66cacf36cb4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2002,2003,2004  Free Software Foundation, Inc.
+ *  Copyright (C) 2002,2003,2004,2006  Free Software Foundation, Inc.
  *
  *  GRUB is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
 
 static grub_err_t (*grub_loader_boot_func) (void);
 static grub_err_t (*grub_loader_unload_func) (void);
+static int grub_loader_noreturn;
 
 static int grub_loader_loaded;
 
@@ -36,14 +37,16 @@ grub_loader_is_loaded (void)
 
 void
 grub_loader_set (grub_err_t (*boot) (void),
-                grub_err_t (*unload) (void))
+                grub_err_t (*unload) (void),
+                int noreturn)
 {
   if (grub_loader_loaded && grub_loader_unload_func)
     grub_loader_unload_func ();
   
   grub_loader_boot_func = boot;
   grub_loader_unload_func = unload;
-
+  grub_loader_noreturn = noreturn;
+  
   grub_loader_loaded = 1;
 }
 
@@ -65,7 +68,8 @@ grub_loader_boot (void)
   if (! grub_loader_loaded)
     return grub_error (GRUB_ERR_NO_KERNEL, "no loaded kernel");
 
-  grub_machine_fini ();
+  if (grub_loader_noreturn)
+    grub_machine_fini ();
   
   return (grub_loader_boot_func) ();
 }
diff --git a/loader/efi/chainloader.c b/loader/efi/chainloader.c
new file mode 100644 (file)
index 0000000..3e0df8e
--- /dev/null
@@ -0,0 +1,315 @@
+/* chainloader.c - boot another boot loader */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2004,2006  Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* TODO: support load options.  */
+
+#include <grub/loader.h>
+#include <grub/file.h>
+#include <grub/err.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/types.h>
+#include <grub/rescue.h>
+#include <grub/dl.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/disk.h>
+#include <grub/efi/chainloader.h>
+
+static grub_dl_t my_mod;
+
+static grub_efi_physical_address_t address;
+static grub_efi_uintn_t pages;
+static grub_efi_device_path_t *file_path;
+static grub_efi_handle_t image_handle;
+
+static grub_err_t
+grub_chainloader_unload (void)
+{
+  grub_efi_boot_services_t *b;
+  
+  b = grub_efi_system_table->boot_services;
+  b->unload_image (image_handle);
+  b->free_pages (address, pages);
+  grub_free (file_path);
+  
+  grub_dl_unref (my_mod);
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_chainloader_boot (void)
+{
+  grub_efi_boot_services_t *b;
+  grub_efi_status_t status;
+  grub_efi_uintn_t exit_data_size;
+  grub_efi_char16_t *exit_data;
+  
+  b = grub_efi_system_table->boot_services;
+  status = b->start_image (image_handle, &exit_data_size, &exit_data);
+  if (status != GRUB_EFI_SUCCESS)
+    {
+      if (exit_data)
+       {
+         char *buf;
+         
+         buf = grub_malloc (exit_data_size * 4 + 1);
+         if (buf)
+           {
+             *grub_utf16_to_utf8 ((grub_uint8_t *) buf,
+                                  exit_data, exit_data_size) = 0;
+             
+             grub_error (GRUB_ERR_BAD_OS, buf);
+             grub_free (buf);
+           }
+         else
+           grub_error (GRUB_ERR_BAD_OS, "unknown error");
+       }
+    }
+
+  if (exit_data)
+    b->free_pool (exit_data);
+
+  grub_chainloader_unload ();
+  
+  return grub_errno;
+}
+
+static void
+copy_file_path (grub_efi_file_path_device_path_t *fp,
+               const char *str, grub_efi_uint16_t len)
+{
+  grub_efi_char16_t *p;
+  grub_efi_uint16_t size;
+  
+  fp->header.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE;
+  fp->header.subtype = GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE;
+  size = len * sizeof (grub_efi_char16_t) + sizeof (*fp);
+  fp->header.length[0] = (grub_efi_uint8_t) (size & 0xff);
+  fp->header.length[1] = (grub_efi_uint8_t) (size >> 8);
+  for (p = fp->path_name; len > 0; len--, p++, str++)
+    {
+      /* FIXME: this assumes that the path is in ASCII.  */
+      *p = (grub_efi_char16_t) (*str == '/' ? '\\' : *str);
+    }
+}
+
+static grub_efi_device_path_t *
+make_file_path (grub_efi_device_path_t *dp, const char *filename)
+{
+  char *dir_start;
+  char *dir_end;
+  grub_size_t size;
+  grub_efi_device_path_t *d;
+
+  dir_start = grub_strchr (filename, ')');
+  if (! dir_start)
+    dir_start = (char *) filename;
+  else
+    dir_start++;
+
+  dir_end = grub_strrchr (dir_start, '/');
+  if (! dir_end)
+    {
+      grub_error (GRUB_ERR_BAD_FILENAME, "invalid EFI file path");
+      return 0;
+    }
+  
+  size = 0;
+  d = dp;
+  while (1)
+    {
+      size += GRUB_EFI_DEVICE_PATH_LENGTH (d);
+      if ((GRUB_EFI_END_ENTIRE_DEVICE_PATH (d)))
+       break;
+      d = GRUB_EFI_NEXT_DEVICE_PATH (d);
+    }
+  
+  file_path = grub_malloc (size
+                          + ((grub_strlen (dir_start) + 1)
+                             * sizeof (grub_efi_char16_t))
+                          + sizeof (grub_efi_file_path_device_path_t) * 2);
+  if (! file_path)
+    return 0;
+
+  grub_memcpy (file_path, dp, size);
+  
+  /* Fill the file path for the directory.  */
+  d = (grub_efi_device_path_t *) ((char *) file_path
+                                 + ((char *) d - (char *) dp));
+  grub_efi_print_device_path (d);
+  copy_file_path ((grub_efi_file_path_device_path_t *) d,
+                 dir_start, dir_end - dir_start);
+
+  /* Fill the file path for the file.  */
+  d = GRUB_EFI_NEXT_DEVICE_PATH (d);
+  copy_file_path ((grub_efi_file_path_device_path_t *) d,
+                 dir_end + 1, grub_strlen (dir_end + 1));
+
+  /* Fill the end of device path nodes.  */
+  d = GRUB_EFI_NEXT_DEVICE_PATH (d);
+  d->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+  d->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+  d->length[0] = sizeof (*d);
+  d->length[1] = 0;
+
+  return file_path;
+}
+
+void
+grub_chainloader_cmd (const char *filename)
+{
+  grub_file_t file = 0;
+  grub_ssize_t size;
+  grub_efi_status_t status;
+  grub_efi_boot_services_t *b;
+  grub_efi_handle_t dev_handle = 0;
+  grub_device_t dev = 0;
+  grub_efi_device_path_t *dp = 0;
+  grub_efi_loaded_image_t *loaded_image;
+  
+  grub_dl_ref (my_mod);
+
+  /* Initialize some global variables.  */
+  address = 0;
+  image_handle = 0;
+  file_path = 0;
+  
+  b = grub_efi_system_table->boot_services;
+
+  file = grub_file_open (filename);
+  if (! file)
+    goto fail;
+
+  /* Get the root device's device path.  */
+  dev = grub_device_open (0);
+  if (! dev)
+    goto fail;
+
+  if (dev->disk)
+    {
+      dev_handle = grub_efidisk_get_device_handle (dev->disk);
+      if (dev_handle)
+       dp = grub_efi_get_device_path (dev_handle);
+    }
+  
+  if (! dev->disk || ! dev_handle || ! dp)
+    {
+      grub_error (GRUB_ERR_BAD_DEVICE, "not a valid root device");
+      goto fail;
+    }
+
+  file_path = make_file_path (dp, filename);
+  if (! file_path)
+    goto fail;
+
+  grub_printf ("file path: ");
+  grub_efi_print_device_path (file_path);
+  
+  size = grub_file_size (file);
+  pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12);
+  
+  status = b->allocate_pages (GRUB_EFI_ALLOCATE_ANY_PAGES,
+                             GRUB_EFI_LOADER_CODE,
+                             pages, &address);
+  if (status != GRUB_EFI_SUCCESS)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate %u pages", pages);
+      goto fail;
+    }
+
+  if (grub_file_read (file, (void *) ((grub_addr_t) address), size) != size)
+    {
+      if (grub_errno == GRUB_ERR_NONE)
+       grub_error (GRUB_ERR_BAD_OS, "too small");
+
+      goto fail;
+    }
+
+  status = b->load_image (0, grub_efi_image_handle, file_path,
+                         (void *) ((grub_addr_t) address), size,
+                         &image_handle);
+  if (status != GRUB_EFI_SUCCESS)
+    {
+      if (status == GRUB_EFI_OUT_OF_RESOURCES)
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
+      else
+       grub_error (GRUB_ERR_BAD_OS, "cannot load image");
+      
+      goto fail;
+    }
+
+  /* LoadImage does not set a device handler when the image is
+     loaded from memory, so it is necessary to set it explicitly here.
+     This is a mess.  */
+  loaded_image = grub_efi_get_loaded_image (image_handle);
+  if (! loaded_image)
+    {
+      grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
+      goto fail;
+    }
+  loaded_image->device_handle = dev_handle;
+  
+  grub_file_close (file);
+  grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
+  return;
+  
+ fail:
+
+  if (dev)
+    grub_device_close (dev);
+  
+  if (file)
+    grub_file_close (file);
+
+  if (file_path)
+    grub_free (file_path);
+  
+  if (address)
+    b->free_pages (address, pages);
+  
+  grub_dl_unref (my_mod);
+}
+
+static void
+grub_rescue_cmd_chainloader (int argc, char *argv[])
+{
+  if (argc == 0)
+    grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
+  else
+    grub_chainloader_cmd (argv[0]);
+}
+
+static const char loader_name[] = "chainloader";
+
+GRUB_MOD_INIT(chainloader)
+{
+  grub_rescue_register_command (loader_name,
+                               grub_rescue_cmd_chainloader,
+                               "load another boot loader");
+  my_mod = mod;
+}
+
+GRUB_MOD_FINI(chainloader)
+{
+  grub_rescue_unregister_command (loader_name);
+}
diff --git a/loader/efi/chainloader_normal.c b/loader/efi/chainloader_normal.c
new file mode 100644 (file)
index 0000000..517b3b2
--- /dev/null
@@ -0,0 +1,49 @@
+/* chainloader_normal.c - boot another boot loader */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2004,2006  Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/efi/chainloader.h>
+#include <grub/err.h>
+#include <grub/normal.h>
+#include <grub/dl.h>
+
+static grub_err_t
+chainloader_command (struct grub_arg_list *state __attribute__ ((unused)),
+                    int argc, char **args)
+{
+  if (argc == 0)
+    grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
+  else
+    grub_chainloader_cmd (args[0]);
+  return grub_errno;
+}
+
+GRUB_MOD_INIT(chainloader_normal)
+{
+  (void) mod; /* To stop warning.  */
+  grub_register_command ("chainloader", chainloader_command,
+                        GRUB_COMMAND_FLAG_BOTH,
+                        "chainloader FILE",
+                        "Prepare to boot another boot loader.", 0);
+}
+
+GRUB_MOD_FINI(chainloader_normal)
+{
+  grub_unregister_command ("chainloader");
+}
index 2ac94bf1de1ac43c8d7ff2fe90abc29785ea9099..e479dc69f409fbaadf91771243ab2bb2622bb96b 100644 (file)
@@ -114,7 +114,7 @@ grub_chainloader_cmd (const char *filename, grub_chainloader_flags_t flags)
     }
 
   grub_file_close (file);
-  grub_loader_set (grub_chainloader_boot, grub_chainloader_unload);
+  grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 1);
   return;
   
  fail:
index f1a18a65a1b214f0eec38c983f549f6dbd70dc65..da62f52b1b9fde05cfaee20840134bfb7b14c26e 100644 (file)
@@ -275,7 +275,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
   if (grub_errno == GRUB_ERR_NONE)
     {
       grub_linux_prot_size = prot_size;
-      grub_loader_set (grub_linux_boot, grub_linux_unload);
+      grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
       loaded = 1;
     }
 
index 114b27bb10c2b6576fb39e058fb99d05144a1948..82dc428f1eadd8c859e40fb2bee99c5dd757370e 100644 (file)
@@ -326,7 +326,7 @@ grub_rescue_cmd_multiboot (int argc, char *argv[])
   mbi->flags |= GRUB_MB_INFO_BOOT_LOADER_NAME;
   mbi->boot_loader_name = (grub_uint32_t) grub_strdup (PACKAGE_STRING);
 
-  grub_loader_set (grub_multiboot_boot, grub_multiboot_unload);
+  grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 1);
 
  fail:
   if (file)
index b69ba5c379633d8dc264928dd84a0837ae2ce6c7..790b3731b763132ebb5569f83d22e93cb7a731db 100644 (file)
@@ -250,7 +250,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
     }
   else
     {
-      grub_loader_set (grub_linux_boot, grub_linux_unload);
+      grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
       initrd_addr = 0;
       loaded = 1;
     }
index e4de7f59abe604949c017770df92e334beac480d..d97892f439efe05d126ef60c3417f35313a6bb89 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <grub/term.h>
+#include <grub/misc.h>
 #include <grub/types.h>
 #include <grub/err.h>
 #include <grub/efi/efi.h>
@@ -70,12 +71,40 @@ grub_console_checkkey (void)
 {
   grub_efi_simple_input_interface_t *i;
   grub_efi_input_key_t key;
+  grub_efi_status_t status;
   
   if (read_key >= 0)
     return 1;
 
   i = grub_efi_system_table->con_in;
-  if (i->read_key_stroke (i, &key) == GRUB_EFI_SUCCESS)
+  status = i->read_key_stroke (i, &key);
+#if 1
+  switch (status)
+    {
+    case GRUB_EFI_SUCCESS:
+      {
+       grub_uint16_t xy;
+       
+       xy = grub_getxy ();
+       grub_gotoxy (0, 0);
+       grub_printf ("scan_code=%x,unicode_char=%x  ",
+                    (unsigned) key.scan_code,
+                    (unsigned) key.unicode_char);
+       grub_gotoxy (xy >> 8, xy & 0xff);
+      }
+      break;
+
+    case GRUB_EFI_NOT_READY:
+      //grub_printf ("not ready   ");
+      break;
+
+    default:
+      //grub_printf ("device error   ");
+      break;
+    }
+#endif
+  
+  if (status == GRUB_EFI_SUCCESS)
     {
       switch (key.scan_code)
        {
@@ -83,45 +112,41 @@ grub_console_checkkey (void)
          read_key = key.unicode_char;
          break;
        case 0x01:
-         read_key = GRUB_CONSOLE_KEY_UP;
+         read_key = 16;
          break;
        case 0x02:
-         read_key = GRUB_CONSOLE_KEY_DOWN;
+         read_key = 14;
          break;
        case 0x03:
-         read_key = GRUB_CONSOLE_KEY_RIGHT;
+         read_key = 6;
          break;
        case 0x04:
-         read_key = GRUB_CONSOLE_KEY_LEFT;
+         read_key = 2;
          break;
        case 0x05:
-         read_key = GRUB_CONSOLE_KEY_HOME;
+         read_key = 1;
          break;
        case 0x06:
-         read_key = GRUB_CONSOLE_KEY_END;
+         read_key = 5;
          break;
        case 0x07:
-         read_key = GRUB_CONSOLE_KEY_IC;
          break;
        case 0x08:
-         read_key = GRUB_CONSOLE_KEY_DC;
+         read_key = 4;
          break;
        case 0x09:
-         read_key = GRUB_CONSOLE_KEY_PPAGE;
          break;
        case 0x0a:
-         read_key = GRUB_CONSOLE_KEY_NPAGE;
+         break;
        case 0x17:
          read_key = '\e';
          break;
        default:
-         return 0;
+         break;
        }
-             
-      return 1;
     }
 
-  return 0;
+  return read_key >= 0;
 }
 
 static int
@@ -147,7 +172,7 @@ grub_console_getkey (void)
     {
       status = b->wait_for_event (1, &(i->wait_for_key), &index);
       if (status != GRUB_EFI_SUCCESS)
-       return -1;
+       return -1;
       
       grub_console_checkkey ();
     }