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.
This commit is contained in:
okuji 2006-04-30 21:09:37 +00:00
parent c0111d6e92
commit 7f362539b7
19 changed files with 743 additions and 64 deletions

View file

@ -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.

View file

@ -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

View 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

View 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

View 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;

View file

@ -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 */

View 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);

View 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
@ -26,11 +26,20 @@
#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 */

View 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;

View 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;

View 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)
{
@ -364,6 +391,19 @@ grub_efi_mm_init (void)
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,
2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));

View 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,13 +37,15 @@ 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) ();
}

315
loader/efi/chainloader.c Normal file
View file

@ -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);
}

View file

@ -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");
}

View 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:

View 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;
}

View 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)

View 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;
}

View 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 ();
}