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:
parent
c0111d6e92
commit
7f362539b7
19 changed files with 743 additions and 64 deletions
77
ChangeLog
77
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.
|
||||
|
|
3
DISTLIST
3
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
|
||||
|
|
116
conf/i386-efi.mk
116
conf/i386-efi.mk
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
25
include/grub/efi/chainloader.h
Normal file
25
include/grub/efi/chainloader.h
Normal 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 */
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
315
loader/efi/chainloader.c
Normal 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);
|
||||
}
|
49
loader/efi/chainloader_normal.c
Normal file
49
loader/efi/chainloader_normal.c
Normal 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");
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue