All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] New x86_64 EFI patch
@ 2008-06-20 17:04 Bean
  2008-06-21 17:04 ` Bean
  2008-07-03 18:11 ` Marco Gerards
  0 siblings, 2 replies; 45+ messages in thread
From: Bean @ 2008-06-20 17:04 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 531 bytes --]

Hi,

This new patch add the following function to the original x86_64 EFI patch:

1, Fix menu drawing problem
It maps the unicode char to EFI char so that the rectangle box is
showed properly

2, Handle command line option for chainloader command

3, Add new command appleloader
The command is used to enable bios boot in apple's bootcamp, for example

boot from legacy mbr:
appleloader HD
boot

boot from legacy cd:
appleloader CD
boot

boot from usb:
appleloader USB
boot

The usb booting may not work in some machine.

-- 
Bean

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: efi_4.diff --]
[-- Type: text/x-diff; name=efi_4.diff, Size: 116924 bytes --]

diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk
index 311b6ab..99bb0d4 100644
--- a/conf/i386-efi.rmk
+++ b/conf/i386-efi.rmk
@@ -74,8 +74,8 @@ sbin_SCRIPTS = grub-install
 grub_install_SOURCES = util/i386/efi/grub-install.in
 
 # Modules.
-pkglib_MODULES = kernel.mod normal.mod _chain.mod chain.mod \
-	_linux.mod linux.mod cpuid.mod halt.mod reboot.mod
+pkglib_MODULES = kernel.mod normal.mod _chain.mod chain.mod appleldr.mod \
+	_linux.mod linux.mod cpuid.mod halt.mod reboot.mod pci.mod lspci.mod
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -123,6 +123,11 @@ chain_mod_SOURCES = loader/efi/chainloader_normal.c
 chain_mod_CFLAGS = $(COMMON_CFLAGS)
 chain_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For appleldr.mod.
+appleldr_mod_SOURCES = loader/efi/appleloader.c
+appleldr_mod_CFLAGS = $(COMMON_CFLAGS)
+appleldr_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # For _linux.mod.
 _linux_mod_SOURCES = loader/i386/efi/linux.c
 _linux_mod_CFLAGS = $(COMMON_CFLAGS)
@@ -148,4 +153,14 @@ reboot_mod_SOURCES = commands/reboot.c
 reboot_mod_CFLAGS = $(COMMON_CFLAGS)
 reboot_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For pci.mod
+pci_mod_SOURCES = bus/pci.c
+pci_mod_CFLAGS = $(COMMON_CFLAGS)
+pci_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For lspci.mod
+lspci_mod_SOURCES = commands/lspci.c
+lspci_mod_CFLAGS = $(COMMON_CFLAGS)
+lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 include $(srcdir)/conf/common.mk
diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk
new file mode 100644
index 0000000..149e726
--- /dev/null
+++ b/conf/x86_64-efi.rmk
@@ -0,0 +1,169 @@
+# -*- makefile -*-
+
+COMMON_ASFLAGS = -nostdinc -fno-builtin -m64
+COMMON_CFLAGS = -fno-builtin -m64
+COMMON_LDFLAGS = -melf_x86_64 -nostdlib
+
+# Used by various components.  These rules need to precede them.
+normal/execute.c_DEPENDENCIES = grub_script.tab.h
+normal/command.c_DEPENDENCIES = grub_script.tab.h
+normal/function.c_DEPENDENCIES = grub_script.tab.h
+normal/lexer.c_DEPENDENCIES = grub_script.tab.h
+
+# Utilities.
+bin_UTILITIES = grub-mkimage
+#sbin_UTILITIES = grub-mkdevicemap
+#ifeq ($(enable_grub_emu), yes)
+#sbin_UTILITIES += grub-emu
+#endif
+
+# For grub-mkimage.
+grub_mkimage_SOURCES = util/i386/efi/grub-mkimage.c util/misc.c \
+	util/resolve.c
+
+# For grub-setup.
+#grub_setup_SOURCES = util/i386/pc/grub-setup.c util/biosdisk.c	\
+#	util/misc.c util/getroot.c kern/device.c kern/disk.c	\
+#	kern/err.c kern/misc.c fs/fat.c fs/ext2.c fs/xfs.c fs/affs.c	\
+#	fs/sfs.c kern/parser.c kern/partition.c partmap/pc.c		\
+#	fs/ufs.c fs/minix.c fs/hfs.c fs/jfs.c fs/hfsplus.c kern/file.c	\
+#	kern/fs.c kern/env.c fs/fshelp.c
+
+# For grub-mkdevicemap.
+grub_mkdevicemap_SOURCES = util/grub-mkdevicemap.c util/misc.c		\
+	util/i386/get_disk_name.c
+
+# For grub-emu.
+util/grub-emu.c_DEPENDENCIES = grub_emu_init.h
+grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c 	\
+	commands/configfile.c commands/help.c				\
+	commands/terminal.c commands/ls.c commands/test.c 		\
+	commands/search.c commands/hexdump.c				\
+	commands/halt.c commands/reboot.c				\
+	commands/i386/cpuid.c						\
+	disk/loopback.c							\
+	\
+	fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c			\
+	fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c		\
+	fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c			\
+	fs/ufs.c fs/xfs.c fs/afs.c					\
+	\
+	io/gzio.c							\
+	kern/device.c kern/disk.c kern/dl.c kern/elf.c kern/env.c	\
+	kern/err.c							\
+	normal/execute.c kern/file.c kern/fs.c normal/lexer.c 		\
+	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
+	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
+	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
+	normal/completion.c normal/context.c normal/main.c		\
+	normal/menu.c normal/menu_entry.c normal/misc.c normal/script.c	\
+	normal/color.c							\
+	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
+	partmap/acorn.c partmap/gpt.c					\
+	util/console.c util/hostfs.c util/grub-emu.c util/misc.c	\
+	util/biosdisk.c util/getroot.c					\
+	util/i386/pc/misc.c						\
+	\
+	disk/raid.c disk/lvm.c						\
+	grub_emu_init.c
+
+grub_emu_LDFLAGS = $(LIBCURSES)
+
+# Scripts.
+sbin_SCRIPTS = grub-install
+
+# For grub-install.
+grub_install_SOURCES = util/i386/efi/grub-install.in
+
+# Modules.
+pkglib_MODULES = kernel.mod normal.mod _chain.mod chain.mod appleldr.mod \
+	cpuid.mod halt.mod reboot.mod _linux.mod linux.mod pci.mod lspci.mod
+
+# For kernel.mod.
+kernel_mod_EXPORTS = no
+kernel_mod_SOURCES = kern/x86_64/efi/startup.S kern/x86_64/efi/callwrap.S \
+	kern/main.c kern/device.c \
+	kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
+	kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
+	kern/x86_64/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \
+	kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \
+	term/efi/console.c disk/efi/efidisk.c
+kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.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 time.h types.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)
+
+MOSTLYCLEANFILES += symlist.c
+MOSTLYCLEANFILES += symlist.c kernel_syms.lst
+DEFSYMFILES += kernel_syms.lst
+
+symlist.c: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h gensymlist.sh
+	/bin/sh gensymlist.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1)
+
+kernel_syms.lst: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h genkernsyms.sh
+	/bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1)
+
+# For normal.mod.
+normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
+	normal/completion.c normal/execute.c 		\
+	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
+	normal/menu_entry.c normal/misc.c grub_script.tab.c 		\
+	normal/script.c normal/x86_64/setjmp.S normal/color.c
+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)
+
+# For appleldr.mod.
+appleldr_mod_SOURCES = loader/efi/appleloader.c
+appleldr_mod_CFLAGS = $(COMMON_CFLAGS)
+appleldr_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For _linux.mod.
+_linux_mod_SOURCES = loader/i386/efi/linux.c
+_linux_mod_CFLAGS = $(COMMON_CFLAGS)
+_linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For linux.mod.
+linux_mod_SOURCES = loader/i386/efi/linux_normal.c
+linux_mod_CFLAGS = $(COMMON_CFLAGS)
+linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For cpuid.mod.
+cpuid_mod_SOURCES = commands/i386/cpuid.c
+cpuid_mod_CFLAGS = $(COMMON_CFLAGS)
+cpuid_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For halt.mod.
+halt_mod_SOURCES = commands/halt.c
+halt_mod_CFLAGS = $(COMMON_CFLAGS)
+halt_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For reboot.mod.
+reboot_mod_SOURCES = commands/reboot.c
+reboot_mod_CFLAGS = $(COMMON_CFLAGS)
+reboot_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For pci.mod
+pci_mod_SOURCES = bus/pci.c
+pci_mod_CFLAGS = $(COMMON_CFLAGS)
+pci_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For lspci.mod
+lspci_mod_SOURCES = commands/lspci.c
+lspci_mod_CFLAGS = $(COMMON_CFLAGS)
+lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+include $(srcdir)/conf/common.mk
diff --git a/configure.ac b/configure.ac
index 5ec7a47..a5ce826 100644
--- a/configure.ac
+++ b/configure.ac
@@ -49,11 +49,6 @@ esac
 
 case "$target_cpu" in
   i[[3456]]86) target_cpu=i386 ;;
-  x86_64) target_cpu=i386 target_m32=1 ;;
-  powerpc) ;;
-  powerpc64) target_cpu=powerpc target_m32=1;;
-  sparc64) ;;
-  *) AC_MSG_ERROR([unsupported CPU type]) ;;
 esac
 
 # Specify the platform (such as firmware).
@@ -74,9 +69,27 @@ else
   platform="$with_platform"
 fi
 
+if test "x$platform" = "xefi" ; then
+  case "$target_cpu" in
+    i386) ;;
+    x86_64) target_m64=1 ;;
+    *) AC_MSG_ERROR([unsupported CPU type for EFI]) ;;
+  esac
+else
+  case "$target_cpu" in
+    i386) ;;
+    x86_64) target_cpu=i386 target_m32=1 ;;
+    powerpc) ;;
+    powerpc64) target_cpu=powerpc target_m32=1;;
+    sparc64) ;;
+    *) AC_MSG_ERROR([unsupported CPU type]) ;;
+  esac
+fi
+
 # Sanity check.
 case "$target_cpu"-"$platform" in
   i386-efi) ;;
+  x86_64-efi) ;;
   i386-pc) ;;
   i386-linuxbios) ;;
   i386-ieee1275) ;;
@@ -238,6 +251,12 @@ if test "x$target_m32" = x1; then
   TARGET_LDFLAGS="$TARGET_LDFLAGS -m32"
 fi
 
+if test "x$target_m64" = x1; then
+  # Force 64-bit mode.
+  TARGET_CFLAGS="$TARGET_CFLAGS -m64"
+  TARGET_LDFLAGS="$TARGET_LDFLAGS -m64"
+fi
+
 #
 # Compiler features.
 #
diff --git a/disk/efi/efidisk.c b/disk/efi/efidisk.c
index e51c2ea..3c5e35f 100644
--- a/disk/efi/efidisk.c
+++ b/disk/efi/efidisk.c
@@ -574,7 +574,7 @@ grub_efidisk_read (struct grub_disk *disk, grub_disk_addr_t sector,
 		"reading 0x%x sectors at the sector 0x%llx from %s\n",
 		size, sector, disk->name);
   
-  status = dio->read (dio, bio->media->media_id,
+  status = efi_call_5 (dio->read, dio, bio->media->media_id,
 		      (grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS,
 		      (grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS,
 		      buf);
@@ -602,7 +602,7 @@ grub_efidisk_write (struct grub_disk *disk, grub_disk_addr_t sector,
 		"writing 0x%x sectors at the sector 0x%llx to %s\n",
 		size, sector, disk->name);
   
-  status = dio->write (dio, bio->media->media_id,
+  status = efi_call_5 (dio->write, dio, bio->media->media_id,
 		       (grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS,
 		       (grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS,
 		       (void *) buf);
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 6c29753..96db9a6 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -1095,4 +1095,42 @@ struct grub_efi_block_io
 };
 typedef struct grub_efi_block_io grub_efi_block_io_t;
 
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
+
+#define efi_call_0(func)		func()
+#define efi_call_1(func, a)		func(a)
+#define efi_call_2(func, a, b)		func(a, b)
+#define efi_call_3(func, a, b, c)	func(a, b, c)
+#define efi_call_4(func, a, b, c, d)	func(a, b, c, d)
+#define efi_call_5(func, a, b, c, d, e)	func(a, b, c, d, e)
+#define efi_call_6(func, a, b, c, d, e, f) func(a, b, c, d, e, f)
+
+#else
+
+#define efi_call_0(func)		efi_wrap_0(func)
+#define efi_call_1(func, a)		efi_wrap_1(func, (grub_uint64_t) a)
+#define efi_call_2(func, a, b)		efi_wrap_2(func, (grub_uint64_t) a, (grub_uint64_t) b)
+#define efi_call_3(func, a, b, c)	efi_wrap_3(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c)
+#define efi_call_4(func, a, b, c, d)	efi_wrap_4(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, (grub_uint64_t) d)
+#define efi_call_5(func, a, b, c, d, e)	efi_wrap_5(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, (grub_uint64_t) d, (grub_uint64_t) e)
+#define efi_call_6(func, a, b, c, d, e, f) efi_wrap_6(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, (grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f)
+
+grub_uint64_t EXPORT_FUNC(efi_wrap_0) (void *func);
+grub_uint64_t EXPORT_FUNC(efi_wrap_1) (void *func, grub_uint64_t arg1);
+grub_uint64_t EXPORT_FUNC(efi_wrap_2) (void *func, grub_uint64_t arg1,
+                                       grub_uint64_t arg2);
+grub_uint64_t EXPORT_FUNC(efi_wrap_3) (void *func, grub_uint64_t arg1,
+                                       grub_uint64_t arg2, grub_uint64_t arg3);
+grub_uint64_t EXPORT_FUNC(efi_wrap_4) (void *func, grub_uint64_t arg1,
+                                       grub_uint64_t arg2, grub_uint64_t arg3,
+                                       grub_uint64_t arg4);
+grub_uint64_t EXPORT_FUNC(efi_wrap_5) (void *func, grub_uint64_t arg1,
+                                       grub_uint64_t arg2, grub_uint64_t arg3,
+                                       grub_uint64_t arg4, grub_uint64_t arg5);
+grub_uint64_t EXPORT_FUNC(efi_wrap_6) (void *func, grub_uint64_t arg1,
+                                       grub_uint64_t arg2, grub_uint64_t arg3,
+                                       grub_uint64_t arg4, grub_uint64_t arg5,
+                                       grub_uint64_t arg6);
+#endif
+
 #endif /* ! GRUB_EFI_API_HEADER */
diff --git a/include/grub/efi/chainloader.h b/include/grub/efi/chainloader.h
index 470132b..d5c11e3 100644
--- a/include/grub/efi/chainloader.h
+++ b/include/grub/efi/chainloader.h
@@ -19,6 +19,6 @@
 #ifndef GRUB_EFI_CHAINLOADER_HEADER
 #define GRUB_EFI_CHAINLOADER_HEADER	1
 
-void grub_chainloader_cmd (const char *filename);
+void grub_rescue_cmd_chainloader (int argc, char *argv[]);
 
 #endif /* ! GRUB_EFI_CHAINLOADER_HEADER */
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
index b6f01a8..f2072c5 100644
--- a/include/grub/efi/pe32.h
+++ b/include/grub/efi/pe32.h
@@ -64,6 +64,7 @@ struct grub_pe32_coff_header
 };
 
 #define GRUB_PE32_MACHINE_I386		0x14c
+#define GRUB_PE32_MACHINE_X86_64	0x8664
 
 #define GRUB_PE32_RELOCS_STRIPPED		0x0001
 #define GRUB_PE32_EXECUTABLE_IMAGE		0x0002
@@ -98,9 +99,13 @@ struct grub_pe32_optional_header
   grub_uint32_t entry_addr;
   grub_uint32_t code_base;
   
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
   grub_uint32_t data_base;
-
   grub_uint32_t image_base;
+#else
+  grub_uint64_t image_base;
+#endif
+
   grub_uint32_t section_alignment;
   grub_uint32_t file_alignment;
   grub_uint16_t major_os_version;
@@ -115,10 +120,23 @@ struct grub_pe32_optional_header
   grub_uint32_t checksum;
   grub_uint16_t subsystem;
   grub_uint16_t dll_characteristics;
+
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
+
   grub_uint32_t stack_reserve_size;
   grub_uint32_t stack_commit_size;
   grub_uint32_t heap_reserve_size;
   grub_uint32_t heap_commit_size;
+
+#else
+
+  grub_uint64_t stack_reserve_size;
+  grub_uint64_t stack_commit_size;
+  grub_uint64_t heap_reserve_size;
+  grub_uint64_t heap_commit_size;
+
+#endif
+
   grub_uint32_t loader_flags;
   grub_uint32_t num_data_directories;
   
@@ -141,8 +159,16 @@ struct grub_pe32_optional_header
   struct grub_pe32_data_directory reserved_entry;
 };
 
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
+
 #define GRUB_PE32_PE32_MAGIC	0x10b
 
+#else
+
+#define GRUB_PE32_PE32_MAGIC	0x20b
+
+#endif
+
 #define GRUB_PE32_SUBSYSTEM_EFI_APPLICATION	10
 
 #define GRUB_PE32_NUM_DATA_DIRECTORIES	16
diff --git a/include/grub/efi/uga_draw.h b/include/grub/efi/uga_draw.h
new file mode 100755
index 0000000..9350430
--- /dev/null
+++ b/include/grub/efi/uga_draw.h
@@ -0,0 +1,76 @@
+/* uga_draw.h - definitions of the uga draw protocol */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* The console control protocol is not a part of the EFI spec,
+   but defined in Intel's Sample Implementation.  */
+
+#ifndef GRUB_EFI_UGA_DRAW_HEADER
+#define GRUB_EFI_UGA_DRAW_HEADER	1
+
+#define GRUB_EFI_UGA_DRAW_GUID \
+  { 0x982c298b, 0xf4fa, 0x41cb, { 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39 }}
+
+enum grub_efi_uga_blt_operation
+{
+  GRUB_EFI_UGA_VIDEO_FILL,
+  GRUB_EFI_UGA_VIDEO_TO_BLT,
+  GRUB_EFI_UGA_BLT_TO_VIDEO,
+  GRUB_EFI_UGA_VIDEO_TO_VIDEO,
+  GRUB_EFI_UGA_GLT_MAX
+};
+
+struct grub_efi_uga_pixel
+{
+  grub_uint8_t Blue;
+  grub_uint8_t Green;
+  grub_uint8_t Red;
+  grub_uint8_t Reserved;
+};
+
+struct grub_efi_uga_draw_protocol
+{
+  grub_efi_status_t
+  (*get_mode) (struct grub_efi_uga_draw_protocol *this,
+	       grub_uint32_t *width,
+	       grub_uint32_t *height,
+	       grub_uint32_t *depth,
+	       grub_uint32_t *refresh_rate);
+
+  grub_efi_status_t
+  (*set_mode) (struct grub_efi_uga_draw_protocol *this,
+	       grub_uint32_t width,
+	       grub_uint32_t height,
+	       grub_uint32_t depth,
+	       grub_uint32_t refresh_rate);
+
+  grub_efi_status_t
+  (*blt) (struct grub_efi_uga_draw_protocol *this,
+	  struct grub_efi_uga_pixel *blt_buffer,
+	  enum grub_efi_uga_blt_operation blt_operation,
+	  grub_efi_uintn_t src_x,
+	  grub_efi_uintn_t src_y,
+	  grub_efi_uintn_t dest_x,
+	  grub_efi_uintn_t dest_y,
+	  grub_efi_uintn_t width,
+	  grub_efi_uintn_t height,
+	  grub_efi_uintn_t delta);
+};
+typedef struct grub_efi_uga_draw_protocol grub_efi_uga_draw_protocol_t;
+
+#endif /* ! GRUB_EFI_UGA_DRAW_HEADER */
diff --git a/include/grub/elf.h b/include/grub/elf.h
index 9aec816..7b76f58 100644
--- a/include/grub/elf.h
+++ b/include/grub/elf.h
@@ -454,6 +454,7 @@ typedef struct
    the end of a chain, meaning no further symbols are found in that bucket.  */
 
 #define STN_UNDEF	0		/* End of a chain.  */
+#define STN_ABS		65521
 
 
 /* How to extract and insert information held in the st_other field.  */
@@ -1108,8 +1109,27 @@ typedef struct
 /* Keep this the last entry.  */
 #define R_386_NUM	   38
 
+
 /* SUN SPARC specific definitions.  */
 
+/* x86_64 specific definitions.  */
+#define R_X86_64_NONE		0
+#define R_X86_64_64		1
+#define R_X86_64_PC32		2
+#define R_X86_64_GOT32		3
+#define R_X86_64_PLT32		4
+#define R_X86_64_COPY		5
+#define R_X86_64_GLOB_DAT	6
+#define R_X86_64_JUMP_SLOT	7
+#define R_X86_64_RELATIVE	8
+#define R_X86_64_GOTPCREL	9
+#define R_X86_64_32		10
+#define R_X86_64_32S		11
+#define R_X86_64_16		12
+#define R_X86_64_PC16		13
+#define R_X86_64_8		14
+#define R_X86_64_PC8		15
+
 /* Legal values for ST_TYPE subfield of st_info (symbol type).  */
 
 #define STT_REGISTER	13		/* Global register reserved to app. */
diff --git a/include/grub/i386/efi/pci.h b/include/grub/i386/efi/pci.h
new file mode 100755
index 0000000..8480fd7
--- /dev/null
+++ b/include/grub/i386/efi/pci.h
@@ -0,0 +1,19 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/i386/pc/pci.h>
diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h
old mode 100644
new mode 100755
index 7a8e006..7ea75fe
--- a/include/grub/i386/linux.h
+++ b/include/grub/i386/linux.h
@@ -44,14 +44,44 @@
 #define GRUB_LINUX_SETUP_MOVE_SIZE	0x9100
 #define GRUB_LINUX_CL_MAGIC		0xA33F
 
+#ifdef __x86_64__
+
 #define GRUB_LINUX_EFI_SIGNATURE	\
-  ('E' << 24 | 'F' << 16 | 'I' << 8 | 'L')
+  ('4' << 24 | '6' << 16 | 'L' << 8 | 'E')
+
+#else
+
+#define GRUB_LINUX_EFI_SIGNATURE	\
+  ('2' << 24 | '3' << 16 | 'L' << 8 | 'E')
+
+#endif
+
+#define GRUB_LINUX_EFI_SIGNATURE_0204	\
+  ('L' << 24 | 'I' << 16 | 'F' << 8 | 'E')
 
 #define GRUB_LINUX_OFW_SIGNATURE	\
   (' ' << 24 | 'W' << 16 | 'F' << 8 | 'O')
 
 #ifndef ASM_FILE
 
+#define GRUB_E820_RAM        1
+#define GRUB_E820_RESERVED   2
+#define GRUB_E820_ACPI       3
+#define GRUB_E820_NVS        4
+#define GRUB_E820_EXEC_CODE  5
+
+#define GRUB_E820_MAX_ENTRY  128
+
+struct grub_e820_mmap
+{
+  grub_uint64_t addr;
+  grub_uint64_t size;
+  grub_uint32_t type;
+} __attribute__((packed));
+
+#define GRUB_VIDEO_TYPE_VLFB	0x23    /* VESA VGA in graphic mode     */
+#define GRUB_VIDEO_TYPE_EFI	0x70
+
 /* For the Linux/i386 boot protocol version 2.03.  */
 struct linux_kernel_header
 { 
@@ -67,6 +97,7 @@ struct linux_kernel_header
   grub_uint16_t vid_mode;		/* Video mode control */
   grub_uint16_t root_dev;		/* Default root device number */
   grub_uint16_t boot_flag;		/* 0xAA55 magic number */
+
   grub_uint16_t jump;			/* Jump instruction */
   grub_uint32_t header;			/* Magic signature "HdrS" */
   grub_uint16_t version;		/* Boot protocol version supported */
@@ -84,6 +115,13 @@ struct linux_kernel_header
   grub_uint16_t pad1;			/* Unused */
   char *cmd_line_ptr;			/* Points to the kernel command line */
   grub_uint32_t initrd_addr_max;        /* Highest address for initrd */
+
+  grub_uint32_t kernel_alignment;
+  grub_uint8_t relocatable_kernel;
+  grub_uint8_t pad2[3];
+  grub_uint32_t hardware_subarch;
+  grub_uint64_t hardware_subarch_data;
+  grub_uint32_t oo;
 } __attribute__ ((packed));
 
 /* Boot parameters for Linux based on 2.6.12. This is used by the setup
@@ -164,26 +202,65 @@ struct linux_kernel_params
   grub_uint32_t ofw_cif_handler;	/* b8 */
   grub_uint32_t ofw_idt;		/* bc */
 
-  grub_uint8_t padding7[0x1c0 - 0xc0];
-  
-  grub_uint32_t efi_signature;		/* 1c0 */
-  grub_uint32_t efi_system_table;	/* 1c4 */
-  grub_uint32_t efi_mem_desc_size;	/* 1c8 */
-  grub_uint32_t efi_mem_desc_version;	/* 1cc */
-  grub_uint32_t efi_mmap;		/* 1d0 */
-  grub_uint32_t efi_mmap_size;		/* 1d4 */
-  
-  grub_uint8_t padding8[0x1e0 - 0x1d8];
+  grub_uint8_t padding7[0x1b8 - 0xc0];
+
+  union
+    {
+      struct
+        {
+          grub_uint32_t efi_system_table;	/* 1b8 */
+          grub_uint32_t padding7_1;		/* 1bc */
+          grub_uint32_t efi_signature;		/* 1c0 */
+          grub_uint32_t efi_mem_desc_size;	/* 1c4 */
+          grub_uint32_t efi_mem_desc_version;	/* 1c8 */
+          grub_uint32_t efi_mmap_size;		/* 1cc */
+          grub_uint32_t efi_mmap;		/* 1d0 */
+        } v0204;
+      struct
+        {
+          grub_uint32_t padding7_1;		/* 1b8 */
+          grub_uint32_t padding7_2;		/* 1bc */
+          grub_uint32_t efi_signature;		/* 1c0 */
+          grub_uint32_t efi_system_table;	/* 1c4 */
+          grub_uint32_t efi_mem_desc_size;	/* 1c8 */
+          grub_uint32_t efi_mem_desc_version;	/* 1cc */
+          grub_uint32_t efi_mmap;		/* 1d0 */
+          grub_uint32_t efi_mmap_size;		/* 1d4 */
+          grub_uint32_t efi_system_table_hi;	/* 1d8 */
+          grub_uint32_t efi_mmap_hi;		/* 1dc */
+        } v0206;
+    };
   
   grub_uint32_t alt_mem;		/* 1e0 */
   
-  grub_uint8_t padding9[0x1e8 - 0x1e4];
+  grub_uint8_t padding8[0x1e8 - 0x1e4];
   
   grub_uint32_t mmap_size;		/* 1e8 */
 
-  grub_uint8_t padding10[0x1ff - 0x1ec];
+  grub_uint8_t padding9[0x1ff - 0x1ec];
   
   grub_uint8_t ps_mouse;		/* 1ff */
+
+  grub_uint16_t jump;			/* Jump instruction */
+  grub_uint32_t header;			/* Magic signature "HdrS" */
+  grub_uint16_t version;		/* Boot protocol version supported */
+  grub_uint32_t realmode_swtch;		/* Boot loader hook */
+  grub_uint16_t start_sys;		/* The load-low segment (obsolete) */
+  grub_uint16_t kernel_version;		/* Points to kernel version string */
+  grub_uint8_t type_of_loader;		/* Boot loader identifier */
+  grub_uint8_t loadflags;		/* Boot protocol option flags */
+  grub_uint16_t setup_move_size;	/* Move to high memory size */
+  grub_uint32_t code32_start;		/* Boot loader hook */
+  grub_uint32_t ramdisk_image;		/* initrd load address */
+  grub_uint32_t ramdisk_size;		/* initrd size */
+  grub_uint32_t bootsect_kludge;	/* obsolete */
+  grub_uint16_t heap_end_ptr;		/* Free memory after setup end */
+  grub_uint16_t pad1;			/* Unused */
+  grub_uint32_t cmd_line_ptr;		/* Points to the kernel command line */
+
+  grub_uint8_t pad2[164];		/* 22c */
+  struct grub_e820_mmap e820_map[GRUB_E820_MAX_ENTRY];	/* 2d0 */
+
 } __attribute__ ((packed));
 #endif /* ! ASM_FILE */
 
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
index 4a4e2cc..9cbbdaf 100644
--- a/include/grub/kernel.h
+++ b/include/grub/kernel.h
@@ -38,6 +38,9 @@ struct grub_module_info
 {
   /* Magic number so we know we have modules present.  */
   grub_uint32_t magic;
+#if GRUB_TARGET_SIZEOF_VOID_P == 8
+  grub_uint32_t padding;
+#endif
   /* The offset of the modules.  */
   grub_target_off_t offset;
   /* The size of all modules plus this header.  */
diff --git a/include/grub/pci.h b/include/grub/pci.h
index 7108886..abc5c90 100644
--- a/include/grub/pci.h
+++ b/include/grub/pci.h
@@ -22,6 +22,19 @@
 #include <grub/types.h>
 #include <grub/symbol.h>
 
+#define  GRUB_PCI_ADDR_SPACE_MASK	0x01
+#define  GRUB_PCI_ADDR_SPACE_MEMORY	0x00
+#define  GRUB_PCI_ADDR_SPACE_IO		0x01
+
+#define  GRUB_PCI_ADDR_MEM_TYPE_MASK	0x06
+#define  GRUB_PCI_ADDR_MEM_TYPE_32	0x00	/* 32 bit address */
+#define  GRUB_PCI_ADDR_MEM_TYPE_1M	0x02	/* Below 1M [obsolete] */
+#define  GRUB_PCI_ADDR_MEM_TYPE_64	0x04	/* 64 bit address */
+#define  GRUB_PCI_ADDR_MEM_PREFETCH	0x08	/* prefetchable */
+
+#define  GRUB_PCI_ADDR_MEM_MASK		~0xf
+#define  GRUB_PCI_ADDR_IO_MASK		~0x03
+
 typedef grub_uint32_t grub_pci_id_t;
 typedef int (*grub_pci_iteratefunc_t) (int bus, int device, int func,
 				       grub_pci_id_t pciid);
diff --git a/include/grub/x86_64/efi/kernel.h b/include/grub/x86_64/efi/kernel.h
new file mode 100644
index 0000000..c0549f4
--- /dev/null
+++ b/include/grub/x86_64/efi/kernel.h
@@ -0,0 +1,33 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2007  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MACHINE_KERNEL_HEADER
+#define GRUB_MACHINE_KERNEL_HEADER   1
+
+/* The prefix which points to the directory where GRUB modules and its
+   configuration file are located.  */
+extern char grub_prefix[];
+
+/* The offset of GRUB_PREFIX.  */
+#define GRUB_KERNEL_MACHINE_PREFIX		0x8
+
+/* End of the data section. */
+#define GRUB_KERNEL_MACHINE_DATA_END		0x50
+
+#endif /* ! GRUB_MACHINE_KERNEL_HEADER */
+
diff --git a/include/grub/x86_64/efi/loader.h b/include/grub/x86_64/efi/loader.h
new file mode 100755
index 0000000..3308be0
--- /dev/null
+++ b/include/grub/x86_64/efi/loader.h
@@ -0,0 +1,27 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2004,2006,2007  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LOADER_MACHINE_HEADER
+#define GRUB_LOADER_MACHINE_HEADER	1
+
+/* It is necessary to export these functions, because normal mode commands
+   reuse rescue mode commands.  */
+void grub_rescue_cmd_linux (int argc, char *argv[]);
+void grub_rescue_cmd_initrd (int argc, char *argv[]);
+
+#endif /* ! GRUB_LOADER_MACHINE_HEADER */
diff --git a/include/grub/x86_64/efi/machine.h b/include/grub/x86_64/efi/machine.h
new file mode 100755
index 0000000..1600768
--- /dev/null
+++ b/include/grub/x86_64/efi/machine.h
@@ -0,0 +1,24 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2007  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MACHINE_MACHINE_HEADER
+#define GRUB_MACHINE_MACHINE_HEADER	1
+
+#define GRUB_MACHINE_EFI	1
+
+#endif /* ! GRUB_MACHINE_MACHINE_HEADER */
diff --git a/include/grub/x86_64/efi/pci.h b/include/grub/x86_64/efi/pci.h
new file mode 100755
index 0000000..8480fd7
--- /dev/null
+++ b/include/grub/x86_64/efi/pci.h
@@ -0,0 +1,19 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/i386/pc/pci.h>
diff --git a/include/grub/x86_64/efi/time.h b/include/grub/x86_64/efi/time.h
new file mode 100644
index 0000000..7a9241f
--- /dev/null
+++ b/include/grub/x86_64/efi/time.h
@@ -0,0 +1,24 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MACHINE_TIME_HEADER
+#define GRUB_MACHINE_TIME_HEADER	1
+
+#include <grub/efi/time.h>
+
+#endif /* ! GRUB_MACHINE_TIME_HEADER */
diff --git a/include/grub/x86_64/linux.h b/include/grub/x86_64/linux.h
new file mode 100644
index 0000000..19ea936
--- /dev/null
+++ b/include/grub/x86_64/linux.h
@@ -0,0 +1,19 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/i386/linux.h>
diff --git a/include/grub/x86_64/setjmp.h b/include/grub/x86_64/setjmp.h
new file mode 100644
index 0000000..e417f65
--- /dev/null
+++ b/include/grub/x86_64/setjmp.h
@@ -0,0 +1,27 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003,2006,2007  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_SETJMP_CPU_HEADER
+#define GRUB_SETJMP_CPU_HEADER	1
+
+typedef unsigned long grub_jmp_buf[8];
+
+int grub_setjmp (grub_jmp_buf env);
+void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn));
+
+#endif /* ! GRUB_SETJMP_CPU_HEADER */
diff --git a/include/grub/x86_64/time.h b/include/grub/x86_64/time.h
new file mode 100644
index 0000000..842882c
--- /dev/null
+++ b/include/grub/x86_64/time.h
@@ -0,0 +1,29 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2007  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KERNEL_CPU_TIME_HEADER
+#define KERNEL_CPU_TIME_HEADER	1
+
+static __inline void
+grub_cpu_idle (void)
+{
+  /* FIXME: this can't work until we handle interrupts.  */
+/*  __asm__ __volatile__ ("hlt"); */
+}
+
+#endif /* ! KERNEL_CPU_TIME_HEADER */
diff --git a/include/grub/x86_64/types.h b/include/grub/x86_64/types.h
new file mode 100644
index 0000000..bdee5a1
--- /dev/null
+++ b/include/grub/x86_64/types.h
@@ -0,0 +1,31 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_TYPES_CPU_HEADER
+#define GRUB_TYPES_CPU_HEADER	1
+
+/* The size of void *.  */
+#define GRUB_TARGET_SIZEOF_VOID_P	8
+
+/* The size of long.  */
+#define GRUB_TARGET_SIZEOF_LONG		8
+
+/* x86_64 is little-endian.  */
+#undef GRUB_TARGET_WORDS_BIGENDIAN
+
+#endif /* ! GRUB_TYPES_CPU_HEADER */
diff --git a/kern/dl.c b/kern/dl.c
index 9e8c24a..9654c3a 100644
--- a/kern/dl.c
+++ b/kern/dl.c
@@ -29,7 +29,7 @@
 #include <grub/env.h>
 #include <grub/cache.h>
 
-#if GRUB_CPU_SIZEOF_VOID_P == 4
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
 
 typedef Elf32_Word Elf_Word;
 typedef Elf32_Addr Elf_Addr;
@@ -40,7 +40,7 @@ typedef Elf32_Sym Elf_Sym;
 # define ELF_ST_BIND(val)	ELF32_ST_BIND (val)
 # define ELF_ST_TYPE(val)	ELF32_ST_TYPE (val)
 
-#elif GRUB_CPU_SIZEOF_VOID_P == 8
+#elif GRUB_TARGET_SIZEOF_VOID_P == 8
 
 typedef Elf64_Word Elf_Word;
 typedef Elf64_Addr Elf_Addr;
diff --git a/kern/efi/efi.c b/kern/efi/efi.c
index 11dac58..d6d9c1d 100644
--- a/kern/efi/efi.c
+++ b/kern/efi/efi.c
@@ -43,9 +43,8 @@ grub_efi_locate_protocol (grub_efi_guid_t *protocol, void *registration)
   void *interface;
   grub_efi_status_t status;
   
-  status = grub_efi_system_table->boot_services->locate_protocol (protocol,
-								  registration,
-								  &interface);
+  status = efi_call_3 (grub_efi_system_table->boot_services->locate_protocol,
+                       protocol, registration, &interface);
   if (status != GRUB_EFI_SUCCESS)
     return 0;
   
@@ -71,7 +70,7 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type,
     return 0;
   
   b = grub_efi_system_table->boot_services;
-  status = b->locate_handle (search_type, protocol, search_key,
+  status = efi_call_5 (b->locate_handle, search_type, protocol, search_key,
 			     &buffer_size, buffer);
   if (status == GRUB_EFI_BUFFER_TOO_SMALL)
     {
@@ -80,7 +79,7 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type,
       if (! buffer)
 	return 0;
       
-      status = b->locate_handle (search_type, protocol, search_key,
+      status = efi_call_5 (b->locate_handle, search_type, protocol, search_key,
 				 &buffer_size, buffer);
     }
 
@@ -104,12 +103,12 @@ grub_efi_open_protocol (grub_efi_handle_t handle,
   void *interface;
   
   b = grub_efi_system_table->boot_services;
-  status = b->open_protocol (handle,
-			     protocol,
-			     &interface,
-			     grub_efi_image_handle,
-			     0,
-			     attributes);
+  status = efi_call_6 (b->open_protocol, handle,
+		       protocol,
+		       &interface,
+		       grub_efi_image_handle,
+		       0,
+		       attributes);
   if (status != GRUB_EFI_SUCCESS)
     return 0;
 
@@ -128,12 +127,12 @@ grub_efi_set_text_mode (int on)
        already in text mode. */
     return 1;
   
-  if (c->get_mode (c, &mode, 0, 0) != GRUB_EFI_SUCCESS)
+  if (efi_call_4 (c->get_mode, c, &mode, 0, 0) != GRUB_EFI_SUCCESS)
     return 0;
 
   new_mode = on ? GRUB_EFI_SCREEN_TEXT : GRUB_EFI_SCREEN_GRAPHICS;
   if (mode != new_mode)
-    if (c->set_mode (c, new_mode) != GRUB_EFI_SUCCESS)
+    if (efi_call_2 (c->set_mode, c, new_mode) != GRUB_EFI_SUCCESS)
       return 0;
 
   return 1;
@@ -142,7 +141,7 @@ grub_efi_set_text_mode (int on)
 void
 grub_efi_stall (grub_efi_uintn_t microseconds)
 {
-  grub_efi_system_table->boot_services->stall (microseconds);
+  efi_call_1 (grub_efi_system_table->boot_services->stall, microseconds);
 }
 
 grub_efi_loaded_image_t *
@@ -157,25 +156,24 @@ void
 grub_exit (void)
 {
   grub_efi_fini ();
-  grub_efi_system_table->boot_services->exit (grub_efi_image_handle,
-					      GRUB_EFI_SUCCESS,
-					      0, 0);
+  efi_call_4 (grub_efi_system_table->boot_services->exit,
+              grub_efi_image_handle, GRUB_EFI_SUCCESS, 0, 0);
 }
 
 void
 grub_reboot (void)
 {
   grub_efi_fini ();
-  grub_efi_system_table->runtime_services->
-    reset_system (GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL);
+  efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
+              GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL);
 }
 
 void
 grub_halt (void)
 {
   grub_efi_fini ();
-  grub_efi_system_table->runtime_services->
-    reset_system (GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL);
+  efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
+              GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL);
 }
 
 int
@@ -185,7 +183,7 @@ grub_efi_exit_boot_services (grub_efi_uintn_t map_key)
   grub_efi_status_t status;
   
   b = grub_efi_system_table->boot_services;
-  status = b->exit_boot_services (grub_efi_image_handle, map_key);
+  status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle, map_key);
   return status == GRUB_EFI_SUCCESS;
 }
 
@@ -196,7 +194,7 @@ grub_get_rtc (void)
   grub_efi_runtime_services_t *r;
 
   r = grub_efi_system_table->runtime_services;
-  if (r->get_time (&time, 0) != GRUB_EFI_SUCCESS)
+  if (efi_call_2 (r->get_time, &time, 0) != GRUB_EFI_SUCCESS)
     /* What is possible in this case?  */
     return 0;
 
diff --git a/kern/efi/mm.c b/kern/efi/mm.c
index 9cd096d..5098ccd 100644
--- a/kern/efi/mm.c
+++ b/kern/efi/mm.c
@@ -30,7 +30,7 @@
 
 /* The size of a memory map obtained from the firmware. This must be
    a multiplier of 4KB.  */
-#define MEMORY_MAP_SIZE	0x1000
+#define MEMORY_MAP_SIZE	0x3000
 
 /* Maintain the list of allocated pages.  */
 struct allocated_page
@@ -59,7 +59,7 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address,
   grub_efi_status_t status;
   grub_efi_boot_services_t *b;
 
-#if GRUB_CPU_SIZEOF_VOID_P < 8
+#if GRUB_TARGET_SIZEOF_VOID_P < 8
   /* Limit the memory access to less than 4GB for 32-bit platforms.  */
   if (address > 0xffffffff)
     return 0;
@@ -79,7 +79,7 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address,
 #endif
 
   b = grub_efi_system_table->boot_services;
-  status = b->allocate_pages (type, GRUB_EFI_LOADER_DATA, pages, &address);
+  status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
   if (status != GRUB_EFI_SUCCESS)
     return 0;
 
@@ -88,7 +88,7 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address,
       /* Uggh, the address 0 was allocated... This is too annoying,
 	 so reallocate another one.  */
       address = 0xffffffff;
-      status = b->allocate_pages (type, GRUB_EFI_LOADER_DATA, pages, &address);
+      status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
       grub_efi_free_pages (0, pages);
       if (status != GRUB_EFI_SUCCESS)
 	return 0;
@@ -135,7 +135,7 @@ grub_efi_free_pages (grub_efi_physical_address_t address,
     }
   
   b = grub_efi_system_table->boot_services;
-  b->free_pages (address, pages);
+  efi_call_2 (b->free_pages, address, pages);
 }
 
 /* Get the memory map as defined in the EFI spec. Return 1 if successful,
@@ -159,7 +159,7 @@ grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size,
     descriptor_version = &version;
   
   b = grub_efi_system_table->boot_services;
-  status = b->get_memory_map (memory_map_size, memory_map, map_key,
+  status = efi_call_5 (b->get_memory_map, memory_map_size, memory_map, map_key,
 			      descriptor_size, descriptor_version);
   if (status == GRUB_EFI_SUCCESS)
     return 1;
@@ -218,7 +218,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
        desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
     {
       if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
-#if GRUB_CPU_SIZEOF_VOID_P < 8
+#if GRUB_TARGET_SIZEOF_VOID_P < 8
 	  && desc->physical_start <= 0xffffffff
 #endif
 	  && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000
@@ -234,7 +234,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
 	      desc->physical_start = 0x100000;
 	    }
 	  
-#if GRUB_CPU_SIZEOF_VOID_P < 8
+#if GRUB_TARGET_SIZEOF_VOID_P < 8
 	  if (BYTES_TO_PAGES (filtered_desc->physical_start)
 	      + filtered_desc->num_pages
 	      > BYTES_TO_PAGES (0x100000000LL))
diff --git a/kern/term.c b/kern/term.c
index 4c45d71..07965b5 100644
--- a/kern/term.c
+++ b/kern/term.c
@@ -21,6 +21,7 @@
 #include <grub/mm.h>
 #include <grub/misc.h>
 #include <grub/env.h>
+#include <grub/efi/efi.h>
 
 /* The list of terminals.  */
 static grub_term_t grub_term_list;
diff --git a/kern/x86_64/dl.c b/kern/x86_64/dl.c
new file mode 100755
index 0000000..bef3270
--- /dev/null
+++ b/kern/x86_64/dl.c
@@ -0,0 +1,121 @@
+/* dl-x86_64.c - arch-dependent part of loadable module support */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2005,2007  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/elf.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+
+/* Check if EHDR is a valid ELF header.  */
+grub_err_t
+grub_arch_dl_check_header (void *ehdr)
+{
+  Elf64_Ehdr *e = ehdr;
+
+  /* Check the magic numbers.  */
+  if (e->e_ident[EI_CLASS] != ELFCLASS64
+      || e->e_ident[EI_DATA] != ELFDATA2LSB
+      || e->e_machine != EM_X86_64)
+    return grub_error (GRUB_ERR_BAD_OS, "invalid arch specific ELF magic");
+
+  return GRUB_ERR_NONE;
+}
+
+/* Relocate symbols.  */
+grub_err_t
+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
+{
+  Elf64_Ehdr *e = ehdr;
+  Elf64_Shdr *s;
+  Elf64_Sym *symtab;
+  Elf64_Word entsize;
+  unsigned i;
+
+  /* Find a symbol table.  */
+  for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf64_Shdr *) ((char *) s + e->e_shentsize))
+    if (s->sh_type == SHT_SYMTAB)
+      break;
+
+  if (i == e->e_shnum)
+    return grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
+
+  symtab = (Elf64_Sym *) ((char *) e + s->sh_offset);
+  entsize = s->sh_entsize;
+
+  for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (Elf64_Shdr *) ((char *) s + e->e_shentsize))
+    if (s->sh_type == SHT_RELA)
+      {
+	grub_dl_segment_t seg;
+
+	/* Find the target segment.  */
+	for (seg = mod->segment; seg; seg = seg->next)
+	  if (seg->section == s->sh_info)
+	    break;
+
+	if (seg)
+	  {
+	    Elf64_Rela *rel, *max;
+
+	    for (rel = (Elf64_Rela *) ((char *) e + s->sh_offset),
+		   max = rel + s->sh_size / s->sh_entsize;
+		 rel < max;
+		 rel++)
+	      {
+		Elf64_Word *addr32;
+		Elf64_Xword *addr64;
+		Elf64_Sym *sym;
+
+		if (seg->size < rel->r_offset)
+		  return grub_error (GRUB_ERR_BAD_MODULE,
+				     "reloc offset is out of the segment");
+
+		addr32 = (Elf64_Word *) ((char *) seg->addr + rel->r_offset);
+		addr64 = (Elf64_Xword *) addr32;
+		sym = (Elf64_Sym *) ((char *) symtab
+				     + entsize * ELF64_R_SYM (rel->r_info));
+
+		switch (ELF64_R_TYPE (rel->r_info))
+		  {
+		  case R_X86_64_64:
+		    *addr64 = rel->r_addend + sym->st_value;
+		    break;
+
+		  case R_X86_64_PC32:
+		    *addr32 = rel->r_addend + sym->st_value -
+		              (Elf64_Xword) seg->addr - rel->r_offset;
+		    break;
+
+                  case R_X86_64_32:
+                  case R_X86_64_32S:
+                    *addr32 = rel->r_addend + sym->st_value;
+                    break;
+
+                  default:
+                    grub_fatal ("Unrecognized relocation: %d\n", ELF64_R_TYPE (rel->r_info));
+		  }
+	      }
+	  }
+      }
+
+  return GRUB_ERR_NONE;
+}
diff --git a/kern/x86_64/efi/callwrap.S b/kern/x86_64/efi/callwrap.S
new file mode 100755
index 0000000..36e5509
--- /dev/null
+++ b/kern/x86_64/efi/callwrap.S
@@ -0,0 +1,96 @@
+/* callwrap.S - wrapper for x86_64 efi calls */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <grub/symbol.h>
+#include <grub/boot.h>
+
+/*
+ * x86_64 uses registry to pass parameters. Unfortuanately, gcc and efi use
+ * different call conversion, so we need to do some conversion.
+ *
+ * gcc:
+ *   %rdi,  %esi,  %rdx,  %rcx, %r8, %r9, 8(%rsp), 16(%rsp), ...
+ *
+ * efi:
+ *   %rcx,  %rdx,  %r8,  %r9,  32(%rsp), 40(%rsp), 48(%rsp), ...
+ *
+ */
+
+        .file   "callwrap.S"
+        .text
+
+FUNCTION(efi_wrap_0)
+	subq $40, %rsp
+	call *%rdi
+	addq $40, %rsp
+	ret
+
+FUNCTION(efi_wrap_1)
+	subq $40, %rsp
+	mov  %rsi, %rcx
+	call *%rdi
+	addq $40, %rsp
+	ret
+
+FUNCTION(efi_wrap_2)
+	subq $40, %rsp
+	mov  %rsi, %rcx
+	call *%rdi
+	addq $40, %rsp
+	ret
+
+FUNCTION(efi_wrap_3)
+	subq $40, %rsp
+	mov  %rcx, %r8
+	mov  %rsi, %rcx
+	call *%rdi
+	addq $40, %rsp
+	ret
+
+FUNCTION(efi_wrap_4)
+	subq $40, %rsp
+	mov %r8, %r9
+	mov %rcx, %r8
+	mov %rsi, %rcx
+	call *%rdi
+	addq $40, %rsp
+	ret
+
+FUNCTION(efi_wrap_5)
+	subq $40, %rsp
+	mov %r9, 32(%rsp)
+	mov %r8, %r9
+	mov %rcx, %r8
+	mov %rsi, %rcx
+	call *%rdi
+	addq $40, %rsp
+	ret
+
+FUNCTION(efi_wrap_6)
+	subq $56, %rsp
+	mov 56+8(%rsp), %rax
+	mov %rax, 40(%rsp)
+	mov %r9, (%rsp)
+	mov %r8, %r9
+	mov %rcx, %r8
+	mov %rsi, %rcx
+	call *%rdi
+	addq $56, %rsp
+	ret
diff --git a/kern/x86_64/efi/startup.S b/kern/x86_64/efi/startup.S
new file mode 100644
index 0000000..592f6a3
--- /dev/null
+++ b/kern/x86_64/efi/startup.S
@@ -0,0 +1,61 @@
+/* startup.S - bootstrap GRUB itself */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <grub/symbol.h>
+#include <grub/boot.h>
+
+        .file   "startup.S"
+        .text
+        .globl  start, _start
+start:
+_start:
+	jmp codestart
+
+        /*
+         *  Compatibility version number
+         *
+         *  These MUST be at byte offset 6 and 7 of the executable
+         *  DO NOT MOVE !!!
+         */
+        . = EXT_C(start) + 0x6
+        .byte   GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
+
+        /*
+         *  This is a special data area 8 bytes from the beginning.
+         */
+
+        . = EXT_C(start) + 0x8
+
+VARIABLE(grub_prefix)
+	/* to be filled by grub-mkimage */
+
+        /*
+         *  Leave some breathing room for the prefix.
+         */
+
+        . = EXT_C(start) + 0x50
+
+codestart:
+
+	movq	%rcx, EXT_C(grub_efi_image_handle)
+	movq	%rdx, EXT_C(grub_efi_system_table)
+
+	call	EXT_C(grub_main)
+	ret
diff --git a/loader/efi/appleloader.c b/loader/efi/appleloader.c
new file mode 100755
index 0000000..910a13d
--- /dev/null
+++ b/loader/efi/appleloader.c
@@ -0,0 +1,208 @@
+/* appleloader.c - apple legacy boot loader.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/loader.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/normal.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+
+static grub_dl_t my_mod;
+
+static grub_efi_handle_t image_handle;
+static grub_efi_char16_t *cmdline;
+
+static grub_err_t
+grub_appleloader_unload (void)
+{
+  grub_efi_boot_services_t *b;
+
+  b = grub_efi_system_table->boot_services;
+  efi_call_1 (b->unload_image, image_handle);
+
+  grub_free (cmdline);
+  cmdline = 0;
+
+  grub_dl_unref (my_mod);
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_appleloader_boot (void)
+{
+  grub_efi_boot_services_t *b;
+
+  b = grub_efi_system_table->boot_services;
+  efi_call_3 (b->start_image, image_handle, 0, 0);
+
+  grub_appleloader_unload ();
+
+  return grub_errno;
+}
+
+/* early 2006 Core Duo / Core Solo models  */
+static grub_uint8_t devpath_1[] =
+{
+  0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+  0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00,
+  0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+  0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+  0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+
+/* mid-2006 Mac Pro (and probably other Core 2 models)  */
+static grub_uint8_t devpath_2[] =
+{
+  0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+  0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0x00, 0x00, 0x00,
+  0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+  0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+  0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+
+/* mid-2007 MBP ("Santa Rosa" based models)  */
+static grub_uint8_t devpath_3[] =
+{
+  0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+  0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
+  0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+  0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+  0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+
+/* early-2008 MBA  */
+static grub_uint8_t devpath_4[] =
+{
+  0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00,
+  0xFF, 0xFF, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00,
+  0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
+  0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
+  0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
+};
+
+struct devdata
+{
+  char *model;
+  grub_efi_device_path_t *devpath;
+};
+
+struct devdata devs[] =
+{
+  {"Core Duo/Solo", (grub_efi_device_path_t *) devpath_1},
+  {"Mac Pro", (grub_efi_device_path_t *) devpath_2},
+  {"MBP", (grub_efi_device_path_t *) devpath_3},
+  {"MBA", (grub_efi_device_path_t *) devpath_4},
+  {NULL, NULL},
+};
+
+static grub_err_t
+grub_cmd_appleloader (struct grub_arg_list *state __attribute__ ((unused)),
+                      int argc, char *argv[])
+{
+  grub_efi_boot_services_t *b;
+  grub_efi_loaded_image_t *loaded_image;
+  struct devdata *pdev;
+
+  grub_dl_ref (my_mod);
+
+  /* Initialize some global variables.  */
+  image_handle = 0;
+
+  b = grub_efi_system_table->boot_services;
+
+  for (pdev = devs ; pdev->devpath ; pdev++)
+    if (efi_call_6 (b->load_image, 0, grub_efi_image_handle, pdev->devpath,
+                    NULL, 0, &image_handle) == GRUB_EFI_SUCCESS)
+      break;
+
+  if (! pdev->devpath)
+    {
+      grub_error (GRUB_ERR_BAD_OS, "can't find model");
+      goto fail;
+    }
+
+  grub_printf ("Model : %s\n", pdev->model);
+
+  loaded_image = grub_efi_get_loaded_image (image_handle);
+  if (! loaded_image)
+    {
+      grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
+      goto fail;
+    }
+
+  if (argc > 0)
+    {
+      int i, len;
+      grub_efi_char16_t *p16;
+
+      for (i = 0, len = 0; i < argc; i++)
+        len += grub_strlen (argv[i]) + 1;
+
+      len *= sizeof (grub_efi_char16_t);
+      cmdline = p16 = grub_malloc (len);
+      if (! cmdline)
+        goto fail;
+
+      for (i = 0; i < argc; i++)
+        {
+          char *p8;
+
+          p8 = argv[i];
+          while (*p8)
+            *(p16++) = *(p8++);
+
+          *(p16++) = ' ';
+        }
+      *(--p16) = 0;
+
+      loaded_image->load_options = cmdline;
+      loaded_image->load_options_size = len;
+    }
+
+  grub_loader_set (grub_appleloader_boot, grub_appleloader_unload, 0);
+
+  return 0;
+
+ fail:
+
+  grub_dl_unref (my_mod);
+  return grub_errno;
+}
+
+GRUB_MOD_INIT(appleloader)
+{
+  grub_register_command ("appleloader", grub_cmd_appleloader,
+			 GRUB_COMMAND_FLAG_BOTH,
+			 "appleloader [OPTS]",
+			 "Boot legacy system.", 0);
+
+  my_mod = mod;
+}
+
+GRUB_MOD_FINI(appleloader)
+{
+  grub_unregister_command ("appleloader");
+}
diff --git a/loader/efi/chainloader.c b/loader/efi/chainloader.c
index 19285d9..fbb7aac 100644
--- a/loader/efi/chainloader.c
+++ b/loader/efi/chainloader.c
@@ -40,6 +40,7 @@ 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_efi_char16_t *cmdline;
 
 static grub_err_t
 grub_chainloader_unload (void)
@@ -47,9 +48,12 @@ 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);
+  efi_call_1 (b->unload_image, image_handle);
+  efi_call_2 (b->free_pages, address, pages);
+
   grub_free (file_path);
+  grub_free (cmdline);
+  cmdline = 0;
   
   grub_dl_unref (my_mod);
   return GRUB_ERR_NONE;
@@ -64,7 +68,7 @@ grub_chainloader_boot (void)
   grub_efi_char16_t *exit_data;
   
   b = grub_efi_system_table->boot_services;
-  status = b->start_image (image_handle, &exit_data_size, &exit_data);
+  status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
   if (status != GRUB_EFI_SUCCESS)
     {
       if (exit_data)
@@ -86,7 +90,7 @@ grub_chainloader_boot (void)
     }
 
   if (exit_data)
-    b->free_pool (exit_data);
+    efi_call_1 (b->free_pool, exit_data);
 
   grub_chainloader_unload ();
   
@@ -175,7 +179,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
 }
 
 void
-grub_chainloader_cmd (const char *filename)
+grub_rescue_cmd_chainloader (int argc, char *argv[])
 {
   grub_file_t file = 0;
   grub_ssize_t size;
@@ -185,6 +189,14 @@ grub_chainloader_cmd (const char *filename)
   grub_device_t dev = 0;
   grub_efi_device_path_t *dp = 0;
   grub_efi_loaded_image_t *loaded_image;
+  char *filename;
+
+  if (argc == 0)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
+      return;
+    }
+  filename = argv[0];
   
   grub_dl_ref (my_mod);
 
@@ -227,7 +239,7 @@ grub_chainloader_cmd (const char *filename)
   size = grub_file_size (file);
   pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12);
   
-  status = b->allocate_pages (GRUB_EFI_ALLOCATE_ANY_PAGES,
+  status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES,
 			      GRUB_EFI_LOADER_CODE,
 			      pages, &address);
   if (status != GRUB_EFI_SUCCESS)
@@ -244,7 +256,7 @@ grub_chainloader_cmd (const char *filename)
       goto fail;
     }
 
-  status = b->load_image (0, grub_efi_image_handle, file_path,
+  status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
 			  (void *) ((grub_addr_t) address), size,
 			  &image_handle);
   if (status != GRUB_EFI_SUCCESS)
@@ -269,6 +281,36 @@ grub_chainloader_cmd (const char *filename)
   loaded_image->device_handle = dev_handle;
   
   grub_file_close (file);
+
+  if (argc > 1)
+    {
+      int i, len;
+      grub_efi_char16_t *p16;
+
+      for (i = 1, len = 0; i < argc; i++)
+        len += grub_strlen (argv[i]) + 1;
+
+      len *= sizeof (grub_efi_char16_t);
+      cmdline = p16 = grub_malloc (len);
+      if (! cmdline)
+        goto fail;
+
+      for (i = 1; i < argc; i++)
+        {
+          char *p8;
+
+          p8 = argv[i];
+          while (*p8)
+            *(p16++) = *(p8++);
+
+          *(p16++) = ' ';
+        }
+      *(--p16) = 0;
+
+      loaded_image->load_options = cmdline;
+      loaded_image->load_options_size = len;
+    }
+
   grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
   return;
   
@@ -284,20 +326,11 @@ grub_chainloader_cmd (const char *filename)
     grub_free (file_path);
   
   if (address)
-    b->free_pages (address, pages);
+    efi_call_2 (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)
diff --git a/loader/efi/chainloader_normal.c b/loader/efi/chainloader_normal.c
index 2ea3368..455669e 100644
--- a/loader/efi/chainloader_normal.c
+++ b/loader/efi/chainloader_normal.c
@@ -29,7 +29,7 @@ chainloader_command (struct grub_arg_list *state __attribute__ ((unused)),
   if (argc == 0)
     grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
   else
-    grub_chainloader_cmd (args[0]);
+    grub_rescue_cmd_chainloader (argc, args);
   return grub_errno;
 }
 
diff --git a/loader/i386/efi/linux.c b/loader/i386/efi/linux.c
index ee3fb99..d6e285f 100644
--- a/loader/i386/efi/linux.c
+++ b/loader/i386/efi/linux.c
@@ -30,6 +30,8 @@
 #include <grub/cpu/linux.h>
 #include <grub/efi/api.h>
 #include <grub/efi/efi.h>
+#include <grub/efi/uga_draw.h>
+#include <grub/pci.h>
 
 #define NEXT_MEMORY_DESCRIPTOR(desc, size)      \
   ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
@@ -60,29 +62,25 @@ static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =
 
 struct gdt_descriptor
 {
-  grub_uint16_t dummy;
   grub_uint16_t limit;
-  grub_uint32_t base;
-} __attribute__ ((aligned(4), packed));
+  void *base;
+} __attribute__ ((packed));
 
 static struct gdt_descriptor gdt_desc =
   {
-    0,
-    sizeof (gdt) - 1,
-    (grub_addr_t) gdt
+    sizeof (gdt),
+    gdt
   };
 
 struct idt_descriptor
 {
-  grub_uint16_t dummy;
   grub_uint16_t limit;
-  grub_uint32_t base;
-} __attribute__ ((aligned(4)));
+  void *base;
+} __attribute__ ((packed));
 
 static struct idt_descriptor idt_desc =
   {
     0,
-    0,
     0
   };
 
@@ -156,24 +154,28 @@ free_pages (void)
 /* Allocate pages for the real mode code and the protected mode code
    for linux as well as a memory map buffer.  */
 static int
-allocate_pages (grub_size_t real_size, grub_size_t prot_size)
+allocate_pages (grub_size_t prot_size)
 {
   grub_efi_uintn_t desc_size;
   grub_efi_memory_descriptor_t *mmap, *mmap_end;
   grub_efi_uintn_t mmap_size, tmp_mmap_size;
   grub_efi_memory_descriptor_t *desc;
+  grub_size_t real_size;
   
   /* Make sure that each size is aligned to a page boundary.  */
-  real_size = page_align (real_size + GRUB_DISK_SECTOR_SIZE);
+  real_size = page_align (sizeof (struct linux_kernel_params));
   prot_size = page_align (prot_size);
   mmap_size = find_mmap_size ();
 
+  if (real_size + mmap_size > GRUB_LINUX_CL_OFFSET)
+    grub_fatal ("Memory map too large");
+
   grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
-		real_size, prot_size, mmap_size);
+		(unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size);
   
   /* Calculate the number of pages; Combine the real mode code with
      the memory map buffer for simplicity.  */
-  real_mode_pages = ((real_size + mmap_size) >> 12);
+  real_mode_pages = (page_align (GRUB_LINUX_CL_END_OFFSET + 1) >> 12);
   prot_mode_pages = (prot_size >> 12);
   
   /* Initialize the memory pointers with NULL for convenience.  */
@@ -200,31 +202,20 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
       /* Probably it is better to put the real mode code in the traditional
 	 space for safety.  */
       if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
-	  && desc->physical_start <= 0x90000
+	  && desc->physical_start < 0xA0000
 	  && desc->num_pages >= real_mode_pages)
 	{
-	  grub_efi_physical_address_t physical_end;
-	  grub_efi_physical_address_t addr;
+          grub_efi_physical_address_t addr;
 	  
-	  physical_end = desc->physical_start + (desc->num_pages << 12);
-	  if (physical_end > 0x90000)
-	    physical_end = 0x90000;
-
-	  grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n",
-			(unsigned) desc->physical_start,
-			(unsigned) physical_end);
-	  addr = physical_end - real_size - mmap_size;
-	  if (addr < 0x10000)
-	    continue;
-
-	  grub_dprintf ("linux", "trying to allocate %u pages at %x\n",
-			real_mode_pages, (unsigned) addr);
-	  real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages);
-	  if (! real_mode_mem)
-	    grub_fatal ("cannot allocate pages");
-	  
-	  desc->num_pages -= real_mode_pages;
-	  break;
+	  addr = desc->physical_start + ((desc->num_pages - real_mode_pages) << 12);
+
+          if (addr > 0x90000)
+            addr = 0x90000;
+
+          /* There could be multiple ranges that means the condition,
+           * use the highest one. */
+          if (addr > (grub_efi_physical_address_t) real_mode_mem)
+            real_mode_mem = (void *) addr;
 	}
     }
 
@@ -233,6 +224,12 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
       grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
       goto fail;
     }
+  else
+    {
+      real_mode_mem = grub_efi_allocate_pages (real_mode_mem, real_mode_pages);
+      if (! real_mode_mem)
+        grub_fatal ("cannot allocate pages");
+    }
 
   mmap_buf = (void *) ((char *) real_mode_mem + real_size);
 	      
@@ -246,6 +243,11 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
       goto fail;
     }
 
+  grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, "
+                "prot_mode_mem = %lx, prot_mode_pages = %x\n",
+                (unsigned long) real_mode_mem, (unsigned) real_mode_pages,
+                (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages);
+
   grub_free (mmap);
   return 1;
 
@@ -255,56 +257,193 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size)
   return 0;
 }
 
+static void
+grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
+                      grub_uint64_t start, grub_uint64_t size,
+                      grub_uint32_t type)
+{
+  int n = *e820_num;
+
+  if (n >= GRUB_E820_MAX_ENTRY)
+    grub_fatal ("Too many e820 memory map entries");
+
+  if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
+      (e820_map[n - 1].type == type))
+      e820_map[n - 1].size += size;
+  else
+    {
+      e820_map[n].addr = start;
+      e820_map[n].size = size;
+      e820_map[n].type = type;
+      (*e820_num)++;
+    }
+}
+
+#ifdef __x86_64__
+struct
+{
+  grub_uint32_t kernel_entry;
+  grub_uint32_t kernel_cs;
+} jumpvector;
+void *jump_start;
+#else
+grub_uint32_t kernel_entry;
+#endif
+
 static grub_err_t
 grub_linux_boot (void)
 {
-  struct linux_kernel_header *lh;
   struct linux_kernel_params *params;
   grub_efi_uintn_t mmap_size;
   grub_efi_uintn_t map_key;
   grub_efi_uintn_t desc_size;
   grub_efi_uint32_t desc_version;
+  grub_efi_memory_descriptor_t *desc;
+  int e820_num;
   
-  lh = real_mode_mem;
   params = real_mode_mem;
 
   grub_dprintf ("linux", "code32_start = %x, idt_desc = %x, gdt_desc = %x\n",
-		(unsigned) lh->code32_start, (grub_addr_t) &(idt_desc.limit),
+		(unsigned) params->code32_start, (grub_addr_t) &(idt_desc.limit),
 		(grub_addr_t) &(gdt_desc.limit));
   grub_dprintf ("linux", "idt = %x:%x, gdt = %x:%x\n",
 		(unsigned) idt_desc.limit, (unsigned) idt_desc.base,
 		(unsigned) gdt_desc.limit, (unsigned) gdt_desc.base);
+
   mmap_size = find_mmap_size ();
   if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
 			       &desc_size, &desc_version) <= 0)
     grub_fatal ("cannot get memory map");
 
+  e820_num = 0;
+  for (desc = mmap_buf;
+       desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
+       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
+    {
+      switch (desc->type)
+        {
+        case GRUB_EFI_ACPI_RECLAIM_MEMORY:
+          grub_e820_add_region (params->e820_map, &e820_num,
+                                desc->physical_start,
+                                desc->num_pages << 12,
+                                GRUB_E820_ACPI);
+          break;
+
+        case GRUB_EFI_ACPI_MEMORY_NVS:
+          grub_e820_add_region (params->e820_map, &e820_num,
+                                desc->physical_start,
+                                desc->num_pages << 12,
+                                GRUB_E820_NVS);
+          break;
+
+        case GRUB_EFI_RUNTIME_SERVICES_CODE:
+          grub_e820_add_region (params->e820_map, &e820_num,
+                                desc->physical_start,
+                                desc->num_pages << 12,
+                                GRUB_E820_EXEC_CODE);
+          break;
+
+        case GRUB_EFI_LOADER_CODE:
+        case GRUB_EFI_LOADER_DATA:
+        case GRUB_EFI_BOOT_SERVICES_CODE:
+        case GRUB_EFI_BOOT_SERVICES_DATA:
+        case GRUB_EFI_CONVENTIONAL_MEMORY:
+          {
+            grub_uint64_t start, size, end;
+
+            start = desc->physical_start;
+            size = desc->num_pages << 12;
+            end = start + size;
+
+            /* Skip A0000 - 100000 region.  */
+            if ((start < 0x100000ULL) && (end > 0xA0000ULL))
+              {
+                if (start < 0xA0000ULL)
+                  {
+                    grub_e820_add_region (params->e820_map, &e820_num,
+                                          start,
+                                          0xA0000ULL - start,
+                                          GRUB_E820_RAM);
+                  }
+
+                if (end <= 0x100000ULL)
+                  continue;
+
+                start = 0x100000ULL;
+                size = end - start;
+              }
+
+            grub_e820_add_region (params->e820_map, &e820_num,
+                                  start, size, GRUB_E820_RAM);
+            break;
+          }
+
+        default:
+          grub_e820_add_region (params->e820_map, &e820_num,
+                                desc->physical_start,
+                                desc->num_pages << 12,
+                                GRUB_E820_RESERVED);
+        }
+    }
+
+  params->mmap_size = e820_num;
+
   if (! grub_efi_exit_boot_services (map_key))
-    grub_fatal ("cannot exit boot services");
+     grub_fatal ("cannot exit boot services");
 
   /* Note that no boot services are available from here.  */
 
+  /* Pass EFI parameters.  */
+  if (grub_le_to_cpu16 (params->version) >= 0x0206)
+    {
+      params->v0206.efi_mem_desc_size = desc_size;
+      params->v0206.efi_mem_desc_version = desc_version;
+      params->v0206.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
+      params->v0206.efi_mmap_size = mmap_size;
+#ifdef __x86_64__
+      params->v0206.efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) mmap_buf >> 32);
+#endif
+    }
+  else if (grub_le_to_cpu16 (params->version) >= 0x0204)
+    {
+      params->v0204.efi_mem_desc_size = desc_size;
+      params->v0204.efi_mem_desc_version = desc_version;
+      params->v0204.efi_mmap = (grub_uint32_t) (unsigned long) mmap_buf;
+      params->v0204.efi_mmap_size = mmap_size;
+    }
+
   /* Hardware interrupts are not safe any longer.  */
   asm volatile ("cli" : : );
   
-  /* Pass EFI parameters.  */
-  params->efi_mem_desc_size = desc_size;
-  params->efi_mem_desc_version = desc_version;
-  params->efi_mmap = (grub_addr_t) mmap_buf;
-  params->efi_mmap_size = mmap_size;
+#ifdef __x86_64__
+
+  jumpvector.kernel_entry = params->code32_start;
+  jumpvector.kernel_cs = 0x10;
+  jump_start = (void *) &jumpvector;
+
+  /* Load the IDT and the GDT for the bootstrap.  */
+  asm volatile ("lidt %0" : : "m" (idt_desc));
+  asm volatile ("lgdt %0" : : "m" (gdt_desc));
+
+  asm volatile ( "mov %0, %%rsi" : : "m" (real_mode_mem));
+  asm volatile ( "mov %0, %%rcx" : : "m" (jump_start));
+
+  asm volatile ( "ljmp *(%%rcx)" : :);
+
+#else
+
+  kernel_entry = params->code32_start;
 
   /* Pass parameters.  */
   asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem));
-  asm volatile ("movl %0, %%ecx" : : "m" (lh->code32_start));
+  asm volatile ("movl %0, %%ecx" : : "m" (kernel_entry));
   asm volatile ("xorl %%ebx, %%ebx" : : );
 
-  /* Load the IDT and the GDT for the bootstrap.  */
-  asm volatile ("lidt %0" : : "m" (idt_desc.limit));
-  asm volatile ("lgdt %0" : : "m" (gdt_desc.limit));
-
   /* Enter Linux.  */
   asm volatile ("jmp *%%ecx" : : );
   
+#endif
+
   /* Never reach here.  */
   return GRUB_ERR_NONE;
 }
@@ -318,6 +457,111 @@ grub_linux_unload (void)
   return GRUB_ERR_NONE;
 }
 
+grub_uint64_t video_base;
+
+static int
+grub_find_video_card (int bus, int dev, int func,
+                      grub_pci_id_t pciid __attribute__ ((unused)))
+{
+  grub_pci_address_t addr;
+
+  addr = grub_pci_make_address (bus, dev, func, 2);
+
+  if (grub_pci_read (addr) >> 24 == 0x3)
+    {
+      int i;
+
+      addr = grub_pci_make_address (bus, dev, func, 4);
+      for (i = 0; i < 6; i++, addr += 4)
+        {
+          grub_uint32_t base, type;
+
+          base = grub_pci_read (addr);
+
+          if ((base == 0) || (base == 0xffffffff) ||
+              (base & GRUB_PCI_ADDR_SPACE_IO))
+            continue;
+
+          type = base & GRUB_PCI_ADDR_MEM_TYPE_MASK;
+          if (! (addr & GRUB_PCI_ADDR_MEM_PREFETCH))
+            {
+              if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
+                {
+                  i++;
+                  addr +=4 ;
+                }
+              continue;
+            }
+
+          base &= GRUB_PCI_ADDR_MEM_MASK;
+          if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
+            {
+              if (i == 5)
+                break;
+
+              video_base = grub_pci_read (addr + 4);
+              video_base <<= 32;
+            }
+
+          video_base |= base;
+
+          return 1;
+        }
+    }
+
+  return 0;
+}
+
+static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID;
+
+static int
+grub_linux_setup_video (struct linux_kernel_params *params)
+{
+  grub_efi_uga_draw_protocol_t *c;
+  grub_uint32_t width, height, depth, rate;
+
+  c = grub_efi_locate_protocol (&uga_draw_guid, 0);
+  if (! c)
+    return 1;
+
+  if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate))
+    return 1;
+
+  grub_printf ("Video mode: %ux%u-%u@%u\n", width, height, depth, rate);
+
+  video_base = 0;
+  grub_pci_iterate (grub_find_video_card);
+
+  if (! video_base)
+    {
+      grub_printf ("Can\'t find frame buffer address\n");
+      return 1;
+    }
+
+  grub_printf ("Video frame buffer: %llx\n", video_base);
+
+  params->lfb_width = width;
+  params->lfb_height = height;
+  params->lfb_depth = depth;
+
+  /* FIXME: shouldn't use fixed value.  */
+  params->lfb_line_len = 8192;
+
+  params->lfb_base = video_base;
+  params->lfb_size = (params->lfb_line_len * params->lfb_height + 65535) >> 16;
+
+  params->red_mask_size = 8;
+  params->red_field_pos = 16;
+  params->green_mask_size = 8;
+  params->green_field_pos = 8;
+  params->blue_mask_size = 8;
+  params->blue_field_pos = 0;
+  params->reserved_mask_size = 8;
+  params->reserved_field_pos = 24;
+
+  return 0;
+}
+
 void
 grub_rescue_cmd_linux (int argc, char *argv[])
 {
@@ -329,6 +573,7 @@ grub_rescue_cmd_linux (int argc, char *argv[])
   grub_ssize_t len;
   int i;
   char *dest;
+  int video_type;
 
   grub_dl_ref (my_mod);
   
@@ -384,19 +629,25 @@ grub_rescue_cmd_linux (int argc, char *argv[])
   real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
   prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
   
-  if (! allocate_pages (real_size, prot_size))
+  if (! allocate_pages (prot_size))
     goto fail;
   
+  params = (struct linux_kernel_params *) real_mode_mem;
+  grub_memset (params, 0, sizeof (struct linux_kernel_params));
+  grub_memcpy (&params->jump, &lh.jump,
+               (char *) &lh.ramdisk_image - (char *) &lh.jump);
+
   /* XXX Linux assumes that only elilo can boot Linux on EFI!!!  */
-  lh.type_of_loader = 0x50;
+  params->type_of_loader = 0x50;
 
-  lh.cl_magic = GRUB_LINUX_CL_MAGIC;
-  lh.cl_offset = GRUB_LINUX_CL_END_OFFSET;
-  lh.cmd_line_ptr = (char *) real_mode_mem + GRUB_LINUX_CL_OFFSET;
-  lh.ramdisk_image = 0;
-  lh.ramdisk_size = 0;
+  params->cl_magic = GRUB_LINUX_CL_MAGIC;
+  params->cl_offset = GRUB_LINUX_CL_OFFSET;
+  params->cmd_line_ptr = (grub_uint32_t) real_mode_mem + GRUB_LINUX_CL_OFFSET;
+  params->ramdisk_image = 0;
+  params->ramdisk_size = 0;
 
-  params = (struct linux_kernel_params *) &lh;
+  params->heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
+  params->loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
 
   /* These are not needed to be precise, because Linux uses these values
      only to raise an error when the decompression code cannot find good
@@ -414,6 +665,23 @@ grub_rescue_cmd_linux (int argc, char *argv[])
   params->have_vga = 0;
   params->font_size = 16; /* XXX */
 
+  if (grub_le_to_cpu16 (params->version) >= 0x0206)
+    {
+      params->v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
+      params->v0206.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
+#ifdef __x86_64__
+      params->v0206.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
+#endif
+    }
+  else if (grub_le_to_cpu16 (params->version) >= 0x0204)
+    {
+      params->v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
+      params->v0204.efi_system_table = (grub_uint32_t) (unsigned long) grub_efi_system_table;
+    }
+
+#if 0
+  /* The structure is zeroed already.  */
+
   /* No VBE on EFI.  */
   params->lfb_width = 0;
   params->lfb_height = 0;
@@ -457,10 +725,6 @@ grub_rescue_cmd_linux (int argc, char *argv[])
   /* No MCA on EFI.  */
   params->rom_config_len = 0;
 
-  params->efi_signature = GRUB_LINUX_EFI_SIGNATURE; /* XXX not used */
-  params->efi_system_table = (grub_addr_t) grub_efi_system_table;
-  /* The other EFI parameters are filled when booting.  */
-
   /* No need to fake the BIOS's memory map.  */
   params->mmap_size = 0;
 
@@ -478,22 +742,19 @@ grub_rescue_cmd_linux (int argc, char *argv[])
   grub_memset (params->padding8, 0, sizeof (params->padding8));
   grub_memset (params->padding9, 0, sizeof (params->padding9));
   
-  /* Put the real mode code at the real location.  */
-  grub_memmove (real_mode_mem, &lh, sizeof (lh));
+#endif
 
-  len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh);
-  if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len)
-    {
-      grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
-      goto fail;
-    }
+  /* The other EFI parameters are filled when booting.  */
+
+  grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
 
   /* XXX there is no way to know if the kernel really supports EFI.  */
   grub_printf ("   [Linux-EFI, setup=0x%x, size=0x%x]\n",
-	       real_size, prot_size);
+	       (unsigned) real_size, (unsigned) prot_size);
 
   /* Detect explicitly specified memory size, if any.  */
   linux_mem_size = 0;
+  video_type = 0;
   for (i = 1; i < argc; i++)
     if (grub_memcmp (argv[i], "mem=", 4) == 0)
       {
@@ -529,6 +790,19 @@ grub_rescue_cmd_linux (int argc, char *argv[])
 	      linux_mem_size <<= shift;
 	  }
       }
+    else if (grub_memcmp (argv[i], "video=", 6) == 0)
+      {
+        if (grub_memcmp (&argv[i][6], "vesafb", 6) == 0)
+          video_type = GRUB_VIDEO_TYPE_VLFB;
+        else if (grub_memcmp (&argv[i][6], "efifb", 5) == 0)
+          video_type = GRUB_VIDEO_TYPE_EFI;
+      }
+
+  if (video_type)
+    {
+      if (!  grub_linux_setup_video (params))
+        params->have_vga = video_type;
+    }
 
   /* Specify the boot file.  */
   dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET,
@@ -601,7 +875,7 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
 
   lh = (struct linux_kernel_header *) real_mode_mem;
   
-  addr_max = grub_cpu_to_le32 (lh->initrd_addr_max);
+  addr_max = (grub_cpu_to_le32 (lh->initrd_addr_max) << 10);
   if (linux_mem_size != 0 && linux_mem_size < addr_max)
     addr_max = linux_mem_size;
   
@@ -612,7 +886,8 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
   addr_max -= 0x10000;
 
   /* Usually, the compression ratio is about 50%.  */
-  addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12);
+  addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12)
+             + page_align (size);
   
   /* Find the highest address to put the initrd.  */
   mmap_size = find_mmap_size ();
@@ -625,8 +900,6 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
        desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
     {
       if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
-	  && desc->physical_start >= addr_min
-	  && desc->physical_start + size < addr_max
 	  && desc->num_pages >= initrd_pages)
 	{
 	  grub_efi_physical_address_t physical_end;
@@ -635,6 +908,9 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
 	  if (physical_end > addr_max)
 	    physical_end = addr_max;
 
+          if (physical_end < addr_min)
+            continue;
+
 	  if (physical_end > addr)
 	    addr = physical_end - page_align (size);
 	}
@@ -657,7 +933,7 @@ grub_rescue_cmd_initrd (int argc, char *argv[])
     }
 
   grub_printf ("   [Initrd, addr=0x%x, size=0x%x]\n",
-	       addr, size);
+	       (unsigned) addr, (unsigned) size);
   
   lh->ramdisk_image = addr;
   lh->ramdisk_size = size;
diff --git a/loader/i386/ieee1275/linux.c b/loader/i386/ieee1275/linux.c
index bc4567e..290d7b9 100644
--- a/loader/i386/ieee1275/linux.c
+++ b/loader/i386/ieee1275/linux.c
@@ -85,6 +85,49 @@ grub_set_bootpath (void)
 
 }
 
+static grub_uint8_t gdt[] __attribute__ ((aligned(16))) =
+  {
+    /* NULL.  */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    /* Reserved.  */
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    /* Code segment.  */
+    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00,
+    /* Data segment.  */
+    0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00
+  };
+
+struct gdt_descriptor
+{
+  grub_uint16_t limit;
+  void *base;
+} __attribute__ ((packed));
+
+static struct gdt_descriptor gdt_desc =
+  {
+    sizeof (gdt),
+    gdt
+  };
+
+struct idt_descriptor
+{
+  grub_uint16_t limit;
+  void *base;
+} __attribute__ ((packed));
+
+static struct idt_descriptor idt_desc =
+  {
+    0,
+    0
+  };
+
+struct
+{
+  grub_uint32_t kernel_entry;
+  grub_uint32_t kernel_cs;
+} jumpvector;
+void *jump_start;
+
 static grub_err_t
 grub_linux_boot (void)
 {
@@ -137,11 +180,33 @@ grub_linux_boot (void)
   prot_code = (char *) GRUB_OFW_LINUX_KERNEL_ADDR;
   grub_memcpy (prot_code, kernel_addr, kernel_size);
 
+  jumpvector.kernel_entry = params->code32_start;
+  jumpvector.kernel_cs = 0x10;
+  jump_start = (void *) &jumpvector;
+
+  /* Load the IDT and the GDT for the bootstrap.  */
+  asm volatile ("lidt %0" : : "m" (idt_desc));
+  asm volatile ("lgdt %0" : : "m" (gdt_desc));
+
+  asm volatile ("movl %0, %%esi" : : "m" (params));
+  asm volatile ("movl %0, %%ecx" : : "m" (prot_code));
+  asm volatile ("xorl %%ebx, %%ebx" : : );
+
+  asm volatile ( "mov $24, %%ax" : : );
+  asm volatile ( "mov %%ax, %%ds" : : );
+  asm volatile ( "mov %%ax, %%ss" : : );
+  asm volatile ( "mov %%esi, %%esp" : : );
+
+  /* Enter Linux.  */
+  asm volatile ( "ljmp *(%%ecx)" : :);
+
+#if 0
   asm volatile ("movl %0, %%esi" : : "m" (params));
   asm volatile ("movl %%esi, %%esp" : : );
   asm volatile ("movl %0, %%ecx" : : "m" (prot_code));
   asm volatile ("xorl %%ebx, %%ebx" : : );
   asm volatile ("jmp *%%ecx" : : );
+#endif
 
   return GRUB_ERR_NONE;
 }
diff --git a/normal/x86_64/setjmp.S b/normal/x86_64/setjmp.S
new file mode 100644
index 0000000..4c8d4b3
--- /dev/null
+++ b/normal/x86_64/setjmp.S
@@ -0,0 +1,60 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003,2007  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
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+	.file	"setjmp.S"
+
+	.text
+
+/*
+ *  jmp_buf:
+ *   rbx rsp rbp r12 r13 r14 r15 rip
+ *   0   8   16  24  32  40  48  56
+ */
+
+/*
+ * int grub_setjmp (grub_jmp_buf env)
+ */
+FUNCTION(grub_setjmp)
+	pop	%rsi		/* Return address, and adjust the stack */
+	xorq	%rax, %rax
+	movq	%rbx, 0(%rdi)	/* RBX */
+	movq	%rsp, 8(%rdi)   /* RSP */
+	push	%rsi
+	movq	%rbp, 16(%rdi)	/* RBP */
+	movq	%r12, 24(%rdi)	/* R12 */
+	movq	%r13, 32(%rdi)	/* R13 */
+	movq	%r14, 40(%rdi)	/* R14 */
+	movq	%r15, 48(%rdi)	/* R15 */
+	movq	%rsi, 56(%rdi)	/* RSI */
+	ret
+
+/*
+ * int grub_longjmp (grub_jmp_buf env, int val)
+ */
+FUNCTION(grub_longjmp)
+	movl	%esi, %eax
+	movq	(%rdi), %rbx
+	movq	8(%rdi), %rsp
+	movq	16(%rdi), %rbp
+	movq	24(%rdi), %r12
+	movq    32(%rdi), %r13
+	movq    40(%rdi), %r14
+	movq    48(%rdi), %r15
+	jmp	*56(%rdi)
diff --git a/term/efi/console.c b/term/efi/console.c
index af198e5..e5c02ad 100644
--- a/term/efi/console.c
+++ b/term/efi/console.c
@@ -36,6 +36,54 @@ grub_console_highlight_color = GRUB_EFI_TEXT_ATTR (GRUB_EFI_BLACK,
 
 static int read_key = -1;
 
+static grub_uint32_t
+map_char (grub_uint32_t c)
+{
+  if (c > 0x7f)
+    {
+      /* Map some unicode characters to the EFI character.  */
+      switch (c)
+	{
+	case 0x2190:	/* left arrow */
+	  c = 0x25c4;
+	  break;
+	case 0x2191:	/* up arrow */
+	  c = 0x25b2;
+	  break;
+	case 0x2192:	/* right arrow */
+	  c = 0x25ba;
+	  break;
+	case 0x2193:	/* down arrow */
+	  c = 0x25bc;
+	  break;
+	case 0x2501:	/* horizontal line */
+	  c = 0x2500;
+	  break;
+	case 0x2503:	/* vertical line */
+	  c = 0x2502;
+	  break;
+	case 0x250F:	/* upper-left corner */
+	  c = 0x250c;
+	  break;
+	case 0x2513:	/* upper-right corner */
+	  c = 0x2510;
+	  break;
+	case 0x2517:	/* lower-left corner */
+	  c = 0x2514;
+	  break;
+	case 0x251B:	/* lower-right corner */
+	  c = 0x2518;
+	  break;
+
+	default:
+	  c = '?';
+	  break;
+	}
+    }
+
+  return c;
+}
+
 static void
 grub_console_putchar (grub_uint32_t c)
 {
@@ -48,14 +96,14 @@ grub_console_putchar (grub_uint32_t c)
   if (c > 0xffff)
     c = '?';
 
-  str[0] = (grub_efi_char16_t)  (c & 0xffff);
+  str[0] = (grub_efi_char16_t)  map_char (c & 0xffff);
   str[1] = 0;
 
   /* Should this test be cached?  */
-  if (c > 0x7f && o->test_string (o, str) != GRUB_EFI_SUCCESS)
+  if (c > 0x7f && efi_call_2 (o->test_string, o, str) != GRUB_EFI_SUCCESS)
     return;
   
-  o->output_string (o, str);
+  efi_call_2 (o->output_string, o, str);
 }
 
 static grub_ssize_t
@@ -76,8 +124,8 @@ grub_console_checkkey (void)
     return 1;
 
   i = grub_efi_system_table->con_in;
-  status = i->read_key_stroke (i, &key);
-#if 1
+  status = efi_call_2 (i->read_key_stroke, i, &key);
+#if 0
   switch (status)
     {
     case GRUB_EFI_SUCCESS:
@@ -169,9 +217,9 @@ grub_console_getkey (void)
 
   do
     {
-      status = b->wait_for_event (1, &(i->wait_for_key), &index);
+      status = efi_call_3 (b->wait_for_event, 1, &(i->wait_for_key), &index);
       if (status != GRUB_EFI_SUCCESS)
-      	return -1;
+	return -1;
       
       grub_console_checkkey ();
     }
@@ -189,7 +237,7 @@ grub_console_getwh (void)
   grub_efi_uintn_t columns, rows;
   
   o = grub_efi_system_table->con_out;
-  if (o->query_mode (o, o->mode->mode, &columns, &rows) != GRUB_EFI_SUCCESS)
+  if (efi_call_4 (o->query_mode, o, o->mode->mode, &columns, &rows) != GRUB_EFI_SUCCESS)
     {
       /* Why does this fail?  */
       columns = 80;
@@ -214,7 +262,7 @@ grub_console_gotoxy (grub_uint8_t x, grub_uint8_t y)
   grub_efi_simple_text_output_interface_t *o;
   
   o = grub_efi_system_table->con_out;
-  o->set_cursor_position (o, x, y);
+  efi_call_3 (o->set_cursor_position, o, x, y);
 }
 
 static void
@@ -225,9 +273,9 @@ grub_console_cls (void)
   
   o = grub_efi_system_table->con_out;
   orig_attr = o->mode->attribute;
-  o->set_attributes (o, GRUB_EFI_BACKGROUND_BLACK);
-  o->clear_screen (o);
-  o->set_attributes (o, orig_attr);
+  efi_call_2 (o->set_attributes, o, GRUB_EFI_BACKGROUND_BLACK);
+  efi_call_1 (o->clear_screen, o);
+  efi_call_2 (o->set_attributes, o, orig_attr);
 }
 
 static void
@@ -239,13 +287,13 @@ grub_console_setcolorstate (grub_term_color_state state)
 
   switch (state) {
     case GRUB_TERM_COLOR_STANDARD:
-      o->set_attributes (o, grub_console_standard_color);
+      efi_call_2 (o->set_attributes, o, grub_console_standard_color);
       break;
     case GRUB_TERM_COLOR_NORMAL:
-      o->set_attributes (o, grub_console_normal_color);
+      efi_call_2 (o->set_attributes, o, grub_console_normal_color);
       break;
     case GRUB_TERM_COLOR_HIGHLIGHT:
-      o->set_attributes (o, grub_console_highlight_color);
+      efi_call_2 (o->set_attributes, o, grub_console_highlight_color);
       break;
     default:
       break;
@@ -272,7 +320,7 @@ grub_console_setcursor (int on)
   grub_efi_simple_text_output_interface_t *o;
 
   o = grub_efi_system_table->con_out;
-  o->enable_cursor (o, on);
+  efi_call_2 (o->enable_cursor, o, on);
 }
 
 static struct grub_term grub_console_term =
diff --git a/util/i386/efi/grub-mkimage.c b/util/i386/efi/grub-mkimage.c
index 57c1fc8..9bd4264 100644
--- a/util/i386/efi/grub-mkimage.c
+++ b/util/i386/efi/grub-mkimage.c
@@ -31,16 +31,56 @@
 #include <grub/efi/pe32.h>
 #include <grub/machine/kernel.h>
 
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
+
+typedef Elf32_Word Elf_Word;
+typedef Elf32_Addr Elf_Addr;
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Shdr Elf_Shdr;
+typedef Elf32_Sym Elf_Sym;
+typedef Elf32_Half Elf_Half;
+typedef Elf32_Off Elf_Off;
+typedef Elf32_Section Elf_Section;
+typedef Elf32_Rel Elf_Rel;
+typedef Elf32_Rela Elf_Rela;
+
+#define ELF_R_SYM	ELF32_R_SYM
+#define ELF_R_TYPE	ELF32_R_TYPE
+#define ELF_R_INFO	ELF32_R_INFO
+
+#define grub_le_to_cpu	grub_le_to_cpu32
+
+#elif GRUB_TARGET_SIZEOF_VOID_P == 8
+
+typedef Elf64_Word Elf_Word;
+typedef Elf64_Addr Elf_Addr;
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Shdr Elf_Shdr;
+typedef Elf64_Sym Elf_Sym;
+typedef Elf64_Half Elf_Half;
+typedef Elf64_Off Elf_Off;
+typedef Elf64_Section Elf_Section;
+typedef Elf64_Rel Elf_Rel;
+typedef Elf64_Rela Elf_Rela;
+
+#define ELF_R_SYM	ELF64_R_SYM
+#define ELF_R_TYPE	ELF64_R_TYPE
+#define ELF_R_INFO	ELF64_R_INFO
+
+#define grub_le_to_cpu	grub_le_to_cpu64
+
+#endif
+
 static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB;
 
-static inline Elf32_Addr
-align_address (Elf32_Addr addr, unsigned alignment)
+static inline Elf_Addr
+align_address (Elf_Addr addr, unsigned alignment)
 {
   return (addr + alignment - 1) & ~(alignment - 1);
 }
 
-static inline Elf32_Addr
-align_pe32_section (Elf32_Addr addr)
+static inline Elf_Addr
+align_pe32_section (Elf_Addr addr)
 {
   return align_address (addr, GRUB_PE32_SECTION_ALIGNMENT);
 }
@@ -60,14 +100,15 @@ read_kernel_module (const char *dir, char *prefix, size_t *size)
 
   if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END)
     grub_util_error ("prefix too long");
-  strcpy (kernel_image + 0x34 + GRUB_KERNEL_MACHINE_PREFIX, prefix);
+
+  strcpy (kernel_image + sizeof (Elf_Ehdr) + GRUB_KERNEL_MACHINE_PREFIX, prefix);
 
   return kernel_image;
 }
 
 /* Return if the ELF header is valid.  */
 static int
-check_elf_header (Elf32_Ehdr *e, size_t size)
+check_elf_header (Elf_Ehdr *e, size_t size)
 {
   if (size < sizeof (*e)
       || e->e_ident[EI_MAG0] != ELFMAG0
@@ -76,9 +117,11 @@ check_elf_header (Elf32_Ehdr *e, size_t size)
       || e->e_ident[EI_MAG3] != ELFMAG3
       || e->e_ident[EI_VERSION] != EV_CURRENT
       || e->e_version != grub_cpu_to_le32 (EV_CURRENT)
-      || e->e_ident[EI_CLASS] != ELFCLASS32
+      || ((e->e_ident[EI_CLASS] != ELFCLASS32) &&
+          (e->e_ident[EI_CLASS] != ELFCLASS64))
       || e->e_ident[EI_DATA] != ELFDATA2LSB
-      || e->e_machine != grub_cpu_to_le16 (EM_386))
+      || ((e->e_machine != grub_cpu_to_le16 (EM_386)) &&
+          (e->e_machine != grub_cpu_to_le16 (EM_X86_64))))
     return 0;
 
   return 1;
@@ -87,7 +130,7 @@ check_elf_header (Elf32_Ehdr *e, size_t size)
 /* Return the starting address right after the header,
    aligned by the section alignment. Allocate 4 section tables for
    .text, .data, .reloc, and mods.  */
-static Elf32_Addr
+static Elf_Addr
 get_starting_section_address (void)
 {
   return align_pe32_section (sizeof (struct grub_pe32_header)
@@ -97,7 +140,7 @@ get_starting_section_address (void)
 /* Determine if this section is a text section. Return false if this
    section is not allocated.  */
 static int
-is_text_section (Elf32_Shdr *s)
+is_text_section (Elf_Shdr *s)
 {
   return ((s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC))
 	  == grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC));
@@ -107,7 +150,7 @@ is_text_section (Elf32_Shdr *s)
    BSS is also a data section, since the converter initializes BSS
    when producing PE32 to avoid a bug in EFI implementations.  */
 static int
-is_data_section (Elf32_Shdr *s)
+is_data_section (Elf_Shdr *s)
 {
   return (s->sh_flags & grub_cpu_to_le32 (SHF_ALLOC)
 	  && ! (s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR)));
@@ -116,14 +159,14 @@ is_data_section (Elf32_Shdr *s)
 /* Locate section addresses by merging code sections and data sections
    into .text and .data, respectively. Return the array of section
    addresses.  */
-static Elf32_Addr *
-locate_sections (Elf32_Shdr *sections, Elf32_Half section_entsize,
-		 Elf32_Half num_sections, const char *strtab)
+static Elf_Addr *
+locate_sections (Elf_Shdr *sections, Elf_Half section_entsize,
+		 Elf_Half num_sections, const char *strtab)
 {
   int i;
-  Elf32_Addr current_address;
-  Elf32_Addr *section_addresses;
-  Elf32_Shdr *s;
+  Elf_Addr current_address;
+  Elf_Addr *section_addresses;
+  Elf_Shdr *s;
   
   section_addresses = xmalloc (sizeof (*section_addresses) * num_sections);
   memset (section_addresses, 0, sizeof (*section_addresses) * num_sections);
@@ -133,10 +176,10 @@ locate_sections (Elf32_Shdr *sections, Elf32_Half section_entsize,
   /* .text */
   for (i = 0, s = sections;
        i < num_sections;
-       i++, s = (Elf32_Shdr *) ((char *) s + section_entsize))
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
     if (is_text_section (s))
       {
-	Elf32_Word align = grub_le_to_cpu32 (s->sh_addralign);
+	Elf_Word align = grub_le_to_cpu32 (s->sh_addralign);
 	const char *name = strtab + grub_le_to_cpu32 (s->sh_name);
 	
 	if (align)
@@ -153,10 +196,10 @@ locate_sections (Elf32_Shdr *sections, Elf32_Half section_entsize,
   /* .data */
   for (i = 0, s = sections;
        i < num_sections;
-       i++, s = (Elf32_Shdr *) ((char *) s + section_entsize))
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
     if (is_data_section (s))
       {
-	Elf32_Word align = grub_le_to_cpu32 (s->sh_addralign);
+	Elf_Word align = grub_le_to_cpu32 (s->sh_addralign);
 	const char *name = strtab + grub_le_to_cpu32 (s->sh_name);
 	
 	if (align)
@@ -172,16 +215,16 @@ locate_sections (Elf32_Shdr *sections, Elf32_Half section_entsize,
 }
 
 /* Return the symbol table section, if any.  */
-static Elf32_Shdr *
-find_symtab_section (Elf32_Shdr *sections,
-		     Elf32_Half section_entsize, Elf32_Half num_sections)
+static Elf_Shdr *
+find_symtab_section (Elf_Shdr *sections,
+		     Elf_Half section_entsize, Elf_Half num_sections)
 {
   int i;
-  Elf32_Shdr *s;
+  Elf_Shdr *s;
   
   for (i = 0, s = sections;
        i < num_sections;
-       i++, s = (Elf32_Shdr *) ((char *) s + section_entsize))
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
     if (s->sh_type == grub_cpu_to_le32 (SHT_SYMTAB))
       return s;
 
@@ -190,12 +233,12 @@ find_symtab_section (Elf32_Shdr *sections,
 
 /* Return the address of the string table.  */
 static const char *
-find_strtab (Elf32_Ehdr *e, Elf32_Shdr *sections, Elf32_Half section_entsize)
+find_strtab (Elf_Ehdr *e, Elf_Shdr *sections, Elf_Half section_entsize)
 {
-  Elf32_Shdr *s;
+  Elf_Shdr *s;
   char *strtab;
   
-  s = (Elf32_Shdr *) ((char *) sections
+  s = (Elf_Shdr *) ((char *) sections
 		      + grub_le_to_cpu16 (e->e_shstrndx) * section_entsize);
   strtab = (char *) e + grub_le_to_cpu32 (s->sh_offset);
   return strtab;
@@ -203,21 +246,21 @@ find_strtab (Elf32_Ehdr *e, Elf32_Shdr *sections, Elf32_Half section_entsize)
 
 /* Relocate symbols; note that this function overwrites the symbol table.
    Return the address of a start symbol.  */
-static Elf32_Addr
-relocate_symbols (Elf32_Ehdr *e, Elf32_Shdr *sections,
-		  Elf32_Shdr *symtab_section, Elf32_Addr *section_addresses,
-		  Elf32_Half section_entsize, Elf32_Half num_sections)
+static Elf_Addr
+relocate_symbols (Elf_Ehdr *e, Elf_Shdr *sections,
+		  Elf_Shdr *symtab_section, Elf_Addr *section_addresses,
+		  Elf_Half section_entsize, Elf_Half num_sections)
 {
-  Elf32_Word symtab_size, sym_size, num_syms;
-  Elf32_Off symtab_offset;
-  Elf32_Addr start_address = 0;
-  Elf32_Sym *sym;
-  Elf32_Word i;
-  Elf32_Shdr *strtab_section;
+  Elf_Word symtab_size, sym_size, num_syms;
+  Elf_Off symtab_offset;
+  Elf_Addr start_address = 0;
+  Elf_Sym *sym;
+  Elf_Word i;
+  Elf_Shdr *strtab_section;
   const char *strtab;
   
   strtab_section
-    = (Elf32_Shdr *) ((char *) sections
+    = (Elf_Shdr *) ((char *) sections
 		      + (grub_le_to_cpu32 (symtab_section->sh_link)
 			 * section_entsize));
   strtab = (char *) e + grub_le_to_cpu32 (strtab_section->sh_offset);
@@ -227,17 +270,21 @@ relocate_symbols (Elf32_Ehdr *e, Elf32_Shdr *sections,
   symtab_offset = grub_le_to_cpu32 (symtab_section->sh_offset);
   num_syms = symtab_size / sym_size;
 
-  for (i = 0, sym = (Elf32_Sym *) ((char *) e + symtab_offset);
+  for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
        i < num_syms;
-       i++, sym = (Elf32_Sym *) ((char *) sym + sym_size))
+       i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
     {
-      Elf32_Section index;
+      Elf_Section index;
       const char *name;
       
       name = strtab + grub_le_to_cpu32 (sym->st_name);
       
       index = grub_le_to_cpu16 (sym->st_shndx);
-      if (index == STN_UNDEF)
+      if (index == STN_ABS)
+        {
+          continue;
+        }
+      else if ((index == STN_UNDEF))
 	{
 	  if (sym->st_name)
 	    grub_util_error ("undefined symbol %s", name);
@@ -260,22 +307,22 @@ relocate_symbols (Elf32_Ehdr *e, Elf32_Shdr *sections,
 }
 
 /* Return the address of a symbol at the index I in the section S.  */
-static Elf32_Addr
-get_symbol_address (Elf32_Ehdr *e, Elf32_Shdr *s, Elf32_Word i)
+static Elf_Addr
+get_symbol_address (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i)
 {
-  Elf32_Sym *sym;
+  Elf_Sym *sym;
   
-  sym = (Elf32_Sym *) ((char *) e
+  sym = (Elf_Sym *) ((char *) e
 		       + grub_le_to_cpu32 (s->sh_offset)
 		       + i * grub_le_to_cpu32 (s->sh_entsize));
   return sym->st_value;
 }
 
 /* Return the address of a modified value.  */
-static Elf32_Addr
-get_target_address (Elf32_Ehdr *e, Elf32_Shdr *s, Elf32_Addr offset)
+static Elf_Addr *
+get_target_address (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset)
 {
-  return (Elf32_Addr) e + grub_le_to_cpu32 (s->sh_offset) + offset;
+  return (Elf_Addr *) ((char *) e + grub_le_to_cpu32 (s->sh_offset) + offset);
 }
 
 /* Deal with relocation information. This function relocates addresses
@@ -283,34 +330,35 @@ get_target_address (Elf32_Ehdr *e, Elf32_Shdr *s, Elf32_Addr offset)
    addresses can be fully resolved. Absolute addresses must be relocated
    again by a PE32 relocator when loaded.  */
 static void
-relocate_addresses (Elf32_Ehdr *e, Elf32_Shdr *sections,
-		    Elf32_Addr *section_addresses,
-		    Elf32_Half section_entsize, Elf32_Half num_sections,
+relocate_addresses (Elf_Ehdr *e, Elf_Shdr *sections,
+		    Elf_Addr *section_addresses,
+		    Elf_Half section_entsize, Elf_Half num_sections,
 		    const char *strtab)
 {
-  Elf32_Half i;
-  Elf32_Shdr *s;
+  Elf_Half i;
+  Elf_Shdr *s;
   
   for (i = 0, s = sections;
        i < num_sections;
-       i++, s = (Elf32_Shdr *) ((char *) s + section_entsize))
-    if (s->sh_type == grub_cpu_to_le32 (SHT_REL))
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+    if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) ||
+        (s->sh_type == grub_cpu_to_le32 (SHT_RELA)))
       {
-	Elf32_Rel *r;
-	Elf32_Word rtab_size, r_size, num_rs;
-	Elf32_Off rtab_offset;
-	Elf32_Shdr *symtab_section;
-	Elf32_Word target_section_index;
-	Elf32_Addr target_section_addr;
-	Elf32_Shdr *target_section;
-	Elf32_Word j;
-
-	symtab_section = (Elf32_Shdr *) ((char *) sections
+	Elf_Rela *r;
+	Elf_Word rtab_size, r_size, num_rs;
+	Elf_Off rtab_offset;
+	Elf_Shdr *symtab_section;
+	Elf_Word target_section_index;
+	Elf_Addr target_section_addr;
+	Elf_Shdr *target_section;
+	Elf_Word j;
+
+	symtab_section = (Elf_Shdr *) ((char *) sections
 					 + (grub_le_to_cpu32 (s->sh_link)
 					    * section_entsize));
 	target_section_index = grub_le_to_cpu32 (s->sh_info);
 	target_section_addr = section_addresses[target_section_index];
-	target_section = (Elf32_Shdr *) ((char *) sections
+	target_section = (Elf_Shdr *) ((char *) sections
 					 + (target_section_index
 					    * section_entsize));
 
@@ -323,47 +371,84 @@ relocate_addresses (Elf32_Ehdr *e, Elf32_Shdr *sections,
 	rtab_offset = grub_le_to_cpu32 (s->sh_offset);
 	num_rs = rtab_size / r_size;
 
-	for (j = 0, r = (Elf32_Rel *) ((char *) e + rtab_offset);
+	for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset);
 	     j < num_rs;
-	     j++, r = (Elf32_Rel *) ((char *) r + r_size))
+	     j++, r = (Elf_Rela *) ((char *) r + r_size))
 	  {
-	    Elf32_Word info;
-	    Elf32_Addr offset;
-	    Elf32_Addr sym_addr;
-	    Elf32_Addr *target;
-	    
-	    offset = grub_le_to_cpu32 (r->r_offset);
-	    target = (Elf32_Addr *) get_target_address (e, target_section,
-							offset);
-	    info = grub_le_to_cpu32 (r->r_info);
+            Elf_Addr info;
+	    Elf_Addr offset;
+	    Elf_Addr sym_addr;
+	    Elf_Addr *target, *value;
+
+	    offset = grub_le_to_cpu (r->r_offset);
+	    target = get_target_address (e, target_section, offset);
+	    info = grub_le_to_cpu (r->r_info);
 	    sym_addr = get_symbol_address (e, symtab_section,
-					   ELF32_R_SYM (info));
+					   ELF_R_SYM (info));
+
+            value = (s->sh_type == grub_cpu_to_le32 (SHT_RELA)) ?
+               (Elf_Addr *) &r->r_addend : target;
 
-	    switch (ELF32_R_TYPE (info))
+            switch (ELF_R_TYPE (info))
 	      {
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
 	      case R_386_NONE:
 		break;
 
 	      case R_386_32:
 		/* This is absolute.  */
-		*target = grub_cpu_to_le32 (grub_le_to_cpu32 (*target)
-					    + sym_addr);
+		*target = grub_cpu_to_le32 (grub_le_to_cpu32 (*value)
+                                            + sym_addr);
 		grub_util_info ("relocating an R_386_32 entry to 0x%x at the offset 0x%x",
 				*target, offset);
 		break;
 
 	      case R_386_PC32:
 		/* This is relative.  */
-		*target = grub_cpu_to_le32 (grub_le_to_cpu32 (*target)
+		*target = grub_cpu_to_le32 (grub_le_to_cpu32 (*value)
 					    + sym_addr
 					    - target_section_addr - offset);
 		grub_util_info ("relocating an R_386_PC32 entry to 0x%x at the offset 0x%x",
 				*target, offset);
 		break;
 
+#else
+
+              case R_X86_64_NONE:
+                break;
+
+              case R_X86_64_64:
+		*target = grub_cpu_to_le64 (grub_le_to_cpu64 (*value) + sym_addr);
+		grub_util_info ("relocating an R_X86_64_64 entry to 0x%llx at the offset 0x%llx",
+				*target, offset);
+		break;
+
+              case R_X86_64_PC32:
+                {
+                  grub_uint32_t *t32 = (grub_uint32_t *) target;
+                  *t32 = grub_cpu_to_le64 (grub_le_to_cpu64 (*value)
+                                           + sym_addr
+                                           - target_section_addr - offset);
+                  grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%llx",
+                                  *t32, offset);
+                  break;
+                }
+
+              case R_X86_64_32:
+              case R_X86_64_32S:
+                {
+                  grub_uint32_t *t32 = (grub_uint32_t *) target;
+                  *t32 = grub_cpu_to_le64 (grub_le_to_cpu64 (*value)
+                                           + sym_addr);
+                  grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%llx",
+                                  *t32, offset);
+                  break;
+                }
+
+#endif
 	      default:
 		grub_util_error ("unknown relocation type %d",
-				 ELF32_R_TYPE (info));
+				 ELF_R_TYPE (info));
 		break;
 	      }
 	  }
@@ -382,9 +467,9 @@ write_padding (FILE *out, size_t size)
 
 /* Add a PE32's fixup entry for a relocation. Return the resulting address
    after having written to the file OUT.  */
-Elf32_Addr
+Elf_Addr
 add_fixup_entry (struct grub_pe32_fixup_block **block, grub_uint16_t type,
-		 Elf32_Addr addr, int flush, Elf32_Addr current_address,
+		 Elf_Addr addr, int flush, Elf_Addr current_address,
 		 FILE *out)
 {
   struct grub_pe32_fixup_block *b = *block;
@@ -400,7 +485,7 @@ add_fixup_entry (struct grub_pe32_fixup_block **block, grub_uint16_t type,
 	    {
 	      /* Add as much padding as necessary to align the address
 		 with a section boundary.  */
-	      Elf32_Addr next_address;
+	      Elf_Addr next_address;
 	      unsigned padding_size;
               size_t index;
 	      
@@ -473,10 +558,10 @@ add_fixup_entry (struct grub_pe32_fixup_block **block, grub_uint16_t type,
 }
 
 /* Write out zeros to make space for the header.  */
-static Elf32_Addr
+static Elf_Addr
 make_header_space (FILE *out)
 {
-  Elf32_Addr addr;
+  Elf_Addr addr;
   
   addr = get_starting_section_address ();
   write_padding (out, addr);
@@ -485,24 +570,24 @@ make_header_space (FILE *out)
 }
 
 /* Write text sections.  */
-static Elf32_Addr
-write_text_sections (FILE *out, Elf32_Addr current_address,
-		     Elf32_Ehdr *e, Elf32_Shdr *sections,
-		     Elf32_Half section_entsize, Elf32_Half num_sections,
+static Elf_Addr
+write_text_sections (FILE *out, Elf_Addr current_address,
+		     Elf_Ehdr *e, Elf_Shdr *sections,
+		     Elf_Half section_entsize, Elf_Half num_sections,
 		     const char *strtab)
 {
-  Elf32_Half i;
-  Elf32_Shdr *s;
-  Elf32_Addr addr;
+  Elf_Half i;
+  Elf_Shdr *s;
+  Elf_Addr addr;
   
   for (i = 0, s = sections;
        i < num_sections;
-       i++, s = (Elf32_Shdr *) ((char *) s + section_entsize))
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
     if (is_text_section (s))
       {
-	Elf32_Word align = grub_le_to_cpu32 (s->sh_addralign);
-	Elf32_Off offset = grub_le_to_cpu32 (s->sh_offset);
-	Elf32_Word size = grub_le_to_cpu32 (s->sh_size);
+	Elf_Word align = grub_le_to_cpu32 (s->sh_addralign);
+	Elf_Off offset = grub_le_to_cpu32 (s->sh_offset);
+	Elf_Word size = grub_le_to_cpu32 (s->sh_size);
 	const char *name = strtab + grub_le_to_cpu32 (s->sh_name);
 	
 	if (align)
@@ -538,24 +623,24 @@ write_text_sections (FILE *out, Elf32_Addr current_address,
 }
 
 /* Write data sections.  */
-static Elf32_Addr
-write_data_sections (FILE *out, Elf32_Addr current_address,
-		     Elf32_Ehdr *e, Elf32_Shdr *sections,
-		     Elf32_Half section_entsize, Elf32_Half num_sections,
+static Elf_Addr
+write_data_sections (FILE *out, Elf_Addr current_address,
+		     Elf_Ehdr *e, Elf_Shdr *sections,
+		     Elf_Half section_entsize, Elf_Half num_sections,
 		     const char *strtab)
 {
-  Elf32_Half i;
-  Elf32_Shdr *s;
-  Elf32_Addr addr;
+  Elf_Half i;
+  Elf_Shdr *s;
+  Elf_Addr addr;
   
   for (i = 0, s = sections;
        i < num_sections;
-       i++, s = (Elf32_Shdr *) ((char *) s + section_entsize))
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
     if (is_data_section (s))
       {
-	Elf32_Word align = grub_le_to_cpu32 (s->sh_addralign);
-	Elf32_Off offset = grub_le_to_cpu32 (s->sh_offset);
-	Elf32_Word size = grub_le_to_cpu32 (s->sh_size);
+	Elf_Word align = grub_le_to_cpu32 (s->sh_addralign);
+	Elf_Off offset = grub_le_to_cpu32 (s->sh_offset);
+	Elf_Word size = grub_le_to_cpu32 (s->sh_size);
 	const char *name = strtab + grub_le_to_cpu32 (s->sh_name);
 	
 	if (align)
@@ -594,15 +679,15 @@ write_data_sections (FILE *out, Elf32_Addr current_address,
 }
 
 /* Write modules.  */
-static Elf32_Addr
-make_mods_section (FILE *out, Elf32_Addr current_address,
+static Elf_Addr
+make_mods_section (FILE *out, Elf_Addr current_address,
 		   const char *dir, char *mods[])
 {
   struct grub_util_path_list *path_list;
   grub_size_t total_module_size;
   struct grub_util_path_list *p;
   struct grub_module_info modinfo;
-  Elf32_Addr addr;
+  Elf_Addr addr;
 
   path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods);
   
@@ -666,26 +751,27 @@ make_mods_section (FILE *out, Elf32_Addr current_address,
 }
 
 /* Make a .reloc section.  */
-static Elf32_Addr
-make_reloc_section (FILE *out, Elf32_Addr current_address, Elf32_Ehdr *e, 
-		    Elf32_Addr *section_addresses, Elf32_Shdr *sections,
-		    Elf32_Half section_entsize, Elf32_Half num_sections,
+static Elf_Addr
+make_reloc_section (FILE *out, Elf_Addr current_address, Elf_Ehdr *e,
+		    Elf_Addr *section_addresses, Elf_Shdr *sections,
+		    Elf_Half section_entsize, Elf_Half num_sections,
 		    const char *strtab)
 {
-  Elf32_Half i;
-  Elf32_Shdr *s;
+  Elf_Half i;
+  Elf_Shdr *s;
   struct grub_pe32_fixup_block *fixup_block = 0;
   
   for (i = 0, s = sections;
        i < num_sections;
-       i++, s = (Elf32_Shdr *) ((char *) s + section_entsize))
-    if (s->sh_type == grub_cpu_to_le32 (SHT_REL))
+       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+    if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) ||
+        (s->sh_type == grub_cpu_to_le32 (SHT_RELA)))
       {
-	Elf32_Rel *r;
-	Elf32_Word rtab_size, r_size, num_rs;
-	Elf32_Off rtab_offset;
-	Elf32_Addr section_address;
-	Elf32_Word j;
+	Elf_Rel *r;
+	Elf_Word rtab_size, r_size, num_rs;
+	Elf_Off rtab_offset;
+	Elf_Addr section_address;
+	Elf_Word j;
 	
 	grub_util_info ("translating the relocation section %s",
 			strtab + grub_le_to_cpu32 (s->sh_name));
@@ -697,20 +783,21 @@ make_reloc_section (FILE *out, Elf32_Addr current_address, Elf32_Ehdr *e,
 	
 	section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)];
 
-	for (j = 0, r = (Elf32_Rel *) ((char *) e + rtab_offset);
+	for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset);
 	     j < num_rs;
-	     j++, r = (Elf32_Rel *) ((char *) r + r_size))
+	     j++, r = (Elf_Rel *) ((char *) r + r_size))
 	  {
-	    Elf32_Word info;
-	    Elf32_Addr offset;
+	    Elf_Addr info;
+	    Elf_Addr offset;
 
 	    offset = grub_le_to_cpu32 (r->r_offset);
 	    info = grub_le_to_cpu32 (r->r_info);
 
 	    /* Necessary to relocate only absolute addresses.  */
-	    if (ELF32_R_TYPE (info) == R_386_32)
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
+	    if (ELF_R_TYPE (info) == R_386_32)
 	      {
-		Elf32_Addr addr;
+		Elf_Addr addr;
 
 		addr = section_address + offset;
 		grub_util_info ("adding a relocation entry for 0x%x", addr);
@@ -719,6 +806,21 @@ make_reloc_section (FILE *out, Elf32_Addr current_address, Elf32_Ehdr *e,
 						   addr, 0, current_address,
 						   out);
 	      }
+#else
+	    if ((ELF_R_TYPE (info) == R_X86_64_64) ||
+                (ELF_R_TYPE (info) == R_X86_64_32) ||
+                (ELF_R_TYPE (info) == R_X86_64_32S))
+	      {
+		Elf_Addr addr;
+
+		addr = section_address + offset;
+		grub_util_info ("adding a relocation entry for 0x%llx", addr);
+		current_address = add_fixup_entry (&fixup_block,
+						   GRUB_PE32_REL_BASED_HIGHLOW,
+						   addr, 0, current_address,
+						   out);
+	      }
+#endif
 	  }
       }
 
@@ -730,9 +832,9 @@ make_reloc_section (FILE *out, Elf32_Addr current_address, Elf32_Ehdr *e,
 
 /* Create the header.  */
 static void
-make_header (FILE *out, Elf32_Addr text_address, Elf32_Addr data_address,
-	     Elf32_Addr mods_address, Elf32_Addr reloc_address,
-	     Elf32_Addr end_address, Elf32_Addr start_address)
+make_header (FILE *out, Elf_Addr text_address, Elf_Addr data_address,
+	     Elf_Addr mods_address, Elf_Addr reloc_address,
+	     Elf_Addr end_address, Elf_Addr start_address)
 {
   struct grub_pe32_header header;
   struct grub_pe32_coff_header *c;
@@ -747,14 +849,22 @@ make_header (FILE *out, Elf32_Addr text_address, Elf32_Addr data_address,
 
   /* The COFF file header.  */
   c = &header.coff_header;
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
   c->machine = grub_cpu_to_le16 (GRUB_PE32_MACHINE_I386);
+#else
+  c->machine = grub_cpu_to_le16 (GRUB_PE32_MACHINE_X86_64);
+#endif
+
   c->num_sections = grub_cpu_to_le16 (4);
   c->time = grub_cpu_to_le32 (time (0));
   c->optional_header_size = grub_cpu_to_le16 (sizeof (header.optional_header));
   c->characteristics = grub_cpu_to_le16 (GRUB_PE32_EXECUTABLE_IMAGE
 					 | GRUB_PE32_LINE_NUMS_STRIPPED
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
+                                         | GRUB_PE32_32BIT_MACHINE
+#endif
 					 | GRUB_PE32_LOCAL_SYMS_STRIPPED
-					 | GRUB_PE32_32BIT_MACHINE);
+                                         | GRUB_PE32_DEBUG_STRIPPED);
 
   /* The PE Optional header.  */
   o = &header.optional_header;
@@ -764,7 +874,9 @@ make_header (FILE *out, Elf32_Addr text_address, Elf32_Addr data_address,
   o->bss_size = 0;
   o->entry_addr = grub_cpu_to_le32 (start_address);
   o->code_base = grub_cpu_to_le32 (text_address);
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
   o->data_base = grub_cpu_to_le32 (data_address);
+#endif
   o->image_base = 0;
   o->section_alignment = grub_cpu_to_le32 (GRUB_PE32_SECTION_ALIGNMENT);
   o->file_alignment = grub_cpu_to_le32 (GRUB_PE32_FILE_ALIGNMENT);
@@ -847,30 +959,31 @@ convert_elf (const char *dir, char *prefix, FILE *out, char *mods[])
   char *kernel_image;
   size_t kernel_size;
   const char *strtab;
-  Elf32_Ehdr *e;
-  Elf32_Shdr *sections;
-  Elf32_Off section_offset;
-  Elf32_Half section_entsize;
-  Elf32_Half num_sections;
-  Elf32_Addr *section_addresses;
-  Elf32_Shdr *symtab_section;
-  Elf32_Addr start_address;
-  Elf32_Addr text_address, data_address, reloc_address, mods_address;
-  Elf32_Addr end_address;
+  Elf_Ehdr *e;
+  Elf_Shdr *sections;
+  Elf_Off section_offset;
+  Elf_Half section_entsize;
+  Elf_Half num_sections;
+  Elf_Addr *section_addresses;
+  Elf_Shdr *symtab_section;
+  Elf_Addr start_address;
+  Elf_Addr text_address, data_address, reloc_address, mods_address;
+  Elf_Addr end_address;
 
   /* Get the kernel image and check the format.  */
   kernel_image = read_kernel_module (dir, prefix, &kernel_size);
-  e = (Elf32_Ehdr *) kernel_image;
+  e = (Elf_Ehdr *) kernel_image;
   if (! check_elf_header (e, kernel_size))
     grub_util_error ("invalid ELF header");
   
   section_offset = grub_cpu_to_le32 (e->e_shoff);
   section_entsize = grub_cpu_to_le16 (e->e_shentsize);
   num_sections = grub_cpu_to_le16 (e->e_shnum);
+
   if (kernel_size < section_offset + section_entsize * num_sections)
     grub_util_error ("invalid ELF format");
 
-  sections = (Elf32_Shdr *) (kernel_image + section_offset);
+  sections = (Elf_Shdr *) (kernel_image + section_offset);
   strtab = find_strtab (e, sections, section_entsize);
 
   /* Relocate sections then symbols in the virtual address space.  */

^ permalink raw reply related	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2008-07-19 15:02 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-20 17:04 [PATCH] New x86_64 EFI patch Bean
2008-06-21 17:04 ` Bean
2008-06-23 11:58   ` Isaac Dupree
2008-06-23 12:53     ` Bean
2008-06-24 12:52   ` Isaac Dupree
2008-06-24 13:12     ` Bean
2008-06-24 16:57       ` Isaac Dupree
2008-06-24 17:11         ` Bean
2008-06-24 21:59           ` Isaac Dupree
2008-06-25  6:49             ` Bean
2008-06-25 12:50               ` Isaac Dupree
2008-06-25 13:54                 ` Bean
2008-06-28 10:51                   ` Isaac Dupree
2008-06-28 11:55                     ` Bean
2008-06-29 23:55                       ` Isaac Dupree
2008-06-30  5:05                         ` Bean
2008-07-02 13:43                           ` Bean
2008-07-05 23:02                           ` Isaac Dupree
2008-07-06  4:31                             ` Bean
2008-07-08 16:16                               ` Isaac Dupree
2008-07-08 16:31                                 ` Bean
2008-07-12 14:41                                   ` Robert Millan
2008-07-12 15:16                                     ` Bean
2008-07-12 15:26                                       ` Bean
2008-07-12 17:10                                         ` Robert Millan
2008-07-12 18:05                                           ` Bean
2008-07-17  9:50                                             ` Bean
2008-07-17 15:02                                               ` Javier Martín
2008-07-17 15:18                                                 ` Bean
2008-07-17 15:28                                                   ` Pavel Roskin
2008-07-17 15:22                                                 ` Pavel Roskin
2008-07-17 15:26                                                   ` Bean
2008-07-17 15:45                                                     ` Javier Martín
2008-07-17 15:50                                                       ` Bean
2008-07-17 16:01                                                         ` Javier Martín
2008-07-17 16:17                                                           ` Pavel Roskin
2008-07-17 16:06                                                         ` Pavel Roskin
2008-07-17 16:17                                                           ` Javier Martín
2008-07-19 15:01                                             ` generic BIOS-less boot (Re: [PATCH] New x86_64 EFI patch) Robert Millan
2008-07-12 15:26                                       ` [PATCH] New x86_64 EFI patch Robert Millan
2008-07-12 15:37                                         ` Bean
2008-07-12 15:48                                           ` Bean
2008-06-25 12:59               ` Isaac Dupree
2008-07-03 18:11 ` Marco Gerards
2008-07-03 19:51   ` Bean

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.