[grub] Move to a single patch again.

Peter Jones pjones at fedoraproject.org
Wed Dec 1 20:37:50 UTC 2010


commit 4fcdb3f71899ba5b8410ab272050b9228dec49eb
Author: Peter Jones <pjones at redhat.com>
Date:   Fri Nov 19 11:51:48 2010 -0500

    Move to a single patch again.

 0001-Get-rid-of-usr-bin-cmp-dependency.patch       |   41 -
 0002-Add-strspn-strcspn-and-strtok_r.patch         |  108 -
 ...ng-multiple-image-files-to-the-initrd-com.patch |   74 -
 0004-Obey-2.06-boot-protocol-s-cmdline_size.patch  |   90 -
 grub-0.97-add-strnchr.patch                        |  234 -
 grub-0.97-better-get-memory-map-rhbz607213.patch   |  572 --
 grub-0.97-bz553741-sha2.patch                      | 1984 ----
 grub-0.97-devpath-parsing-error-rhbz626447.patch   |   63 -
 grub-0.97-efi-graphics-mode-selection.patch        |  510 -
 grub-0.97-eficd.patch                              |   50 -
 grub-0.97-efigraph-use-blt.patch                   |   62 -
 grub-0.97-efimap.patch                             | 2005 ----
 grub-0.97-efipxe.patch                             | 1440 ---
 grub-0.97-efislice.patch                           |   21 -
 grub-0.97-efistatus.patch                          |   15 -
 grub-0.97-fat-lowercase.patch                      |   73 -
 grub-0.97-gate-a20.patch                           |  135 -
 grub-0.97-handle-bad-tftp.patch                    |  118 -
 ...7-invert-highlighted-menu-line-rhbz613153.patch |  116 -
 grub-0.97-partitionable-md.patch                   |   11 -
 grub-0.97-printf_hex.patch                         |  174 -
 grub-0.97-relocatable-kernel-on-x86_64-uefi.patch  |  138 -
 grub-0.97-tolower.patch                            |   32 -
 grub-0.97-use-gnuefi.patch                         |   94 -
 grub-0.97-version-command-rhbz621989.patch         |  135 -
 grub-0.97-xfs-buildfix.patch                       |   19 -
 grub-0.97-xfs-writable-strings.patch               |   16 -
 grub-chainloader-timeout.patch                     |  139 -
 grub-efi-large-memory-map.patch                    |   80 -
 grub-ext4-support.patch                            |  474 -
 grub-fedora-9.patch => grub-fedora-14.patch        |10040 ++++++++++++++------
 grub-fix-memory-corruption.patch                   |   22 -
 grub-install_virtio_blk_support.patch              |   21 -
 grub-keystatus.patch                               |  627 --
 grub-low-memory.patch                              |   36 -
 grub-silent.patch                                  |   91 -
 grub.spec                                          |   83 +-
 37 files changed, 7264 insertions(+), 12679 deletions(-)
---
diff --git a/grub-fedora-9.patch b/grub-fedora-14.patch
similarity index 89%
rename from grub-fedora-9.patch
rename to grub-fedora-14.patch
index 9b3dda3..b7075c3 100644
--- a/grub-fedora-9.patch
+++ b/grub-fedora-14.patch
@@ -1,3 +1,16 @@
+From: Peter Jones <pjones at redhat.com>
+Date: Fri, 19 Nov 2010 11:25:00 -0500
+Subject: [PATCH] Changes from grub-0.97 to fedora-14
+
+This patch is a bundle of the changes between grub-0.97 and fedora-14.
+It can be reginerated from the git repository at:
+
+http://git.kernel.org/?p=boot/grub-fedora/grub-fedora.git;a=summary
+
+Using the command:
+
+git diff grub-0.97 fedora-14
+
 diff --git a/ChangeLog b/ChangeLog
 index 0f93033..9602fb9 100644
 --- a/ChangeLog
@@ -8943,719 +8956,17 @@ index 537ab89..0000000
 -  $ac_cs_success || { (exit 1); exit 1; }
 -fi
 -
-diff --git a/configure.ac b/configure.ac
-deleted file mode 100644
-index bb9e1d9..0000000
+diff --git a/configure.ac b/configure.in
+similarity index 86%
+rename from configure.ac
+rename to configure.in
+index bb9e1d9..baa1229 100644
 --- a/configure.ac
-+++ /dev/null
-@@ -1,670 +0,0 @@
--dnl Configure script for GRUB.
--dnl Copyright 1999,2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc.
--
--dnl Permission to use, copy, modify and distribute this software and its
--dnl documentation is hereby granted, provided that both the copyright
--dnl notice and this permission notice appear in all copies of the
--dnl software, derivative works or modified versions, and any portions
--dnl thereof, and that both notices appear in supporting documentation.
--dnl
--dnl THE FREE SOFTWARE FOUNDATION ALLOWS FREE USE OF THIS SOFTWARE IN ITS
--dnl "AS IS" CONDITION.  THE FREE SOFTWARE FOUNDATION DISCLAIMS ANY
--dnl LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE
--dnl USE OF THIS SOFTWARE.
--
--AC_PREREQ(2.57)
--AC_INIT([GRUB], [0.97], [bug-grub at gnu.org])
--AC_CONFIG_SRCDIR([stage2/stage2.c])
--AC_CONFIG_HEADER([config.h])
--AM_INIT_AUTOMAKE
--
--AC_CANONICAL_HOST
--
--case "$host_cpu" in
--i[[3456]]86) host_cpu=i386 ;;
--x86_64) host_cpu=x86_64 ;;
--*) AC_MSG_ERROR([unsupported CPU type]) ;;
--esac
--
--AC_SUBST(host_cpu)
--AC_SUBST(host_vendor)
--
--#
--# Options
--#
--
--AM_MAINTAINER_MODE
--if test "x$enable_maintainer_mode" = xyes; then
--  AC_PATH_PROG(PERL,perl)
--  if test -z "$PERL"; then
--    AC_MSG_ERROR([perl not found])
--  fi
--fi
--
--# This should be checked before AC_PROG_CC
--if test "x$CFLAGS" = x; then
--  default_CFLAGS=yes
--fi
--
--if test "x$host_cpu" = xx86_64; then
--  CFLAGS="-m32 $CFLAGS"
--fi
--
--#
--# Programs
--#
--
--AC_CHECK_TOOL(CC, gcc)
--AC_PROG_CC
--# We need this for older versions of Autoconf.
--_AM_DEPENDENCIES(CC)
--
--dnl Because recent automake complains about AS, set it here.
--CCAS="$CC"
--AC_SUBST(CCAS)
--
--AC_ARG_WITH(binutils,
--  [  --with-binutils=DIR     search the directory DIR to find binutils])
--
--if test "x$with_binutils" != x; then
--dnl AC_PATH_TOOL is not seen in autoconf 2.13, so use AC_PATH_PROG
--dnl instead for now. It is preferable when you cross-compile GRUB.
--dnl  AC_PATH_TOOL(RANLIB, ranlib, :, "$with_binutils:$PATH")
--  AC_PATH_PROG(RANLIB, ranlib, :, "$with_binutils:$PATH")
--else
--  AC_PROG_RANLIB
--fi
--
--# optimization flags
--if test "x$ac_cv_prog_gcc" = xyes; then
--  if test "x$default_CFLAGS" = xyes; then
--    # Autoconf may set CFLAGS to -O2 and/or -g. So eliminate them.
--    CFLAGS="`echo $CFLAGS | sed -e 's/-g//g' -e 's/-O[[0-9]]//g'` -g"
--    # If the user specify the directory for binutils, add the option `-B'.
--    if test "x$with_binutils" != x; then
--      CFLAGS="-B$with_binutils/ $CFLAGS"
--    fi
--    STAGE1_CFLAGS="-O2"
--    GRUB_CFLAGS="-O2"
--    AC_CACHE_CHECK([whether optimization for size works], size_flag, [
--      saved_CFLAGS=$CFLAGS
--      CFLAGS="-Os -g"
--      AC_TRY_COMPILE(, , size_flag=yes, size_flag=no)
--      CFLAGS=$saved_CFLAGS
--    ])
--    if test "x$size_flag" = xyes; then
--      STAGE2_CFLAGS="-Os"
--    else
--      STAGE2_CFLAGS="-O2 -fno-strength-reduce -fno-unroll-loops"
--    fi
--    # OpenBSD has a GCC extension for protecting applications from
--    # stack smashing attacks, but GRUB doesn't want this feature.
--    AC_CACHE_CHECK([whether gcc has -fno-stack-protector],
--		   no_stack_protector_flag, [
--      saved_CFLAGS=$CFLAGS
--      CFLAGS="-fno-stack-protector"
--      AC_TRY_COMPILE(,
--		     ,
--		     no_stack_protector_flag=yes,
--		     no_stack_protector_flag=no)
--      CFLAGS=$saved_CFLAGS
--    ])
--    if test "x$no_stack_protector_flag" = xyes; then
--      STAGE2_CFLAGS="$STAGE2_CFLAGS -fno-stack-protector"
--    fi
--  fi
--fi
--
--AC_SUBST(STAGE1_CFLAGS)
--AC_SUBST(STAGE2_CFLAGS)
--AC_SUBST(GRUB_CFLAGS)
--
--# Enforce coding standards.
--CPPFLAGS="$CPPFLAGS -Wall -Wmissing-prototypes -Wunused -Wshadow"
--CPPFLAGS="$CPPFLAGS -Wpointer-arith"
--
--AC_CACHE_CHECK([whether -Wundef works], undef_flag, [
--  saved_CPPFLAGS="$CPPFLAGS"
--  CPPFLAGS="-Wundef"
--  AC_TRY_COMPILE(, , undef_flag=yes, undef_flag=no)
--  CPPFLAGS="$saved_CPPFLAGS"
--])
--
--# The options `-falign-*' are supported by gcc 3.0 or later.
--# Probably it is sufficient to only check for -falign-loops.
--AC_CACHE_CHECK([whether -falign-loops works], [falign_loop_flag], [
--  saved_CPPFLAGS="$CPPFLAGS"
--  CPPFLAGS="-falign-loops=1"
--  AC_TRY_COMPILE(, , [falign_loop_flag=yes], [falign_loop_flag=no])
--  CPPFLAGS="$saved_CPPFLAGS"
--])
--
--# Force no alignment to save space.
--if test "x$falign_loop_flag" = xyes; then
--  CPPFLAGS="$CPPFLAGS -falign-jumps=1 -falign-loops=1 -falign-functions=1"
--else
--  CPPFLAGS="$CPPFLAGS -malign-jumps=1 -malign-loops=1 -malign-functions=1"
--fi
--
--if test "x$undef_flag" = xyes; then
--  CPPFLAGS="$CPPFLAGS -Wundef"
--fi
--
--if test "x$with_binutils" != x; then
--dnl  AC_PATH_TOOL(OBJCOPY, objcopy, , "$with_binutils:$PATH")
--  AC_PATH_PROG(OBJCOPY, objcopy, , "$with_binutils:$PATH")
--else
--  AC_CHECK_TOOL(OBJCOPY, objcopy)
--fi
--
--# Defined in acinclude.m4.
--grub_ASM_USCORE
--grub_PROG_OBJCOPY_ABSOLUTE
--if test "x$grub_cv_prog_objcopy_absolute" != xyes; then
--  AC_MSG_ERROR([GRUB requires a working absolute objcopy; upgrade your binutils])
--fi
--
--grub_ASM_PREFIX_REQUIREMENT
--
--grub_ASM_ADDR32
--if test "x$grub_cv_asm_addr32" != xyes; then
--  AC_MSG_ERROR([GRUB requires GAS .code16 addr32 support; upgrade your binutils])
--fi
--
--grub_ASM_ABSOLUTE_WITHOUT_ASTERISK
--
--grub_CHECK_START_SYMBOL
--grub_CHECK_USCORE_START_SYMBOL
--if test "x$grub_cv_check_start_symbol" != "xyes" \
--	-a "x$grub_cv_check_uscore_start_symbol" != "xyes"; then
--  AC_MSG_ERROR([Neither start nor _start is defined])
--fi
--
--grub_CHECK_USCORE_USCORE_BSS_START_SYMBOL
--grub_CHECK_USCORE_EDATA_SYMBOL
--grub_CHECK_EDATA_SYMBOL
--if test "x$grub_cv_check_uscore_uscore_bss_start_symbol" != "xyes" \
--	-a "x$grub_cv_check_uscore_edata_symbol" != "xyes" \
--	-a "x$grub_cv_check_edata_symbol" != "xyes"; then
--  AC_MSG_ERROR([None of __bss_start, _edata, edata defined])
--fi
--
--grub_CHECK_END_SYMBOL
--grub_CHECK_USCORE_END_SYMBOL
--if test "x$grub_cv_check_end_symbol" != "xyes" \
--	-a "x$grub_cv_check_uscore_end_symbol" != "xyes"; then
--  AC_MSG_ERROR([Neither end nor _end is defined])
--fi
--
--# Check for curses libraries.
--AC_ARG_WITH(curses,
--  [  --without-curses        do not use curses])
--
--# Get the filename or the whole disk and open it.
--# Known to work on NetBSD.
--AC_CHECK_LIB(util, opendisk, [GRUB_LIBS="$GRUB_LIBS -lutil"
--  AC_DEFINE(HAVE_OPENDISK, 1, [Define if opendisk() in -lutil can be used])])
--
--# Unless the user specify --without-curses, check for curses.
--if test "x$with_curses" != "xno"; then
--  AC_CHECK_LIB(ncurses, wgetch, [GRUB_LIBS="$GRUB_LIBS -lncurses"
--  AC_DEFINE(HAVE_LIBCURSES, 1, [Define if you have a curses library])],
--    [AC_CHECK_LIB(curses, wgetch, [GRUB_LIBS="$GRUB_LIBS -lcurses"
--       AC_DEFINE(HAVE_LIBCURSES, 1, [Define if you have a curses library])])])
--fi
--
--AC_SUBST(GRUB_LIBS)
--
--# Check for headers.
--AC_CHECK_HEADERS(string.h strings.h ncurses/curses.h ncurses.h curses.h)
--
--# Check for user options.
--
--# filesystems support.
--AC_ARG_ENABLE(ext2fs,
--  [  --disable-ext2fs        disable ext2fs support in Stage 2])
--
--if test x"$enable_ext2fs" != xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_EXT2FS=1"
--fi
--
--AC_ARG_ENABLE(fat,
--  [  --disable-fat           disable FAT support in Stage 2])
--
--if test x"$enable_fat" != xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_FAT=1"
--fi
--
--AC_ARG_ENABLE(ffs,
--  [  --disable-ffs           disable FFS support in Stage 2])
--
--if test x"$enable_ffs" != xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_FFS=1"
--fi
--
--AC_ARG_ENABLE(ufs2,
--  [  --disable-ufs2          disable UFS2 support in Stage 2])
--
--if test x"$enable_ufs2" != xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_UFS2=1"
--fi
--
--AC_ARG_ENABLE(minix,
--  [  --disable-minix         disable Minix fs support in Stage 2])
--
--if test x"$enable_minix" != xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_MINIX=1"
--fi
--
--AC_ARG_ENABLE(reiserfs,
--  [  --disable-reiserfs      disable ReiserFS support in Stage 2])
--
--if test x"$enable_reiserfs" != xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_REISERFS=1"
--fi
--
--AC_ARG_ENABLE(vstafs,
--  [  --disable-vstafs        disable VSTa FS support in Stage 2])
--
--if test x"$enable_vstafs" != xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_VSTAFS=1"
--fi
--
--AC_ARG_ENABLE(jfs,
--  [  --disable-jfs           disable IBM JFS support in Stage 2])
--
--if test x"$enable_jfs" != xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_JFS=1"
--fi
--
--AC_ARG_ENABLE(xfs,
--  [  --disable-xfs           disable SGI XFS support in Stage 2])
--
--if test x"$enable_xfs" != xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_XFS=1"
--fi
--
--AC_ARG_ENABLE(iso9660,
--  [  --disable-iso9660       disable ISO9660 support in Stage 2])
--
--if test x"$enable_iso9660" != xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_ISO9660=1"
--fi
--
--dnl AC_ARG_ENABLE(tftp,
--dnl [  --enable-tftp           enable TFTP support in Stage 2])
--dnl 
--dnl #if test x"$enable_tftp" = xyes; then
--dnl FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_TFTP=1"
--dnl fi
--
--AC_ARG_ENABLE(gunzip,
--  [  --disable-gunzip        disable decompression in Stage 2])
--
--if test x"$enable_gunzip" = xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DNO_DECOMPRESSION=1"
--fi
--
--AC_ARG_ENABLE(md5-password,
--  [  --disable-md5-password  disable MD5 password support in Stage 2])
--if test "x$enable_md5_password" != xno; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DUSE_MD5_PASSWORDS=1"
--fi
--
--dnl The netboot support.
--dnl General options.
--AC_ARG_ENABLE(packet-retransmission,
--  [  --disable-packet-retransmission
--                          turn off packet retransmission])
--if test "x$enable_packet_retransmission" != xno; then
--  NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCONGESTED=1"
--fi
--
--AC_ARG_ENABLE(pci-direct,
--  [  --enable-pci-direct     access PCI directly instead of using BIOS])
--if test "x$enable_pci_direct" = xyes; then
--  NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCONFIG_PCI_DIRECT=1"
--fi
--
--dnl Device drivers.
--AC_ARG_ENABLE(3c509,
--  [  --enable-3c509          enable 3Com509 driver])
--if test "x$enable_3c509" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C509"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c509.o"
--fi
--
--AC_ARG_ENABLE(3c529,
--  [  --enable-3c529          enable 3Com529 driver])
--if test "x$enable_3c529" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C529=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c529.o"
--fi
--
--AC_ARG_ENABLE(3c595,
--  [  --enable-3c595          enable 3Com595 driver])
--if test "x$enable_3c595" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C595=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c595.o"
--fi
--
--AC_ARG_ENABLE(3c90x,
--  [  --enable-3c90x          enable 3Com90x driver])
--if test "x$enable_3c90x" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C90X=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c90x.o"
--fi
--
--AC_ARG_ENABLE(cs89x0,
--  [  --enable-cs89x0         enable CS89x0 driver])
--if test "x$enable_cs89x0" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_CS89X0=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS cs89x0.o"
--fi
--
--AC_ARG_ENABLE(davicom,
--  [  --enable-davicom        enable Davicom driver])
--if test "x$enable_davicom" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_DAVICOM=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS davicom.o"
--fi
--
--AC_ARG_ENABLE(depca,
--  [  --enable-depca          enable DEPCA and EtherWORKS driver])
--if test "x$enable_depca" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_DEPCA=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS depca.o"
--fi
--
--AC_ARG_ENABLE(eepro,
--  [  --enable-eepro          enable Etherexpress Pro/10 driver])
--if test "x$enable_eepro" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EEPRO=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS eepro.o"
--fi
--
--AC_ARG_ENABLE(eepro100,
--  [  --enable-eepro100       enable Etherexpress Pro/100 driver])
--if test "x$enable_eepro100" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EEPRO100=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS eepro100.o"
--fi
--
--AC_ARG_ENABLE(epic100,
--  [  --enable-epic100        enable SMC 83c170 EPIC/100 driver])
--if test "x$enable_epic100" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EPIC100=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS epic100.o"
--fi
--
--AC_ARG_ENABLE(3c507,
--  [  --enable-3c507          enable 3Com507 driver])
--if test "x$enable_3c507" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C507=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c507.o"
--fi
--
--AC_ARG_ENABLE(exos205,
--  [  --enable-exos205        enable EXOS205 driver])
--if test "x$enable_exos205" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EXOS205=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS exos205.o"
--fi
--
--AC_ARG_ENABLE(ni5210,
--  [  --enable-ni5210         enable Racal-Interlan NI5210 driver])
--if test "x$enable_ni5210" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI5210=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni5210.o"
--fi
--
--AC_ARG_ENABLE(lance,
--  [  --enable-lance          enable Lance PCI PCNet/32 driver])
--if test "x$enable_lance" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_LANCE=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS lance.o"
--fi
--
--AC_ARG_ENABLE(ne2100,
--  [  --enable-ne2100         enable Novell NE2100 driver])
--if test "x$enable_ne2100" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NE2100=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ne2100.o"
--fi
--
--AC_ARG_ENABLE(ni6510,
--  [  --enable-ni6510         enable Racal-Interlan NI6510 driver])
--if test "x$enable_ni6510" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI6510=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni6510.o"
--fi
--
--AC_ARG_ENABLE(natsemi,
--  [  --enable-natsemi        enable NatSemi DP8381x driver])
--if test "x$enable_natsemi" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NATSEMI=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS natsemi.o"
--fi
--
--AC_ARG_ENABLE(ni5010,
--  [  --enable-ni5010         enable Racal-Interlan NI5010 driver])
--if test "x$enable_ni5010" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI5010=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni5010.o"
--fi
--
--AC_ARG_ENABLE(3c503,
--  [  --enable-3c503          enable 3Com503 driver])
--if test "x$enable_3c503" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C503=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c503.o"
--fi
--
--AC_ARG_ENABLE(ne,
--  [  --enable-ne             enable NE1000/2000 ISA driver])
--if test "x$enable_ne" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NE=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ne.o"
--fi
--
--AC_ARG_ENABLE(ns8390,
--  [  --enable-ns8390         enable NE2000 PCI driver])
--if test "x$enable_ns8390" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NS8390=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ns8390.o"
--fi
--
--AC_ARG_ENABLE(wd,
--  [  --enable-wd             enable WD8003/8013, SMC8216/8416 driver])
--if test "x$enable_wd" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_WD=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS wd.o"
--fi
--
--AC_ARG_ENABLE(otulip,
--  [  --enable-otulip         enable old Tulip driver])
--if test "x$enable_otulip" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_OTULIP=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS otulip.o"
--fi
--
--AC_ARG_ENABLE(rtl8139,
--  [  --enable-rtl8139        enable Realtek 8139 driver])
--if test "x$enable_rtl8139" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_RTL8139=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS rtl8139.o"
--fi
--
--AC_ARG_ENABLE(sis900,
--  [  --enable-sis900         enable SIS 900 and SIS 7016 driver])
--if test "x$enable_sis900" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SIS900=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS sis900.o"
--fi
--
--AC_ARG_ENABLE(sk-g16,
--  [  --enable-sk-g16         enable Schneider and Koch G16 driver])
--if test "x$enable_sk_g16" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SK_G16=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS sk_g16.o"
--fi
--
--AC_ARG_ENABLE(smc9000,
--  [  --enable-smc9000        enable SMC9000 driver])
--if test "x$enable_smc9000" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SMC9000=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS smc9000.o"
--fi
--
--AC_ARG_ENABLE(tiara,
--  [  --enable-tiara          enable Tiara driver])
--if test "x$enable_tiara" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_TIARA=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS tiara.o"
--fi
--
--AC_ARG_ENABLE(tulip,
--  [  --enable-tulip          enable Tulip driver])
--if test "x$enable_tulip" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_TULIP=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS tulip.o"
--fi
--
--AC_ARG_ENABLE(via-rhine,
--  [  --enable-via-rhine      enable Rhine-I/II driver])
--if test "x$enable_via_rhine" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_VIA_RHINE=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS via_rhine.o"
--fi
--
--AC_ARG_ENABLE(w89c840,
--  [  --enable-w89c840        enable Winbond W89c840, Compex RL100-ATX driver])
--if test "x$enable_w89c840" = xyes; then
--  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_W89C840=1"
--  NETBOOT_DRIVERS="$NETBOOT_DRIVERS w89c840.o"
--fi
--
--dnl Check if the netboot support is turned on.
--AM_CONDITIONAL(NETBOOT_SUPPORT, test "x$NET_CFLAGS" != x)
--if test "x$NET_CFLAGS" != x; then
--  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_TFTP=1"
--fi
--
--dnl Extra options.
--AC_ARG_ENABLE(3c503-shmem,
--  [  --enable-3c503-shmem    use 3c503 shared memory mode])
--if test "x$enable_3c503_shmem" = xyes; then
--  NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DT503_SHMEM=1"
--fi
--
--AC_ARG_ENABLE(3c503-aui,
--  [  --enable-3c503-aui      use AUI by default on 3c503 cards])
--if test "x$enable_3c503_aui" = xyes; then
--  NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DT503_AUI=1"
--fi
--
--AC_ARG_ENABLE(compex-rl2000-fix,
--  [  --enable-compex-rl2000-fix
--                          specify this if you have a Compex RL2000 PCI])
--if test "x$enable_compex_rl2000_fix" = xyes; then
--  NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCOMPEX_RL2000_FIX=1"
--fi
--
--AC_ARG_ENABLE(smc9000-scan,
--  [  --enable-smc9000-scan=LIST
--                          probe for SMC9000 I/O addresses using LIST],
--  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DSMC9000_SCAN=$enable_smc9000_scan"])
--
--AC_ARG_ENABLE(ne-scan,
--  [  --enable-ne-scan=LIST   probe for NE base address using LIST],
--  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=$enable_ne_scan"],
--  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=0x280,0x300,0x320,0x340"])
--
--AC_ARG_ENABLE(wd-default-mem,
--  [  --enable-wd-default-mem=MEM
--                          set the default memory location for WD/SMC],
--  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=$enable_wd_default_mem"],
--  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=0xCC000"])
--
--AC_ARG_ENABLE(cs-scan,
--  [  --enable-cs-scan=LIST   probe for CS89x0 base address using LIST],
--  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCS_SCAN=$enable_cs_scan"])
--
--dnl Diskless
--AC_ARG_ENABLE(diskless,
--  [  --enable-diskless       enable diskless support])
--AM_CONDITIONAL(DISKLESS_SUPPORT, test "x$enable_diskless" = xyes)
--
--dnl Hercules terminal
--AC_ARG_ENABLE(hercules,
--  [  --disable-hercules      disable hercules terminal support])
--AM_CONDITIONAL(HERCULES_SUPPORT, test "x$enable_hercules" != xno)
--
--dnl Serial terminal
--AC_ARG_ENABLE(serial,
--  [  --disable-serial        disable serial terminal support])
--AM_CONDITIONAL(SERIAL_SUPPORT, test "x$enable_serial" != xno)
--
--dnl Simulation of the slowness of a serial device.
--AC_ARG_ENABLE(serial-speed-simulation,
--  [  --enable-serial-speed-simulation
--                          simulate the slowness of a serial device])
--AM_CONDITIONAL(SERIAL_SPEED_SIMULATION,
--  test "x$enable_serial_speed_simulation" = xyes)
--
--# Sanity check.
--if test "x$enable_diskless" = xyes; then
--  if test "x$NET_CFLAGS" = x; then
--    AC_MSG_ERROR([You must enable at least one network driver])
--  fi
--fi
--
--dnl Embed a menu string in GRUB itself.
--AC_ARG_ENABLE(preset-menu,
--  [  --enable-preset-menu=FILE
--                          preset a menu file FILE in Stage 2])
--if test "x$enable_preset_menu" = x; then
--  :
--else
--  if test -r $enable_preset_menu; then
--    grub_DEFINE_FILE(PRESET_MENU_STRING, [$enable_preset_menu],
--    		     [Define if there is user specified preset menu string])
--  else
--    AC_MSG_ERROR([Cannot read the preset menu file $enable_preset_menu])
--  fi
--fi
--
--dnl Build the example Multiboot kernel.
--AC_ARG_ENABLE(example-kernel,
--  [  --enable-example-kernel
--                          build the example Multiboot kernel])
--AM_CONDITIONAL(BUILD_EXAMPLE_KERNEL, test "x$enable_example_kernel" = xyes)
--
--dnl Automatic Linux mem= option.
--AC_ARG_ENABLE(auto-linux-mem-opt,
--  [  --disable-auto-linux-mem-opt
--                          don't pass Linux mem= option automatically])
--if test "x$enable_auto_linux_mem_opt" = xno; then
--  :
--else
--  AC_DEFINE(AUTO_LINUX_MEM_OPT, 1, [Define if you don't want to pass the mem= option to Linux])
--fi
--
--dnl Now substitute the variables.
--AC_SUBST(FSYS_CFLAGS)
--AC_SUBST(NET_CFLAGS)
--AC_SUBST(NET_EXTRAFLAGS)
--AC_SUBST(NETBOOT_DRIVERS)
--
--dnl Because recent automake complains about CCASFLAGS, set it here.
--CCASFLAGS='$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)'
--AC_SUBST(CCASFLAGS)
--
--
--dnl Output.
--AC_CONFIG_FILES([Makefile stage1/Makefile stage2/Makefile \
--		 docs/Makefile lib/Makefile util/Makefile \
--		 grub/Makefile netboot/Makefile util/grub-image \
--		 util/grub-install util/grub-md5-crypt \
--		 util/grub-terminfo util/grub-set-default])
--AC_OUTPUT
-diff --git a/configure.in b/configure.in
-new file mode 100644
-index 0000000..62209dc
---- /dev/null
 +++ b/configure.in
-@@ -0,0 +1,757 @@
-+dnl Configure script for GRUB.
-+dnl Copyright 1999,2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc.
-+
-+dnl Permission to use, copy, modify and distribute this software and its
-+dnl documentation is hereby granted, provided that both the copyright
-+dnl notice and this permission notice appear in all copies of the
-+dnl software, derivative works or modified versions, and any portions
-+dnl thereof, and that both notices appear in supporting documentation.
-+dnl
-+dnl THE FREE SOFTWARE FOUNDATION ALLOWS FREE USE OF THIS SOFTWARE IN ITS
-+dnl "AS IS" CONDITION.  THE FREE SOFTWARE FOUNDATION DISCLAIMS ANY
-+dnl LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE
-+dnl USE OF THIS SOFTWARE.
-+
-+AC_PREREQ(2.57)
-+AC_INIT([GRUB], [0.97], [bug-grub at gnu.org])
-+AC_CONFIG_SRCDIR([stage2/stage2.c])
-+AC_CONFIG_HEADER([config.h])
-+AM_INIT_AUTOMAKE
-+
-+AC_CANONICAL_HOST
-+
-+case "$host_cpu" in
-+i[[3456]]86) host_cpu=i386 ;;
-+x86_64) host_cpu=x86_64 ;;
-+*) AC_MSG_ERROR([unsupported CPU type]) ;;
-+esac
-+
-+AC_SUBST(host_cpu)
-+AC_SUBST(host_vendor)
-+
+@@ -29,6 +29,63 @@ esac
+ AC_SUBST(host_cpu)
+ AC_SUBST(host_vendor)
+ 
 +# Specify the platform (such as firmware).
 +AC_ARG_WITH([platform],
 +            AS_HELP_STRING([--with-platform=PLATFORM],
@@ -9690,7 +9001,7 @@ index 0000000..62209dc
 +  AC_SUBST(EFI_ARCH)
 +fi
 +
-+gnuefi_path=/usr/lib/gnuefi
++gnuefi_path=${libdir}/gnuefi
 +gnuefi_crt0=${gnuefi_path}/crt0-efi-${EFI_ARCH}.o
 +if ! test -f $gnuefi_crt0 ; then
 +  gnuefi_crt0=crt0-efi.o
@@ -9703,6 +9014,8 @@ index 0000000..62209dc
 +fi
 +GNUEFI_LDS=${gnuefi_lds}
 +AC_SUBST(GNUEFI_LDS)
++LIBGNUEFI=${libdir}/libgnuefi.a
++AC_SUBST(LIBGNUEFI)
 +
 +AC_SUBST(platform)
 +AM_CONDITIONAL(PLATFORM_EFI, test "x$platform" = xefi)
@@ -9711,93 +9024,31 @@ index 0000000..62209dc
 +   AC_DEFINE(PLATFORM_EFI, 1, [Define if you run on EFI platform.])
 +fi
 +
-+#
-+# Options
-+#
-+
-+AM_MAINTAINER_MODE
-+if test "x$enable_maintainer_mode" = xyes; then
-+  AC_PATH_PROG(PERL,perl)
-+  if test -z "$PERL"; then
-+    AC_MSG_ERROR([perl not found])
-+  fi
-+fi
-+
-+# This should be checked before AC_PROG_CC
-+if test "x$CFLAGS" = x; then
-+  default_CFLAGS=yes
-+fi
-+
+ #
+ # Options
+ #
+@@ -46,7 +103,7 @@ if test "x$CFLAGS" = x; then
+   default_CFLAGS=yes
+ fi
+ 
+-if test "x$host_cpu" = xx86_64; then
 +if test "x$platform" = xpc -a "x$host_cpu" = xx86_64; then
-+  CFLAGS="-m32 $CFLAGS"
-+fi
-+
-+#
-+# Programs
-+#
-+
-+AC_CHECK_TOOL(CC, gcc)
-+AC_PROG_CC
-+# We need this for older versions of Autoconf.
-+_AM_DEPENDENCIES(CC)
-+
-+dnl Because recent automake complains about AS, set it here.
-+CCAS="$CC"
-+AC_SUBST(CCAS)
-+
+   CFLAGS="-m32 $CFLAGS"
+ fi
+ 
+@@ -63,6 +120,8 @@ dnl Because recent automake complains about AS, set it here.
+ CCAS="$CC"
+ AC_SUBST(CCAS)
+ 
 +_AM_DEPENDENCIES(CCAS)
 +
-+AC_ARG_WITH(binutils,
-+  [  --with-binutils=DIR     search the directory DIR to find binutils])
-+
-+if test "x$with_binutils" != x; then
-+dnl AC_PATH_TOOL is not seen in autoconf 2.13, so use AC_PATH_PROG
-+dnl instead for now. It is preferable when you cross-compile GRUB.
-+dnl  AC_PATH_TOOL(RANLIB, ranlib, :, "$with_binutils:$PATH")
-+  AC_PATH_PROG(RANLIB, ranlib, :, "$with_binutils:$PATH")
-+else
-+  AC_PROG_RANLIB
-+fi
-+
-+# optimization flags
-+if test "x$ac_cv_prog_gcc" = xyes; then
-+  if test "x$default_CFLAGS" = xyes; then
-+    # Autoconf may set CFLAGS to -O2 and/or -g. So eliminate them.
-+    CFLAGS="`echo $CFLAGS | sed -e 's/-g//g' -e 's/-O[[0-9]]//g'` -g"
-+    # If the user specify the directory for binutils, add the option `-B'.
-+    if test "x$with_binutils" != x; then
-+      CFLAGS="-B$with_binutils/ $CFLAGS"
-+    fi
-+    STAGE1_CFLAGS="-O2"
-+    GRUB_CFLAGS="-O2"
-+    AC_CACHE_CHECK([whether optimization for size works], size_flag, [
-+      saved_CFLAGS=$CFLAGS
-+      CFLAGS="-Os -g"
-+      AC_TRY_COMPILE(, , size_flag=yes, size_flag=no)
-+      CFLAGS=$saved_CFLAGS
-+    ])
-+    if test "x$size_flag" = xyes; then
-+      STAGE2_CFLAGS="-Os"
-+    else
-+      STAGE2_CFLAGS="-O2 -fno-strength-reduce -fno-unroll-loops"
-+    fi
-+    # OpenBSD has a GCC extension for protecting applications from
-+    # stack smashing attacks, but GRUB doesn't want this feature.
-+    AC_CACHE_CHECK([whether gcc has -fno-stack-protector],
-+		   no_stack_protector_flag, [
-+      saved_CFLAGS=$CFLAGS
-+      CFLAGS="-fno-stack-protector"
-+      AC_TRY_COMPILE(,
-+		     ,
-+		     no_stack_protector_flag=yes,
-+		     no_stack_protector_flag=no)
-+      CFLAGS=$saved_CFLAGS
-+    ])
-+    if test "x$no_stack_protector_flag" = xyes; then
-+      STAGE2_CFLAGS="$STAGE2_CFLAGS -fno-stack-protector"
-+    fi
-+  fi
-+fi
+ AC_ARG_WITH(binutils,
+   [  --with-binutils=DIR     search the directory DIR to find binutils])
+ 
+@@ -114,6 +173,20 @@ if test "x$ac_cv_prog_gcc" = xyes; then
+     fi
+   fi
+ fi
 +STAGE2_CFLAGS="$STAGE2_CFLAGS -isystem `$CC -print-file-name=include`"
 +
 +LIBGCC=$(gcc $CFLAGS -static-libgcc -print-libgcc-file-name)
@@ -9812,576 +9063,102 @@ index 0000000..62209dc
 +     STAGE2_CFLAGS="$STAGE2_CFLAGS -DEFI_FUNCTION_WRAPPER"
 +  fi
 +fi
-+
-+AC_SUBST(STAGE1_CFLAGS)
-+AC_SUBST(STAGE2_CFLAGS)
-+AC_SUBST(GRUB_CFLAGS)
-+
-+# Enforce coding standards.
-+CPPFLAGS="$CPPFLAGS -Wall -Wmissing-prototypes -Wunused -Wshadow"
-+CPPFLAGS="$CPPFLAGS -Wpointer-arith"
-+
-+AC_CACHE_CHECK([whether -Wundef works], undef_flag, [
-+  saved_CPPFLAGS="$CPPFLAGS"
-+  CPPFLAGS="-Wundef"
-+  AC_TRY_COMPILE(, , undef_flag=yes, undef_flag=no)
-+  CPPFLAGS="$saved_CPPFLAGS"
-+])
-+
-+# The options `-falign-*' are supported by gcc 3.0 or later.
-+# Probably it is sufficient to only check for -falign-loops.
-+AC_CACHE_CHECK([whether -falign-loops works], [falign_loop_flag], [
-+  saved_CPPFLAGS="$CPPFLAGS"
-+  CPPFLAGS="-falign-loops=1"
-+  AC_TRY_COMPILE(, , [falign_loop_flag=yes], [falign_loop_flag=no])
-+  CPPFLAGS="$saved_CPPFLAGS"
-+])
-+
-+# Force no alignment to save space.
-+if test "x$falign_loop_flag" = xyes; then
-+  CPPFLAGS="$CPPFLAGS -falign-jumps=1 -falign-loops=1 -falign-functions=1"
-+else
-+  CPPFLAGS="$CPPFLAGS -malign-jumps=1 -malign-loops=1 -malign-functions=1"
-+fi
-+
-+if test "x$undef_flag" = xyes; then
-+  CPPFLAGS="$CPPFLAGS -Wundef"
-+fi
-+
-+if test "x$with_binutils" != x; then
-+dnl  AC_PATH_TOOL(OBJCOPY, objcopy, , "$with_binutils:$PATH")
-+  AC_PATH_PROG(OBJCOPY, objcopy, , "$with_binutils:$PATH")
-+else
-+  AC_CHECK_TOOL(OBJCOPY, objcopy)
-+fi
-+
-+# Defined in acinclude.m4.
-+grub_ASM_USCORE
+ 
+ AC_SUBST(STAGE1_CFLAGS)
+ AC_SUBST(STAGE2_CFLAGS)
+@@ -159,9 +232,12 @@ fi
+ 
+ # Defined in acinclude.m4.
+ grub_ASM_USCORE
+-grub_PROG_OBJCOPY_ABSOLUTE
+-if test "x$grub_cv_prog_objcopy_absolute" != xyes; then
+-  AC_MSG_ERROR([GRUB requires a working absolute objcopy; upgrade your binutils])
 +
 +if test "x$platform" != xefi; then
 +  grub_PROG_OBJCOPY_ABSOLUTE
 +  if test "x$grub_cv_prog_objcopy_absolute" != xyes; then
 +    AC_MSG_ERROR([GRUB requires a working absolute objcopy; upgrade your binutils])
 +  fi
-+fi
-+
-+grub_ASM_PREFIX_REQUIREMENT
-+
-+grub_ASM_ADDR32
-+if test "x$grub_cv_asm_addr32" != xyes; then
-+  AC_MSG_ERROR([GRUB requires GAS .code16 addr32 support; upgrade your binutils])
-+fi
-+
-+grub_ASM_ABSOLUTE_WITHOUT_ASTERISK
-+
-+grub_CHECK_START_SYMBOL
-+grub_CHECK_USCORE_START_SYMBOL
-+if test "x$grub_cv_check_start_symbol" != "xyes" \
-+	-a "x$grub_cv_check_uscore_start_symbol" != "xyes"; then
-+  AC_MSG_ERROR([Neither start nor _start is defined])
-+fi
-+
-+grub_CHECK_USCORE_USCORE_BSS_START_SYMBOL
-+grub_CHECK_USCORE_EDATA_SYMBOL
-+grub_CHECK_EDATA_SYMBOL
-+if test "x$grub_cv_check_uscore_uscore_bss_start_symbol" != "xyes" \
-+	-a "x$grub_cv_check_uscore_edata_symbol" != "xyes" \
-+	-a "x$grub_cv_check_edata_symbol" != "xyes"; then
-+  AC_MSG_ERROR([None of __bss_start, _edata, edata defined])
-+fi
-+
-+grub_CHECK_END_SYMBOL
-+grub_CHECK_USCORE_END_SYMBOL
-+if test "x$grub_cv_check_end_symbol" != "xyes" \
-+	-a "x$grub_cv_check_uscore_end_symbol" != "xyes"; then
-+  AC_MSG_ERROR([Neither end nor _end is defined])
-+fi
-+
-+# Check for curses libraries.
-+AC_ARG_WITH(curses,
-+  [  --without-curses        do not use curses])
-+
-+# Get the filename or the whole disk and open it.
-+# Known to work on NetBSD.
-+AC_CHECK_LIB(util, opendisk, [GRUB_LIBS="$GRUB_LIBS -lutil"
-+  AC_DEFINE(HAVE_OPENDISK, 1, [Define if opendisk() in -lutil can be used])])
-+
-+# Unless the user specify --without-curses, check for curses.
-+if test "x$with_curses" != "xno"; then
+ fi
+ 
+ grub_ASM_PREFIX_REQUIREMENT
+@@ -207,9 +283,9 @@ AC_CHECK_LIB(util, opendisk, [GRUB_LIBS="$GRUB_LIBS -lutil"
+ 
+ # Unless the user specify --without-curses, check for curses.
+ if test "x$with_curses" != "xno"; then
+-  AC_CHECK_LIB(ncurses, wgetch, [GRUB_LIBS="$GRUB_LIBS -lncurses"
 +  AC_CHECK_LIB(ncurses, wgetch, [GRUB_LIBS="$GRUB_LIBS -Wl,-Bstatic -lncurses -ltinfo -Wl,-Bdynamic"
-+  AC_DEFINE(HAVE_LIBCURSES, 1, [Define if you have a curses library])],
+   AC_DEFINE(HAVE_LIBCURSES, 1, [Define if you have a curses library])],
+-    [AC_CHECK_LIB(curses, wgetch, [GRUB_LIBS="$GRUB_LIBS -lcurses"
 +    [AC_CHECK_LIB(curses, wgetch, [GRUB_LIBS="$GRUB_LIBS -Wl,-Bstatic -lcurses -Wl,-Bdynamic"
-+       AC_DEFINE(HAVE_LIBCURSES, 1, [Define if you have a curses library])])])
-+fi
-+
-+AC_SUBST(GRUB_LIBS)
-+
-+# Check for headers.
-+AC_CHECK_HEADERS(string.h strings.h ncurses/curses.h ncurses.h curses.h)
-+
-+# Check for user options.
-+
-+# filesystems support.
-+AC_ARG_ENABLE(ext2fs,
-+  [  --disable-ext2fs        disable ext2fs support in Stage 2])
+        AC_DEFINE(HAVE_LIBCURSES, 1, [Define if you have a curses library])])])
+ fi
+ 
+@@ -595,9 +671,18 @@ AC_ARG_ENABLE(diskless,
+   [  --enable-diskless       enable diskless support])
+ AM_CONDITIONAL(DISKLESS_SUPPORT, test "x$enable_diskless" = xyes)
+ 
++dnl Graphical splashscreen support
++AC_ARG_ENABLE(graphics,
++  [  --disable-graphics      disable graphics terminal support])
++AM_CONDITIONAL(GRAPHICS_SUPPORT, test "x$enable_graphics" != xno)
 +
-+if test x"$enable_ext2fs" != xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_EXT2FS=1"
+ dnl Hercules terminal
+-AC_ARG_ENABLE(hercules,
+-  [  --disable-hercules      disable hercules terminal support])
++if test "x$platform" = xefi; then
++  enable_hercules=no
++else
++  AC_ARG_ENABLE(hercules,
++    [  --disable-hercules      disable hercules terminal support])
 +fi
-+
-+AC_ARG_ENABLE(fat,
-+  [  --disable-fat           disable FAT support in Stage 2])
-+
-+if test x"$enable_fat" != xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_FAT=1"
-+fi
-+
-+AC_ARG_ENABLE(ffs,
-+  [  --disable-ffs           disable FFS support in Stage 2])
-+
-+if test x"$enable_ffs" != xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_FFS=1"
-+fi
-+
-+AC_ARG_ENABLE(ufs2,
-+  [  --disable-ufs2          disable UFS2 support in Stage 2])
-+
-+if test x"$enable_ufs2" != xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_UFS2=1"
-+fi
-+
-+AC_ARG_ENABLE(minix,
-+  [  --disable-minix         disable Minix fs support in Stage 2])
-+
-+if test x"$enable_minix" != xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_MINIX=1"
-+fi
-+
-+AC_ARG_ENABLE(reiserfs,
-+  [  --disable-reiserfs      disable ReiserFS support in Stage 2])
-+
-+if test x"$enable_reiserfs" != xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_REISERFS=1"
-+fi
-+
-+AC_ARG_ENABLE(vstafs,
-+  [  --disable-vstafs        disable VSTa FS support in Stage 2])
-+
-+if test x"$enable_vstafs" != xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_VSTAFS=1"
-+fi
-+
-+AC_ARG_ENABLE(jfs,
-+  [  --disable-jfs           disable IBM JFS support in Stage 2])
-+
-+if test x"$enable_jfs" != xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_JFS=1"
-+fi
-+
-+AC_ARG_ENABLE(xfs,
-+  [  --disable-xfs           disable SGI XFS support in Stage 2])
-+
-+if test x"$enable_xfs" != xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_XFS=1"
-+fi
-+
-+AC_ARG_ENABLE(iso9660,
-+  [  --disable-iso9660       disable ISO9660 support in Stage 2])
-+
-+if test x"$enable_iso9660" != xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_ISO9660=1"
-+fi
-+
-+dnl AC_ARG_ENABLE(tftp,
-+dnl [  --enable-tftp           enable TFTP support in Stage 2])
-+dnl 
-+dnl #if test x"$enable_tftp" = xyes; then
-+dnl FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_TFTP=1"
-+dnl fi
-+
-+AC_ARG_ENABLE(gunzip,
-+  [  --disable-gunzip        disable decompression in Stage 2])
-+
-+if test x"$enable_gunzip" = xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DNO_DECOMPRESSION=1"
-+fi
-+
-+AC_ARG_ENABLE(md5-password,
-+  [  --disable-md5-password  disable MD5 password support in Stage 2])
-+if test "x$enable_md5_password" != xno; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DUSE_MD5_PASSWORDS=1"
-+fi
-+
-+dnl The netboot support.
-+dnl General options.
-+AC_ARG_ENABLE(packet-retransmission,
-+  [  --disable-packet-retransmission
-+                          turn off packet retransmission])
-+if test "x$enable_packet_retransmission" != xno; then
-+  NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCONGESTED=1"
-+fi
-+
-+AC_ARG_ENABLE(pci-direct,
-+  [  --enable-pci-direct     access PCI directly instead of using BIOS])
-+if test "x$enable_pci_direct" = xyes; then
-+  NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCONFIG_PCI_DIRECT=1"
-+fi
-+
-+dnl Device drivers.
-+AC_ARG_ENABLE(3c509,
-+  [  --enable-3c509          enable 3Com509 driver])
-+if test "x$enable_3c509" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C509"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c509.o"
-+fi
-+
-+AC_ARG_ENABLE(3c529,
-+  [  --enable-3c529          enable 3Com529 driver])
-+if test "x$enable_3c529" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C529=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c529.o"
-+fi
-+
-+AC_ARG_ENABLE(3c595,
-+  [  --enable-3c595          enable 3Com595 driver])
-+if test "x$enable_3c595" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C595=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c595.o"
-+fi
-+
-+AC_ARG_ENABLE(3c90x,
-+  [  --enable-3c90x          enable 3Com90x driver])
-+if test "x$enable_3c90x" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C90X=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c90x.o"
-+fi
-+
-+AC_ARG_ENABLE(cs89x0,
-+  [  --enable-cs89x0         enable CS89x0 driver])
-+if test "x$enable_cs89x0" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_CS89X0=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS cs89x0.o"
-+fi
-+
-+AC_ARG_ENABLE(davicom,
-+  [  --enable-davicom        enable Davicom driver])
-+if test "x$enable_davicom" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_DAVICOM=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS davicom.o"
-+fi
-+
-+AC_ARG_ENABLE(depca,
-+  [  --enable-depca          enable DEPCA and EtherWORKS driver])
-+if test "x$enable_depca" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_DEPCA=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS depca.o"
-+fi
-+
-+AC_ARG_ENABLE(eepro,
-+  [  --enable-eepro          enable Etherexpress Pro/10 driver])
-+if test "x$enable_eepro" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EEPRO=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS eepro.o"
-+fi
-+
-+AC_ARG_ENABLE(eepro100,
-+  [  --enable-eepro100       enable Etherexpress Pro/100 driver])
-+if test "x$enable_eepro100" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EEPRO100=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS eepro100.o"
-+fi
-+
-+AC_ARG_ENABLE(epic100,
-+  [  --enable-epic100        enable SMC 83c170 EPIC/100 driver])
-+if test "x$enable_epic100" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EPIC100=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS epic100.o"
-+fi
-+
-+AC_ARG_ENABLE(3c507,
-+  [  --enable-3c507          enable 3Com507 driver])
-+if test "x$enable_3c507" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C507=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c507.o"
-+fi
-+
-+AC_ARG_ENABLE(exos205,
-+  [  --enable-exos205        enable EXOS205 driver])
-+if test "x$enable_exos205" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EXOS205=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS exos205.o"
-+fi
-+
-+AC_ARG_ENABLE(ni5210,
-+  [  --enable-ni5210         enable Racal-Interlan NI5210 driver])
-+if test "x$enable_ni5210" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI5210=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni5210.o"
-+fi
-+
-+AC_ARG_ENABLE(lance,
-+  [  --enable-lance          enable Lance PCI PCNet/32 driver])
-+if test "x$enable_lance" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_LANCE=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS lance.o"
-+fi
-+
-+AC_ARG_ENABLE(ne2100,
-+  [  --enable-ne2100         enable Novell NE2100 driver])
-+if test "x$enable_ne2100" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NE2100=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ne2100.o"
-+fi
-+
-+AC_ARG_ENABLE(ni6510,
-+  [  --enable-ni6510         enable Racal-Interlan NI6510 driver])
-+if test "x$enable_ni6510" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI6510=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni6510.o"
-+fi
-+
-+AC_ARG_ENABLE(natsemi,
-+  [  --enable-natsemi        enable NatSemi DP8381x driver])
-+if test "x$enable_natsemi" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NATSEMI=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS natsemi.o"
-+fi
-+
-+AC_ARG_ENABLE(ni5010,
-+  [  --enable-ni5010         enable Racal-Interlan NI5010 driver])
-+if test "x$enable_ni5010" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI5010=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni5010.o"
-+fi
-+
-+AC_ARG_ENABLE(3c503,
-+  [  --enable-3c503          enable 3Com503 driver])
-+if test "x$enable_3c503" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C503=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c503.o"
-+fi
-+
-+AC_ARG_ENABLE(ne,
-+  [  --enable-ne             enable NE1000/2000 ISA driver])
-+if test "x$enable_ne" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NE=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ne.o"
-+fi
-+
-+AC_ARG_ENABLE(ns8390,
-+  [  --enable-ns8390         enable NE2000 PCI driver])
-+if test "x$enable_ns8390" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NS8390=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS ns8390.o"
-+fi
-+
-+AC_ARG_ENABLE(wd,
-+  [  --enable-wd             enable WD8003/8013, SMC8216/8416 driver])
-+if test "x$enable_wd" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_WD=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS wd.o"
-+fi
-+
-+AC_ARG_ENABLE(otulip,
-+  [  --enable-otulip         enable old Tulip driver])
-+if test "x$enable_otulip" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_OTULIP=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS otulip.o"
-+fi
-+
-+AC_ARG_ENABLE(rtl8139,
-+  [  --enable-rtl8139        enable Realtek 8139 driver])
-+if test "x$enable_rtl8139" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_RTL8139=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS rtl8139.o"
-+fi
-+
-+AC_ARG_ENABLE(sis900,
-+  [  --enable-sis900         enable SIS 900 and SIS 7016 driver])
-+if test "x$enable_sis900" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SIS900=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS sis900.o"
-+fi
-+
-+AC_ARG_ENABLE(sk-g16,
-+  [  --enable-sk-g16         enable Schneider and Koch G16 driver])
-+if test "x$enable_sk_g16" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SK_G16=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS sk_g16.o"
-+fi
-+
-+AC_ARG_ENABLE(smc9000,
-+  [  --enable-smc9000        enable SMC9000 driver])
-+if test "x$enable_smc9000" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SMC9000=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS smc9000.o"
-+fi
-+
-+AC_ARG_ENABLE(tiara,
-+  [  --enable-tiara          enable Tiara driver])
-+if test "x$enable_tiara" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_TIARA=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS tiara.o"
-+fi
-+
-+AC_ARG_ENABLE(tulip,
-+  [  --enable-tulip          enable Tulip driver])
-+if test "x$enable_tulip" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_TULIP=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS tulip.o"
-+fi
-+
-+AC_ARG_ENABLE(via-rhine,
-+  [  --enable-via-rhine      enable Rhine-I/II driver])
-+if test "x$enable_via_rhine" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_VIA_RHINE=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS via_rhine.o"
-+fi
-+
-+AC_ARG_ENABLE(w89c840,
-+  [  --enable-w89c840        enable Winbond W89c840, Compex RL100-ATX driver])
-+if test "x$enable_w89c840" = xyes; then
-+  NET_CFLAGS="$NET_CFLAGS -DINCLUDE_W89C840=1"
-+  NETBOOT_DRIVERS="$NETBOOT_DRIVERS w89c840.o"
-+fi
-+
-+dnl Check if the netboot support is turned on.
-+AM_CONDITIONAL(NETBOOT_SUPPORT, test "x$NET_CFLAGS" != x)
-+if test "x$NET_CFLAGS" != x; then
-+  FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_TFTP=1"
-+fi
-+
-+dnl Extra options.
-+AC_ARG_ENABLE(3c503-shmem,
-+  [  --enable-3c503-shmem    use 3c503 shared memory mode])
-+if test "x$enable_3c503_shmem" = xyes; then
-+  NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DT503_SHMEM=1"
-+fi
-+
-+AC_ARG_ENABLE(3c503-aui,
-+  [  --enable-3c503-aui      use AUI by default on 3c503 cards])
-+if test "x$enable_3c503_aui" = xyes; then
-+  NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DT503_AUI=1"
-+fi
-+
-+AC_ARG_ENABLE(compex-rl2000-fix,
-+  [  --enable-compex-rl2000-fix
-+                          specify this if you have a Compex RL2000 PCI])
-+if test "x$enable_compex_rl2000_fix" = xyes; then
-+  NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCOMPEX_RL2000_FIX=1"
-+fi
-+
-+AC_ARG_ENABLE(smc9000-scan,
-+  [  --enable-smc9000-scan=LIST
-+                          probe for SMC9000 I/O addresses using LIST],
-+  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DSMC9000_SCAN=$enable_smc9000_scan"])
-+
-+AC_ARG_ENABLE(ne-scan,
-+  [  --enable-ne-scan=LIST   probe for NE base address using LIST],
-+  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=$enable_ne_scan"],
-+  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=0x280,0x300,0x320,0x340"])
-+
-+AC_ARG_ENABLE(wd-default-mem,
-+  [  --enable-wd-default-mem=MEM
-+                          set the default memory location for WD/SMC],
-+  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=$enable_wd_default_mem"],
-+  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=0xCC000"])
-+
-+AC_ARG_ENABLE(cs-scan,
-+  [  --enable-cs-scan=LIST   probe for CS89x0 base address using LIST],
-+  [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCS_SCAN=$enable_cs_scan"])
-+
-+dnl Diskless
-+AC_ARG_ENABLE(diskless,
-+  [  --enable-diskless       enable diskless support])
-+AM_CONDITIONAL(DISKLESS_SUPPORT, test "x$enable_diskless" = xyes)
-+
-+dnl Graphical splashscreen support
-+AC_ARG_ENABLE(graphics,
-+  [  --disable-graphics      disable graphics terminal support])
-+AM_CONDITIONAL(GRAPHICS_SUPPORT, test "x$enable_graphics" != xno)
-+
-+dnl Hercules terminal
-+if test "x$platform" = xefi; then
-+  enable_hercules=no
-+else
-+  AC_ARG_ENABLE(hercules,
-+    [  --disable-hercules      disable hercules terminal support])
-+fi
-+AM_CONDITIONAL(HERCULES_SUPPORT, test "x$enable_hercules" != xno)
-+
-+dnl Serial terminal
-+AC_ARG_ENABLE(serial,
-+  [  --disable-serial        disable serial terminal support])
-+AM_CONDITIONAL(SERIAL_SUPPORT, test "x$enable_serial" != xno)
-+
-+dnl Simulation of the slowness of a serial device.
-+AC_ARG_ENABLE(serial-speed-simulation,
-+  [  --enable-serial-speed-simulation
-+                          simulate the slowness of a serial device])
-+AM_CONDITIONAL(SERIAL_SPEED_SIMULATION,
-+  test "x$enable_serial_speed_simulation" = xyes)
-+
-+# Sanity check.
-+if test "x$enable_diskless" = xyes; then
-+  if test "x$NET_CFLAGS" = x; then
-+    AC_MSG_ERROR([You must enable at least one network driver])
-+  fi
-+fi
-+
-+dnl Embed a menu string in GRUB itself.
-+AC_ARG_ENABLE(preset-menu,
-+  [  --enable-preset-menu=FILE
-+                          preset a menu file FILE in Stage 2])
-+if test "x$enable_preset_menu" = x; then
-+  :
-+else
-+  if test -r $enable_preset_menu; then
-+    grub_DEFINE_FILE(PRESET_MENU_STRING, [$enable_preset_menu],
-+    		     [Define if there is user specified preset menu string])
-+  else
-+    AC_MSG_ERROR([Cannot read the preset menu file $enable_preset_menu])
-+  fi
-+fi
-+
-+dnl Build the example Multiboot kernel.
-+AC_ARG_ENABLE(example-kernel,
-+  [  --enable-example-kernel
-+                          build the example Multiboot kernel])
-+AM_CONDITIONAL(BUILD_EXAMPLE_KERNEL, test "x$enable_example_kernel" = xyes)
-+
-+dnl Automatic Linux mem= option.
-+AC_ARG_ENABLE(auto-linux-mem-opt,
-+  [  --disable-auto-linux-mem-opt
-+                          don't pass Linux mem= option automatically])
-+if test "x$enable_auto_linux_mem_opt" = xno; then
-+  :
-+else
-+  AC_DEFINE(AUTO_LINUX_MEM_OPT, 1, [Define if you don't want to pass the mem= option to Linux])
-+fi
-+
-+dnl Now substitute the variables.
-+AC_SUBST(FSYS_CFLAGS)
-+AC_SUBST(NET_CFLAGS)
-+AC_SUBST(NET_EXTRAFLAGS)
-+AC_SUBST(NETBOOT_DRIVERS)
-+
-+dnl Because recent automake complains about CCASFLAGS, set it here.
-+CCASFLAGS='$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)'
-+AC_SUBST(CCASFLAGS)
-+
-+
-+dnl Output.
+ AM_CONDITIONAL(HERCULES_SUPPORT, test "x$enable_hercules" != xno)
+ 
+ dnl Serial terminal
+@@ -662,9 +747,13 @@ AC_SUBST(CCASFLAGS)
+ 
+ 
+ dnl Output.
 +if test "x$platform" = xefi; then
 +  AC_CONFIG_FILES([efi/Makefile])
 +  AC_CONFIG_LINKS([efi/grub/cpu:efi/grub/$host_cpu])
 +fi
-+AC_CONFIG_FILES([Makefile stage1/Makefile stage2/Makefile \
-+		 docs/Makefile lib/Makefile util/Makefile \
-+		 grub/Makefile netboot/Makefile util/grub-image \
-+		 util/grub-install util/grub-md5-crypt \
+ AC_CONFIG_FILES([Makefile stage1/Makefile stage2/Makefile \
+ 		 docs/Makefile lib/Makefile util/Makefile \
+-		 grub/Makefile netboot/Makefile util/grub-image \
+-		 util/grub-install util/grub-md5-crypt \
+-		 util/grub-terminfo util/grub-set-default])
++		 grub/Makefile netboot/Makefile util/grub-crypt \
++		 util/grub-image util/grub-install util/grub-md5-crypt \
 +		 util/grub-terminfo])
-+AC_OUTPUT
+ AC_OUTPUT
+diff --git a/docs/Makefile.am b/docs/Makefile.am
+index db99e2d..fe6b22b 100644
+--- a/docs/Makefile.am
++++ b/docs/Makefile.am
+@@ -2,7 +2,8 @@ info_TEXINFOS = grub.texi multiboot.texi
+ grub_TEXINFOS = internals.texi
+ EXAMPLES = boot.S kernel.c multiboot.h
+ multiboot_TEXINFOS = boot.S.texi kernel.c.texi multiboot.h.texi
+-man_MANS = grub.8 mbchk.1 grub-install.8 grub-md5-crypt.8 grub-terminfo.8
++man_MANS = grub.8 mbchk.1 grub-crypt.8 grub-install.8 grub-md5-crypt.8 \
++	grub-terminfo.8
+ HELP2MAN = help2man
+ SRC2TEXI = src2texi
+ noinst_SCRIPTS = $(HELP2MAN) $(SRC2TEXI)
+@@ -51,6 +52,12 @@ $(srcdir)/mbchk.1: ../util/mbchk $(srcdir)/$(HELP2MAN)
+ 		--name="check the format of a Multiboot kernel" \
+ 		--section=1 --output=$@ $<
+ 
++$(srcdir)/grub-crypt.8: ../util/grub-crypt $(srcdir)/$(HELP2MAN)
++	chmod 755 $<
++	$(PERL) $(srcdir)/$(HELP2MAN) \
++		--name="Encrypt a password" \
++		--section=8 --output=$@ $<
++
+ $(srcdir)/grub-md5-crypt.8: ../util/grub-md5-crypt $(srcdir)/$(HELP2MAN)
+ 	chmod 755 $<
+ 	$(PERL) $(srcdir)/$(HELP2MAN) \
 diff --git a/docs/Makefile.in b/docs/Makefile.in
 index 3e2de4b..f350fcd 100644
 --- a/docs/Makefile.in
@@ -10912,6 +9689,51 @@ index 3e2de4b..f350fcd 100644
  
  
  @BUILD_EXAMPLE_KERNEL_TRUE at boot.o: multiboot.h
+diff --git a/docs/grub-crypt.8 b/docs/grub-crypt.8
+new file mode 100644
+index 0000000..eb132d7
+--- /dev/null
++++ b/docs/grub-crypt.8
+@@ -0,0 +1,39 @@
++.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.23.
++.TH GRUB-CRYPT "1" "January 2010" "grub-crypt (GNU GRUB 0.97)" FSF
++.SH NAME
++grub-crypt \- manual page for grub-crypt (GNU GRUB 0.97)
++.SH SYNOPSIS
++.B grub-crypt
++[\fIOPTION\fR]...
++.SH DESCRIPTION
++Encrypt a password.
++.TP
++\fB\-h\fR, \fB\-\-help\fR
++Print this message and exit
++.TP
++\fB\-v\fR, \fB\-\-version\fR
++Print the version information and exit
++.TP
++\fB\-\-md5\fR
++Use MD5 to encrypt the password
++.TP
++\fB\-\-sha\-256\fR
++Use SHA-256 to encrypt the password
++.TP
++\fB\-\-sha\-512\fR
++Use SHA-512 to encrypt the password (default)
++.SH "REPORTING BUGS"
++Report bugs to <bug-grub at gnu.org>.
++EOF
++.SH "SEE ALSO"
++The full documentation for
++.B grub-crypt
++is maintained as a Texinfo manual.  If the
++.B info
++and
++.B grub-crypt
++programs are properly installed at your site, the command
++.IP
++.B info grub-crypt
++.PP
++should give you access to the complete manual.
 diff --git a/docs/grub-install.8 b/docs/grub-install.8
 index ac588a3..accff22 100644
 --- a/docs/grub-install.8
@@ -11401,10 +10223,29 @@ index f48783c..7692f31 100644
  
  End Tag Table
 diff --git a/docs/grub.texi b/docs/grub.texi
-index 51d330a..84ff641 100644
+index 51d330a..5fd324d 100644
 --- a/docs/grub.texi
 +++ b/docs/grub.texi
-@@ -1265,7 +1265,7 @@ OS. There's a solution to that - GRUB provides a menu interface
+@@ -21,6 +21,7 @@
+ @dircategory Kernel
+ @direntry
+ * GRUB: (grub).                 The GRand Unified Bootloader
++* grub-crypt: (grub)Invoking grub-crypt.        Encrypt a password
+ * grub-install: (grub)Invoking grub-install.    Install GRUB on your drive
+ * grub-md5-crypt: (grub)Invoking grub-md5-crypt.        Encrypt a password
+                                                         in MD5 format
+@@ -115,8 +116,9 @@ This edition documents version @value{VERSION}.
+ * Commands::                    The list of available builtin commands
+ * Troubleshooting::             Error messages produced by GRUB
+ * Invoking the grub shell::     How to use the grub shell
++* Invoking grub-crypt::         How to generate an encrypted password
+ * Invoking grub-install::       How to use the GRUB installer
+-* Invoking grub-md5-crypt::     How to generate a cryptic password
++* Invoking grub-md5-crypt::     How to generate an MD5-encrypted password
+ * Invoking grub-terminfo::      How to generate a terminfo command
+ * Invoking grub-set-default::   How to set a default boot entry
+ * Invoking mbchk::              How to use the Multiboot checker
+@@ -1265,7 +1267,7 @@ OS. There's a solution to that - GRUB provides a menu interface
  keys) that will do everything to boot an OS.
  
  To enable the menu, you need a configuration file,
@@ -11413,7 +10254,40 @@ index 51d330a..84ff641 100644
  file.
  
  The file first contains some general settings, the menu interface
-@@ -1882,8 +1882,8 @@ There are two ways to specify files, by @dfn{absolute file name} and by
+@@ -1685,27 +1687,17 @@ run the command @command{password} in your configuration file
+ (@pxref{password}), like this:
+ 
+ @example
+-password --md5 PASSWORD
++password --encrypted PASSWORD
+ @end example
+ 
+ If this is specified, GRUB disallows any interactive control, until you
+ press the key @key{p} and enter a correct password.  The option
+- at option{--md5} tells GRUB that @samp{PASSWORD} is in MD5 format.  If it
++ at option{--encrypted} tells GRUB that @samp{PASSWORD} is encrypted format.  If it
+ is omitted, GRUB assumes the @samp{PASSWORD} is in clear text.
+ 
+-You can encrypt your password with the command @command{md5crypt}
+-(@pxref{md5crypt}). For example, run the grub shell (@pxref{Invoking the
+-grub shell}), and enter your password:
+-
+- at example
+- at group
+-grub> md5crypt
+-Password: **********
+-Encrypted: $1$U$JK7xFegdxWH6VuppCUSIb.
+- at end group
+- at end example
+-
+-Then, cut and paste the encrypted password to your configuration file.
++You can encrypt your password with the program @command{grub-crypt}
++(@pxref{Invoking grub-crypt}). Then, cut and paste the encrypted password to
++your configuration file.
+ 
+ Also, you can specify an optional argument to @command{password}. See
+ this example:
+@@ -1882,8 +1874,8 @@ There are two ways to specify files, by @dfn{absolute file name} and by
  
  An absolute file name resembles a Unix absolute file name, using
  @samp{/} for the directory separator (not @samp{\} as in DOS). One
@@ -11424,7 +10298,7 @@ index 51d330a..84ff641 100644
  disk. If you omit the device name in an absolute file name, GRUB uses
  GRUB's @dfn{root device} implicitly. So if you set the root device to,
  say, @samp{(hd1,0)} by the command @command{root} (@pxref{root}), then
-@@ -2199,6 +2199,7 @@ Commands usable anywhere in the menu and in the command-line.
+@@ -2199,6 +2191,7 @@ Commands usable anywhere in the menu and in the command-line.
  * rarp::                        Initialize a network device via RARP
  * serial::                      Set up a serial device
  * setkey::                      Configure the key map
@@ -11432,7 +10306,27 @@ index 51d330a..84ff641 100644
  * terminal::                    Choose a terminal
  * terminfo::                    Define escape sequences for a terminal
  * tftpserver::                  Specify a TFTP server
-@@ -2578,6 +2579,16 @@ character each of the symbols corresponds:
+@@ -2398,7 +2391,7 @@ is the new partition type and must be a number in the range 0-0xff.
+ @node password
+ @subsection password
+ 
+- at deffn Command password [@option{--md5}] passwd [new-config-file]
++ at deffn Command password [@option{--md5}] [@option{--encrypted}] passwd [new-config-file]
+ If used in the first section of a menu file, disable all interactive
+ editing control (menu entry editor and command-line) and entries
+ protected by the command @command{lock}. If the password @var{passwd} is
+@@ -2408,7 +2401,9 @@ specified. Otherwise, GRUB will just unlock the privileged instructions.
+ You can also use this command in the script section, in which case it
+ will ask for the password, before continuing.  The option
+ @option{--md5} tells GRUB that @var{passwd} is encrypted with
+- at command{md5crypt} (@pxref{md5crypt}).
++ at command{md5crypt} (@pxref{md5crypt}), the option @option{--encrypted}
++tells GRUB that @var{passwd} is using one of the crypt formats (GRUB currently
++supports MD5, SHA-256 and SHA-512 encryption).
+ @end deffn
+ 
+ 
+@@ -2578,6 +2573,16 @@ character each of the symbols corresponds:
  @end deffn
  
  
@@ -11449,7 +10343,7 @@ index 51d330a..84ff641 100644
  @node terminal
  @subsection terminal
  
-@@ -3542,7 +3553,7 @@ ignores this option.
+@@ -3542,7 +3547,7 @@ ignores this option.
  
  @item --config-file=@var{file}
  Read the configuration file @var{file} instead of
@@ -11458,7 +10352,39 @@ index 51d330a..84ff641 100644
  syntax. See @ref{Filesystem}, for more information.
  
  @item --boot-drive=@var{drive}
-@@ -3702,8 +3713,9 @@ Use @var{file} as the grub shell. You can append arbitrary options to
+@@ -3653,6 +3658,31 @@ comments in the file if needed, as the grub shell assumes that a line is
+ just a comment if the first character is @samp{#}.
+ 
+ 
++ at node Invoking grub-crypt
++ at chapter Invoking grub-crypt
++
++The program @command{grub-crypt} encrypts a password in one of the specified
++formats. Passwords encrypted by this program can be used with the
++command @command{password} (@pxref{password}).
++
++ at command{grub-crypt} accepts the following options:
++
++ at table @option
++ at item --help
++Print a summary of the command-line options and exit.
++
++ at item --version
++Print the version information and exit.
++
++ at item --md5
++Use MD5 for password encryption.
++ at item --sha-256
++Use SHA-256 for password encryption.
++ at item --sha-512
++Use SHA-512 for password encryption. This is the default.
++ at end table
++
++
+ @node Invoking grub-install
+ @chapter Invoking grub-install
+ 
+@@ -3702,8 +3732,9 @@ Use @var{file} as the grub shell. You can append arbitrary options to
  
  @item --recheck
  Recheck the device map, even if @file{/boot/grub/device.map} already
@@ -11494,10 +10420,10 @@ index b97de24..eb5144d 100644
  @set VERSION 0.97
 diff --git a/efi/Makefile.am b/efi/Makefile.am
 new file mode 100644
-index 0000000..4d97dbe
+index 0000000..4cffe7d
 --- /dev/null
 +++ b/efi/Makefile.am
-@@ -0,0 +1,78 @@
+@@ -0,0 +1,76 @@
 +
 +pkglibdir = $(libdir)/$(PACKAGE)/$(host_cpu)-$(host_vendor)
 +pkgdatadir = $(datadir)/$(PACKAGE)/$(host_cpu)-$(host_vendor)
@@ -11532,8 +10458,9 @@ index 0000000..4d97dbe
 +GRUBSO_LD_SCRIPT = @GNUEFI_LDS@
 +GRUBSO_LD_FLAGS = -T $(GRUBSO_LD_SCRIPT) -nostdlib -shared -Bsymbolic
 +
-+GRUBSO_OBJS = reloc.o efimain.o @GNUEFI_CRT0@
-+GRUBSO_LIBS = $(top_srcdir)/stage2/libstage2.a libgrubefi.a @LIBGCC@
++GRUBSO_OBJS = efimain.o
++GRUBSO_LIBS = @GNUEFI_CRT0@ $(top_srcdir)/stage2/libstage2.a \
++		libgrubefi.a @LIBGCC@
 +
 +if NETBOOT_SUPPORT
 +GRUBSO_LIBS += $(top_srcdir)/netboot/libdrivers.a
@@ -11545,7 +10472,7 @@ index 0000000..4d97dbe
 +	$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
 +                   -j .rela -j .reloc --target=$(GRUBEFI_FORMAT) $^ $@
 +
-+grub.so: $(GRUBSO_OBJS) $(GRUBSO_LIBS)
++grub.so: $(GRUBSO_OBJS) $(GRUBSO_LIBS) @LIBGNUEFI@
 +	$(LD) -o $@ $(GRUBSO_LD_FLAGS) $^
 +	echo '-------------- unresolved symbols ---------------------'
 +	! nm $@ | grep -iw u
@@ -11557,9 +10484,6 @@ index 0000000..4d97dbe
 +efimain.o: efimain.c
 +	$(CC) -o $@ -c $(libgrubefi_a_CFLAGS) $^
 +
-+reloc.o: $(EFI_ARCH)/reloc.c
-+	$(CC) -o $@ -c $(RELOC_FLAGS) $^
-+
 +clean-local:
 +	-rm -rf grub.so grub.efi
 +
@@ -11570,12 +10494,194 @@ index 0000000..4d97dbe
 +
 +noinst_LIBRARIES = libgrubefi.a
 +libgrubefi_a_SOURCES = $(EFI_ARCH)/callwrap.c eficore.c efimm.c efimisc.c \
-+	$(EFI_ARCH)/setjmp.S eficon.c efidisk.c graphics.c efigraph.c efiuga.c \
++	eficon.c efidisk.c graphics.c efigraph.c efiuga.c efidp.c \
 +	font_8x16.c efiserial.c $(EFI_ARCH)/loader/linux.c efichainloader.c \
-+	xpm.c
++	xpm.c pxe.c efitftp.c
 +libgrubefi_a_CFLAGS = $(RELOC_FLAGS) -nostdinc
 +
 +endif
+diff --git a/efi/byteswap.h b/efi/byteswap.h
+new file mode 100644
+index 0000000..5a057c4
+--- /dev/null
++++ b/efi/byteswap.h
+@@ -0,0 +1,37 @@
++#ifndef BYTESWAP_H
++#define BYTESWAP_H 1
++
++#if defined(__i386__)
++#define LITTLE_ENDIAN 1
++#elif defined(__x86_64__)
++#define LITTLE_ENDIAN 1
++#else
++#error endian not defined
++#endif
++
++#define bswap_16(x) \
++     ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
++
++#define bswap_32(x) \
++     ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) |		      \
++      (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
++
++static inline grub_efi_uint16_t htons(grub_efi_uint16_t hostshort)
++{
++#ifdef LITTLE_ENDIAN
++	return bswap_16(hostshort);
++#else
++	return hostshort;
++#endif
++}
++
++static inline grub_efi_uint32_t htonl(grub_efi_uint32_t hostshort)
++{
++#ifdef LITTLE_ENDIAN
++	return bswap_32(hostshort);
++#else
++	return hostshort;
++#endif
++}
++
++#endif /* BYTESWAP_H */
+diff --git a/efi/dhcp.h b/efi/dhcp.h
+new file mode 100644
+index 0000000..a82a522
+--- /dev/null
++++ b/efi/dhcp.h
+@@ -0,0 +1,133 @@
++#ifndef DHCP_H
++#define DHCP_H 1
++
++#include "pxe.h"
++
++#define EFI_DHCP4_PROTOCOL_GUID \
++{ 0x8a219718, 0x4ef5, 0x4761, {0x91,0xc8,0xc0,0xf0,0x4b,0xda,0x9e,0x56} }
++static grub_efi_guid_t DHCP4Protocol = EFI_DHCP4_PROTOCOL_GUID;
++
++#define EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \
++{ 0x9d9a39d8, 0xbd42, 0x4a73, {0xa4,0xd5,0x8e,0xe9,0x4b,0xe1,0x13,0x80} }
++static grub_efi_guid_t DHCP4SbProtocol = EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID;
++
++#define EFI_PXE_DHCP4_PROTOCOL_GUID \
++{ 0x03c4e624, 0xac28, 0x11d3, {0x9a,0x2d,0x00,0x90,0x29,0x3f,0xc1,0x4d} }
++static grub_efi_guid_t PxeDHCP4Protocol = EFI_PXE_DHCP4_PROTOCOL_GUID;
++
++
++typedef EFI_STATUS (*EFI_DHCP4_GET_MODE_DATA)();
++typedef EFI_STATUS (*EFI_DHCP4_CONFIGURE)();
++typedef EFI_STATUS (*EFI_DHCP4_START)();
++typedef EFI_STATUS (*EFI_DHCP4_RENEW_REBIND)();
++typedef EFI_STATUS (*EFI_DHCP4_RELEASE)();
++typedef EFI_STATUS (*EFI_DHCP4_STOP)();
++typedef EFI_STATUS (*EFI_DHCP4_BUILD)();
++typedef EFI_STATUS (*EFI_DHCP4_TRANSMIT_RECIEVE)();
++typedef EFI_STATUS (*EFI_DHCP4_PARSE)();
++
++typedef struct _EFI_DHCP4_PROTOCOL {
++	EFI_DHCP4_GET_MODE_DATA GetModeData;
++	EFI_DHCP4_CONFIGURE Configure;
++	EFI_DHCP4_START Start;
++	EFI_DHCP4_RENEW_REBIND RenewRebind;
++	EFI_DHCP4_RELEASE Release;
++	EFI_DHCP4_STOP Stop;
++	EFI_DHCP4_BUILD Build;
++	EFI_DHCP4_TRANSMIT_RECIEVE TransmitReceive;
++	EFI_DHCP4_PARSE Parse;
++} EFI_DHCP4_PROTOCOL;
++
++typedef enum {
++	Dhcp4Stopped,
++	Dhcp4Init,
++	Dhcp4Selecting,
++	Dhcp4Requesting,
++	Dhcp4Bound,
++	Dhcp4Renewing,
++	Dhcp4Rebinding,
++	Dhcp4InitReboot,
++	Dhcp4Rebooting,
++} EFI_DHCP4_STATE;
++
++typedef enum {
++	Dhcp4SendDiscover = 0x1,
++	Dhcp4RcvdOffer,
++	Dhcp4SelectOffer,
++	Dhcp4SendRequest,
++	Dhcp4RcvdAck,
++	Dhcp4RcvdNak,
++	Dhcp4SendDecline,
++	Dhcp4BoundCompleted,
++	Dhcp4EnterRenewing,
++	Dhcp4EnterRebinding,
++	Dhcp4AddressLost,
++	Dhcp4Fail,
++} EFI_DHCP4_EVENT;
++
++typedef struct {
++	grub_efi_uint8_t OpCode;
++	grub_efi_uint8_t HwType;
++	grub_efi_uint8_t HwAddrLen;
++	grub_efi_uint8_t Hops;
++	grub_efi_uint32_t xid;
++	grub_efi_uint16_t Seconds;
++	grub_efi_uint16_t reserved;
++	EFI_IPv4_ADDRESS ClientAddr;
++	EFI_IPv4_ADDRESS YourAddr;
++	EFI_IPv4_ADDRESS ServerAddr;
++	EFI_IPv4_ADDRESS GatewayAddr;
++	grub_efi_uint8_t ClientHwAddr[16];
++	char ServerName[64];
++	char BootFileName[128];
++} EFI_DHCP4_HEADER;
++
++typedef struct {
++	grub_efi_uint32_t Size;
++	grub_efi_uint32_t Length;
++	struct {
++		EFI_DHCP4_HEADER Header;
++		grub_efi_uint32_t Magik;
++		grub_efi_uint8_t option[];
++	} Dhcp4;
++} EFI_DHCP4_PACKET;
++
++typedef struct {
++	grub_efi_uint8_t OpCode;
++	grub_efi_uint8_t Length;
++	grub_efi_uint8_t Data[1];
++} EFI_DHCP4_PACKET_OPTION;
++
++typedef EFI_STATUS (*EFI_DHCP4_CALLBACK) (
++	EFI_DHCP4_PROTOCOL *This,
++	void *Context,
++	EFI_DHCP4_STATE CurrentState,
++	EFI_DHCP4_EVENT Dhcp4Event,
++	EFI_DHCP4_PACKET *Packet,
++	EFI_DHCP4_PACKET **NewPacket);
++
++typedef struct {
++	grub_efi_uint32_t DiscoverTryCount;
++	grub_efi_uint32_t *DiscoverTimeout;
++	grub_efi_uint32_t RequestTryCount;
++	grub_efi_uint32_t *RequestTimeout;
++	EFI_IPv4_ADDRESS ClientAddress;
++	EFI_DHCP4_CALLBACK Dhcp4Callback;
++	void *CallbackContext;
++	grub_efi_uint32_t OptionCount;
++	EFI_DHCP4_PACKET_OPTION **OptionList;
++} EFI_DHCP4_CONFIG_DATA;
++
++typedef struct {
++	EFI_DHCP4_STATE State;
++	EFI_DHCP4_CONFIG_DATA ConfigData;
++	EFI_IPv4_ADDRESS ClientAddress;
++	EFI_MAC_ADDRESS ClientMacAddress;
++	EFI_IPv4_ADDRESS ServerAddress;
++	EFI_IPv4_ADDRESS RouterAddress;
++	EFI_IPv4_ADDRESS SubnetMask;
++	grub_efi_uint32_t LeaseTime;
++	EFI_DHCP4_PACKET *ReplyPacket;
++} EFI_DHCP4_MODE_DATA;
++
++#endif /* DHCP_H */
 diff --git a/efi/efichainloader.c b/efi/efichainloader.c
 new file mode 100644
 index 0000000..016636c
@@ -11849,10 +10955,10 @@ index 0000000..016636c
 +}
 diff --git a/efi/eficon.c b/efi/eficon.c
 new file mode 100644
-index 0000000..63cc2cc
+index 0000000..037f050
 --- /dev/null
 +++ b/efi/eficon.c
-@@ -0,0 +1,299 @@
+@@ -0,0 +1,306 @@
 +/*
 + *  GRUB  --  GRand Unified Bootloader
 + *  Copyright (C) 2006  Free Software Foundation, Inc.
@@ -12067,6 +11173,13 @@ index 0000000..63cc2cc
 +}
 +
 +int
++console_keystatus (void)
++{
++  /* Doesn't look like EFI can support this... */
++  return 0;
++}
++
++int
 +console_getxy (void)
 +{
 +  grub_efi_simple_text_output_interface_t *o;
@@ -12097,73 +11210,1055 @@ index 0000000..63cc2cc
 +  Call_Service_2 (o->set_attributes , o, orig_attr);
 +}
 +
-+void
-+console_setcolorstate (color_state state)
++void
++console_setcolorstate (color_state state)
++{
++  grub_efi_simple_text_output_interface_t *o;
++
++  o = grub_efi_system_table->con_out;
++
++  switch (state) {
++    case COLOR_STATE_STANDARD:
++      Call_Service_2 (o->set_attributes, o, grub_console_standard_color);
++      break;
++    case COLOR_STATE_NORMAL:
++      Call_Service_2 (o->set_attributes, o, grub_console_normal_color);
++      break;
++    case COLOR_STATE_HIGHLIGHT:
++      Call_Service_2 (o->set_attributes, o, grub_console_highlight_color);
++      break;
++    default:
++      break;
++  }
++}
++
++void
++console_setcolor (int normal_color, int highlight_color)
++{
++  grub_console_normal_color = normal_color;
++  grub_console_highlight_color = highlight_color;
++}
++
++int
++console_setcursor (int on)
++{
++  grub_efi_simple_text_output_interface_t *o;
++
++  o = grub_efi_system_table->con_out;
++  Call_Service_2 (o->enable_cursor, o, on);
++  return on;
++}
++
++void
++grub_console_init (void)
++{
++  /* FIXME: it is necessary to consider the case where no console control
++     is present but the default is already in text mode.  */
++  if (! grub_efi_set_text_mode (1))
++    {
++      grub_printf ("cannot set text mode");
++      return;
++    }
++}
++
++void
++grub_console_fini (void)
++{
++}
+diff --git a/efi/eficore.c b/efi/eficore.c
+new file mode 100644
+index 0000000..259c5dc
+--- /dev/null
++++ b/efi/eficore.c
+@@ -0,0 +1,231 @@
++/* eficore.c - generic EFI support */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2006  Free Software Foundation, Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <config.h>
++#include <grub/misc.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/efi/eficall.h>
++#include <grub/efi/console_control.h>
++#include <grub/efi/time.h>
++
++#include <shared.h>
++
++/* The handle of GRUB itself. Filled in by the startup code.  */
++grub_efi_handle_t grub_efi_image_handle;
++
++/* The pointer to a system table. Filled in by the startup code.  */
++grub_efi_system_table_t *grub_efi_system_table;
++
++static grub_efi_guid_t console_control_guid = GRUB_EFI_CONSOLE_CONTROL_GUID;
++static grub_efi_guid_t loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID;
++static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
++
++/* temporary, until we're using gnu-efi's include files --pjones */
++extern int setjmp(grub_jmp_buf env);
++int grub_setjmp(grub_jmp_buf env)
++{
++	return setjmp(env);
++}
++
++extern void longjmp(grub_jmp_buf env, int val);
++void grub_longjmp(grub_jmp_buf env, int val)
++{
++	longjmp(env, val);
++}
++
++grub_efi_status_t
++grub_efi_locate_handle_buffer (grub_efi_locate_search_type_t search_type,
++				grub_efi_guid_t *protocol,
++				void *search_key,
++				grub_efi_uintn_t *no_handles,
++				grub_efi_handle_t **buffer)
++{
++	return Call_Service_5(
++		grub_efi_system_table->boot_services->locate_handle_buffer,
++		search_type, protocol, search_key, no_handles, buffer);
++}
++
++void *
++grub_efi_locate_protocol (grub_efi_guid_t *protocol, void *registration)
++{
++  void *interface;
++  grub_efi_status_t status;
++
++  status = Call_Service_3 (grub_efi_system_table->boot_services->locate_protocol,
++				protocol,
++				registration,
++				&interface);
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++
++  return interface;
++}
++
++/* Return the array of handles which meet the requirement. If successful,
++   the number of handles is stored in NUM_HANDLES. The array is allocated
++   from the heap.  */
++grub_efi_handle_t *
++grub_efi_locate_handle (grub_efi_locate_search_type_t search_type,
++			grub_efi_guid_t *protocol,
++			void *search_key,
++			grub_efi_uintn_t *num_handles)
++{
++  grub_efi_boot_services_t *b;
++  grub_efi_status_t status;
++  grub_efi_handle_t *buffer;
++  grub_efi_uintn_t buffer_size = 8 * sizeof (grub_efi_handle_t);
++
++  buffer = grub_malloc (buffer_size);
++  if (! buffer)
++    return 0;
++
++  b = grub_efi_system_table->boot_services;
++  status = Call_Service_5 (b->locate_handle, search_type, protocol,
++				 search_key, &buffer_size, buffer);
++  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++    {
++      grub_free (buffer);
++      buffer = grub_malloc (buffer_size);
++      if (! buffer)
++	return 0;
++
++      status = Call_Service_5 (b->locate_handle, search_type, protocol,
++				 search_key, &buffer_size, buffer);
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (buffer);
++      return 0;
++    }
++
++  *num_handles = buffer_size / sizeof (grub_efi_handle_t);
++  return buffer;
++}
++
++void *
++grub_efi_open_protocol (grub_efi_handle_t handle,
++			grub_efi_guid_t *protocol,
++			grub_efi_uint32_t attributes)
++{
++  grub_efi_boot_services_t *b;
++  grub_efi_status_t status;
++  void *interface;
++
++  b = grub_efi_system_table->boot_services;
++  status = Call_Service_6 ( b->open_protocol,
++			     handle,
++			     protocol,
++			     &interface,
++			     grub_efi_image_handle,
++			     0,
++			     attributes);
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++
++  return interface;
++}
++
++int
++grub_efi_set_text_mode (int on)
++{
++  grub_efi_console_control_protocol_t *c;
++  grub_efi_screen_mode_t mode, new_mode;
++
++  c = grub_efi_locate_protocol (&console_control_guid, 0);
++  if (! c)
++    /* No console control protocol instance available, assume it is
++       already in text mode. */
++    return 1;
++
++  if (Call_Service_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 (Call_Service_2 (c->set_mode , c, new_mode) != GRUB_EFI_SUCCESS)
++      return 0;
++
++  return 1;
++}
++
++void
++grub_efi_stall (grub_efi_uintn_t microseconds)
++{
++  Call_Service_1 (grub_efi_system_table->boot_services->stall , microseconds);
++}
++
++grub_efi_loaded_image_t *
++grub_efi_get_loaded_image (grub_efi_handle_t image_handle)
++{
++  return grub_efi_open_protocol (image_handle,
++			 &loaded_image_guid,
++			 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++}
++
++void
++grub_exit (void)
++{
++  grub_efi_fini ();
++  Call_Service_4(grub_efi_system_table->boot_services->exit,
++		 grub_efi_image_handle,
++		 GRUB_EFI_SUCCESS,
++		 0,
++		 0 );
++  for (;;);
++}
++
++int
++grub_efi_exit_boot_services (grub_efi_uintn_t map_key)
++{
++  grub_efi_boot_services_t *b;
++  grub_efi_status_t status;
++
++  b = grub_efi_system_table->boot_services;
++  status = Call_Service_2 (b->exit_boot_services ,
++				grub_efi_image_handle,
++				map_key);
++  return status == GRUB_EFI_SUCCESS;
++}
++
++grub_uint32_t
++grub_get_rtc (void)
++{
++  grub_efi_time_t time;
++  grub_efi_runtime_services_t *r;
++
++  r = grub_efi_system_table->runtime_services;
++  if (Call_Service_2(r->get_time , &time, 0) != GRUB_EFI_SUCCESS)
++    /* What is possible in this case?  */
++    return 0;
++
++  return (((time.minute * 60 + time.second) * 1000
++	   + time.nanosecond / 1000000)
++	  * GRUB_TICKS_PER_SECOND / 1000);
++}
++
++grub_efi_device_path_t *
++grub_efi_get_device_path (grub_efi_handle_t handle)
++{
++  return grub_efi_open_protocol (handle, &device_path_guid,
++				 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++}
++
+diff --git a/efi/efidisk.c b/efi/efidisk.c
+new file mode 100644
+index 0000000..145ed16
+--- /dev/null
++++ b/efi/efidisk.c
+@@ -0,0 +1,740 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2006  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB; if not, write to the Free Software
++ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <grub/types.h>
++#include <grub/misc.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/efi/misc.h>
++
++#include <shared.h>
++
++struct grub_efidisk_data
++{
++  grub_efi_handle_t handle;
++  grub_efi_device_path_t *device_path;
++  grub_efi_device_path_t *last_device_path;
++  grub_efi_block_io_t *block_io;
++  grub_efi_disk_io_t *disk_io;
++  struct grub_efidisk_data *next;
++};
++
++/* GUIDs.  */
++static grub_efi_guid_t disk_io_guid = GRUB_EFI_DISK_IO_GUID;
++static grub_efi_guid_t block_io_guid = GRUB_EFI_BLOCK_IO_GUID;
++static grub_efi_guid_t device_path_from_text_guid = GRUB_EFI_DEVICE_PATH_FROM_TEXT_GUID;
++
++static struct grub_efidisk_data *fd_devices;
++static struct grub_efidisk_data *hd_devices;
++static struct grub_efidisk_data *cd_devices;
++
++static struct grub_efidisk_data *
++make_devices (void)
++{
++  grub_efi_uintn_t num_handles;
++  grub_efi_handle_t *handles;
++  grub_efi_handle_t *handle;
++  struct grub_efidisk_data *devices = 0;
++
++  /* Find handles which support the disk io interface.  */
++  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &disk_io_guid,
++				    0, &num_handles);
++  if (! handles)
++    return 0;
++
++  /* Make a linked list of devices.  */
++  for (handle = handles; num_handles--; handle++)
++    {
++      grub_efi_device_path_t *dp;
++      grub_efi_device_path_t *ldp;
++      struct grub_efidisk_data *d;
++      grub_efi_block_io_t *bio;
++      grub_efi_disk_io_t *dio;
++
++      dp = grub_efi_get_device_path (*handle);
++      if (! dp)
++	continue;
++
++      ldp = find_last_device_path (dp);
++      if (! ldp)
++	/* This is empty. Why?  */
++	continue;
++
++      bio = grub_efi_open_protocol (*handle, &block_io_guid,
++				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++      dio = grub_efi_open_protocol (*handle, &disk_io_guid,
++				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++      if (! bio || ! dio)
++	/* This should not happen... Why?  */
++	continue;
++
++      d = grub_malloc (sizeof (*d));
++      if (! d)
++	{
++	  /* Uggh.  */
++	  grub_free (handles);
++	  return 0;
++	}
++
++      d->handle = *handle;
++      d->device_path = dp;
++      d->last_device_path = ldp;
++      d->block_io = bio;
++      d->disk_io = dio;
++      d->next = devices;
++      devices = d;
++    }
++
++  grub_free (handles);
++
++  return devices;
++}
++
++static int
++iterate_child_devices (struct grub_efidisk_data *devices,
++		       struct grub_efidisk_data *d,
++		       int (*hook) (struct grub_efidisk_data *child))
++{
++  struct grub_efidisk_data *p;
++
++  for (p = devices; p; p = p->next)
++    {
++      grub_efi_device_path_t *dp, *ldp;
++
++      dp = duplicate_device_path (p->device_path);
++      if (! dp)
++	return 0;
++
++      ldp = find_last_device_path (dp);
++      ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++      ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++      ldp->length[0] = sizeof (*ldp);
++      ldp->length[1] = 0;
++
++      if (compare_device_paths (dp, d->device_path) == 0)
++	if (hook (p))
++	  {
++	    grub_free (dp);
++	    return 1;
++	  }
++
++      grub_free (dp);
++    }
++
++  return 0;
++}
++
++/* Add a device into a list of devices in an ascending order.  */
++static void
++add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d)
++{
++  struct grub_efidisk_data **p;
++  struct grub_efidisk_data *n;
++
++  for (p = devices; *p; p = &((*p)->next))
++    {
++      int ret;
++
++      ret = compare_device_paths (find_last_device_path ((*p)->device_path),
++				  find_last_device_path (d->device_path));
++      if (ret == 0)
++	ret = compare_device_paths ((*p)->device_path,
++				    d->device_path);
++      if (ret == 0)
++	return;
++      else if (ret > 0)
++	break;
++    }
++
++  n = grub_malloc (sizeof (*n));
++  if (! n)
++    return;
++
++  grub_memcpy (n, d, sizeof (*n));
++  n->next = (*p);
++  (*p) = n;
++}
++
++/* Name the devices.  */
++static void
++name_devices (struct grub_efidisk_data *devices)
++{
++  struct grub_efidisk_data *d;
++
++  /* Let's see what can be added more.  */
++  for (d = devices; d; d = d->next)
++    {
++      grub_efi_device_path_t *dp;
++      grub_efi_block_io_media_t *m;
++
++      dp = d->last_device_path;
++      if (! dp)
++	continue;
++
++      m = d->block_io->media;
++      if (GRUB_EFI_DEVICE_PATH_TYPE(dp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
++	{
++	  if (m->read_only && m->block_size > SECTOR_SIZE)
++	    {
++	      add_device (&cd_devices, d);
++	    } else
++	    {
++	      add_device (&hd_devices, d);
++	    }
++	}
++      if (GRUB_EFI_DEVICE_PATH_TYPE(dp) == GRUB_EFI_ACPI_DEVICE_PATH_TYPE)
++	{
++	  add_device (&fd_devices, d);
++	}
++    }
++}
++
++static void
++free_devices (struct grub_efidisk_data *devices)
++{
++  struct grub_efidisk_data *p, *q;
++
++  for (p = devices; p; p = q)
++    {
++      q = p->next;
++      grub_free (p);
++    }
++}
++
++/* Enumerate all disks to name devices.  */
++static void
++enumerate_disks (void)
++{
++  struct grub_efidisk_data *devices;
++
++  devices = make_devices ();
++  if (! devices)
++    return;
++
++  name_devices (devices);
++  free_devices (devices);
++}
++
++static struct grub_efidisk_data *
++get_device (struct grub_efidisk_data *devices, int num)
++{
++  struct grub_efidisk_data *d;
++
++  for (d = devices; d && num; d = d->next, num--)
++    ;
++
++  if (num == 0)
++    return d;
++
++  return 0;
++}
++
++static int
++grub_efidisk_read (struct grub_efidisk_data *d, grub_disk_addr_t sector,
++		   grub_size_t size, char *buf)
++{
++  /* For now, use the disk io interface rather than the block io's.  */
++  grub_efi_disk_io_t *dio;
++  grub_efi_block_io_t *bio;
++  grub_efi_status_t status;
++  grub_efi_uint64_t sector_size;
++
++  dio = d->disk_io;
++  bio = d->block_io;
++  sector_size = d->block_io->media->block_size;
++
++  status = Call_Service_5 (dio->read ,
++			   dio, bio->media->media_id,
++			   sector * sector_size,
++			   size * sector_size,
++			   buf);
++  if (status != GRUB_EFI_SUCCESS)
++    return -1;
++
++  return 0;
++}
++
++static int
++grub_efidisk_write (struct grub_efidisk_data *d, grub_disk_addr_t sector,
++		    grub_size_t size, const char *buf)
++{
++  /* For now, use the disk io interface rather than the block io's.  */
++  grub_efi_disk_io_t *dio;
++  grub_efi_block_io_t *bio;
++  grub_efi_status_t status;
++  grub_efi_uint64_t sector_size;
++
++  dio = d->disk_io;
++  bio = d->block_io;
++  sector_size = d->block_io->media->block_size;
++
++  grub_dprintf ("efidisk",
++		"writing 0x%x sectors at the sector 0x%x to ??\n",
++		(unsigned) size, (unsigned int) sector);
++
++  status = Call_Service_5 (dio->write ,
++			   dio, bio->media->media_id,
++			   sector * sector_size,
++			   size * sector_size,
++			   (void *) buf);
++  if (status != GRUB_EFI_SUCCESS)
++    return -1;
++
++  return 0;
++}
++
++void
++grub_efidisk_init (void)
++{
++  enumerate_disks ();
++}
++
++void
++grub_efidisk_fini (void)
++{
++  free_devices (fd_devices);
++  free_devices (hd_devices);
++  free_devices (cd_devices);
++}
++
++static struct grub_efidisk_data *
++get_device_from_drive (int drive)
++{
++#ifdef SUPPORT_NETBOOT
++  /* Not supported */
++  if (drive == NETWORK_DRIVE)
++    return NULL;
++#endif
++  if (drive == GRUB_INVALID_DRIVE)
++    return NULL;
++  if (drive == cdrom_drive)
++    return get_device (cd_devices, 0);
++  /* Hard disk */
++  if (drive & 0x80)
++    return get_device (hd_devices, drive - 0x80);
++  /* Floppy disk */
++  else
++    return get_device (fd_devices, drive);
++}
++
++/* Low-level disk I/O.  Our stubbed version just returns a file
++   descriptor, not the actual geometry. */
++int
++get_diskinfo (int drive, struct geometry *geometry)
++{
++  struct grub_efidisk_data *d;
++
++  d = get_device_from_drive (drive);
++  if (!d)
++    return -1;
++  geometry->total_sectors = d->block_io->media->last_block+1;
++  geometry->sector_size = d->block_io->media->block_size;
++  geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION;
++  geometry->sectors = 63;
++  if (geometry->total_sectors / 63 < 255)
++    geometry->heads = 1;
++  else
++    geometry->heads = 255;
++  geometry->cylinders = geometry->total_sectors / 63 / geometry->heads;
++  return 0;
++}
++
++int
++biosdisk (int subfunc, int drive, struct geometry *geometry,
++	  int sector, int nsec, int segment)
++{
++  char *buf;
++  struct grub_efidisk_data *d;
++  int ret;
++
++  d = get_device_from_drive (drive);
++  if (!d)
++    return -1;
++  buf = (char *) ((unsigned long) segment << 4);
++  switch (subfunc)
++    {
++    case BIOSDISK_READ:
++      ret = grub_efidisk_read (d, sector, nsec, buf);
++      break;
++    case BIOSDISK_WRITE:
++      ret = grub_efidisk_write (d, sector, nsec, buf);
++      break;
++    default:
++      return -1;
++    }
++
++  return 0;
++}
++
++/* Some utility functions to map GRUB devices with EFI devices.  */
++grub_efi_handle_t
++grub_efidisk_get_current_bdev_handle (void)
++{
++  struct grub_efidisk_data *d;
++
++  d = get_device_from_drive (current_drive);
++  if (d == NULL)
++    return NULL;
++
++  if (current_drive == GRUB_INVALID_DRIVE)
++    return NULL;
++
++  if (current_drive == cdrom_drive)
++    return d->handle;
++
++  if (! (current_drive & 0x80))
++    return d->handle;
++  /* If this is the whole disk, just return its own data.  */
++  else if (current_partition == 0xFFFFFF)
++    return d->handle;
++  /* Otherwise, we must query the corresponding device to the firmware.  */
++  else
++    {
++      struct grub_efidisk_data *devices;
++      grub_efi_handle_t handle = 0;
++      auto int find_partition (struct grub_efidisk_data *c);
++
++      int find_partition (struct grub_efidisk_data *c)
++	{
++	  grub_efi_hard_drive_device_path_t hd;
++
++	  grub_memcpy (&hd, c->last_device_path, sizeof (hd));
++
++	  if ((GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path)
++	       == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
++	      && (GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path)
++		  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)
++	      && (part_start == hd.partition_start)
++	      && (part_length == hd.partition_size))
++	    {
++	      handle = c->handle;
++	      return 1;
++	    }
++
++	  return 0;
++	}
++
++      devices = make_devices ();
++      iterate_child_devices (devices, d, find_partition);
++      free_devices (devices);
++
++      if (handle != 0)
++	return handle;
++    }
++
++  return 0;
++}
++
++int
++grub_get_drive_partition_from_bdev_handle (grub_efi_handle_t handle,
++					   unsigned long *drive,
++					   unsigned long *partition)
++{
++  grub_efi_device_path_t *dp, *dp1;
++  struct grub_efidisk_data *d, *devices;
++  int drv;
++  unsigned long part;
++  grub_efi_hard_drive_device_path_t hd;
++  int found;
++  int part_type, part_entry;
++  unsigned long partition_start, partition_len, part_offset, part_extoffset;
++  unsigned long gpt_offset;
++  int gpt_count, gpt_size;
++  char buf[SECTOR_SIZE];
++  auto int find_bdev (struct grub_efidisk_data *c);
++
++  int find_bdev (struct grub_efidisk_data *c)
++    {
++      if (! compare_device_paths (c->device_path, dp))
++	{
++	  grub_memcpy (&hd, c->last_device_path, sizeof (hd));
++	  found = 1;
++	  return 1;
++	}
++      return 0;
++    }
++
++  dp = grub_efi_get_device_path (handle);
++  if (! dp)
++    return 0;
++
++  dp1 = dp;
++  while (1)
++    {
++      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
++      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE(dp1);
++
++      if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE &&
++	      subtype == GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE)
++	{
++	  dp1->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++	  dp1->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++	  dp1->length[0] = 4;
++	  dp1->length[1] = 0;
++	}
++
++      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
++	break;
++
++      dp1 = GRUB_EFI_NEXT_DEVICE_PATH(dp1);
++    }
++
++  drv = 0;
++  for (d = fd_devices; d; d = d->next, drv++)
++    {
++      if (! compare_device_paths (d->device_path, dp))
++	{
++	  *partition = 0xFFFFFF;
++	  *drive = drv;
++	  return 1;
++	}
++    }
++
++  drv = cdrom_drive;
++  if (cd_devices  && ! compare_device_paths (cd_devices->device_path, dp))
++    {
++      *partition = 0xFFFFFF;
++      *drive = drv;
++      return 1;
++    }
++
++  drv = 0x80;
++  for (d = hd_devices; d; d = d->next, drv++)
++    {
++      if (! compare_device_paths (d->device_path, dp))
++	{
++	  *partition = 0xFFFFFF;
++	  *drive = drv;
++	  return 1;
++	}
++    }
++
++  devices = make_devices ();
++
++  drv = 0x80;
++  found = 0;
++  for (d = hd_devices; d; d = d->next, drv++)
++    {
++      iterate_child_devices (devices, d, find_bdev);
++      if (found)
++	break;
++    }
++
++  free_devices (devices);
++
++  if (! found)
++    return 0;
++
++  part = 0xFFFFFF;
++  while (next_partition (drv, 0, &part, &part_type,
++			 &partition_start, &partition_len,
++			 &part_offset, &part_entry,
++			 &part_extoffset, &gpt_offset, &gpt_count,
++			 &gpt_size, buf))
++    {
++      if (part_type
++	  && partition_start == hd.partition_start
++	  && partition_len == hd.partition_size)
++	{
++	  *drive = drv;
++	  *partition = part;
++	  return 1;
++	}
++    }
++
++  return 0;
++}
++
++int
++check_device (const char *device)
++{
++  grub_efi_device_path_t *dp;
++
++  dp = device_path_from_utf8(device);
++  if (dp == NULL)
++    return 0;
++
++  grub_free(dp);
++  return 1;
++}
++
++static void
++swap_devices (struct grub_efidisk_data *d0,
++	      struct grub_efidisk_data *d1)
++{
++  struct grub_efidisk_data tmp;
++
++  if (!d0 || !d1)
++    return;
++
++  memcpy(&tmp, d1, sizeof(*d1));
++
++  memcpy(&d0->handle, &d1->handle, sizeof(d1->handle));
++  d0->device_path = d1->device_path;
++  d0->last_device_path = d1->last_device_path;
++  d0->block_io = d1->block_io;
++  d0->disk_io = d1->disk_io;
++
++  memcpy(d1->handle, tmp.handle, sizeof(tmp.handle));
++  d1->device_path = tmp.device_path;
++  d1->last_device_path = tmp.last_device_path;
++  d1->block_io = tmp.block_io;
++  d1->disk_io = tmp.disk_io;
++}
++
++static int
++compare_hd_device_paths(grub_efi_hard_drive_device_path_t *hd0,
++			grub_efi_hard_drive_device_path_t *hd1)
 +{
-+  grub_efi_simple_text_output_interface_t *o;
++  grub_efi_uint64_t x;
++  int sigsize;
 +
-+  o = grub_efi_system_table->con_out;
++  if ((x = hd1->partition_number - hd0->partition_number))
++    return x;
 +
-+  switch (state) {
-+    case COLOR_STATE_STANDARD:
-+      Call_Service_2 (o->set_attributes, o, grub_console_standard_color);
-+      break;
-+    case COLOR_STATE_NORMAL:
-+      Call_Service_2 (o->set_attributes, o, grub_console_normal_color);
++  if ((x = hd1->partition_start - hd0->partition_start))
++    return x;
++
++
++  if ((x = hd1->partition_size - hd0->partition_size))
++    return x;
++
++  if ((x = hd1->signature_type - hd0->signature_type))
++    return x;
++
++  switch (hd0->signature_type)
++    {
++    case 1:
++      sigsize = 4;
 +      break;
-+    case COLOR_STATE_HIGHLIGHT:
-+      Call_Service_2 (o->set_attributes, o, grub_console_highlight_color);
++    case 2:
++      sigsize = 16;
 +      break;
 +    default:
++      sigsize = 0;
 +      break;
-+  }
++    }
++  x = grub_memcmp((char *)hd0->partition_signature,
++                  (char *)hd1->partition_signature, sigsize);
++  return x;
 +}
 +
-+void
-+console_setcolor (int normal_color, int highlight_color)
++static grub_efi_device_path_t *
++get_parent_of_disk(grub_efi_device_path_t *hd)
 +{
-+  grub_console_normal_color = normal_color;
-+  grub_console_highlight_color = highlight_color;
-+}
++  grub_efi_uintn_t num_handles;
++  grub_efi_handle_t *handles;
++  grub_efi_handle_t *handle;
++  grub_efi_device_path_t *ret;
 +
-+int
-+console_setcursor (int on)
-+{
-+  grub_efi_simple_text_output_interface_t *o;
++  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL,
++				     &simple_file_system_guid,
++                                    0, &num_handles);
++  for (handle = handles; num_handles--; handle++)
++    {
++      grub_efi_device_path_t *fsdp, *hddp;
 +
-+  o = grub_efi_system_table->con_out;
-+  Call_Service_2 (o->enable_cursor, o, on);
-+  return on;
++      fsdp = grub_efi_get_device_path (*handle);
++      if (!fsdp)
++	continue;
++      hddp = find_last_device_path(fsdp);
++
++      if (compare_hd_device_paths((grub_efi_hard_drive_device_path_t *)hddp,
++				   (grub_efi_hard_drive_device_path_t *)hd) == 0)
++        {
++	  grub_efi_device_path_t *p;
++	  ret = duplicate_device_path((grub_efi_device_path_t *)fsdp);
++	  if (!ret)
++	    return NULL;
++	  for (p = ret; ; p = GRUB_EFI_NEXT_DEVICE_PATH(p))
++	    {
++	      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH(p))
++		break;
++	      if ((GRUB_EFI_DEVICE_PATH_TYPE(p) ==
++			GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
++		      && (GRUB_EFI_DEVICE_PATH_SUBTYPE(p) ==
++				GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
++	        {
++		  p->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++		  p->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++		  p->length[0] = 4;
++		  p->length[1] = 0;
++		  break;
++		}
++	    }
++	  return ret;
++	}
++    }
++  return NULL;
 +}
 +
 +void
-+grub_console_init (void)
++assign_device_name (int drive, const char *device)
 +{
-+  /* FIXME: it is necessary to consider the case where no console control
-+     is present but the default is already in text mode.  */
-+  if (! grub_efi_set_text_mode (1))
++  grub_efi_device_path_t *dp0, *dp1;
++  struct grub_efidisk_data *devices;
++  struct grub_efidisk_data *d, *d0 = NULL, *d1 = NULL;
++  int n = -1;
++
++  dp0 = device_path_from_utf8(device);
++  if (!dp0)
++    return;
++
++  dp1 = get_parent_of_disk(dp0);
++  grub_free(dp0);
++  if (!dp1)
++    return;
++
++  if (drive & 0x80)
 +    {
-+      grub_printf ("cannot set text mode");
-+      return;
++      drive -= 0x80;
++      devices = hd_devices;
++    }
++  else
++    {
++      devices = cd_devices;
++      drive -= 0x100;
 +    }
-+}
 +
-+void
-+grub_console_fini (void)
-+{
++  for (d = devices; d; d = d->next)
++    {
++      if (!d->device_path)
++	continue;
++
++      if (++n == drive)
++	d0 = d;
++
++      int x;
++      if (!(x = compare_device_paths(dp1, d->device_path)))
++	d1 = d;
++
++      if (d0 && d1)
++        {
++	  /* if they're the same node, that just means it's already at
++	   * the right position. */
++	  if (d0 != d1)
++	    {
++	      swap_devices(d0, d1);
++	      grub_free(dp1);
++	      return;
++	    }
++	}
++    }
++  grub_free(dp1);
 +}
-diff --git a/efi/eficore.c b/efi/eficore.c
+diff --git a/efi/efidp.c b/efi/efidp.c
 new file mode 100644
-index 0000000..394d82d
+index 0000000..3e0019d
 --- /dev/null
-+++ b/efi/eficore.c
-@@ -0,0 +1,626 @@
-+/* eficore.c - generic EFI support */
++++ b/efi/efidp.c
+@@ -0,0 +1,984 @@
 +/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2006  Free Software Foundation, Inc.
++ * GRUB  --  GRand Unified Bootloader
++ * Copyright (C) 2010 Free Software Foundation, Inc.
 + *
-+ *  This program is free software; you can redistribute it and/or modify
++ *  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 2 of the License, or
 + *  (at your option) any later version.
@@ -12174,194 +12269,105 @@ index 0000000..394d82d
 + *  GNU General Public License for more details.
 + *
 + *  You should have received a copy of the GNU General Public License
-+ *  along with this program; if not, write to the Free Software
++ *  along with GRUB; if not, write to the Free Software
 + *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + */
 +
-+#include <config.h>
++#include <grub/types.h>
 +#include <grub/misc.h>
 +#include <grub/efi/api.h>
 +#include <grub/efi/efi.h>
-+#include <grub/efi/eficall.h>
-+#include <grub/efi/console_control.h>
-+#include <grub/efi/time.h>
++#include <grub/efi/misc.h>
 +
 +#include <shared.h>
 +
-+/* The handle of GRUB itself. Filled in by the startup code.  */
-+grub_efi_handle_t grub_efi_image_handle;
-+
-+/* The pointer to a system table. Filled in by the startup code.  */
-+grub_efi_system_table_t *grub_efi_system_table;
-+
-+static grub_efi_guid_t console_control_guid = GRUB_EFI_CONSOLE_CONTROL_GUID;
-+static grub_efi_guid_t loaded_image_guid = GRUB_EFI_LOADED_IMAGE_GUID;
-+static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
-+
-+void *
-+grub_efi_locate_protocol (grub_efi_guid_t *protocol, void *registration)
-+{
-+  void *interface;
-+  grub_efi_status_t status;
-+
-+  status = Call_Service_3 (grub_efi_system_table->boot_services->locate_protocol,
-+				protocol,
-+				registration,
-+				&interface);
-+  if (status != GRUB_EFI_SUCCESS)
-+    return 0;
-+
-+  return interface;
-+}
-+
-+/* Return the array of handles which meet the requirement. If successful,
-+   the number of handles is stored in NUM_HANDLES. The array is allocated
-+   from the heap.  */
-+grub_efi_handle_t *
-+grub_efi_locate_handle (grub_efi_locate_search_type_t search_type,
-+			grub_efi_guid_t *protocol,
-+			void *search_key,
-+			grub_efi_uintn_t *num_handles)
++/* Duplicate a device path.  */
++grub_efi_device_path_t *
++duplicate_device_path (const grub_efi_device_path_t *dp)
 +{
-+  grub_efi_boot_services_t *b;
-+  grub_efi_status_t status;
-+  grub_efi_handle_t *buffer;
-+  grub_efi_uintn_t buffer_size = 8 * sizeof (grub_efi_handle_t);
-+
-+  buffer = grub_malloc (buffer_size);
-+  if (! buffer)
-+    return 0;
++  grub_efi_device_path_t *p;
++  grub_size_t total_size = 0;
 +
-+  b = grub_efi_system_table->boot_services;
-+  status = Call_Service_5 (b->locate_handle, search_type, protocol,
-+				 search_key, &buffer_size, buffer);
-+  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++  for (p = (grub_efi_device_path_t *) dp;
++       ;
++       p = GRUB_EFI_NEXT_DEVICE_PATH (p))
 +    {
-+      grub_free (buffer);
-+      buffer = grub_malloc (buffer_size);
-+      if (! buffer)
-+	return 0;
-+
-+      status = Call_Service_5 (b->locate_handle, search_type, protocol,
-+				 search_key, &buffer_size, buffer);
++      total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p);
++      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p))
++	break;
 +    }
 +
-+  if (status != GRUB_EFI_SUCCESS)
-+    {
-+      grub_free (buffer);
-+      return 0;
-+    }
++  p = grub_malloc (total_size);
++  if (! p)
++    return 0;
 +
-+  *num_handles = buffer_size / sizeof (grub_efi_handle_t);
-+  return buffer;
++  grub_memcpy (p, dp, total_size);
++  return p;
 +}
 +
-+void *
-+grub_efi_open_protocol (grub_efi_handle_t handle,
-+			grub_efi_guid_t *protocol,
-+			grub_efi_uint32_t attributes)
++/* Return the device path node right before the end node.  */
++grub_efi_device_path_t *
++find_last_device_path (const grub_efi_device_path_t *dp)
 +{
-+  grub_efi_boot_services_t *b;
-+  grub_efi_status_t status;
-+  void *interface;
++  grub_efi_device_path_t *next, *p;
 +
-+  b = grub_efi_system_table->boot_services;
-+  status = Call_Service_6 ( b->open_protocol,
-+			     handle,
-+			     protocol,
-+			     &interface,
-+			     grub_efi_image_handle,
-+			     0,
-+			     attributes);
-+  if (status != GRUB_EFI_SUCCESS)
++  if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
 +    return 0;
 +
-+  return interface;
++  for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p);
++       ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next);
++       p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next))
++    ;
++
++  return p;
 +}
 +
++/* Compare device paths.  */
 +int
-+grub_efi_set_text_mode (int on)
++compare_device_paths (const grub_efi_device_path_t *dp1,
++		      const grub_efi_device_path_t *dp2)
 +{
-+  grub_efi_console_control_protocol_t *c;
-+  grub_efi_screen_mode_t mode, new_mode;
-+
-+  c = grub_efi_locate_protocol (&console_control_guid, 0);
-+  if (! c)
-+    /* No console control protocol instance available, assume it is
-+       already in text mode. */
++  if (! dp1 || ! dp2)
++    /* Return non-zero.  */
 +    return 1;
 +
-+  if (Call_Service_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 (Call_Service_2 (c->set_mode , c, new_mode) != GRUB_EFI_SUCCESS)
-+      return 0;
++  while (1)
++    {
++      grub_efi_uint8_t type1, type2;
++      grub_efi_uint8_t subtype1, subtype2;
++      grub_efi_uint16_t len1, len2;
++      int ret;
 +
-+  return 1;
-+}
++      type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
++      type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2);
 +
-+void
-+grub_efi_stall (grub_efi_uintn_t microseconds)
-+{
-+  Call_Service_1 (grub_efi_system_table->boot_services->stall , microseconds);
-+}
++      if (type1 != type2)
++	return (int) type2 - (int) type1;
 +
-+grub_efi_loaded_image_t *
-+grub_efi_get_loaded_image (grub_efi_handle_t image_handle)
-+{
-+  return grub_efi_open_protocol (image_handle,
-+			 &loaded_image_guid,
-+			 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-+}
++      subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1);
++      subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2);
 +
-+void
-+grub_exit (void)
-+{
-+  grub_efi_fini ();
-+  Call_Service_4(grub_efi_system_table->boot_services->exit,
-+		 grub_efi_image_handle,
-+		 GRUB_EFI_SUCCESS,
-+		 0,
-+		 0 );
-+  for (;;);
-+}
++      if (subtype1 != subtype2)
++	return (int) subtype1 - (int) subtype2;
 +
-+int
-+grub_efi_exit_boot_services (grub_efi_uintn_t map_key)
-+{
-+  grub_efi_boot_services_t *b;
-+  grub_efi_status_t status;
++      len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1);
++      len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2);
 +
-+  b = grub_efi_system_table->boot_services;
-+  status = Call_Service_2 (b->exit_boot_services ,
-+				grub_efi_image_handle,
-+				map_key);
-+  return status == GRUB_EFI_SUCCESS;
-+}
++      if (len1 != len2)
++	return (int) len1 - (int) len2;
 +
-+grub_uint32_t
-+grub_get_rtc (void)
-+{
-+  grub_efi_time_t time;
-+  grub_efi_runtime_services_t *r;
++      ret = grub_memcmp ((char *)dp1, (char *)dp2, len1);
++      if (ret != 0)
++	return ret;
 +
-+  r = grub_efi_system_table->runtime_services;
-+  if (Call_Service_2(r->get_time , &time, 0) != GRUB_EFI_SUCCESS)
-+    /* What is possible in this case?  */
-+    return 0;
++      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
++	break;
 +
-+  return (((time.minute * 60 + time.second) * 1000
-+	   + time.nanosecond / 1000000)
-+	  * GRUB_TICKS_PER_SECOND / 1000);
-+}
++      dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1);
++      dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2);
++    }
 +
-+grub_efi_device_path_t *
-+grub_efi_get_device_path (grub_efi_handle_t handle)
-+{
-+  return grub_efi_open_protocol (handle, &device_path_guid,
-+				 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++  return 0;
 +}
 +
 +/* Print the chain of Device Path nodes. This is mainly for debugging. */
@@ -12672,20 +12678,26 @@ index 0000000..394d82d
 +	      {
 +		grub_efi_hard_drive_device_path_t hd;
 +		grub_memcpy (&hd, dp, len);
-+		grub_printf ("/HD(%u,%llx,%llx,%02x%02x%02x%02x%02x%02x%02x%02x,%x,%x)",
++		grub_printf ("/HD(%u,%llx,%llx,%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x)",
 +			     hd.partition_number,
 +			     hd.partition_start,
 +			     hd.partition_size,
-+			     (unsigned) hd.partition_signature[0],
-+			     (unsigned) hd.partition_signature[1],
-+			     (unsigned) hd.partition_signature[2],
 +			     (unsigned) hd.partition_signature[3],
-+			     (unsigned) hd.partition_signature[4],
++			     (unsigned) hd.partition_signature[2],
++			     (unsigned) hd.partition_signature[1],
++			     (unsigned) hd.partition_signature[0],
 +			     (unsigned) hd.partition_signature[5],
-+			     (unsigned) hd.partition_signature[6],
++			     (unsigned) hd.partition_signature[4],
 +			     (unsigned) hd.partition_signature[7],
-+			     (unsigned) hd.mbr_type,
-+			     (unsigned) hd.signature_type);
++			     (unsigned) hd.partition_signature[6],
++			     (unsigned) hd.partition_signature[9],
++			     (unsigned) hd.partition_signature[8],
++			     (unsigned) hd.partition_signature[10],
++			     (unsigned) hd.partition_signature[11],
++			     (unsigned) hd.partition_signature[12],
++			     (unsigned) hd.partition_signature[13],
++			     (unsigned) hd.partition_signature[14],
++			     (unsigned) hd.partition_signature[15]);
 +	      }
 +	      break;
 +	    case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE:
@@ -12779,652 +12791,459 @@ index 0000000..394d82d
 +	}
 +
 +      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
-+	break;
-+
-+      dp = (grub_efi_device_path_t *) ((char *) dp + len);
-+    }
-+}
-diff --git a/efi/efidisk.c b/efi/efidisk.c
-new file mode 100644
-index 0000000..bc9d3bd
---- /dev/null
-+++ b/efi/efidisk.c
-@@ -0,0 +1,629 @@
-+/*
-+ *  GRUB  --  GRand Unified Bootloader
-+ *  Copyright (C) 2006  Free Software Foundation, Inc.
-+ *
-+ *  GRUB is free software; you can redistribute it and/or modify
-+ *  it under the terms of the GNU General Public License as published by
-+ *  the Free Software Foundation; either version 2 of the License, or
-+ *  (at your option) any later version.
-+ *
-+ *  This program is distributed in the hope that it will be useful,
-+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ *  GNU General Public License for more details.
-+ *
-+ *  You should have received a copy of the GNU General Public License
-+ *  along with GRUB; if not, write to the Free Software
-+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-+ */
-+
-+#include <grub/types.h>
-+#include <grub/misc.h>
-+#include <grub/efi/api.h>
-+#include <grub/efi/efi.h>
-+#include <grub/efi/misc.h>
-+
-+#include <shared.h>
-+
-+struct grub_efidisk_data
-+{
-+  grub_efi_handle_t handle;
-+  grub_efi_device_path_t *device_path;
-+  grub_efi_device_path_t *last_device_path;
-+  grub_efi_block_io_t *block_io;
-+  grub_efi_disk_io_t *disk_io;
-+  struct grub_efidisk_data *next;
-+};
-+
-+/* GUIDs.  */
-+static grub_efi_guid_t disk_io_guid = GRUB_EFI_DISK_IO_GUID;
-+static grub_efi_guid_t block_io_guid = GRUB_EFI_BLOCK_IO_GUID;
-+
-+static struct grub_efidisk_data *fd_devices;
-+static struct grub_efidisk_data *hd_devices;
-+static struct grub_efidisk_data *cd_devices;
-+
-+/* Duplicate a device path.  */
-+static grub_efi_device_path_t *
-+duplicate_device_path (const grub_efi_device_path_t *dp)
-+{
-+  grub_efi_device_path_t *p;
-+  grub_size_t total_size = 0;
-+
-+  for (p = (grub_efi_device_path_t *) dp;
-+       ;
-+       p = GRUB_EFI_NEXT_DEVICE_PATH (p))
-+    {
-+      total_size += GRUB_EFI_DEVICE_PATH_LENGTH (p);
-+      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (p))
-+	break;
-+    }
-+
-+  p = grub_malloc (total_size);
-+  if (! p)
-+    return 0;
-+
-+  grub_memcpy (p, dp, total_size);
-+  return p;
-+}
-+
-+/* Return the device path node right before the end node.  */
-+static grub_efi_device_path_t *
-+find_last_device_path (const grub_efi_device_path_t *dp)
-+{
-+  grub_efi_device_path_t *next, *p;
-+
-+  if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
-+    return 0;
-+
-+  for (p = (grub_efi_device_path_t *) dp, next = GRUB_EFI_NEXT_DEVICE_PATH (p);
-+       ! GRUB_EFI_END_ENTIRE_DEVICE_PATH (next);
-+       p = next, next = GRUB_EFI_NEXT_DEVICE_PATH (next))
-+    ;
-+
-+  return p;
-+}
-+
-+/* Compare device paths.  */
-+static int
-+compare_device_paths (const grub_efi_device_path_t *dp1,
-+		      const grub_efi_device_path_t *dp2)
-+{
-+  if (! dp1 || ! dp2)
-+    /* Return non-zero.  */
-+    return 1;
-+
-+  while (1)
-+    {
-+      grub_efi_uint8_t type1, type2;
-+      grub_efi_uint8_t subtype1, subtype2;
-+      grub_efi_uint16_t len1, len2;
-+      int ret;
-+
-+      type1 = GRUB_EFI_DEVICE_PATH_TYPE (dp1);
-+      type2 = GRUB_EFI_DEVICE_PATH_TYPE (dp2);
-+
-+      if (type1 != type2)
-+	return (int) type2 - (int) type1;
-+
-+      subtype1 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp1);
-+      subtype2 = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp2);
-+
-+      if (subtype1 != subtype2)
-+	return (int) subtype1 - (int) subtype2;
-+
-+      len1 = GRUB_EFI_DEVICE_PATH_LENGTH (dp1);
-+      len2 = GRUB_EFI_DEVICE_PATH_LENGTH (dp2);
-+
-+      if (len1 != len2)
-+	return (int) len1 - (int) len2;
-+
-+      ret = grub_memcmp ((char *)dp1, (char *)dp2, len1);
-+      if (ret != 0)
-+	return ret;
-+
-+      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp1))
-+	break;
-+
-+      dp1 = (grub_efi_device_path_t *) ((char *) dp1 + len1);
-+      dp2 = (grub_efi_device_path_t *) ((char *) dp2 + len2);
-+    }
-+
-+  return 0;
-+}
-+
-+static struct grub_efidisk_data *
-+make_devices (void)
-+{
-+  grub_efi_uintn_t num_handles;
-+  grub_efi_handle_t *handles;
-+  grub_efi_handle_t *handle;
-+  struct grub_efidisk_data *devices = 0;
-+
-+  /* Find handles which support the disk io interface.  */
-+  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &disk_io_guid,
-+				    0, &num_handles);
-+  if (! handles)
-+    return 0;
-+
-+  /* Make a linked list of devices.  */
-+  for (handle = handles; num_handles--; handle++)
-+    {
-+      grub_efi_device_path_t *dp;
-+      grub_efi_device_path_t *ldp;
-+      struct grub_efidisk_data *d;
-+      grub_efi_block_io_t *bio;
-+      grub_efi_disk_io_t *dio;
-+
-+      dp = grub_efi_get_device_path (*handle);
-+      if (! dp)
-+	continue;
-+
-+      ldp = find_last_device_path (dp);
-+      if (! ldp)
-+	/* This is empty. Why?  */
-+	continue;
-+
-+      bio = grub_efi_open_protocol (*handle, &block_io_guid,
-+				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-+      dio = grub_efi_open_protocol (*handle, &disk_io_guid,
-+				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
-+      if (! bio || ! dio)
-+	/* This should not happen... Why?  */
-+	continue;
-+
-+      d = grub_malloc (sizeof (*d));
-+      if (! d)
-+	{
-+	  /* Uggh.  */
-+	  grub_free (handles);
-+	  return 0;
-+	}
-+
-+      d->handle = *handle;
-+      d->device_path = dp;
-+      d->last_device_path = ldp;
-+      d->block_io = bio;
-+      d->disk_io = dio;
-+      d->next = devices;
-+      devices = d;
-+    }
-+
-+  grub_free (handles);
++	break;
 +
-+  return devices;
++      dp = (grub_efi_device_path_t *) ((char *) dp + len);
++    }
 +}
 +
-+static int
-+iterate_child_devices (struct grub_efidisk_data *devices,
-+		       struct grub_efidisk_data *d,
-+		       int (*hook) (struct grub_efidisk_data *child))
++static inline int
++dpname_matches(char *str, char *candidate)
 +{
-+  struct grub_efidisk_data *p;
++  grub_size_t clen = grub_strlen(candidate);
++  char scratch[clen + 2];
++  int rc;
 +
-+  for (p = devices; p; p = p->next)
++  grub_strncpy(scratch, candidate, clen);
++  scratch[clen+1] = '\0';
++  if (scratch[clen-1] == '$')
 +    {
-+      grub_efi_device_path_t *dp, *ldp;
-+
-+      dp = duplicate_device_path (p->device_path);
-+      if (! dp)
-+	return 0;
-+
-+      ldp = find_last_device_path (dp);
-+      ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
-+      ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-+      ldp->length[0] = sizeof (*ldp);
-+      ldp->length[1] = 0;
-+
-+      if (compare_device_paths (dp, d->device_path) == 0)
-+	if (hook (p))
-+	  {
-+	    grub_free (dp);
-+	    return 1;
-+	  }
-+
-+      grub_free (dp);
++      scratch[--clen] = '\0';
++      rc = !grub_strncasecmp(str, scratch, clen);
++      return rc;
 +    }
 +
-+  return 0;
++    grub_strncpy(scratch+clen, "(", 2);
++    clen = grub_strlen(scratch);
++    rc = !grub_strncasecmp(str, scratch, clen);
++    return rc;
 +}
 +
-+/* Add a device into a list of devices in an ascending order.  */
 +static void
-+add_device (struct grub_efidisk_data **devices, struct grub_efidisk_data *d)
++finish_param_parse(char *pos, char **end, char *tmp)
 +{
-+  struct grub_efidisk_data **p;
-+  struct grub_efidisk_data *n;
-+
-+  for (p = devices; *p; p = &((*p)->next))
-+    {
-+      int ret;
-+
-+      ret = compare_device_paths (find_last_device_path ((*p)->device_path),
-+				  find_last_device_path (d->device_path));
-+      if (ret == 0)
-+	ret = compare_device_paths ((*p)->device_path,
-+				    d->device_path);
-+      if (ret == 0)
-+	return;
-+      else if (ret > 0)
-+	break;
-+    }
-+
-+  n = grub_malloc (sizeof (*n));
-+  if (! n)
++  if (!pos || !end || !tmp)
 +    return;
 +
-+  grub_memcpy (n, d, sizeof (*n));
-+  n->next = (*p);
-+  (*p) = n;
++  if (*end)
++    **end = *tmp;
 +}
 +
-+/* Name the devices.  */
-+static void
-+name_devices (struct grub_efidisk_data *devices)
++static char *
++get_next_param(char *pos, char **end, char *tmp)
 +{
-+  struct grub_efidisk_data *d;
++  char *comma = NULL;
++  char *openparen = NULL;
++  char *closeparen = NULL;
 +
-+  /* Let's see what can be added more.  */
-+  for (d = devices; d; d = d->next)
-+    {
-+      grub_efi_device_path_t *dp;
-+      grub_efi_block_io_media_t *m;
++  if (!pos || !end || !tmp)
++    return NULL;
 +
-+      dp = d->last_device_path;
-+      if (! dp)
-+	continue;
++  if (*end)
++    **end = *tmp;
 +
-+      m = d->block_io->media;
-+      if (GRUB_EFI_DEVICE_PATH_TYPE(dp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
++  openparen = grub_strchr(pos, '(');
++  if (openparen && *openparen)
++    {
++      pos = grub_strnchr(openparen + 1, ' ');
++      comma = grub_strchr(pos, ',');
++      closeparen = grub_strchr(pos, ')');
++
++      if (comma && *comma)
 +	{
-+	  if (m->read_only && m->block_size > SECTOR_SIZE)
-+	    {
-+	      add_device (&cd_devices, d);
-+	    } else
-+	    {
-+	      add_device (&hd_devices, d);
-+	    }
++	  *tmp = *comma;
++	  *comma = '\0';
++	  *end = comma;
 +	}
-+      if (GRUB_EFI_DEVICE_PATH_TYPE(dp) == GRUB_EFI_ACPI_DEVICE_PATH_TYPE)
++      else if (closeparen && *closeparen)
 +	{
-+	  add_device (&fd_devices, d);
++	  *tmp = *closeparen;
++	  *closeparen = '\0';
++	  *end = closeparen;
 +	}
++      return pos;
 +    }
-+}
-+
-+static void
-+free_devices (struct grub_efidisk_data *devices)
-+{
-+  struct grub_efidisk_data *p, *q;
 +
-+  for (p = devices; p; p = q)
++  comma = grub_strchr(pos, ',');
++  if (comma && *comma)
 +    {
-+      q = p->next;
-+      grub_free (p);
-+    }
-+}
-+
-+/* Enumerate all disks to name devices.  */
-+static void
-+enumerate_disks (void)
-+{
-+  struct grub_efidisk_data *devices;
-+
-+  devices = make_devices ();
-+  if (! devices)
-+    return;
-+
-+  name_devices (devices);
-+  free_devices (devices);
-+}
-+
-+static struct grub_efidisk_data *
-+get_device (struct grub_efidisk_data *devices, int num)
-+{
-+  struct grub_efidisk_data *d;
-+
-+  for (d = devices; d && num; d = d->next, num--)
-+    ;
-+
-+  if (num == 0)
-+    return d;
-+
-+  return 0;
-+}
-+
-+static int
-+grub_efidisk_read (struct grub_efidisk_data *d, grub_disk_addr_t sector,
-+		   grub_size_t size, char *buf)
-+{
-+  /* For now, use the disk io interface rather than the block io's.  */
-+  grub_efi_disk_io_t *dio;
-+  grub_efi_block_io_t *bio;
-+  grub_efi_status_t status;
-+  grub_efi_uint64_t sector_size;
-+
-+  dio = d->disk_io;
-+  bio = d->block_io;
-+  sector_size = d->block_io->media->block_size;
-+
-+  status = Call_Service_5 (dio->read ,
-+			   dio, bio->media->media_id,
-+			   sector * sector_size,
-+			   size * sector_size,
-+			   buf);
-+  if (status != GRUB_EFI_SUCCESS)
-+    return -1;
-+
-+  return 0;
-+}
-+
-+static int
-+grub_efidisk_write (struct grub_efidisk_data *d, grub_disk_addr_t sector,
-+		    grub_size_t size, const char *buf)
-+{
-+  /* For now, use the disk io interface rather than the block io's.  */
-+  grub_efi_disk_io_t *dio;
-+  grub_efi_block_io_t *bio;
-+  grub_efi_status_t status;
-+  grub_efi_uint64_t sector_size;
-+
-+  dio = d->disk_io;
-+  bio = d->block_io;
-+  sector_size = d->block_io->media->block_size;
-+
-+  grub_dprintf ("efidisk",
-+		"writing 0x%x sectors at the sector 0x%x to ??\n",
-+		(unsigned) size, (unsigned int) sector);
-+
-+  status = Call_Service_5 (dio->write ,
-+			   dio, bio->media->media_id,
-+			   sector * sector_size,
-+			   size * sector_size,
-+			   (void *) buf);
-+  if (status != GRUB_EFI_SUCCESS)
-+    return -1;
-+
-+  return 0;
-+}
++      pos = grub_strnchr(comma + 1, ' ');
++      comma = grub_strchr(pos, ',');
++      closeparen = grub_strchr(pos, ')');
 +
-+void
-+grub_efidisk_init (void)
-+{
-+  enumerate_disks ();
-+}
++      if (comma && *comma)
++	{
++	  *tmp = *comma;
++	  *comma = '\0';
++	  *end = comma;
++	}
++      else if (closeparen && *closeparen)
++	{
++	  *tmp = *closeparen;
++	  *closeparen = '\0';
++	  *end = closeparen;
++	}
++      return pos;
++    }
 +
-+void
-+grub_efidisk_fini (void)
-+{
-+  free_devices (fd_devices);
-+  free_devices (hd_devices);
-+  free_devices (cd_devices);
-+}
++  closeparen = grub_strchr(pos, ')');
++  if (closeparen && *closeparen)
++    pos = grub_strnchr(closeparen + 1, ' ');
 +
-+static struct grub_efidisk_data *
-+get_device_from_drive (int drive)
-+{
-+#ifdef SUPPORT_NETBOOT
-+  /* Not supported */
-+  if (drive == NETWORK_DRIVE)
-+    return NULL;
-+#endif
-+  if (drive == GRUB_INVALID_DRIVE)
-+    return NULL;
-+  if (drive == cdrom_drive)
-+    return get_device (cd_devices, 0);
-+  /* Hard disk */
-+  if (drive & 0x80)
-+    return get_device (hd_devices, drive - 0x80);
-+  /* Floppy disk */
-+  else
-+    return get_device (fd_devices, drive);
++  return pos;
 +}
 +
-+/* Low-level disk I/O.  Our stubbed version just returns a file
-+   descriptor, not the actual geometry. */
-+int
-+get_diskinfo (int drive, struct geometry *geometry)
-+{
-+  struct grub_efidisk_data *d;
-+
-+  d = get_device_from_drive (drive);
-+  if (!d)
-+    return -1;
-+  geometry->total_sectors = d->block_io->media->last_block+1;
-+  geometry->sector_size = d->block_io->media->block_size;
-+  geometry->flags = BIOSDISK_FLAG_LBA_EXTENSION;
-+  geometry->sectors = 63;
-+  if (geometry->total_sectors / 63 < 255)
-+    geometry->heads = 1;
-+  else
-+    geometry->heads = 255;
-+  geometry->cylinders = geometry->total_sectors / 63 / geometry->heads;
-+  return 0;
-+}
++struct generic_device_path
++  {
++    grub_efi_uint8_t type;
++    grub_efi_uint8_t subtype;
++    grub_efi_uint16_t length;
++  } __attribute__((packed));
 +
-+int
-+biosdisk (int subfunc, int drive, struct geometry *geometry,
-+	  int sector, int nsec, int segment)
-+{
-+  char *buf;
-+  struct grub_efidisk_data *d;
-+  int ret;
++struct hd_media_device_path
++  {
++    grub_efi_uint8_t type;
++    grub_efi_uint8_t subtype;
++    grub_efi_uint16_t length;
++    grub_efi_uint32_t partition;
++    grub_efi_uint64_t startlba;
++    grub_efi_uint64_t size;
++    grub_efi_uint8_t signature[16];
++    grub_efi_uint8_t mbr_type;
++    grub_efi_uint8_t signature_type;
++  } __attribute__((packed));
++
++static inline int
++parse_device_path_component(const char *orig_str, void *data)
++{
++  int orig_str_len = strlen(orig_str) + 1;
++  char str[orig_str_len];
++  char tmp;
++  char *pos = str;
++  int ret = 0;
 +
-+  d = get_device_from_drive (drive);
-+  if (!d)
-+    return -1;
-+  buf = (char *) ((unsigned long) segment << 4);
-+  switch (subfunc)
++  grub_strcpy(str, orig_str);
++  if (dpname_matches(str, "pci"))
 +    {
-+    case BIOSDISK_READ:
-+      ret = grub_efidisk_read (d, sector, nsec, buf);
-+      break;
-+    case BIOSDISK_WRITE:
-+      ret = grub_efidisk_write (d, sector, nsec, buf);
-+      break;
-+    default:
-+      return -1;
 +    }
-+
-+  return 0;
-+}
-+
-+/* Some utility functions to map GRUB devices with EFI devices.  */
-+grub_efi_handle_t
-+grub_efidisk_get_current_bdev_handle (void)
-+{
-+  struct grub_efidisk_data *d;
-+
-+  d = get_device_from_drive (current_drive);
-+  if (d == NULL)
-+    return NULL;
-+
-+  if (current_drive == GRUB_INVALID_DRIVE)
-+    return NULL;
-+
-+  if (current_drive == cdrom_drive)
-+    return d->handle;
-+
-+  if (! (current_drive & 0x80))
-+    return d->handle;
-+  /* If this is the whole disk, just return its own data.  */
-+  else if (current_partition == 0xFFFFFF)
-+    return d->handle;
-+  /* Otherwise, we must query the corresponding device to the firmware.  */
-+  else
++  else if (dpname_matches(str, "pccard"))
 +    {
-+      struct grub_efidisk_data *devices;
-+      grub_efi_handle_t handle = 0;
-+      auto int find_partition (struct grub_efidisk_data *c);
-+
-+      int find_partition (struct grub_efidisk_data *c)
++    }
++  else if (dpname_matches(str, "mmap"))
++    {
++    }
++  else if (dpname_matches(str, "ctrl"))
++    {
++    }
++  else if (dpname_matches(str, "acpi"))
++    {
++    }
++    /* XXX what about _ADR? */
++  /* messaging device paths */
++  else if (dpname_matches(str, "atapi"))
++    {
++    }
++  else if (dpname_matches(str, "scsi"))
++    {
++    }
++  else if (dpname_matches(str, "fibrechannel"))
++    {
++    }
++  else if (dpname_matches(str, "1394"))
++    {
++    }
++  else if (dpname_matches(str, "usb"))
++    {
++    }
++  else if (dpname_matches(str, "sata"))
++    {
++    }
++    /* XXX what about usb-wwid */
++    /* XXX what about lun */
++  else if (dpname_matches(str, "usbclass"))
++    {
++    }
++  else if (dpname_matches(str, "i2o"))
++    {
++    }
++  else if (dpname_matches(str, "macaddr"))
++    {
++    }
++  else if (dpname_matches(str, "ipv4"))
++    {
++    }
++  else if (dpname_matches(str, "ipv6"))
++    {
++    }
++    /* XXX what about vlan */
++  else if (dpname_matches(str, "infiniband"))
++    {
++    }
++  else if (dpname_matches(str, "uart"))
++    {
++    }
++  else if (dpname_matches(str, "uartflowctrl"))
++    {
++    }
++  else if (dpname_matches(str, "sas"))
++    {
++    }
++  else if (dpname_matches(str, "iscsi"))
++    {
++    }
++  /* media device paths */
++  else if (dpname_matches(str, "hd"))
++    {
++      /* these look roughly like:
++       *  HD(Partition,Type,Signature,Start, Size)
++       * but:
++       * - type may be optional.  1 or "MBR" means MBR. 2 or "GPT" means GPT.
++       * - start and size are optional
++       * - there can be random spaces
++       */
++      struct hd_media_device_path hddp;
++      unsigned long tmpul;
++      char *end = NULL, c;
++      char tmps[19] = "0x";
++      char *tmpsp;
++
++      ret = 42;
++
++      hddp.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE;
++      hddp.subtype = GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE;
++      hddp.length = ret;
++
++      //pos += grub_strcspn(pos, '(');
++      pos = get_next_param(pos, &end, &c);
++      if (!*pos)
 +	{
-+	  grub_efi_hard_drive_device_path_t hd;
-+
-+	  grub_memcpy (&hd, c->last_device_path, sizeof (hd));
-+
-+	  if ((GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path)
-+	       == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
-+	      && (GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path)
-+		  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)
-+	      && (part_start == hd.partition_start)
-+	      && (part_length == hd.partition_size))
-+	    {
-+	      handle = c->handle;
-+	      return 1;
-+	    }
-+
++broken_hd:
++	  finish_param_parse(pos, &end, &c);
 +	  return 0;
 +	}
++      grub_strncpy(tmps+2, pos, 16);
++      tmps[18] = '\0';
++      tmpsp = tmps;
++      safe_parse_maxulong(&tmpsp, &tmpul);
++      hddp.partition = tmpul;
++
++      pos = get_next_param(pos, &end, &c);
++      if (!*pos)
++	goto broken_hd;
++      grub_strcpy(tmps+2, pos);
++      tmpsp = tmps;
++      safe_parse_maxulong(&tmpsp, &tmpul);
++      hddp.startlba = tmpul;
++
++      pos = get_next_param(pos, &end, &c);
++      if (!*pos)
++	goto broken_hd;
++      grub_strcpy(tmps+2, pos);
++      tmpsp = tmps;
++      safe_parse_maxulong(&tmpsp, &tmpul);
++      hddp.size = tmpul;
++
++      pos = get_next_param(pos, &end, &c);
++      if (!*pos)
++	goto broken_hd;
++      if (!grub_strcmp(pos, "None"))
++	{
++	  hddp.signature_type = 0;
++	  grub_memset(hddp.signature, '\0', sizeof(hddp.signature));
++	}
++      else if (grub_strnlen(pos, 36) == 8)
++        {
++	  grub_efi_uint32_t tmpu32;
++	  grub_strncpy(tmps+2, pos, 8);
++	  tmps[10] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu32 = tmpul;
++	  hddp.signature_type = 1;
++	  grub_memcpy(hddp.signature, &tmpu32, sizeof(tmpu32));
++	}
++      else if (grub_strnlen(pos, 36) == 36)
++	{
++	  grub_efi_uint32_t tmpu32;
++	  grub_efi_uint16_t tmpu16;
++	  grub_efi_uint8_t tmpu8;
++
++	  grub_strncpy(tmps+2, pos, 8);
++	  tmps[10] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu32 = tmpul;
++	  grub_memcpy(hddp.signature, &tmpu32, sizeof(tmpu32));
++
++	  grub_strncpy(tmps+2, pos+9, 4);
++	  tmps[6] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu16 = tmpul;
++	  grub_memcpy(hddp.signature + 4, &tmpu16, sizeof(tmpu16));
++
++	  grub_strncpy(tmps+2, pos+14, 4);
++	  tmps[6] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu16 = tmpul;
++	  grub_memcpy(hddp.signature + 6, &tmpu16, sizeof(tmpu16));
++
++	  /* these are displayed like a u16, but they're a u8.  thanks. */
++	  grub_strncpy(tmps+2, pos+19, 2);
++	  tmps[4] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu8 = tmpul;
++	  grub_memcpy(hddp.signature + 8, &tmpu8, sizeof(tmpu8));
++	  grub_strncpy(tmps+2, pos+21, 2);
++	  tmps[4] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu8 = tmpul;
++	  grub_memcpy(hddp.signature + 9, &tmpu8, sizeof(tmpu8));
++
++	  grub_strncpy(tmps+2, pos+24, 2);
++	  tmps[4] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu8 = tmpul;
++	  grub_memcpy(hddp.signature + 10, &tmpu8, sizeof(tmpu8));
++
++	  grub_strncpy(tmps+2, pos+26, 2);
++	  tmps[4] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu8 = tmpul;
++	  grub_memcpy(hddp.signature + 11, &tmpu8, sizeof(tmpu8));
++
++	  grub_strncpy(tmps+2, pos+28, 2);
++	  tmps[4] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu8 = tmpul;
++	  grub_memcpy(hddp.signature + 12, &tmpu8, sizeof(tmpu8));
++
++	  grub_strncpy(tmps+2, pos+30, 2);
++	  tmps[4] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu8 = tmpul;
++	  grub_memcpy(hddp.signature + 13, &tmpu8, sizeof(tmpu8));
++
++	  grub_strncpy(tmps+2, pos+32, 2);
++	  tmps[4] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu8 = tmpul;
++	  grub_memcpy(hddp.signature + 14, &tmpu8, sizeof(tmpu8));
++
++	  grub_strncpy(tmps+2, pos+34, 2);
++	  tmps[4] = '\0';
++	  tmpsp = tmps;
++	  safe_parse_maxulong(&tmpsp, &tmpul);
++	  tmpu8 = tmpul;
++	  grub_memcpy(hddp.signature + 15, &tmpu8, sizeof(tmpu8));
++
++	  hddp.signature_type = 2;
++	}
++      else
++	goto broken_hd;
 +
-+      devices = make_devices ();
-+      iterate_child_devices (devices, d, find_partition);
-+      free_devices (devices);
++      hddp.mbr_type = hddp.signature_type;
 +
-+      if (handle != 0)
-+	return handle;
++      if (data)
++	grub_memcpy(data, &hddp, sizeof(hddp));
 +    }
-+
-+  return 0;
-+}
-+
-+int
-+grub_get_drive_partition_from_bdev_handle (grub_efi_handle_t handle,
-+					   unsigned long *drive,
-+					   unsigned long *partition)
-+{
-+  grub_efi_device_path_t *dp;
-+  struct grub_efidisk_data *d, *devices;
-+  int drv;
-+  unsigned long part;
-+  grub_efi_hard_drive_device_path_t hd;
-+  int found;
-+  int part_type, part_entry;
-+  unsigned long partition_start, partition_len, part_offset, part_extoffset;
-+  unsigned long gpt_offset;
-+  int gpt_count, gpt_size;
-+  char buf[SECTOR_SIZE];
-+  auto int find_bdev (struct grub_efidisk_data *c);
-+
-+  int find_bdev (struct grub_efidisk_data *c)
++  else if (dpname_matches(str, "cd"))
 +    {
-+      if (! compare_device_paths (c->device_path, dp))
-+	{
-+	  grub_memcpy (&hd, c->last_device_path, sizeof (hd));
-+	  found = 1;
-+	  return 1;
-+	}
-+      return 0;
 +    }
-+
-+  dp = grub_efi_get_device_path (handle);
-+  if (! dp)
-+    return 0;
-+
-+  drv = 0;
-+  for (d = fd_devices; d; d = d->next, drv++)
++  else if (dpname_matches(str, "file"))
 +    {
-+      if (! compare_device_paths (d->device_path, dp))
-+	{
-+	  *partition = 0xFFFFFF;
-+	  *drive = drv;
-+	  return 1;
-+	}
 +    }
-+
-+  drv = cdrom_drive;
-+  if (cd_devices  && ! compare_device_paths (cd_devices->device_path, dp))
++  else if (dpname_matches(str, "protocol"))
 +    {
-+      *partition = 0xFFFFFF;
-+      *drive = drv;
-+      return 1;
 +    }
-+
-+  drv = 0x80;
-+  for (d = hd_devices; d; d = d->next, drv++)
++    /* what about piwg firmware file? */
++    /* what about piwg firmware volume? */
++    /* what about relative offset media */
++  else if (dpname_matches(str, "bios"))
 +    {
-+      if (! compare_device_paths (d->device_path, dp))
-+	{
-+	  *partition = 0xFFFFFF;
-+	  *drive = drv;
-+	  return 1;
-+	}
 +    }
-+
-+  devices = make_devices ();
-+
-+  drv = 0x80;
-+  found = 0;
-+  for (d = hd_devices; d; d = d->next, drv++)
++  /* This is the end beautiful friend */
++  else if (dpname_matches(str, "EndEntire$"))
++    {
++      struct generic_device_path gdp = {
++	      .type = GRUB_EFI_END_DEVICE_PATH_TYPE,
++	      .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE,
++	      .length = 4
++      };
++      ret = 4;
++      if (data)
++	grub_memmove(data, &gdp, sizeof(gdp));
++    }
++  else if (dpname_matches(str, "EndThis$"))
++    {
++      struct generic_device_path gdp = {
++	      .type = GRUB_EFI_END_DEVICE_PATH_TYPE,
++	      .subtype = GRUB_EFI_END_THIS_DEVICE_PATH_SUBTYPE,
++	      .length = 4
++      };
++      ret = 4;
++      if (data)
++	grub_memmove(data, &gdp, sizeof(gdp));
++    }
++  else if (dpname_matches(str, "EndUnknown$"))
++    {
++      struct generic_device_path gdp = {
++	      .type = GRUB_EFI_END_DEVICE_PATH_TYPE,
++	      .subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE,
++	      .length = 4
++      };
++      ret = 4;
++      if (data)
++	grub_memmove(data, &gdp, sizeof(gdp));
++    }
++  /* handle anything we didn't recognize */
++  else if (dpname_matches(str, "vendor"))
++    {
++      /* needs to handle:
++       * 1) hw vendor
++       * 2) messaging vendor
++       * 3) media vendor
++       */
++    }
++  else
 +    {
-+      iterate_child_devices (devices, d, find_bdev);
-+      if (found)
-+	break;
 +    }
 +
-+  free_devices (devices);
++  return ret;
++}
 +
-+  if (! found)
-+    return 0;
++grub_efi_device_path_t *
++device_path_from_utf8 (const char *device)
++{
++  grub_size_t device_len;
++  grub_efi_device_path_t *dp = NULL;
 +
-+  part = 0xFFFFFF;
-+  while (next_partition (drv, 0, &part, &part_type,
-+			 &partition_start, &partition_len,
-+			 &part_offset, &part_entry,
-+			 &part_extoffset, &gpt_offset, &gpt_count,
-+			 &gpt_size, buf))
-+    {
-+      if (part_type
-+	  && partition_start == hd.partition_start
-+	  && partition_len == hd.partition_size)
-+	{
-+	  *drive = drv;
-+	  *partition = part;
-+	  return 1;
-+	}
-+    }
++  device_len = parse_device_path_component(device, dp);
++  device_len += parse_device_path_component("EndEntire", dp);
++  dp = grub_malloc(device_len);
++  if (!dp)
++    return NULL;
++  device_len = parse_device_path_component(device, dp);
++  device_len += parse_device_path_component("EndEntire",
++				     (void *)((unsigned long)dp + device_len));
 +
-+  return 0;
++
++  return dp;
 +}
 diff --git a/efi/efigraph.c b/efi/efigraph.c
 new file mode 100644
-index 0000000..0babe11
+index 0000000..51bfc2d
 --- /dev/null
 +++ b/efi/efigraph.c
-@@ -0,0 +1,1199 @@
+@@ -0,0 +1,1457 @@
 +/* efigraph.c - EFI "graphics output" support for GRUB/EFI */
 +/*
 + *  GRUB  --  GRand Unified Bootloader
@@ -13464,6 +13283,23 @@ index 0000000..0babe11
 +#include "graphics.h"
 +#include "xpm.h"
 +
++#define dbgdelay(_f, _l) ({\
++	if (debug_graphics) {				\
++  		do {					\
++			grub_efi_stall(1000);		\
++		} while (console_getkey() < 0);		\
++	}						\
++	})
++
++#define dprintf(format, args...) ({			\
++	if (debug_graphics) {				\
++		struct term_entry *_tt = current_term;	\
++		current_term = term_table;		\
++		grub_printf(format, ##args);		\
++		current_term = _tt;			\
++	}						\
++	})
++
 +struct grub_pixel_info
 +{
 +  char depth_bits;
@@ -13566,6 +13402,59 @@ index 0000000..0babe11
 +  *len = bit_len;
 +}
 +
++static grub_efi_graphics_output_mode_information_t *
++get_graphics_mode_info_for_mode(struct eg *eg, int mode)
++{
++	int i;
++	
++	for (i = 0; i < eg->max_mode; i++) {
++		if (eg->modes[i] == NULL)
++			continue;
++		if (eg->modes[i]->number == mode)
++			return eg->modes[i]->info;
++	}
++	return NULL;
++}
++
++static grub_efi_graphics_output_mode_information_t *
++get_graphics_mode_info(struct eg *eg)
++{
++	return get_graphics_mode_info_for_mode(eg, eg->graphics_mode);
++}
++
++static void
++print_mode_info(struct video_mode *mode)
++{
++	grub_efi_graphics_output_mode_information_t *info = mode->info;
++	dprintf("mode %d (%dx%d, pitch %d, ",
++		mode->number,
++		info->horizontal_resolution,
++		info->vertical_resolution,
++		info->pixels_per_scan_line);
++	switch(info->pixel_format) {
++		case GRUB_EFI_PIXEL_RGBR_8BIT_PER_COLOR:
++			dprintf("rgbr 8bpc");
++			break;
++		case GRUB_EFI_PIXEL_BGRR_8BIT_PER_COLOR:
++			dprintf("bgrr 8bpc");
++			break;
++		case GRUB_EFI_PIXEL_BIT_MASK:
++			dprintf("bitmask color");
++			break;
++		case GRUB_EFI_PIXEL_BLT_ONLY:
++			dprintf("blt only");
++			break;
++	}
++	dprintf(")\n");
++	if (info->pixel_format == GRUB_EFI_PIXEL_BIT_MASK) {
++		dprintf("red: %08x green: %08x blue: %08x res: %08x\n",
++		info->pixel_information.red_mask,
++		info->pixel_information.green_mask,
++		info->pixel_information.blue_mask,
++		info->pixel_information.reserved_mask);
++	}
++}
++
 +static void
 +set_kernel_params(struct graphics_backend *backend,
 +            struct linux_kernel_params *params)
@@ -13624,7 +13513,7 @@ index 0000000..0babe11
 +            params->blue_field_pos = 0;
 +            params->reserved_mask_size = 8;
 +            params->reserved_field_pos = 24;
-+            params->lfb_line_len = gop_info->pixels_per_scan_line * 4;
++	    params->lfb_line_len = gop_info->pixels_per_scan_line * 4;
 +        } else if (gop_info->pixel_format == GRUB_EFI_PIXEL_BIT_MASK) {
 +            find_bits (gop_info->pixel_information.red_mask,
 +      		 &params->red_field_pos, &params->red_mask_size);
@@ -13732,11 +13621,28 @@ index 0000000..0babe11
 +	return buf;
 +}
 +
++
++static void
++hw_blt_pos_to_screen_pos(struct eg *eg, struct bltbuf *bltbuf,
++                      position_t *bltpos, position_t *bltsz, position_t *pos)
++{
++    position_t phys;
++
++    position_to_phys(eg, pos, &phys);
++
++    Call_Service_10(eg->output_intf->blt, eg->output_intf, (void *)bltbuf->pixbuf,
++                    GRUB_EFI_BLT_BUFFER_TO_VIDEO,
++                    bltpos->x, bltpos->y,
++                    phys.x, phys.y,
++                    bltsz->x, bltsz->y,
++                    0);
++}
++
 +static void
 +blt_pos_to_screen_pos(struct eg *eg, struct bltbuf *bltbuf,
 +        position_t *bltpos, position_t *bltsz, position_t *pos)
 +{
-+    grub_efi_graphics_output_mode_information_t *info = eg->modes[eg->graphics_mode]->info;
++    grub_efi_graphics_output_mode_information_t *info = get_graphics_mode_info(eg);
 +    grub_efi_graphics_output_pixel_t *pixel;
 +    position_t phys;
 +    const int pxlstride = info->pixels_per_scan_line;
@@ -13744,8 +13650,9 @@ index 0000000..0babe11
 +
 +    position_to_phys(eg, pos, &phys);
 +
-+    if (info->pixel_format == GRUB_EFI_PIXEL_BLT_ONLY) {
-+        ;
++    if (info->pixel_format == GRUB_EFI_PIXEL_BLT_ONLY || 1) {
++        hw_blt_pos_to_screen_pos(eg, bltbuf, bltpos, bltsz, pos);
++#if 0
 +    } else if (info->pixel_format == GRUB_EFI_PIXEL_BIT_MASK) {
 +        int y;
 +        grub_pixel_info_t *pinfo = &eg->pixel_info;
@@ -13793,19 +13700,24 @@ index 0000000..0babe11
 +            }
 +            memmove(fb, raw_pixels, maxpixels * pinfo->depth_bytes);
 +        }
++#endif
 +    } else {
 +        int y;
++        grub_pixel_info_t *pinfo = &eg->pixel_info;
++        const int maxpixels =
++            MIN(info->horizontal_resolution - pos->x, bltsz->x);
++
++	//char *line = &fb[phys.y * bytestride + phys.x * sizeof(*pixel)];
 +        for (y = bltpos->y; y < bltpos->y + bltsz->y; y++, phys.y++) {
++	    char raw_pixels[maxpixels * sizeof(*pixel)];
 +            char *fb = (char *)(unsigned long)eg->output_intf->mode->frame_buffer_base;
-+            char *line = &fb[phys.y * bytestride + phys.x * sizeof(*pixel)];
-+            const int maxpixels =
-+                MIN(info->horizontal_resolution - pos->x, bltsz->x);
 +            int x;
 +
-+            pixel = &bltbuf->pixbuf[y * bltbuf->width + bltpos->x];
++            pixel = (void *)&bltbuf->pixbuf[y * bltbuf->width + bltpos->x];
++            fb += phys.y * pinfo->line_length + phys.x * pinfo->depth_bytes;
 +
 +            if (info->pixel_format == GRUB_EFI_PIXEL_BGRR_8BIT_PER_COLOR) {
-+                memmove(line, pixel, maxpixels * sizeof (*pixel));
++                memmove(raw_pixels, pixel, maxpixels * sizeof (*pixel));
 +                continue;
 +            } else if (info->pixel_format==GRUB_EFI_PIXEL_RGBR_8BIT_PER_COLOR) {
 +                grub_efi_graphics_output_pixel_t shadow[maxpixels];
@@ -13814,8 +13726,42 @@ index 0000000..0babe11
 +                    shadow[x].rgbr.green = pixel[x].bgrr.green;
 +                    shadow[x].rgbr.blue = pixel[x].bgrr.blue;
 +                }
-+                memmove(line, shadow, maxpixels * sizeof (*pixel));
-+            }
++            
++                memmove(raw_pixels, shadow, maxpixels * sizeof (*pixel));
++            } else if (info->pixel_format == GRUB_EFI_PIXEL_BIT_MASK) {
++                for (x = 0; x < maxpixels; x++) {
++                    char depth_bytes = pinfo->depth_bytes;
++                    char *raw_pixel = raw_pixels + x * depth_bytes;
++
++                    int red, green, blue, color;
++                    char *colorp;
++
++#if 0
++                    red = pixel[x].bgrr.red & 0x3f;
++                    green = pixel[x].bgrr.green & 0x3f;
++                    blue = pixel[x].bgrr.blue & 0x3f;
++                    red = red * ((1 << pinfo->red_size) - 1) / 0x3f;
++                    green = green * ((1 << pinfo->green_size) - 1) / 0x3f;
++                    blue = blue * ((1 << pinfo->blue_size) - 1) / 0x3f;
++#else
++                    red = pixel[x].bgrr.red;
++                    green = pixel[x].bgrr.green;
++                    blue = pixel[x].bgrr.blue;
++
++                    red >>= 8 - pinfo->red_size;
++                    green >>= 8 - pinfo->green_size;
++                    blue >>= 8 - pinfo->blue_size;
++#endif
++
++                    color = (red << pinfo->red_pos) | 
++                            (green << pinfo->green_pos) |
++                            (blue << pinfo->blue_pos);
++                    colorp = (void *)&color;
++                    while (depth_bytes--)
++                        *raw_pixel++ = *colorp++;
++                }
++	    }
++	    memmove(fb, raw_pixels, maxpixels * pinfo->depth_bytes);
 +        }
 +    }
 +}
@@ -13844,25 +13790,6 @@ index 0000000..0babe11
 +#endif
 +}
 +
-+
-+#if 0
-+static void
-+blt_pos_to_screen_pos(struct eg *eg, struct bltbuf *bltbuf,
-+                      position_t *bltpos, position_t *bltsz, position_t *pos)
-+{
-+    position_t phys;
-+
-+    position_to_phys(eg, pos, &phys);
-+
-+    Call_Service_10(eg->output_intf->blt, eg->output_intf, bltbuf->pixbuf,
-+                    GRUB_EFI_BLT_BUFFER_TO_VIDEO,
-+                    bltpos->x, bltpos->y,
-+                    phys.x, phys.y,
-+                    bltsz->x, bltsz->y,
-+                    0);
-+}
-+#endif
-+
 +static void
 +blt_to_screen_pos(struct eg *eg, struct bltbuf *bltbuf, position_t *pos)
 +{
@@ -13889,13 +13816,13 @@ index 0000000..0babe11
 +    struct eg *eg = backend->priv;
 +    grub_efi_graphics_output_mode_information_t *info;
 +
-+    info = eg->modes[eg->graphics_mode]->info;
++    info = get_graphics_mode_info(eg);
 +
 +    size->x = info->horizontal_resolution;
 +    size->y = info->vertical_resolution;
 +}
 +
-+static void 
++static void
 +bltbuf_set_pixel(struct bltbuf *bltbuf, position_t *pos,
 +                             grub_efi_graphics_output_pixel_t *pixel)
 +{
@@ -13995,7 +13922,7 @@ index 0000000..0babe11
 +    offset = fpos.y * screensz.x + fpos.x;
 +
 +    if (set)
-+        text[offset] |= 0x200;
++        text[offset] |= 0x0200;
 +
 +    graphics_clbl(fpos.x, fpos.y, 1, 1, 1);
 +
@@ -14013,7 +13940,7 @@ index 0000000..0babe11
 +    grub_efi_graphics_output_mode_information_t *info;
 +    position_t screensz;
 +
-+    info = eg->modes[eg->graphics_mode]->info;
++    info = get_graphics_mode_info(eg);
 +
 +    if (xpm) {
 +        eg->screen_pos.x =
@@ -14108,7 +14035,7 @@ index 0000000..0babe11
 +    grub_efi_uintn_t x, y, i, j;
 +    unsigned char r = 0 ,g = 0;
 +
-+    info = eg->modes[eg->graphics_mode]->info;
++    info = get_graphics_mode_info(eg);
 +    x = info->horizontal_resolution;
 +    y = info->vertical_resolution;
 +
@@ -14273,18 +14200,19 @@ index 0000000..0babe11
 +            int bit = glyph[glyphpos.y] & (1 << ((fontsz.x-1) - glyphpos.x));
 +            int idx = -1;
 +
-+            if (set)
-+                idx = bit ? 0 : 15;
-+            else
++            if (!set) {
 +                if (invert)
-+                idx = bit ? 15 : 0;
-+            else if (bit)
-+                idx = 15;
-+
-+            if (idx == -1) {
-+                if (is_shadow_pixel(screensz, charpos, glyphpos, fontsz) ||
-+                        !eg->background)
-+                    idx = invert ? 15 : 0;
++                    idx = bit ? 0 : 15;
++                else if (bit)
++                    idx = 15;
++
++                if (idx == -1) {
++                    if (is_shadow_pixel(screensz, charpos, glyphpos, fontsz) ||
++                            !eg->background)
++                        idx = invert ? 15 : 0;
++                }
++            } else {
++                idx = bit ? 0 : 15;
 +            }
 +
 +            if (idx != -1)
@@ -14341,10 +14269,10 @@ index 0000000..0babe11
 +    width = MIN(width, screensz.x - col);
 +    height = MIN(height, screensz.y - row);
 +    graphics_get_font_size(&fontsz);
-+ 
++
 +    blsz.x = width * fontsz.x;
 +    blsz.y = height * fontsz.y;
-+   
++
 +    bltbuf = alloc_bltbuf(blsz.x, blsz.y);
 +    if (!bltbuf)
 +        return;
@@ -14392,13 +14320,21 @@ index 0000000..0babe11
 +    rgb_to_pixel(0xff,0xff,0xff, &eg->palette[16]); // 16 Also white ;)
 +}
 +
++static grub_efi_status_t
++set_video_mode(struct eg *eg, int mode)
++{
++	grub_efi_status_t efi_status;
++	efi_status = Call_Service_2(eg->output_intf->set_mode, eg->output_intf, mode);
++	return efi_status;
++}
++
 +static void disable(struct graphics_backend *backend)
 +{
 +    struct eg *eg;
-+    
++
 +    if (!backend)
 +        return;
-+    
++
 +    eg = backend->priv;
 +    if (!eg || eg->current_mode != GRAPHICS)
 +        return;
@@ -14406,7 +14342,7 @@ index 0000000..0babe11
 +#if 0
 +    blank(backend);
 +
-+    set_video_mode(eg, &eg->text_mode);
++    set_video_mode(eg, eg->text_mode);
 +    grub_efi_set_text_mode(1);
 +#endif
 +    eg->current_mode = TEXT;
@@ -14465,13 +14401,130 @@ index 0000000..0babe11
 +  return 1;
 +}
 +
++/* 1 = prefer a
++ * 0 = prefer neither
++ * -1 = prefer b
++ */
++static int
++modecmp_helper(struct eg *eg, struct video_mode *amode, struct video_mode *bmode)
++{
++        grub_efi_graphics_output_mode_information_t *a = amode->info;
++        grub_efi_graphics_output_mode_information_t *b = bmode->info;
++
++        if (a != NULL && b == NULL)
++                return 1;
++        if (a == NULL && b == NULL)
++                return 0;
++        if (a == NULL && b != NULL)
++                return -1;
++
++#if 0
++	if (amode->number == eg->graphics_mode && bmode->number != eg->graphics_mode)
++		return 1;
++	if (amode->number == eg->graphics_mode && bmode->number == eg->graphics_mode)
++		return 0;
++	if (amode->number != eg->graphics_mode && bmode->number == eg->graphics_mode)
++		return -1;
++#endif
++
++
++	/* kernel doesn't deal with blt only modes, so prefer against them. */
++        if (a->pixel_format != GRUB_EFI_PIXEL_BLT_ONLY &&
++                        b->pixel_format == GRUB_EFI_PIXEL_BLT_ONLY)
++                return 1;
++        if (b->pixel_format != GRUB_EFI_PIXEL_BLT_ONLY &&
++                        a->pixel_format == GRUB_EFI_PIXEL_BLT_ONLY)
++                return -1;
++
++	/* XXX PJFIX there's something wrong with what we're passing to the
++	 * kernel for stride in the bgrr/rgbr modes, and I haven't figured out
++	 * just what yet, so for now, prefer bitmask modes.
++	 */
++	if (a->pixel_format == GRUB_EFI_PIXEL_BIT_MASK &&
++			b->pixel_format != GRUB_EFI_PIXEL_BIT_MASK)
++		return 1;
++	if (a->pixel_format != GRUB_EFI_PIXEL_BIT_MASK &&
++			b->pixel_format == GRUB_EFI_PIXEL_BIT_MASK)
++		return -1;
++
++        if (a->pixel_format == GRUB_EFI_PIXEL_BGRR_8BIT_PER_COLOR &&
++			b->pixel_format != GRUB_EFI_PIXEL_BGRR_8BIT_PER_COLOR)
++		return 1;
++        if (a->pixel_format != GRUB_EFI_PIXEL_BGRR_8BIT_PER_COLOR &&
++			b->pixel_format == GRUB_EFI_PIXEL_BGRR_8BIT_PER_COLOR)
++		return -1;
++
++        if (a->pixel_format == GRUB_EFI_PIXEL_RGBR_8BIT_PER_COLOR &&
++			b->pixel_format != GRUB_EFI_PIXEL_RGBR_8BIT_PER_COLOR)
++		return 1;
++        if (a->pixel_format != GRUB_EFI_PIXEL_RGBR_8BIT_PER_COLOR &&
++			b->pixel_format == GRUB_EFI_PIXEL_RGBR_8BIT_PER_COLOR)
++		return -1;
++
++        if (a->horizontal_resolution > b->horizontal_resolution &&
++                        a->vertical_resolution > b->vertical_resolution)
++                return 1;
++        if (a->horizontal_resolution < b->horizontal_resolution &&
++                        a->vertical_resolution < b->vertical_resolution)
++                return -1;
++        return 0;
++}
++
++static int
++modecmp(struct eg *eg, struct video_mode *amode, struct video_mode *bmode)
++{
++        int rc;
++#if 0
++        grub_efi_graphics_output_mode_information_t *a = amode->info;
++        grub_efi_graphics_output_mode_information_t *b = bmode->info;
++#endif
++        rc = modecmp_helper(eg, amode, bmode);
++#if 0
++        grub_printf("comparing nodes:\n");
++        print_mode_info(amode);
++        print_mode_info(bmode);
++        if (rc > 0)
++                grub_printf("result: a > b\n");
++        else if (rc < 0)
++                grub_printf("result: a < b\n");
++        else
++                grub_printf("result: a == b\n");
++
++        //dbgdelay(__FILE__, __LINE__);
++#endif
++        return rc;
++}
++
++static void
++modeswap(struct video_mode *amode, struct video_mode *bmode)
++{
++        struct video_mode tmp;
++
++        memcpy(&tmp, amode, sizeof (tmp));
++        memcpy(amode, bmode, sizeof (tmp));
++        memcpy(bmode, &tmp, sizeof(tmp));
++}
++
++static void
++sort_modes(struct eg *eg, int p, int r)
++{
++	struct video_mode **modes = eg->modes;
++
++        int i, j;
++	for (i = 0; i < eg->max_mode; i++) {
++		for (j = i + 1; j < eg->max_mode; j++) {
++			if (modecmp(eg, modes[j], modes[i]) < 0)
++				modeswap(modes[j], modes[i]);
++		}
++	}
++}
++
 +static int
 +try_enable(struct graphics_backend *backend)
 +{
 +    struct eg *eg = backend->priv;
 +    grub_efi_status_t efi_status;
 +    int i;
-+    void *tmp_term = current_term;
 +
 +    if (eg->text_mode == 0xffffffff) {
 +        grub_efi_set_text_mode(1);
@@ -14480,50 +14533,74 @@ index 0000000..0babe11
 +
 +    if (eg->graphics_mode == 0xffffffff) {
 +        grub_efi_graphics_output_mode_information_t *info;
-+        grub_efi_graphics_output_mode_information_t *bestinfo;
-+        int largest_mode = 0;
 +
 +        if (!graphics_alloc_text_buf())
 +            return 0;
 +
-+	bestinfo = eg->modes[0]->info;
-+        
++        grub_efi_set_text_mode(0);
 +        eg->graphics_mode = eg->output_intf->mode->mode;
++        grub_efi_set_text_mode(1);
++#if 0
++	dprintf("graphics mode is %d\n", eg->graphics_mode);
++	/* this is okay here because we haven't sorted yet.*/
++	print_mode_info(eg->modes[eg->graphics_mode]);
++	dprintf("text mode is %d\n", eg->text_mode);
++	print_mode_info(eg->modes[eg->text_mode]);
++#endif
 +
-+        for (i = 0; i < eg->max_mode; i++) {
++        sort_modes(eg, 0, eg->max_mode-1);
++
++#if 0
++        for (i = eg->max_mode - 1; i >= 0; i--)
++            print_mode_info(eg->modes[i]);
++	dbgdelay(__FILE__, __LINE__);
++#endif
++
++        for (i = eg->max_mode - 1; i >= 0; i--) {
 +            if (!eg->modes[i])
 +                continue;
++
 +            info = eg->modes[i]->info;
 +
-+	    if (info->pixel_format != GRUB_EFI_PIXEL_RGBR_8BIT_PER_COLOR &&
++#if 0
++            if (info->pixel_format != GRUB_EFI_PIXEL_RGBR_8BIT_PER_COLOR &&
 +                 info->pixel_format != GRUB_EFI_PIXEL_BGRR_8BIT_PER_COLOR &&
 +                 info->pixel_format != GRUB_EFI_PIXEL_BIT_MASK) {
-+                info = NULL;
 +                continue;
 +            }
++#endif
 +
-+            if (info->horizontal_resolution > bestinfo->horizontal_resolution &&
-+                    info->vertical_resolution > bestinfo->vertical_resolution) {
-+                bestinfo = info;
-+                largest_mode = i;
-+                continue;
++            grub_efi_set_text_mode(0);
++            efi_status = set_video_mode(eg, eg->modes[i]->number);
++            if (efi_status == GRUB_EFI_SUCCESS) {
++#if 0
++                grub_efi_set_text_mode(1);
++	        dprintf("switched to mode %d successfully\n",
++		        eg->modes[i]->number);
++	        dbgdelay(__FILE__,__LINE__);
++                grub_efi_set_text_mode(0);
++#endif
++                eg->graphics_mode = eg->modes[i]->number;
++	        fill_pixel_info(&eg->pixel_info, info);
++                break;
++            } else {
++#if 0
++                set_video_mode(eg, eg->text_mode);
++                grub_efi_set_text_mode(1);
++		dprintf("return code was %d\n", efi_status);
++#endif
 +            }
 +        }
-+        eg->graphics_mode = largest_mode;
-+
-+        info = eg->modes[eg->graphics_mode]->info;
-+
-+        grub_efi_set_text_mode(0);
-+        efi_status = Call_Service_2(eg->output_intf->set_mode, eg->output_intf,
-+                           eg->graphics_mode);
 +        if (efi_status != GRUB_EFI_SUCCESS) {
++#if 1
 +            grub_efi_set_text_mode(1);
++            set_video_mode(eg, eg->text_mode);
++#endif
 +            return 0;
 +        }
 +
-+        fill_pixel_info(&eg->pixel_info, eg->modes[eg->graphics_mode]->info);
 +    }
-+    
++
 +    eg->current_mode = GRAPHICS;
 +    return 1;
 +}
@@ -14564,7 +14641,7 @@ index 0000000..0babe11
 +            eg->modes[i] = grub_malloc(sizeof eg->modes[0]);
 +            if (!eg->modes[i])
 +                goto fail;
-+            memset(eg->modes, '\0', sizeof (eg->modes[0]));
++            memset(eg->modes[i], '\0', sizeof (eg->modes[0]));
 +            eg->modes[i]->number = i;
 +
 +            efi_status = Call_Service_4(eg->output_intf->query_mode,
@@ -14573,7 +14650,7 @@ index 0000000..0babe11
 +            if (efi_status != GRUB_EFI_SUCCESS) {
 +                grub_free(eg->modes[i]);
 +                eg->modes[i] = NULL;
-+                eg->max_mode = i;
++                //eg->max_mode = i;
 +                break;
 +            }
 +        }
@@ -14591,7 +14668,7 @@ index 0000000..0babe11
 +        reset_screen_geometry(backend);
 +        return 1;
 +    }
-+    
++
 +fail:
 +    backend->priv = NULL;
 +    if (eg->modes) {
@@ -14626,10 +14703,10 @@ index 0000000..0babe11
 +#endif /* SUPPORT_GRAPHICS */
 diff --git a/efi/efimain.c b/efi/efimain.c
 new file mode 100644
-index 0000000..ed73ca2
+index 0000000..e1a1e66
 --- /dev/null
 +++ b/efi/efimain.c
-@@ -0,0 +1,110 @@
+@@ -0,0 +1,129 @@
 +/*
 + *  GRUB  --  GRand Unified Bootloader
 + *  Copyright (C) 2007 Intel Corp.
@@ -14656,6 +14733,9 @@ index 0000000..ed73ca2
 +#include <grub/misc.h>
 +
 +#include <shared.h>
++#include <efistubs.h>
++
++#include "pxe.h"
 +
 +#define GRUB_SCRATCH_MEM_PAGES  (GRUB_SCRATCH_MEM_SIZE >> 12)
 +
@@ -14666,25 +14746,41 @@ index 0000000..ed73ca2
 +#define LOW_STACK_PAGES (LOW_STACK_SIZE >> 12)
 +static void *low_stack, *real_stack;
 +
++extern int grub_test_pxe(grub_efi_loaded_image_t *loaded_image);
++
 +static void
 +real_main (void)
 +{
 +  grub_efi_loaded_image_t *loaded_image;
-+  char *path_name;
++  char *path_name = NULL;
 +
 +  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
-+  grub_get_drive_partition_from_bdev_handle (loaded_image->device_handle,
-+					     &boot_drive,
-+					     &install_partition);
-+  path_name = grub_efi_file_path_to_path_name (loaded_image->file_path);
-+  if (path_name)
-+    {
-+      grub_set_config_file (path_name);
-+      grub_free (path_name);
-+    }
-+  grub_load_saved_default (loaded_image->device_handle);
++
++  path_name = grub_efi_pxe_get_config_path(loaded_image);
++
++  if (path_name) {
++    network_ready = 1;
++
++    grub_set_config_file (path_name);
++    grub_free (path_name);
++  } else {
++      grub_get_drive_partition_from_bdev_handle (loaded_image->device_handle,
++						 &boot_drive,
++						 &install_partition);
++      path_name = grub_efi_file_path_to_path_name (loaded_image->file_path);
++
++    if (path_name)
++      {
++        grub_set_config_file (path_name);
++        grub_free (path_name);
++      }
++
++    grub_load_saved_default (loaded_image->device_handle);
++  }
 +
 +  init_bios_info ();
++  while (console_getkey() < 0)
++    grub_efi_stall(1000);
 +}
 +
 +grub_efi_status_t
@@ -14742,10 +14838,10 @@ index 0000000..ed73ca2
 +}
 diff --git a/efi/efimisc.c b/efi/efimisc.c
 new file mode 100644
-index 0000000..4818617
+index 0000000..480ba25
 --- /dev/null
 +++ b/efi/efimisc.c
-@@ -0,0 +1,603 @@
+@@ -0,0 +1,665 @@
 +/*
 + *  GRUB  --  GRand Unified Bootloader
 + *  Copyright (C) 2006  Free Software Foundation, Inc.
@@ -14856,6 +14952,79 @@ index 0000000..4818617
 +  va_end (args);
 +}
 +
++grub_size_t
++grub_utf8_char_len(grub_uint8_t ch)
++{
++  return ((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1;
++}
++
++#define UTF8_SHIFT_AND_MASK(unicode, byte)  (unicode)<<=6; (unicode) |= (0x3f & (byte))
++
++/* convert utf8 to utf32 */
++grub_uint32_t
++grub_utf8_to_utf32(const grub_uint8_t *src, grub_size_t length)
++{
++  grub_uint32_t unicode;
++
++  switch (length)
++    {
++    case 1:
++      return src[0];
++    case 2:
++      unicode = src[0] & 0x1f;
++      UTF8_SHIFT_AND_MASK(unicode, src[1]);
++      return unicode;
++    case 3:
++      unicode = src[0] & 0x0f;
++      UTF8_SHIFT_AND_MASK(unicode, src[1]);
++      UTF8_SHIFT_AND_MASK(unicode, src[2]);
++      return unicode;
++    case 4:
++      unicode = src[0] & 0x07;
++      UTF8_SHIFT_AND_MASK(unicode, src[1]);
++      UTF8_SHIFT_AND_MASK(unicode, src[2]);
++      UTF8_SHIFT_AND_MASK(unicode, src[3]);
++      return unicode;
++    default:
++      return 0xffff;
++    }
++}
++
++/* convert utf8 to utf16 */
++void
++grub_utf8_to_utf16(const grub_uint8_t *src, grub_size_t srclen,
++		   grub_uint16_t *dst, grub_size_t dstlen)
++{
++  const grub_uint8_t *end = src + srclen;
++  grub_efi_char16_t *dstend = dst + dstlen;
++
++  while (src < end && dst < dstend)
++    {
++      grub_size_t len = grub_utf8_char_len(*src);
++      /* get the utf32 codepoint */
++      grub_uint32_t codepoint = grub_utf8_to_utf32(src, len);
++
++      /* convert that codepoint to utf16 codepoints */
++      if (codepoint <= 0xffff)
++	{
++	  /* it's a single utf16 character */
++	  *dst++ = (grub_efi_char16_t) codepoint;
++	}
++      else
++	{
++	  /* it's multiple utf16 characters, with surrogate pairs */
++	  codepoint = codepoint - 0x10000;
++	  *dst++ = (grub_efi_char16_t) ((codepoint >> 10) + 0xd800);
++	  *dst++ = (grub_efi_char16_t) ((codepoint & 0x3ff) + 0xdc00);
++	}
++
++	src += len;
++    }
++
++  if (dst < dstend)
++    *dst = 0;
++}
++
 +/* Convert UTF-16 to UTF-8.  */
 +grub_uint8_t *
 +grub_utf16_to_utf8 (grub_uint8_t *dest, grub_uint16_t *src,
@@ -15004,6 +15173,19 @@ index 0000000..4818617
 +  /* NOTUSED */
 +}
 +
++char *
++grub_strndup (const char *s, int n)
++{
++  int l = grub_strnlen(s, n);
++  char *new = grub_malloc(l + 1);
++
++  if (new == NULL)
++    return NULL;
++
++  new[l] = '\0';
++  return grub_strncpy(new, s, l);
++}
++
 +int
 +safe_parse_maxulong (char **str_ptr, unsigned long *myulong_ptr)
 +{
@@ -15058,34 +15240,6 @@ index 0000000..4818617
 +  return 1;
 +}
 +
-+char *
-+grub_strchr (const char *s, int c)
-+{
-+  while (*s)
-+    {
-+      if (*s == c)
-+	return (char *) s;
-+      s++;
-+    }
-+
-+  return 0;
-+}
-+
-+char *
-+grub_strrchr (const char *s, int c)
-+{
-+  char *p = 0;
-+
-+  while (*s)
-+    {
-+      if (*s == c)
-+	p = (char *) s;
-+      s++;
-+    }
-+
-+  return p;
-+}
-+
 +int
 +currticks (void)
 +{
@@ -15237,11 +15391,15 @@ index 0000000..4818617
 +      grub_strcpy (saved_default_file, DEFAULT_SAVED_DEFAULT_FILE_NAME);
 +      return;
 +    }
-+  path_name_len = dir_end + 1 - path_name;
-+  if (path_name_len + sizeof (DEFAULT_CONFIG_FILE_NAME) > 128)
-+    return;
-+  grub_memmove (config_file, path_name, path_name_len);
-+  grub_strcpy (config_file + path_name_len, DEFAULT_CONFIG_FILE_NAME);
++  if (strlen(dir_end) == 1) {
++    path_name_len = dir_end + 1 - path_name;
++    if (path_name_len + sizeof (DEFAULT_CONFIG_FILE_NAME) > 128)
++      return;
++    grub_memmove (config_file, path_name, path_name_len);
++    grub_strcpy (config_file + path_name_len, DEFAULT_CONFIG_FILE_NAME);
++  } else {
++    grub_memmove (config_file, path_name, path_name_len+1);
++  }
 +  if (path_name_len + sizeof (DEFAULT_SAVED_DEFAULT_FILE_NAME) > 128)
 +    return;
 +  path_name_len = dir_end + 1 - path_name;
@@ -15250,7 +15408,7 @@ index 0000000..4818617
 +	       DEFAULT_SAVED_DEFAULT_FILE_NAME);
 +}
 +
-+static grub_efi_guid_t simple_file_system_guid = GRUB_EFI_SIMPLE_FILE_SYSTEM_GUID;
++grub_efi_guid_t simple_file_system_guid = GRUB_EFI_SIMPLE_FILE_SYSTEM_GUID;
 +
 +static grub_efi_file_t *
 +simple_open_file(grub_efi_handle_t dev_handle,
@@ -15351,10 +15509,10 @@ index 0000000..4818617
 +}
 diff --git a/efi/efimm.c b/efi/efimm.c
 new file mode 100644
-index 0000000..d14b630
+index 0000000..c3cbfc4
 --- /dev/null
 +++ b/efi/efimm.c
-@@ -0,0 +1,438 @@
+@@ -0,0 +1,512 @@
 +/*
 + *  GRUB  --  GRand Unified Bootloader
 + *  Copyright (C) 2006  Free Software Foundation, Inc.
@@ -15389,9 +15547,11 @@ index 0000000..d14b630
 +#define BYTES_TO_PAGES(bytes)	((bytes) >> 12)
 +#define PAGES_TO_BYTES(pages)	((pages) << 12)
 +
-+/* The size of a memory map obtained from the firmware. This must be
-+   a multiplier of 4KB.  */
-+#define MEMORY_MAP_SIZE	0x2000
++/* Global variables used to store memory map, its size, and the number of
++ * pages allocated for the buffer. */
++void *mmap_buf;
++grub_efi_uintn_t mmap_size;
++grub_efi_uintn_t mmap_pages;
 +
 +/* Maintain the list of allocated pages.  */
 +struct allocated_page
@@ -15435,6 +15595,45 @@ index 0000000..d14b630
 +  Call_Service_1(b->free_pool, buffer);
 +}
 +
++void *
++grub_efi_allocate_anypages(grub_efi_uintn_t pages)
++{
++  grub_efi_boot_services_t *b;
++  grub_efi_status_t status;
++  grub_efi_physical_address_t address;
++
++  b = grub_efi_system_table->boot_services;
++  status = Call_Service_4 (b->allocate_pages,
++			    GRUB_EFI_ALLOCATE_ANY_PAGES,
++			    GRUB_EFI_LOADER_DATA,
++			    pages,
++			    &address);
++  if (status != GRUB_EFI_SUCCESS)
++  	return 0;
++
++  if (allocated_pages)
++     {
++       unsigned i;
++ 
++       for (i = 0; i < MAX_ALLOCATED_PAGES; i++)
++ 	if (allocated_pages[i].addr == 0)
++        {
++              allocated_pages[i].addr = address;
++              allocated_pages[i].num_pages = pages;
++              break;
++        }
++ 
++       if (i == MAX_ALLOCATED_PAGES)
++        {
++           grub_printf ("too many page allocations");
++           return NULL;
++        }
++     }
++ 
++  return (void *) ((grub_addr_t) address);
++
++}
++
 +/* Allocate pages. Return the pointer to the first of allocated pages.  */
 +void *
 +grub_efi_allocate_pages (grub_efi_physical_address_t address,
@@ -15523,11 +15722,14 @@ index 0000000..d14b630
 +}
 +
 +/* Get the memory map as defined in the EFI spec. Return 1 if successful,
-+   return 0 if partial, or return -1 if an error occurs.  */
++   return 0 if partial, or return -1 if an error occurs.
++
++   This function will allocate memory for (global) mmap_buf if there isn't
++   already a buffer allocated, and will free & reallocate if it needs to
++   be larger. */
++
 +int
-+grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size,
-+			 grub_efi_memory_descriptor_t *memory_map,
-+			 grub_efi_uintn_t *map_key,
++grub_efi_get_memory_map (grub_efi_uintn_t *map_key,
 +			 grub_efi_uintn_t *descriptor_size,
 +			 grub_efi_uint32_t *descriptor_version)
 +{
@@ -15535,6 +15737,7 @@ index 0000000..d14b630
 +  grub_efi_boot_services_t *b;
 +  grub_efi_uintn_t key;
 +  grub_efi_uint32_t version;
++  grub_efi_uintn_t tmp_mmap_size;
 +
 +  /* Allow some parameters to be missing.  */
 +  if (! map_key)
@@ -15542,22 +15745,44 @@ index 0000000..d14b630
 +  if (! descriptor_version)
 +    descriptor_version = &version;
 +
-+  b = grub_efi_system_table->boot_services;
-+  status = Call_Service_5 (b->get_memory_map,
-+			      memory_map_size, memory_map, map_key,
++  while (1)
++    {
++      b = grub_efi_system_table->boot_services;
++      tmp_mmap_size = PAGES_TO_BYTES(mmap_pages);
++      status = Call_Service_5 (b->get_memory_map,
++			      &tmp_mmap_size, mmap_buf, map_key,
 +			      descriptor_size, descriptor_version);
-+  if (status == GRUB_EFI_SUCCESS)
-+    return 1;
-+  else if (status == GRUB_EFI_BUFFER_TOO_SMALL)
-+    return 0;
-+  else
-+    return -1;
++      if (status == GRUB_EFI_SUCCESS)
++        {
++          mmap_size = tmp_mmap_size;
++          return 1;
++        }
++      else if (status != GRUB_EFI_BUFFER_TOO_SMALL)
++        return -1;
++
++      /* we need a larger buffer */
++      if (mmap_buf)
++        grub_efi_free_pages ((grub_addr_t) mmap_buf, mmap_pages);
++
++      /* get 1 more page than we need, just in case */
++      mmap_pages = BYTES_TO_PAGES(tmp_mmap_size + 4095) + 1;
++      mmap_buf = grub_efi_allocate_pages (0, mmap_pages);
++      if (! mmap_buf)
++        {
++          mmap_pages = 0;
++          grub_printf ("cannot allocate memory for memory map");
++          return -1;
++        }
++    }
 +}
 +
 +#define MMAR_DESC_LENGTH	20
 +
 +/*
 + * Add a memory region to the kernel e820 map.
++ *
++ * Convert EFI memory map to E820 map for the operating system
++ * This code is based on a Linux kernel patch submitted by Edgar Hucek 
 + */
 +static void
 +add_memory_region (struct e820_entry *e820_map,
@@ -15567,25 +15792,49 @@ index 0000000..d14b630
 +		   unsigned int type)
 +{
 +  int x = *e820_nr_map;
++  static unsigned long long estart = 0ULL;
++  static unsigned long esize = 0L;
++  static unsigned int etype = -1;
++  static int merge = 0;
 +
-+  if (x == E820_MAX)
-+    {
-+      grub_printf ("Too many entries in the memory map!\n");
-+      return;
-+    }
-+
-+  if (e820_map[x-1].addr + e820_map[x-1].size == start
++  /* merge adjacent regions of same type */
++  if ((x > 0) && e820_map[x-1].addr + e820_map[x-1].size == start
 +      && e820_map[x-1].type == type)
 +    {
 +      e820_map[x-1].size += size;
++      estart = e820_map[x-1].addr;
++      esize  = e820_map[x-1].size;
++      etype  = e820_map[x-1].type;
++      merge++;
++      return;
 +    }
-+  else
++
++    /* fill up to E820_MAX */
++    if ( x < E820_MAX )
 +    {
 +      e820_map[x].addr = start;
 +      e820_map[x].size = size;
 +      e820_map[x].type = type;
 +      (*e820_nr_map)++;
++      merge=0;
++      return;
++    }
++
++    /* different type means another region didn't fit */
++    /* or same type, but there's a hole */
++    if (etype != type || (estart + esize) != start)
++    {
++      merge = 0;
++      estart = start;
++      esize = size;
++      etype = type;
++      return;
 +    }
++
++    /* same type and no hole, merge it */
++    estart += esize;
++    esize += size;
++    merge++;
 +}
 +
 +/*
@@ -15663,33 +15912,16 @@ index 0000000..d14b630
 +update_e820_map (struct e820_entry *e820_map,
 +		 int *e820_nr_map)
 +{
-+  grub_efi_memory_descriptor_t *memory_map;
-+  grub_efi_uintn_t map_size;
 +  grub_efi_uintn_t desc_size;
 +
-+  /* Prepare a memory region to store memory map.  */
-+  memory_map = grub_efi_allocate_pages (0, BYTES_TO_PAGES (MEMORY_MAP_SIZE));
-+  if (! memory_map)
-+    {
-+      grub_printf ("cannot allocate memory");
-+      return;
-+    }
-+
-+  /* Obtain descriptors for available memory.  */
-+  map_size = MEMORY_MAP_SIZE;
-+
-+  if (grub_efi_get_memory_map (&map_size, memory_map, 0, &desc_size, 0) < 0)
++  if (grub_efi_get_memory_map (0, &desc_size, 0) < 0)
 +    {
 +      grub_printf ("cannot get memory map");
 +      return;
 +    }
 +
 +  e820_map_from_efi_map (e820_map, e820_nr_map,
-+			 memory_map, desc_size, map_size);
-+
-+  /* Release the memory map.  */
-+  grub_efi_free_pages ((grub_addr_t) memory_map,
-+		       BYTES_TO_PAGES (MEMORY_MAP_SIZE));
++			 mmap_buf, desc_size, mmap_size);
 +}
 +
 +/* Simulated memory sizes. */
@@ -16067,12 +16299,246 @@ index 0000000..32898a9
 +}
 +
 +#endif /* SUPPORT_SERIAL */
+diff --git a/efi/efitftp.c b/efi/efitftp.c
+new file mode 100644
+index 0000000..ba6918f
+--- /dev/null
++++ b/efi/efitftp.c
+@@ -0,0 +1,228 @@
++#include <grub/efi/efi.h>
++#include <grub/efi/api.h>
++#include <grub/efi/misc.h>
++#include <grub/misc.h>
++
++#include <shared.h>
++#include <filesys.h>
++#include "pxe.h"
++
++struct tftp_info tftp_info = {
++	.LoadedImage = NULL,
++	.Pxe = NULL,
++	.ServerIp = NULL,
++	.BasePath = NULL
++};
++
++/*
++ * CLIENT MAC ADDR: 00 15 17 4C E6 74
++ * CLIENT IP: 10.16.52.158  MASK: 255.255.255.0  DHCP IP: 10.16.52.16
++ * GATEWAY IP: 10.16.52.254
++ *
++ * TSize.Running LoadFile()
++ *
++ * TFTP.status: 5
++ * got to grub_efi_pxe_get_config_path
++ * SiAddr: 10.16.52.16
++ * BootpHwAddr: 00:15:17:4c:e6:74:00:00:00:00:00:00:00:00:00:00
++ * BootpSrvName:
++ * BootpBootFile: X86PC/UNDI/pxelinux/bootx64.efi
++ */
++
++static grub_efi_status_t tftp_get_file_size_defective_buffer_fallback(
++	char *Filename,
++	grub_efi_uintn_t *Size)
++{
++	EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE;
++	char *Buffer = NULL;
++	grub_efi_boolean_t Overwrite = 0;
++	grub_efi_boolean_t DontUseBuffer = 0;
++	grub_efi_uint64_t BufferSize = 4096;
++	grub_efi_uintn_t BlockSize = 512;
++	grub_efi_status_t rc = GRUB_EFI_BUFFER_TOO_SMALL;
++	char *FullPath = NULL;
++
++	while (rc == GRUB_EFI_BUFFER_TOO_SMALL) {
++		char *NewBuffer;
++
++		if (Buffer) {
++			grub_free(Buffer);
++			Buffer = NULL;
++		}
++		BufferSize *= 2;
++		NewBuffer = grub_malloc(BufferSize);
++		if (!NewBuffer)
++			return GRUB_EFI_OUT_OF_RESOURCES;
++		Buffer = NewBuffer;
++
++		if (tftp_info.BasePath) {
++			int PathSize = 0;
++			PathSize = strlen(tftp_info.BasePath) + 2 +
++				   strlen(Filename);
++			FullPath = grub_malloc(PathSize);
++			grub_sprintf(FullPath, "%s/%s", tftp_info.BasePath,
++				     Filename);
++		} else {
++			FullPath = grub_malloc(strlen(Filename));
++			strcpy(FullPath, Filename);
++		}
++
++		rc = Call_Service_10(tftp_info.Pxe->Mtftp, tftp_info.Pxe,
++			OpCode, Buffer, Overwrite, &BufferSize, &BlockSize,
++			tftp_info.ServerIp, FullPath, NULL, DontUseBuffer);
++		if (rc == GRUB_EFI_SUCCESS || rc == GRUB_EFI_BUFFER_TOO_SMALL)
++			*Size = BufferSize;
++	}
++	grub_free(FullPath);
++	grub_free(Buffer);
++	return rc;
++}
++
++grub_efi_status_t tftp_get_file_size(
++	char *Filename,
++	grub_efi_uintn_t *Size)
++{
++	EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode = EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE;
++	char Buffer[8192];
++	grub_efi_boolean_t Overwrite = 0;
++	grub_efi_boolean_t DontUseBuffer = 0;
++	grub_efi_uint64_t BufferSize = 8192;
++	grub_efi_uintn_t BlockSize = 512;
++	grub_efi_status_t rc;
++	char *FullPath = NULL;
++
++	if (tftp_info.BasePath) {
++		int PathSize = 0;
++		PathSize = strlen(tftp_info.BasePath) + 2 + strlen(Filename);
++		FullPath = grub_malloc(PathSize);
++		grub_sprintf(FullPath, "%s/%s", tftp_info.BasePath, Filename);
++	} else {
++		FullPath = grub_malloc(strlen(Filename));
++		strcpy(FullPath, Filename);
++	}
++
++	rc = Call_Service_10(tftp_info.Pxe->Mtftp, tftp_info.Pxe, OpCode,
++		Buffer, Overwrite, &BufferSize, &BlockSize, tftp_info.ServerIp,
++		FullPath, NULL, DontUseBuffer);
++	if (rc == GRUB_EFI_BUFFER_TOO_SMALL)
++		rc = tftp_get_file_size_defective_buffer_fallback(Filename, Size);
++	if (rc == GRUB_EFI_SUCCESS)
++		*Size = BufferSize;
++	grub_free(FullPath);
++	return rc;
++}
++
++static grub_efi_status_t tftp_read_file(
++	char *Filename,
++	char *Buffer,
++	grub_efi_uint64_t BufferSize)
++{
++	EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE;
++	grub_efi_boolean_t Overwrite = 0;
++	grub_efi_boolean_t DontUseBuffer = 0;
++	grub_efi_uintn_t BlockSize = 512;
++	grub_efi_status_t rc;
++	char *FullPath = NULL;
++
++	if (tftp_info.BasePath) {
++		int PathSize = 0;
++		PathSize = strlen(tftp_info.BasePath) + 2 + strlen(Filename);
++		FullPath = grub_malloc(PathSize);
++		grub_sprintf(FullPath, "%s/%s", tftp_info.BasePath, Filename);
++	} else {
++		FullPath = grub_malloc(strlen(Filename));
++		strcpy(FullPath, Filename);
++	}
++
++	rc = Call_Service_10(tftp_info.Pxe->Mtftp, tftp_info.Pxe, OpCode,
++		Buffer, Overwrite, &BufferSize, &BlockSize, tftp_info.ServerIp,
++		FullPath, NULL, DontUseBuffer);
++	grub_free(FullPath);
++	return rc;
++}
++
++int
++efi_tftp_mount (void)
++{
++	if (current_drive != NETWORK_DRIVE) {
++		return 0;
++	}
++	return 1;
++}
++
++int
++efi_tftp_read (char *addr, int size)
++{
++	int rc;
++
++	if (tftp_info.LastPath == NULL) {
++		grub_printf(" = 0 (no path known)\n");
++		return 0;
++	}
++	if (tftp_info.Buffer == NULL) {
++		grub_printf(" = 0 (no file open)\n");
++		return 0;
++	}
++	if (filemax == -1) {
++		grub_printf(" = 0 (file not found)\n");
++		return 0;
++	}
++	if (filepos == 0) {
++		rc = tftp_read_file(tftp_info.LastPath, tftp_info.Buffer,
++				    filemax);
++	}
++
++	grub_memmove(addr, tftp_info.Buffer+filepos, size);
++	filepos += size;
++
++	return size;
++}
++
++int
++efi_tftp_dir (char *dirname)
++{
++	int rc;
++	int ch;
++	grub_efi_uintn_t size;
++	int len;
++	char *name;
++
++	ch = nul_terminate(dirname);
++	len = strlen(dirname);
++
++	name = grub_malloc(len + 1);
++	grub_memmove(name, dirname, len);
++	name[len] = '\0';
++	dirname[len] = ch;
++
++#if 0
++	if (print_possibilities)
++		return 1;
++#endif
++
++	filemax = -1;
++
++	rc = tftp_get_file_size(name, &size);
++	if (rc == GRUB_EFI_SUCCESS) {
++		tftp_info.LastPath = grub_malloc(strlen(name) + 1);
++		sprintf(tftp_info.LastPath, "%s", name);
++		filemax = size;
++		filepos = 0;
++
++		tftp_info.Buffer = grub_malloc(filemax);
++
++		return 1;
++	}
++	return 0;
++}
++
++void
++efi_tftp_close (void)
++{
++	filepos = 0;
++	filemax = -1;
++	grub_free(tftp_info.LastPath);
++	tftp_info.LastPath = NULL;
++	grub_free(tftp_info.Buffer);
++	tftp_info.Buffer = NULL;
++}
 diff --git a/efi/efiuga.c b/efi/efiuga.c
 new file mode 100644
-index 0000000..063d3b2
+index 0000000..b762eb8
 --- /dev/null
 +++ b/efi/efiuga.c
-@@ -0,0 +1,945 @@
+@@ -0,0 +1,946 @@
 +/* efiuga.c - "univeral graphics adapter" support for GRUB/EFI */
 +/*
 + *  GRUB  --  GRand Unified Bootloader
@@ -16746,18 +17212,19 @@ index 0000000..063d3b2
 +            int bit = glyph[glyphpos.y] & (1 << ((fontsz.x-1) - glyphpos.x));
 +            int idx = -1;
 +
-+            if (set)
-+                idx = bit ? 0 : 15;
-+            else
++            if (!set) {
 +                if (invert)
-+                idx = bit ? 15 : 0;
-+            else if (bit)
-+                idx = 15;
-+
-+            if (idx == -1) {
-+                if (is_shadow_pixel(screensz, charpos, glyphpos, fontsz) ||
-+                        !uga->background)
-+                    idx = invert ? 15 : 0;
++                    idx = bit ? 0 : 15;
++                else if (bit)
++                    idx = 15;
++
++                if (idx == -1) {
++                    if (is_shadow_pixel(screensz, charpos, glyphpos, fontsz) ||
++                            !uga->background)
++                        idx = invert ? 15 : 0;
++                }
++            } else {
++                idx = bit ? 0 : 15;
 +            }
 +
 +            if (idx != -1)
@@ -22323,10 +22790,10 @@ index 0000000..7bdd647
 +#endif /* GRUB_EFI_GRAPHICS_H */
 diff --git a/efi/grub/efi/api.h b/efi/grub/efi/api.h
 new file mode 100644
-index 0000000..6743a0b
+index 0000000..8f75a68
 --- /dev/null
 +++ b/efi/grub/efi/api.h
-@@ -0,0 +1,1459 @@
+@@ -0,0 +1,1471 @@
 +/* efi.h - declare EFI types and functions */
 +/*
 + *  GRUB  --  GRand Unified Bootloader
@@ -22419,6 +22886,11 @@ index 0000000..6743a0b
 +    { 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
 +  }
 +
++#define GRUB_EFI_DEVICE_PATH_FROM_TEXT_GUID	\
++  { 0x05c99a21, 0xc70f, 0x4ad2, \
++    { 0x8a, 0x5f, 0x35, 0xdf, 0x33, 0x43, 0xf5, 0x1e } \
++  }
++
 +#define GRUB_EFI_GRAPHICS_OUTPUT_GUID	\
 +  { 0x9042a9de, 0x23dc, 0x4a38, \
 +    { 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a } \
@@ -22882,7 +23354,7 @@ index 0000000..6743a0b
 +  grub_efi_uint32_t partition_number;
 +  grub_efi_lba_t partition_start;
 +  grub_efi_lba_t partition_size;
-+  grub_efi_uint8_t partition_signature[8];
++  grub_efi_uint8_t partition_signature[16];
 +  grub_efi_uint8_t mbr_type;
 +  grub_efi_uint8_t signature_type;
 +};
@@ -22944,6 +23416,13 @@ index 0000000..6743a0b
 +};
 +typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t;
 +
++struct grub_efi_device_path_from_text
++{
++  grub_efi_device_path_t * (*convert_text_to_device_node) (const grub_efi_char16_t *text_device_node);
++  grub_efi_device_path_t * (*convert_text_to_device_path) (const grub_efi_char16_t *text_device_path);
++};
++typedef struct grub_efi_device_path_from_text grub_efi_device_path_from_text_t;
++
 +struct grub_efi_open_protocol_information_entry
 +{
 +  grub_efi_handle_t agent_handle;
@@ -23853,10 +24332,10 @@ index 0000000..ffc4305
 +#endif /* ! GRUB_EFI_CONSOLE_CONTROL_HEADER */
 diff --git a/efi/grub/efi/efi.h b/efi/grub/efi/efi.h
 new file mode 100644
-index 0000000..0424fbb
+index 0000000..936759b
 --- /dev/null
 +++ b/efi/grub/efi/efi.h
-@@ -0,0 +1,70 @@
+@@ -0,0 +1,79 @@
 +/* efi.h - declare variables and functions for EFI support */
 +/*
 + *  GRUB  --  GRand Unified Bootloader
@@ -23884,6 +24363,12 @@ index 0000000..0424fbb
 +#include <grub/efi/api.h>
 +
 +/* Functions.  */
++grub_efi_status_t
++grub_efi_locate_handle_buffer (grub_efi_locate_search_type_t search_type,
++				grub_efi_guid_t *protocol,
++				void *search_key,
++				grub_efi_uintn_t *no_handles,
++				grub_efi_handle_t **buffer);
 +void *grub_efi_locate_protocol (grub_efi_guid_t * protocol,
 +				void *registration);
 +grub_efi_handle_t *grub_efi_locate_handle (grub_efi_locate_search_type_t
@@ -23898,15 +24383,14 @@ index 0000000..0424fbb
 +void grub_efi_stall (grub_efi_uintn_t microseconds);
 +void *grub_efi_allocate_pool (grub_efi_uintn_t size);
 +void grub_efi_free_pool (void *buffer);
++void *grub_efi_allocate_anypages (grub_efi_uintn_t pages);
 +void *grub_efi_allocate_pages (grub_efi_physical_address_t address,
 +			       grub_efi_uintn_t pages);
 +void
 +grub_efi_free_pages (grub_efi_physical_address_t address,
 +		     grub_efi_uintn_t pages);
 +int
-+grub_efi_get_memory_map (grub_efi_uintn_t * memory_map_size,
-+			 grub_efi_memory_descriptor_t * memory_map,
-+			 grub_efi_uintn_t * map_key,
++grub_efi_get_memory_map (grub_efi_uintn_t * map_key,
 +			 grub_efi_uintn_t * descriptor_size,
 +			 grub_efi_uint32_t * descriptor_version);
 +grub_efi_loaded_image_t *grub_efi_get_loaded_image (grub_efi_handle_t
@@ -23923,16 +24407,20 @@ index 0000000..0424fbb
 +void grub_efi_set_prefix (void);
 +
 +/* Variables.  */
++extern void *mmap_buf;
++extern grub_efi_uintn_t mmap_size;
++extern grub_efi_uintn_t mmap_pages;
++
 +extern grub_efi_system_table_t *grub_efi_system_table;
 +extern grub_efi_handle_t grub_efi_image_handle;
 +
 +#endif /* ! GRUB_EFI_EFI_HEADER */
 diff --git a/efi/grub/efi/eficall.h b/efi/grub/efi/eficall.h
 new file mode 100644
-index 0000000..32c380f
+index 0000000..2e79e04
 --- /dev/null
 +++ b/efi/grub/efi/eficall.h
-@@ -0,0 +1,161 @@
+@@ -0,0 +1,162 @@
 +/*
 + *  GRUB  --  GRand Unified Bootloader
 + *  Copyright (C) 2006  Free Software Foundation, Inc.
@@ -24080,6 +24568,7 @@ index 0000000..32c380f
 +
 +#else
 +
++typedef long EFI_STATUS;
 +#define Call_Service(func)                      func()
 +#define Call_Service_1(func,a)                  func(a)
 +#define Call_Service_2(func,a,b)                func(a,b)
@@ -24096,10 +24585,10 @@ index 0000000..32c380f
 +#endif
 diff --git a/efi/grub/efi/misc.h b/efi/grub/efi/misc.h
 new file mode 100644
-index 0000000..b089904
+index 0000000..7dc34e7
 --- /dev/null
 +++ b/efi/grub/efi/misc.h
-@@ -0,0 +1,46 @@
+@@ -0,0 +1,58 @@
 +/* misc.h - prototypes for misc EFI functions */
 +/*
 + *  GRUB  --  GRand Unified Bootloader
@@ -24145,6 +24634,18 @@ index 0000000..b089904
 +char *grub_efi_file_path_to_path_name (grub_efi_device_path_t *file_path);
 +void grub_load_saved_default (grub_efi_handle_t dev_handle);
 +
++grub_efi_device_path_t *
++find_last_device_path (const grub_efi_device_path_t *dp);
++grub_efi_device_path_t *
++duplicate_device_path (const grub_efi_device_path_t *dp);
++int
++compare_device_paths (const grub_efi_device_path_t *dp1,
++		      const grub_efi_device_path_t *dp2);
++grub_efi_device_path_t *
++device_path_from_utf8 (const char *device);
++
++extern grub_efi_guid_t simple_file_system_guid;
++
 +#endif /* ! GRUB_EFI_MISC_HEADER */
 diff --git a/efi/grub/efi/net.h b/efi/grub/efi/net.h
 new file mode 100644
@@ -24458,10 +24959,10 @@ index 0000000..ec4174e
 +#endif /* ! GRUB_TYPES_CPU_HEADER */
 diff --git a/efi/grub/misc.h b/efi/grub/misc.h
 new file mode 100644
-index 0000000..0d9b09b
+index 0000000..5ef2226
 --- /dev/null
 +++ b/efi/grub/misc.h
-@@ -0,0 +1,66 @@
+@@ -0,0 +1,71 @@
 +/* misc.h - prototypes for misc functions */
 +/*
 + *  GRUB  --  GRand Unified Bootloader
@@ -24492,8 +24993,6 @@ index 0000000..0d9b09b
 +	grub_real_dprintf(__FILE__, __LINE__, condition, fmt, ## args)
 +
 +char *grub_stpcpy (char *dest, const char *src);
-+char *grub_strchr (const char *s, int c);
-+char *grub_strrchr (const char *s, int c);
 +void grub_real_dprintf (const char *file,
 +			const int line,
 +			const char *condition,
@@ -24502,12 +25001,19 @@ index 0000000..0d9b09b
 +void grub_exit (void) __attribute__ ((noreturn));
 +void grub_abort (void) __attribute__ ((noreturn));
 +void grub_fatal (const char *fmt, ...) __attribute__ ((noreturn));
++grub_size_t grub_utf8_char_len(grub_uint8_t ch);
++grub_uint32_t grub_utf8_to_utf32(const grub_uint8_t *src, grub_size_t length);
++void grub_utf8_to_utf16(const grub_uint8_t *src, grub_size_t srclen,
++			grub_uint16_t *dst, grub_size_t dstlen);
 +grub_uint8_t *grub_utf16_to_utf8 (grub_uint8_t * dest,
 +				  grub_uint16_t * src, grub_size_t size);
 +
 +void *grub_malloc (grub_size_t size);
 +void grub_free (void *ptr);
 +
++char *grub_strndup (const char *s, int n);
++#define strndup grub_strndup
++
 +int safe_parse_maxulong (char **str_ptr, unsigned long *myulong_ptr);
 +
 +#define E820_RAM        1
@@ -25181,10 +25687,10 @@ index 0000000..4cff104
 +
 diff --git a/efi/ia32/loader/linux.c b/efi/ia32/loader/linux.c
 new file mode 100644
-index 0000000..41f1ce6
+index 0000000..eb6b5de
 --- /dev/null
 +++ b/efi/ia32/loader/linux.c
-@@ -0,0 +1,711 @@
+@@ -0,0 +1,641 @@
 +/*
 + *  GRUB  --  GRand Unified Bootloader
 + *  Copyright (C) 2006  Free Software Foundation, Inc.
@@ -25229,11 +25735,9 @@ index 0000000..41f1ce6
 +static void *real_mode_mem;
 +static void *prot_mode_mem;
 +static void *initrd_mem;
-+static void *mmap_buf;
 +static grub_efi_uintn_t real_mode_pages;
 +static grub_efi_uintn_t prot_mode_pages;
 +static grub_efi_uintn_t initrd_pages;
-+static grub_efi_uintn_t mmap_pages;
 +static grub_efi_guid_t graphics_output_guid = GRUB_EFI_GRAPHICS_OUTPUT_GUID;
 +
 +static inline grub_size_t
@@ -25242,45 +25746,6 @@ index 0000000..41f1ce6
 +  return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
 +}
 +
-+/* Find the optimal number of pages for the memory map. Is it better to
-+   move this code to efimm.c?  */
-+static grub_efi_uintn_t
-+find_mmap_size (void)
-+{
-+  static grub_efi_uintn_t mmap_size = 0;
-+
-+  if (mmap_size != 0)
-+    return mmap_size;
-+
-+  mmap_size = (1 << 12);
-+  while (1)
-+    {
-+      int ret;
-+      grub_efi_memory_descriptor_t *mmap;
-+      grub_efi_uintn_t desc_size;
-+
-+      mmap = grub_malloc (mmap_size);
-+      if (! mmap)
-+	return 0;
-+
-+      ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
-+      grub_free (mmap);
-+
-+      if (ret < 0)
-+	grub_fatal ("cannot get memory map");
-+      else if (ret > 0)
-+	break;
-+
-+      mmap_size += (1 << 12);
-+    }
-+
-+  /* Increase the size a bit for safety, because GRUB allocates more on
-+     later, and EFI itself may allocate more.  */
-+  mmap_size += (1 << 11);
-+
-+  return page_align (mmap_size);
-+}
-+
 +static void
 +free_pages (void)
 +{
@@ -25315,15 +25780,13 @@ index 0000000..41f1ce6
 +allocate_pages (grub_size_t real_size, 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 *mmap_end;
 +  grub_efi_memory_descriptor_t *desc;
 +  grub_efi_physical_address_t addr;
 +
 +  /* Make sure that each size is aligned to a page boundary.  */
 +  real_size = page_align (real_size + SECTOR_SIZE);
 +  prot_size = page_align (prot_size);
-+  mmap_size = find_mmap_size ();
 +
 +  grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
 +		(unsigned int) real_size, (unsigned int) prot_size,
@@ -25333,30 +25796,19 @@ index 0000000..41f1ce6
 +     the memory map buffer for simplicity.  */
 +  real_mode_pages = (real_size >> 12);
 +  prot_mode_pages = (prot_size >> 12);
-+  mmap_pages = (mmap_size >> 12);
 +
 +  /* Initialize the memory pointers with NULL for convenience.  */
 +  real_mode_mem = 0;
 +  prot_mode_mem = 0;
-+  mmap_buf = 0;
 +
-+  /* Read the memory map temporarily, to find free space.  */
-+  mmap = grub_malloc (mmap_size);
-+  if (! mmap)
-+    {
-+      errnum = ERR_UNRECOGNIZED;
-+      return 0;
-+    }
-+
-+  tmp_mmap_size = mmap_size;
-+  if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)
++  if (grub_efi_get_memory_map (0, &desc_size, 0) <= 0)
 +    grub_fatal ("cannot get memory map");
 +
 +  addr = 0;
-+  mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
++  mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
 +  /* First, find free pages for the real mode code
 +     and the memory map buffer.  */
-+  for (desc = mmap;
++  for (desc = mmap_buf;
 +       desc < mmap_end;
 +       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
 +    {
@@ -25370,7 +25822,7 @@ index 0000000..41f1ce6
 +          grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n",
 +                        (unsigned) desc->physical_start,
 +                        (unsigned) physical_end);
-+          addr = physical_end - real_size - mmap_size;
++          addr = physical_end - real_size;
 +          if (addr < 0x10000)
 +            continue;
 +
@@ -25392,29 +25844,15 @@ index 0000000..41f1ce6
 +      goto fail;
 +    }
 +
-+  mmap_buf = grub_efi_allocate_pages (0, mmap_pages);
-+  if (! mmap_buf)
-+    {
-+      grub_printf("cannot allocate efi mmap pages");
-+      errnum = ERR_WONT_FIT;
-+      goto fail;
-+    }
-+
 +  /* Next, find free pages for the protected mode code.  */
 +  /* XXX what happens if anything is using this address?  */
 +  prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages);
 +  if (! prot_mode_mem)
-+    {
-+      errnum = ERR_WONT_FIT;
-+      grub_printf ("cannot allocate protected mode pages");
-+      goto fail;
-+    }
++	grub_fatal("Cannot allocate pages for VMLINUZ");
 +
-+  grub_free (mmap);
 +  return 1;
 +
 + fail:
-+  grub_free (mmap);
 +  free_pages ();
 +  return 0;
 +}
@@ -25461,7 +25899,6 @@ index 0000000..41f1ce6
 +{
 +  struct linux_kernel_params *params;
 +  struct grub_linux_kernel_header *lh;
-+  grub_efi_uintn_t mmap_size;
 +  grub_efi_uintn_t map_key;
 +  grub_efi_uintn_t desc_size;
 +  grub_efi_uint32_t desc_version;
@@ -25472,9 +25909,7 @@ index 0000000..41f1ce6
 +
 +  graphics_set_kernel_params (params);
 +
-+  mmap_size = find_mmap_size ();
-+  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
-+			       &desc_size, &desc_version) <= 0)
++  if (grub_efi_get_memory_map (&map_key, &desc_size, &desc_version) <= 0)
 +    grub_fatal ("cannot get memory map");
 +
 +  /* Pass e820 memmap. */
@@ -25786,10 +26221,12 @@ index 0000000..41f1ce6
 +  grub_ssize_t size;
 +  grub_addr_t addr_min, addr_max;
 +  grub_addr_t addr;
-+  grub_efi_uintn_t mmap_size;
++  grub_efi_uintn_t map_key;
++  grub_efi_memory_descriptor_t *mmap_end;
 +  grub_efi_memory_descriptor_t *desc;
 +  grub_efi_memory_descriptor_t tdesc;
 +  grub_efi_uintn_t desc_size;
++  grub_efi_uint32_t desc_version;
 +  struct linux_kernel_params *params;
 +
 +  if (initrd == NULL)
@@ -25831,14 +26268,13 @@ index 0000000..41f1ce6
 +  grub_dprintf(__func__, "prot_mode_mem=%p prot_mode_pages=%lu\n", prot_mode_mem, prot_mode_pages);
 +
 +  /* Find the highest address to put the initrd.  */
-+  mmap_size = find_mmap_size ();
-+  grub_dprintf(__func__, "addr_min: 0x%lx addr_max: 0x%lx mmap_size: %lu\n", addr_min, addr_max, mmap_size);
-+  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0)
++  if (grub_efi_get_memory_map (&map_key, &desc_size, &desc_version) <= 0)
 +    grub_fatal ("cannot get memory map");
 +
++  mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
 +  addr = 0;
 +  for (desc = mmap_buf;
-+       desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
++       desc < mmap_end;
 +       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
 +    {
 +      if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY)
@@ -26222,6 +26658,699 @@ index 0000000..38c33af
 +	jnz	0f
 +	incl	%eax
 +0:	jmp	*20(%ecx)		/* done, return.... */
+diff --git a/efi/pxe.c b/efi/pxe.c
+new file mode 100644
+index 0000000..1a74315
+--- /dev/null
++++ b/efi/pxe.c
+@@ -0,0 +1,444 @@
++
++#include <grub/efi/efi.h>
++#include <grub/efi/api.h>
++#include <grub/efi/misc.h>
++#include <grub/misc.h>
++
++#include <shared.h>
++#include <stddef.h>
++
++#include "pxe.h"
++#include "dhcp.h"
++
++/* Search path is:
++ *
++ * X86PC/UNDI/pxelinux/pxelinux.cfg/1902dcf5-7190-d811-bbd6-6ef21c690030
++ * X86PC/UNDI/pxelinux/pxelinux.cfg/01-00-30-6e-f2-1c-69
++ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A103437
++ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A10343
++ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A1034
++ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A103
++ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A10
++ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A1
++ * X86PC/UNDI/pxelinux/pxelinux.cfg/0A
++ * X86PC/UNDI/pxelinux/pxelinux.cfg/0
++ * X86PC/UNDI/pxelinux/pxelinux.cfg/default
++ *
++ * The paths we get from uefi are like:
++ * .BootBootFile: X86PC/UNDI/pxelinux/bootx64.efi
++ * .BootCiAddr: 0.0.0.0
++ * .BootYiAddr: 10.16.52.158
++ * .BootSiAddr: 10.16.52.16
++ */
++
++typedef struct {
++	char *options;
++	EFI_DHCP4_PACKET_OPTION *current_option;
++} dhcp_option_parser;
++
++static void dhcp_option_parser_reset(dhcp_option_parser *parser,
++				EFI_PXE_BASE_CODE_PACKET *packet)
++{
++	char *addr;
++
++	addr = (char *)packet;
++	addr += offsetof(EFI_PXE_BASE_CODE_DHCPV4_PACKET, DhcpOptions);
++	parser->current_option = (void *)addr;
++	parser->options = (void *)addr;
++}
++
++static int dhcp_option_parser_next(dhcp_option_parser *parser,
++				EFI_DHCP4_PACKET_OPTION **option)
++{
++	char *current_option;
++	if (parser->current_option->OpCode == 255) {
++		*option = NULL;
++		return 0;
++	}
++	current_option = (char *)parser->current_option;
++	current_option += 2 + parser->current_option->Length;
++	parser->current_option = (EFI_DHCP4_PACKET_OPTION *)current_option;
++
++	*option = parser->current_option;
++	return 1;
++}
++
++#define DHCPMAGIK "\x63\x82\x53\x63"
++
++static int get_dhcp_client_id(EFI_PXE_BASE_CODE_PACKET *packet, uuid_t *uuid)
++{
++	dhcp_option_parser parser;
++	EFI_DHCP4_PACKET_OPTION *option;
++
++	dhcp_option_parser_reset(&parser, packet);
++
++	if (memcmp((char *)&packet->Dhcpv4.DhcpMagik, DHCPMAGIK, 4))
++		return 0;
++
++	while (dhcp_option_parser_next(&parser, &option)) {
++		int i;
++		char data[option->Length];
++
++		if (option->OpCode != 97)
++			continue;
++
++		if (option->Length != 17)
++			continue;
++
++		memcpy(data, option->Data, option->Length);
++		if (data[0] != 0)
++			continue;
++
++		/* 97[17]: 009cfe245ed0c8bd45a79f54ea5fbd3d97
++		 *                               ^^^^^^^^^^^^ uint8_t[]
++		 *                             ^^ uint8_t
++		 *                           ^^ uint8_t
++		 *                       ^^^^ BE uint16_t
++		 *                   ^^^^ BE uint16_t
++		 *           ^^^^^^^^ BE uint32_t
++		 *         ^^ "type".  0 means UUID.
++		 */
++		memcpy(uuid, data+1, 16);
++		uuid->time_low = htonl(uuid->time_low);
++		uuid->time_mid = htons(uuid->time_mid);
++		uuid->time_hi_ver = htons(uuid->time_hi_ver);
++
++		return 1;
++	}
++	return 0;
++}
++
++#if 0
++static void grub_dump_dhcp_options(EFI_PXE_BASE_CODE_PACKET *packet)
++{
++	dhcp_option_parser parser;
++	EFI_DHCP4_PACKET_OPTION *option;
++	char hex[] = "0123456789abcdef";
++	int i;
++	int j = 0;
++
++	dhcp_option_parser_reset(&parser, packet);
++
++	if (memcmp((char *)&packet->Dhcpv4.DhcpMagik, DHCPMAGIK, 4))
++		return;
++
++	/* 54[4]: a0014301
++	 * 51[4]: 00004506
++	 * 1[4]: ffffff00
++	 * 3[4]: a00143ef
++	 * 6[8]: a001ff20a001ff30
++	 * 15[48]: 96e6374716c6c6e226f637e2275646861647e236f6d60226f637e2275646861647e236f6d602275646861647e236f6d6
++	 * 28[4]: a00143ff
++	 * 40[10]: 275646861647e236f6d6
++	 * 41[8]: a001ff20a001ff30
++	 * 58[4]: 0000a203
++	 * 59[4]: 0000944d
++	 * this is the one we want:
++	 * 97[17]: 009cfe245ed0c8bd45a79f54ea5fbd3d97
++	 *                               ^^^^^^^^^^^^ in order
++	 *                             ^^
++	 *                           ^^
++	 *                       ^^^^ out of order
++	 *                   ^^^^ out of order
++	 *           ^^^^^^^^ out of order
++	 *         ^^ "type".  0 means UUID.
++	 * 255[0]:
++	 */
++	while (dhcp_option_parser_next(&parser, &option)) {
++		char data[option->Length + 1];
++
++		memcpy(data, option->Data, option->Length);
++		data[option->Length] = '\0';
++
++		grub_printf("%d[%d]: ", option->OpCode, option->Length);
++		for (i = 0; i < option->Length; i++) {
++			grub_printf("%c%c", hex[data[i] & 0xf],
++					hex[(data[i] & 0xf0) >> 4]);
++		}
++		printf("\n");
++	}
++
++}
++
++void grub_print_dhcp_info(grub_efi_loaded_image_t *loaded_image)
++{
++	EFI_PXE_BASE_CODE *pxe = NULL;
++	EFI_PXE_BASE_CODE_PACKET *packet;
++
++	grub_printf("got to %s\n", __func__);
++
++	pxe = grub_efi_locate_protocol(&PxeBaseCodeProtocol, NULL);
++	if (pxe == NULL)
++		return;
++
++	printf("DhcpDiscover options:\n");
++	packet = (EFI_PXE_BASE_CODE_PACKET *)&pxe->Mode->DhcpDiscover.Dhcpv4;
++	grub_dump_dhcp_options(packet);
++
++	printf("DhcpAck options:\n");
++	packet = (EFI_PXE_BASE_CODE_PACKET *)&pxe->Mode->DhcpAck.Dhcpv4;
++	grub_dump_dhcp_options(packet);
++
++	printf("PxeDiscover options:\n");
++	packet = (EFI_PXE_BASE_CODE_PACKET *)&pxe->Mode->PxeDiscover.Dhcpv4;
++	grub_dump_dhcp_options(packet);
++
++	printf("PxeReply options:\n");
++	packet = (EFI_PXE_BASE_CODE_PACKET *)&pxe->Mode->PxeReply.Dhcpv4;
++	grub_dump_dhcp_options(packet);
++
++#if 0
++	printf("pxe->Mode->DhcpAck.Dhcpv4: \n");
++	printf("\t.BootSrvName: %s\n", pxe->Mode->DhcpAck.Dhcpv4.BootpSrvName);
++	printf("\t.BootBootFile: %s\n", pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile);
++	printf("\t.BootCiAddr: %d.%d.%d.%d\n",
++		pxe->Mode->DhcpAck.Dhcpv4.BootpCiAddr[0],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpCiAddr[1],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpCiAddr[2],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpCiAddr[3]);
++	printf("\t.BootYiAddr: %d.%d.%d.%d\n",
++		pxe->Mode->DhcpAck.Dhcpv4.BootpYiAddr[0],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpYiAddr[1],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpYiAddr[2],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpYiAddr[3]);
++	printf("\t.BootSiAddr: %d.%d.%d.%d\n",
++		pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr[0],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr[1],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr[2],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr[3]);
++	printf("\t.BootGiAddr: %d.%d.%d.%d\n",
++		pxe->Mode->DhcpAck.Dhcpv4.BootpGiAddr[0],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpGiAddr[1],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpGiAddr[2],
++		pxe->Mode->DhcpAck.Dhcpv4.BootpGiAddr[3]);
++	}
++	printf("\n");
++#endif
++
++
++}
++#endif
++
++static void icmp_print_error(EFI_PXE_BASE_CODE *pxe)
++{
++	EFI_PXE_BASE_CODE_ICMP_ERROR *err = &pxe->Mode->IcmpError;
++	int i;
++	//char hex[] = "0123456789abcdef";
++
++	printf("icmp error\n");
++	printf("type: %d code: %d\n", err->Type, err->Code);
++	printf("data: \n");
++	for(i = 0; i < 464; i+=16) {
++		int x;
++		for (x = i; x < i+4; x++)
++			printf("%02x ", err->Data[x]);
++		printf(" ");
++		for (x = i+4; x < i+8; x++)
++			printf("%02x ", err->Data[x]);
++		printf(" ");
++		printf(" ");
++		for (x = i+8; x < i+12; x++)
++			printf("%02x ", err->Data[x]);
++		printf(" ");
++		for (x = i+12; x < i+16; x++)
++			printf("%02x ", err->Data[x]);
++		printf("\n");
++	}
++}
++
++static int grub_efi_pxe_check_for_file(
++	EFI_PXE_BASE_CODE *pxe,
++	EFI_IP_ADDRESS *ServerIp,
++	char *BootpBootFile,
++	char *configname,
++	char **returnpath)
++{
++	size_t bplen = strlen(BootpBootFile);
++	char *Filename = grub_malloc(24 + bplen + 40);
++	char *lastslash = Filename + bplen;
++	grub_efi_uintn_t size;
++	int i;
++	EFI_STATUS rc;
++	char Buffer[8192];
++
++	memcpy(Filename, BootpBootFile, bplen);
++
++	for (i = 0; i < bplen; i++) {
++		if (Filename[i] == '/')
++			lastslash = Filename + i;
++	}
++	if (*lastslash) {
++		*lastslash++ = '/';
++		*lastslash = '\0';
++	}
++
++	sprintf(lastslash, configname);
++
++	printf("tftp://%d.%d.%d.%d/%s\n",
++		ServerIp->v4.Addr[0], ServerIp->v4.Addr[1],
++		ServerIp->v4.Addr[2], ServerIp->v4.Addr[3],
++		Filename);
++
++	rc = tftp_get_file_size(Filename, &size);
++	if (rc == GRUB_EFI_ICMP_ERROR)
++		icmp_print_error(pxe);
++
++	if (rc == GRUB_EFI_SUCCESS) {
++		*returnpath = Filename;
++		return size;
++	}
++	grub_free(Filename);
++	return 0;
++}
++
++static void get_pxe_server(EFI_PXE_BASE_CODE *pxe, EFI_IP_ADDRESS **Address)
++{
++	EFI_IP_ADDRESS *tmp = grub_malloc(sizeof *tmp);
++	if (tmp) {
++		memset(tmp, '\0', sizeof (*tmp));
++		memcpy(&tmp->Addr[0], pxe->Mode->DhcpAck.Dhcpv4.BootpSiAddr, 4);
++		*Address = tmp;
++	}
++}
++
++static char *get_pxe_file_dir(EFI_PXE_BASE_CODE *pxe)
++{
++	char *FileDir = NULL;
++	char *DirEnd = NULL;
++	char *BootpBootFile;
++	size_t bplen;
++
++	BootpBootFile = pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile;
++	bplen = strlen(BootpBootFile);
++	FileDir = grub_malloc(bplen + 1);
++	memcpy(FileDir, BootpBootFile, bplen);
++	FileDir[bplen] = '\0';
++
++	DirEnd = grub_strrchr(FileDir, '/');
++	if (!DirEnd)
++		DirEnd = FileDir;
++
++	*DirEnd = '\0';
++
++	return FileDir;
++}
++
++static void set_pxe_info(grub_efi_loaded_image_t *LoadedImage,
++			EFI_PXE_BASE_CODE *pxe)
++{
++	tftp_info.LoadedImage = LoadedImage;
++	tftp_info.Pxe = pxe;
++	get_pxe_server(pxe, &tftp_info.ServerIp);
++	tftp_info.BasePath = get_pxe_file_dir(pxe);
++}
++
++char *grub_efi_pxe_get_config_path(grub_efi_loaded_image_t *LoadedImage)
++{
++	EFI_PXE_BASE_CODE *pxe = NULL;
++	EFI_IP_ADDRESS ServerIp;
++	char *FileName = NULL;
++	EFI_PXE_BASE_CODE_DHCPV4_PACKET *packet;
++	uuid_t uuid;
++	grub_efi_uintn_t FileSize = 0;
++	grub_efi_status_t rc = GRUB_EFI_SUCCESS;
++	char *ConfigPath = NULL;
++	char hex[] = "0123456789ABCDEF";
++	char hexip[9];
++	int hexiplen;
++
++	pxe = grub_efi_locate_protocol(&PxeBaseCodeProtocol, NULL);
++	if (pxe == NULL)
++		return NULL;
++
++	if (!pxe->Mode->Started)
++		return NULL;
++
++	set_pxe_info(LoadedImage, pxe);
++
++	FileName = grub_malloc(strlen("1902dcf5-7190-d811-bbd6-6ef21c690030"));
++
++	packet = &pxe->Mode->DhcpDiscover.Dhcpv4;
++
++	if (get_dhcp_client_id((EFI_PXE_BASE_CODE_PACKET *)packet, &uuid)) {
++
++		uuid.time_mid = 0x0011;
++		sprintf(FileName,
++			"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
++			uuid.time_low, uuid.time_mid, uuid.time_hi_ver,
++			uuid.clock_seq_hi, uuid.clock_seq_low,
++			uuid.node[0], uuid.node[1], uuid.node[2],
++			uuid.node[3], uuid.node[4], uuid.node[5]);
++
++		rc = tftp_get_file_size(FileName, &FileSize);
++		if (rc == GRUB_EFI_SUCCESS) {
++			char *ReturnFile = grub_malloc(strlen("(nd)/") +
++						strlen(FileName) + 1);
++			sprintf(ReturnFile, "(nd)/%s", FileName);
++			grub_free(FileName);
++			//sprintf(tftp_info.LastPath, FileName);
++			return ReturnFile;
++		}
++	}
++
++	packet = &pxe->Mode->DhcpAck.Dhcpv4;
++
++	if (!memcmp(packet->BootpHwAddr + 6, "\x00\x00\x00\x00\x00"
++					     "\x00\x00\x00\x00\x00", 10) &&
++			memcmp(packet->BootpHwAddr, "\x00\x00\x00\x00\x00\x00",
++				6)) {
++		char mac[21];
++		sprintf(mac, "01-%c%c-%c%c-%c%c-%c%c-%c%c-%c%c",
++			hex[(packet->BootpHwAddr[0] & 0xf0) >> 4],
++			hex[packet->BootpHwAddr[0] & 0xf],
++			hex[(packet->BootpHwAddr[1] & 0xf0) >> 4],
++			hex[packet->BootpHwAddr[1] & 0xf],
++			hex[(packet->BootpHwAddr[2] & 0xf0) >> 4],
++			hex[packet->BootpHwAddr[2] & 0xf],
++			hex[(packet->BootpHwAddr[3] & 0xf0) >> 4],
++			hex[packet->BootpHwAddr[3] & 0xf],
++			hex[(packet->BootpHwAddr[4] & 0xf0) >> 4],
++			hex[packet->BootpHwAddr[4] & 0xf],
++			hex[(packet->BootpHwAddr[5] & 0xf0) >> 4],
++			hex[packet->BootpHwAddr[5] & 0xf]);
++
++		rc = tftp_get_file_size(mac, &FileSize);
++		if (rc == GRUB_EFI_SUCCESS) {
++			char *ReturnFile = grub_malloc(strlen("(nd)/") +
++						strlen(mac) + 1);
++			sprintf(ReturnFile, "(nd)/%s", mac);
++			return ReturnFile;
++		}
++
++	}
++
++	sprintf(hexip, "%c%c%c%c%c%c%c%c",
++		hex[(packet->BootpYiAddr[0] & 0xf0) >> 4],
++		hex[packet->BootpYiAddr[0] & 0xf],
++		hex[(packet->BootpYiAddr[1] & 0xf0) >> 4],
++		hex[packet->BootpYiAddr[1] & 0xf],
++		hex[(packet->BootpYiAddr[2] & 0xf0) >> 4],
++		hex[packet->BootpYiAddr[2] & 0xf],
++		hex[(packet->BootpYiAddr[3] & 0xf0) >> 4],
++		hex[packet->BootpYiAddr[3] & 0xf]);
++
++	for (hexiplen = strlen(hexip); hexiplen > 0; hexiplen--)
++	{
++		hexip[hexiplen] = '\0';
++		rc = tftp_get_file_size(hexip, &FileSize);
++		if (rc == GRUB_EFI_SUCCESS) {
++			char *ReturnFile = grub_malloc(strlen("(nd)/") +
++						strlen(hexip) + 1);
++			sprintf(ReturnFile, "(nd)/%s", hexip);
++			return ReturnFile;
++		}
++	}
++
++	rc = tftp_get_file_size("efidefault", &FileSize);
++	if (rc == GRUB_EFI_SUCCESS) {
++		char *ReturnFile = grub_malloc(strlen("(nd)/efidefault")+1);
++		sprintf(ReturnFile, "(nd)/efidefault");
++		return ReturnFile;
++	}
++
++	return NULL;
++}
+diff --git a/efi/pxe.h b/efi/pxe.h
+new file mode 100644
+index 0000000..0a68007
+--- /dev/null
++++ b/efi/pxe.h
+@@ -0,0 +1,237 @@
++#ifndef PXE_H
++#define PXE_H 1
++
++#include "byteswap.h"
++
++extern char *grub_efi_pxe_get_config_path(grub_efi_loaded_image_t *LoadedImage);
++extern void grub_print_dhcp_info(grub_efi_loaded_image_t *loaded_image);
++extern char *grub_efi_pxe_path_to_path_name(void);
++
++
++#define EFI_PXE_BASE_CODE_PROTOCOL \
++    { 0x03c4e603, 0xac28, 0x11d3, {0x9a, 0x2d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d} }
++static grub_efi_guid_t PxeBaseCodeProtocol = EFI_PXE_BASE_CODE_PROTOCOL;
++
++struct _EFI_PXE_BASE_CODE;
++
++typedef enum {
++	EFI_PXE_BASE_CODE_TFTP_FIRST,
++	EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
++	EFI_PXE_BASE_CODE_TFTP_READ_FILE,
++	EFI_PXE_BASE_CODE_TFTP_WRITE_FILE,
++	EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY,
++	EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE,
++	EFI_PXE_BASE_CODE_MTFTP_READ_FILE,
++	EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY,
++	EFI_PXE_BASE_CODE_MTFTP_LAST
++} EFI_PXE_BASE_CODE_TFTP_OPCODE;
++
++typedef struct {
++    grub_efi_uint8_t                   Addr[4];
++} EFI_IPv4_ADDRESS;
++
++typedef struct {
++    grub_efi_uint8_t                   Addr[16];
++} EFI_IPv6_ADDRESS;
++
++typedef struct {
++    grub_efi_uint8_t                   Addr[32];
++} EFI_MAC_ADDRESS;
++
++typedef union {
++    grub_efi_uint32_t      Addr[4];
++    EFI_IPv4_ADDRESS    v4;
++    EFI_IPv6_ADDRESS    v6;
++} EFI_IP_ADDRESS;
++
++typedef grub_efi_uint16_t EFI_PXE_BASE_CODE_UDP_PORT;
++
++typedef struct {
++	EFI_IP_ADDRESS MCastIp;
++	EFI_PXE_BASE_CODE_UDP_PORT CPort;
++	EFI_PXE_BASE_CODE_UDP_PORT SPort;
++	grub_efi_uint16_t ListenTimeout;
++	grub_efi_uint16_t TransmitTimeout;
++} EFI_PXE_BASE_CODE_MTFTP_INFO;
++
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_MTFTP)(
++	struct _EFI_PXE_BASE_CODE *This,
++	EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
++	void *BufferPtr,
++	grub_efi_boolean_t Overwrite,
++	grub_efi_uint64_t *BufferSize,
++	grub_efi_uintn_t *BlockSize,
++	EFI_IP_ADDRESS *ServerIp,
++	grub_efi_uint8_t *Filename,
++	EFI_PXE_BASE_CODE_MTFTP_INFO *Info,
++	grub_efi_boolean_t DontUseBuffer);
++
++typedef struct {
++    grub_efi_uint8_t                           BootpOpcode;
++    grub_efi_uint8_t                           BootpHwType;
++    grub_efi_uint8_t                           BootpHwAddrLen;
++    grub_efi_uint8_t                           BootpGateHops;
++    grub_efi_uint32_t                          BootpIdent;
++    grub_efi_uint16_t                          BootpSeconds;
++    grub_efi_uint16_t                          BootpFlags;
++    grub_efi_uint8_t                           BootpCiAddr[4];
++    grub_efi_uint8_t                           BootpYiAddr[4];
++    grub_efi_uint8_t                           BootpSiAddr[4];
++    grub_efi_uint8_t                           BootpGiAddr[4];
++    grub_efi_uint8_t                           BootpHwAddr[16];
++    grub_efi_uint8_t                           BootpSrvName[64];
++    grub_efi_uint8_t                           BootpBootFile[128];
++    grub_efi_uint32_t                          DhcpMagik;
++    grub_efi_uint8_t                           DhcpOptions[56];
++} EFI_PXE_BASE_CODE_DHCPV4_PACKET;
++
++// TBD in EFI v1.1
++//typedef struct {
++//    grub_efi_uint8_t                           reserved;
++//} EFI_PXE_BASE_CODE_DHCPV6_PACKET;
++
++typedef union {
++    grub_efi_uint8_t                               Raw[1472];
++    EFI_PXE_BASE_CODE_DHCPV4_PACKET     Dhcpv4;
++//    EFI_PXE_BASE_CODE_DHCPV6_PACKET     Dhcpv6;
++} EFI_PXE_BASE_CODE_PACKET;
++
++typedef struct {
++    grub_efi_uint8_t                   Type;
++    grub_efi_uint8_t                   Code;
++    grub_efi_uint16_t                  Checksum;
++    union {
++        grub_efi_uint32_t              reserved;
++        grub_efi_uint32_t              Mtu;
++        grub_efi_uint32_t              Pointer;
++        struct {
++            grub_efi_uint16_t          Identifier;
++            grub_efi_uint16_t          Sequence;
++        } Echo;
++    } u;
++    grub_efi_uint8_t                   Data[494];
++} EFI_PXE_BASE_CODE_ICMP_ERROR;
++
++typedef struct {
++    grub_efi_uint8_t                   ErrorCode;
++    grub_efi_char8_t                   ErrorString[127];
++} EFI_PXE_BASE_CODE_TFTP_ERROR;
++
++
++#define EFI_PXE_BASE_CODE_MAX_IPCNT             8
++typedef struct {
++    grub_efi_uint8_t                       Filters;
++    grub_efi_uint8_t                       IpCnt;
++    grub_efi_uint16_t                      reserved;
++    EFI_IP_ADDRESS              IpList[EFI_PXE_BASE_CODE_MAX_IPCNT];
++} EFI_PXE_BASE_CODE_IP_FILTER;
++
++#define EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP             0x0001
++#define EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST              0x0002
++#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS            0x0004
++#define EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST  0x0008
++
++typedef struct {
++    EFI_IP_ADDRESS       IpAddr;
++    EFI_MAC_ADDRESS      MacAddr;
++} EFI_PXE_BASE_CODE_ARP_ENTRY;
++
++typedef struct {
++    EFI_IP_ADDRESS       IpAddr;
++    EFI_IP_ADDRESS       SubnetMask;
++    EFI_IP_ADDRESS       GwAddr;
++} EFI_PXE_BASE_CODE_ROUTE_ENTRY;
++
++#define EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES       8
++#define EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES     8
++
++typedef struct {
++    grub_efi_boolean_t                         Started;
++    grub_efi_boolean_t                         Ipv6Available;
++    grub_efi_boolean_t                         Ipv6Supported;
++    grub_efi_boolean_t                         UsingIpv6;
++    grub_efi_boolean_t                         BisSupported;
++    grub_efi_boolean_t                         BisDetected;
++    grub_efi_boolean_t                         AutoArp;
++    grub_efi_boolean_t                         SendGUID;
++    grub_efi_boolean_t                         DhcpDiscoverValid;
++    grub_efi_boolean_t                         DhcpAckReceived;
++    grub_efi_boolean_t                         ProxyOfferReceived;
++    grub_efi_boolean_t                         PxeDiscoverValid;
++    grub_efi_boolean_t                         PxeReplyReceived;
++    grub_efi_boolean_t                         PxeBisReplyReceived;
++    grub_efi_boolean_t                         IcmpErrorReceived;
++    grub_efi_boolean_t                         TftpErrorReceived;
++    grub_efi_boolean_t                         MakeCallbacks;
++    grub_efi_uint8_t                           TTL;
++    grub_efi_uint8_t                           ToS;
++    EFI_IP_ADDRESS                  StationIp;
++    EFI_IP_ADDRESS                  SubnetMask;
++    EFI_PXE_BASE_CODE_PACKET        DhcpDiscover;
++    EFI_PXE_BASE_CODE_PACKET        DhcpAck;
++    EFI_PXE_BASE_CODE_PACKET        ProxyOffer;
++    EFI_PXE_BASE_CODE_PACKET        PxeDiscover;
++    EFI_PXE_BASE_CODE_PACKET        PxeReply;
++    EFI_PXE_BASE_CODE_PACKET        PxeBisReply;
++    EFI_PXE_BASE_CODE_IP_FILTER     IpFilter;
++    grub_efi_uint32_t                          ArpCacheEntries;
++    EFI_PXE_BASE_CODE_ARP_ENTRY     ArpCache[EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES];
++    grub_efi_uint32_t                          RouteTableEntries;
++    EFI_PXE_BASE_CODE_ROUTE_ENTRY   RouteTable[EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES];
++    EFI_PXE_BASE_CODE_ICMP_ERROR    IcmpError;
++    EFI_PXE_BASE_CODE_TFTP_ERROR    TftpError;
++} EFI_PXE_BASE_CODE_MODE;
++
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_START)();
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_STOP)();
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_DHCP)();
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_DISCOVER)();
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_UDP_WRITE)();
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_UDP_READ)();
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_SET_IP_FILTER)();
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_ARP)();
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_SET_PARAMETERS)();
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_SET_STATION_IP)();
++typedef EFI_STATUS (*EFI_PXE_BASE_CODE_SET_PACKETS)();
++
++typedef struct _EFI_PXE_BASE_CODE{
++	grub_efi_uint64_t Revision;
++	EFI_PXE_BASE_CODE_START             Start;
++	EFI_PXE_BASE_CODE_STOP              Stop;
++	EFI_PXE_BASE_CODE_DHCP              Dhcp;
++	EFI_PXE_BASE_CODE_DISCOVER          Discover;
++	EFI_PXE_BASE_CODE_MTFTP             Mtftp;
++	EFI_PXE_BASE_CODE_UDP_WRITE         UdpWrite;
++	EFI_PXE_BASE_CODE_UDP_READ          UdpRead;
++	EFI_PXE_BASE_CODE_SET_IP_FILTER     SetIpFilter;
++	EFI_PXE_BASE_CODE_ARP               Arp;
++	EFI_PXE_BASE_CODE_SET_PARAMETERS    SetParameters;
++	EFI_PXE_BASE_CODE_SET_STATION_IP    SetStationIp;
++	EFI_PXE_BASE_CODE_SET_PACKETS       SetPackets;
++	EFI_PXE_BASE_CODE_MODE              *Mode;
++} EFI_PXE_BASE_CODE;
++
++typedef struct {
++	grub_efi_uint32_t time_low;
++	grub_efi_uint16_t time_mid;
++	grub_efi_uint16_t time_hi_ver;
++	grub_efi_uint8_t clock_seq_hi;
++	grub_efi_uint8_t clock_seq_low;
++	grub_efi_uint8_t node[6];
++} uuid_t;
++
++struct tftp_info {
++	grub_efi_loaded_image_t *LoadedImage;
++	EFI_PXE_BASE_CODE *Pxe;
++	EFI_IP_ADDRESS *ServerIp;
++	char *BasePath;
++	char *LastPath;
++	char *Buffer;
++};
++
++extern struct tftp_info tftp_info;
++extern grub_efi_status_t tftp_get_file_size(
++	char *Filename,
++	grub_efi_uintn_t *Size);
++
++#endif /* PXE_H */
 diff --git a/efi/ugadebug.h b/efi/ugadebug.h
 new file mode 100644
 index 0000000..f461c8b
@@ -27003,10 +28132,10 @@ index 0000000..4cff104
 +
 diff --git a/efi/x86_64/loader/linux.c b/efi/x86_64/loader/linux.c
 new file mode 100644
-index 0000000..7ac4ff8
+index 0000000..18746ea
 --- /dev/null
 +++ b/efi/x86_64/loader/linux.c
-@@ -0,0 +1,626 @@
+@@ -0,0 +1,580 @@
 +/*
 + *  GRUB  --  GRand Unified Bootloader
 + *  Copyright (C) 2006  Free Software Foundation, Inc.
@@ -27049,12 +28178,12 @@ index 0000000..7ac4ff8
 +static unsigned long linux_mem_size;
 +static int loaded;
 +static void *real_mode_mem;
++static void *prot_mode_mem;
++static grub_size_t prot_kernel_size;
 +static void *initrd_mem;
-+static void *mmap_buf;
 +static grub_efi_uintn_t real_mode_pages;
 +static grub_efi_uintn_t prot_mode_pages;
 +static grub_efi_uintn_t initrd_pages;
-+static grub_efi_uintn_t mmap_pages;
 +static grub_efi_guid_t graphics_output_guid = GRUB_EFI_GRAPHICS_OUTPUT_GUID;
 +
 +static inline grub_size_t
@@ -27063,45 +28192,6 @@ index 0000000..7ac4ff8
 +  return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
 +}
 +
-+/* Find the optimal number of pages for the memory map. Is it better to
-+   move this code to efimm.c?  */
-+static grub_efi_uintn_t
-+find_mmap_size (void)
-+{
-+  static grub_efi_uintn_t mmap_size = 0;
-+
-+  if (mmap_size != 0)
-+    return mmap_size;
-+
-+  mmap_size = (1 << 12);
-+  while (1)
-+    {
-+      int ret;
-+      grub_efi_memory_descriptor_t *mmap;
-+      grub_efi_uintn_t desc_size;
-+
-+      mmap = grub_malloc (mmap_size);
-+      if (! mmap)
-+	return 0;
-+
-+      ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0);
-+      grub_free (mmap);
-+
-+      if (ret < 0)
-+	grub_fatal ("cannot get memory map");
-+      else if (ret > 0)
-+	break;
-+
-+      mmap_size += (1 << 12);
-+    }
-+
-+  /* Increase the size a bit for safety, because GRUB allocates more on
-+     later, and EFI itself may allocate more.  */
-+  mmap_size += (1 << 11);
-+
-+  return page_align (mmap_size);
-+}
-+
 +static void
 +free_pages (void)
 +{
@@ -27130,15 +28220,13 @@ index 0000000..7ac4ff8
 +allocate_pages (grub_size_t real_size, 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 *mmap_end;
 +  grub_efi_memory_descriptor_t *desc;
 +  grub_efi_physical_address_t addr;
 +
 +  /* Make sure that each size is aligned to a page boundary.  */
 +  real_size = page_align (real_size + SECTOR_SIZE);
 +  prot_size = page_align (prot_size);
-+  mmap_size = find_mmap_size ();
 +
 +  grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n",
 +		(unsigned int) real_size, (unsigned int) prot_size,
@@ -27148,29 +28236,19 @@ index 0000000..7ac4ff8
 +     the memory map buffer for simplicity.  */
 +  real_mode_pages = (real_size >> 12);
 +  prot_mode_pages = (prot_size >> 12);
-+  mmap_pages = (mmap_size >> 12);
 +
 +  /* Initialize the memory pointers with NULL for convenience.  */
 +  real_mode_mem = 0;
-+  mmap_buf = 0;
-+
-+  /* Read the memory map temporarily, to find free space.  */
-+  mmap = grub_malloc (mmap_size);
-+  if (! mmap)
-+    {
-+      errnum = ERR_UNRECOGNIZED;
-+      return 0;
-+    }
++  prot_mode_mem = 0;
 +
-+  tmp_mmap_size = mmap_size;
-+  if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)
++  if (grub_efi_get_memory_map (0, &desc_size, 0) <= 0)
 +    grub_fatal ("cannot get memory map");
 +
 +  addr = 0;
-+  mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
++  mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
 +  /* First, find free pages for the real mode code
 +     and the memory map buffer.  */
-+  for (desc = mmap;
++  for (desc = mmap_buf;
 +       desc < mmap_end;
 +       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
 +    {
@@ -27184,10 +28262,17 @@ index 0000000..7ac4ff8
 +          grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n",
 +                        (unsigned) desc->physical_start,
 +                        (unsigned) physical_end);
-+          addr = physical_end - real_size - mmap_size;
++          addr = physical_end - real_size;
 +          if (addr < 0x10000)
 +            continue;
 +
++          /* the kernel wants this address to be under 1 gig.*/
++          if (desc->physical_start > 0x40000000 - real_size)
++            continue;
++
++          if (addr > 0x40000000 - real_size)
++            addr = 0x40000000 - real_size;
++
 +          grub_dprintf ("linux", "trying to allocate %u pages at %x\n",
 +                        (unsigned) real_mode_pages, (unsigned) addr);
 +          real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages);
@@ -27206,19 +28291,16 @@ index 0000000..7ac4ff8
 +      goto fail;
 +    }
 +
-+  mmap_buf = grub_efi_allocate_pages (0, mmap_pages);
-+  if (! mmap_buf)
-+    {
-+      grub_printf("cannot allocate efi mmap pages");
-+      errnum = ERR_WONT_FIT;
-+      goto fail;
-+    }
++  grub_printf("Trying to allocate %u pages for VMLINUZ\n",
++		(unsigned) prot_mode_pages);
++  prot_mode_mem = grub_efi_allocate_anypages(prot_mode_pages);
 +
-+  grub_free (mmap);
++  if (!prot_mode_mem)
++	grub_fatal("Cannot allocate pages for VMLINUZ");
++    
 +  return 1;
 +
 + fail:
-+  grub_free (mmap);
 +  free_pages ();
 +  return 0;
 +}
@@ -27236,7 +28318,6 @@ index 0000000..7ac4ff8
 +{
 +  struct linux_kernel_params *params;
 +  struct grub_linux_kernel_header *lh;
-+  grub_efi_uintn_t mmap_size;
 +  grub_efi_uintn_t map_key;
 +  grub_efi_uintn_t desc_size;
 +  grub_efi_uint32_t desc_version;
@@ -27246,9 +28327,7 @@ index 0000000..7ac4ff8
 +
 +  graphics_set_kernel_params (params);
 +
-+  mmap_size = find_mmap_size ();
-+  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key,
-+			       &desc_size, &desc_version) <= 0)
++  if (grub_efi_get_memory_map (&map_key, &desc_size, &desc_version) <= 0)
 +    grub_fatal ("cannot get memory map");
 +
 +  /* Pass e820 memmap. */
@@ -27260,6 +28339,11 @@ index 0000000..7ac4ff8
 +    grub_fatal ("cannot exit boot services");
 +
 +  /* Note that no boot services are available from here.  */
++
++  /* copy vmlinuz image to hdr.code32_start */
++  memcpy ((char *)(unsigned long)(params->hdr.code32_start), (char *)prot_mode_mem,
++	  prot_kernel_size);
++  /* copy switch image */
 +  memcpy ((void *) 0x700, switch_image, switch_size);
 +
 +  lh = &params->hdr;
@@ -27371,6 +28455,7 @@ index 0000000..7ac4ff8
 +
 +  real_size = 0x1000 + grub_strlen(arg);
 +  prot_size = grub_file_size () - (setup_sects << SECTOR_BITS) - SECTOR_SIZE;
++  prot_kernel_size = prot_size;
 +
 +  if (! allocate_pages (real_size, prot_size))
 +    goto fail;
@@ -27502,7 +28587,7 @@ index 0000000..7ac4ff8
 +
 +  grub_seek ((setup_sects << SECTOR_BITS) + SECTOR_SIZE);
 +  len = prot_size;
-+  if (grub_read ((char *) GRUB_LINUX_BZIMAGE_ADDR, len) != len)
++  if (grub_read ((char *)prot_mode_mem, len) != len)
 +    grub_printf ("Couldn't read file");
 +
 +  if (errnum == ERR_NONE)
@@ -27529,7 +28614,6 @@ index 0000000..7ac4ff8
 +  grub_ssize_t size;
 +  grub_addr_t addr_min, addr_max;
 +  grub_addr_t addr;
-+  grub_efi_uintn_t mmap_size;
 +  grub_efi_memory_descriptor_t *desc;
 +  grub_efi_memory_descriptor_t tdesc;
 +  grub_efi_uintn_t desc_size;
@@ -27567,9 +28651,8 @@ index 0000000..7ac4ff8
 +  addr_min = 0;
 +
 +  /* Find the highest address to put the initrd.  */
-+  mmap_size = find_mmap_size ();
 +  grub_dprintf(__func__, "addr_min: 0x%lx addr_max: 0x%lx mmap_size: %lu\n", addr_min, addr_max, mmap_size);
-+  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0)
++  if (grub_efi_get_memory_map (0, &desc_size, 0) <= 0)
 +    grub_fatal ("cannot get memory map");
 +
 +  addr = 0;
@@ -28632,6 +29715,17 @@ index 0000000..7e5982d
 +
 +* Wed May 23 2001 Erik Troan <ewt at redhat.com>
 +- initial build for Red Hat
+diff --git a/grub/Makefile.am b/grub/Makefile.am
+index 7eb2eaa..d4353f7 100644
+--- a/grub/Makefile.am
++++ b/grub/Makefile.am
+@@ -15,5 +15,5 @@ AM_CPPFLAGS = -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \
+ 
+ AM_CFLAGS = $(GRUB_CFLAGS)
+ 
+-grub_SOURCES = main.c asmstub.c
++grub_SOURCES = main.c asmstub.c efitftp.c
+ grub_LDADD = ../stage2/libgrub.a  ../lib/libcommon.a $(GRUB_LIBS)
 diff --git a/grub/Makefile.in b/grub/Makefile.in
 index 136c38f..0e40e1b 100644
 --- a/grub/Makefile.in
@@ -28943,7 +30037,7 @@ index 136c38f..0e40e1b 100644
  # Tell versions [3.59,3.63) of GNU make to not export all variables.
  # Otherwise a system limit (for SysV at least) may be exceeded.
 diff --git a/grub/asmstub.c b/grub/asmstub.c
-index ab95b4b..dac7484 100644
+index ab95b4b..f420074 100644
 --- a/grub/asmstub.c
 +++ b/grub/asmstub.c
 @@ -42,6 +42,7 @@ int grub_stage2 (void);
@@ -29117,7 +30211,21 @@ index ab95b4b..dac7484 100644
    grub_scratch_mem = 0;
  
    if (serial_device)
-@@ -766,7 +853,7 @@ get_diskinfo (int drive, struct geometry *geometry)
+@@ -699,6 +786,13 @@ console_getkey (void)
+   return console_translate_key (c);
+ }
+ 
++/* returns modifier status */
++int
++console_keystatus (void)
++{
++  return 0;
++}
++
+ /* returns packed values, LSB+1 is x, LSB is y */
+ int
+ console_getxy (void)
+@@ -766,7 +860,7 @@ get_diskinfo (int drive, struct geometry *geometry)
      {
        /* The unpartitioned device name: /dev/XdX */
        char *devname = device_map[drive];
@@ -29126,7 +30234,7 @@ index ab95b4b..dac7484 100644
  
        if (! devname)
  	return -1;
-@@ -777,13 +864,13 @@ get_diskinfo (int drive, struct geometry *geometry)
+@@ -777,13 +871,13 @@ get_diskinfo (int drive, struct geometry *geometry)
  
        /* Open read/write, or read-only if that failed. */
        if (! read_only)
@@ -29142,7 +30250,7 @@ index ab95b4b..dac7484 100644
  	      if (disks[drive].flags == -1)
  		{
  		  assign_device_name (drive, 0);
-@@ -797,6 +884,10 @@ get_diskinfo (int drive, struct geometry *geometry)
+@@ -797,6 +891,10 @@ get_diskinfo (int drive, struct geometry *geometry)
  	    }
  	}
  
@@ -29153,7 +30261,7 @@ index ab95b4b..dac7484 100644
        /* Attempt to read the first sector.  */
        if (read (disks[drive].flags, buf, 512) != 512)
  	{
-@@ -808,6 +899,7 @@ get_diskinfo (int drive, struct geometry *geometry)
+@@ -808,6 +906,7 @@ get_diskinfo (int drive, struct geometry *geometry)
  
        if (disks[drive].flags != -1)
  	get_drive_geometry (&disks[drive], device_map, drive);
@@ -29161,7 +30269,7 @@ index ab95b4b..dac7484 100644
      }
  
    if (disks[drive].flags == -1)
-@@ -829,24 +921,34 @@ static int
+@@ -829,24 +928,34 @@ static int
  nread (int fd, char *buf, size_t len)
  {
    int size = len;
@@ -29200,7 +30308,7 @@ index ab95b4b..dac7484 100644
  }
  
  /* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
-@@ -855,10 +957,18 @@ static int
+@@ -855,10 +964,18 @@ static int
  nwrite (int fd, char *buf, size_t len)
  {
    int size = len;
@@ -29220,7 +30328,7 @@ index ab95b4b..dac7484 100644
  
        if (ret <= 0)
  	{
-@@ -959,7 +1069,7 @@ biosdisk (int subfunc, int drive, struct geometry *geometry,
+@@ -959,7 +1076,7 @@ biosdisk (int subfunc, int drive, struct geometry *geometry,
    }
  #endif
  
@@ -29229,7 +30337,7 @@ index ab95b4b..dac7484 100644
  
    switch (subfunc)
      {
-@@ -1273,3 +1383,21 @@ hercules_setcursor (int on)
+@@ -1273,3 +1390,21 @@ hercules_setcursor (int on)
  {
    return 1;
  }
@@ -29251,6 +30359,46 @@ index ab95b4b..dac7484 100644
 +{
 +  return 0;
 +}
+diff --git a/grub/efitftp.c b/grub/efitftp.c
+new file mode 100644
+index 0000000..5355dec
+--- /dev/null
++++ b/grub/efitftp.c
+@@ -0,0 +1,34 @@
++#include <shared.h>
++#include <filesys.h>
++
++int efi_tftp_mount (void);
++int efi_tftp_read (char *buf, int len);
++int efi_tftp_dir (char *dirname);
++void efi_tftp_close (void);
++
++int
++efi_tftp_mount (void)
++{
++	grub_printf("non-efi efi_tftp_mount()\n");
++	return 0;
++}
++
++int
++efi_tftp_read (char *addr, int size)
++{
++	grub_printf ("non-efi efi_tftp_read (0x%x, %d)\n", (long) addr, size);
++	return 0;
++}
++
++int
++efi_tftp_dir (char *dirname)
++{
++	grub_printf ("non-efi efi_ftp_dir (%s)\n", dirname);
++	return 0;
++}
++
++void
++efi_tftp_close (void)
++{
++	grub_printf ("non-efi efi_tftp_close ()\n");
++}
 diff --git a/grub/main.c b/grub/main.c
 index dfe847e..6083641 100644
 --- a/grub/main.c
@@ -29548,7 +30696,7 @@ index 3dae206..e46d1c4 100644
  # Tell versions [3.59,3.63) of GNU make to not export all variables.
  # Otherwise a system limit (for SysV at least) may be exceeded.
 diff --git a/lib/device.c b/lib/device.c
-index d0663b3..d939ac1 100644
+index d0663b3..45a300e 100644
 --- a/lib/device.c
 +++ b/lib/device.c
 @@ -131,6 +131,152 @@ get_kfreebsd_version ()
@@ -29967,7 +31115,7 @@ index d0663b3..d939ac1 100644
    
    if ((partition & 0x00FF00) != 0x00FF00)
      {
-@@ -861,7 +1101,15 @@ write_to_partition (char **map, int drive, int partition,
+@@ -861,7 +1101,16 @@ write_to_partition (char **map, int drive, int partition,
        if (strcmp (dev + strlen(dev) - 5, "/disc") == 0)
  	strcpy (dev + strlen(dev) - 5, "/part");
      }
@@ -29978,13 +31126,14 @@ index d0663b3..d939ac1 100644
 +	   (strncmp(dev, "/dev/ida/", 9) == 0 ||
 +	    strncmp(dev, "/dev/ataraid/", 13) == 0 ||
 +	    strncmp(dev, "/dev/mapper/", 12) == 0 || 
++	    strncmp(dev, "/dev/md", 7) == 0 ||
 +	    strncmp(dev, "/dev/cciss/", 11) == 0 ||
 +	    strncmp(dev, "/dev/rd/", 8) == 0) ? "p" : "",
 +	   ((partition >> 16) & 0xFF) + 1);
    
    /* Open the partition.  */
    fd = open (dev, O_RDWR);
-@@ -870,35 +1118,13 @@ write_to_partition (char **map, int drive, int partition,
+@@ -870,35 +1119,13 @@ write_to_partition (char **map, int drive, int partition,
        errnum = ERR_NO_PART;
        return 0;
      }
@@ -31589,8 +32738,30 @@ index 7134bdf..c7e251b 100644
  
  .exec:
  	$(OBJCOPY) -O binary $< $@
+diff --git a/stage1/stage1.S b/stage1/stage1.S
+index 985963d..3a896be 100644
+--- a/stage1/stage1.S
++++ b/stage1/stage1.S
+@@ -31,6 +31,8 @@
+ 
+ 	/* Print message string */
+ #define MSG(x)	movw $ABS(x), %si; call message
++	/* Print verbose message string */
++#define VMSG(x)
+ 
+ 	/* XXX:	binutils-2.9.1.0.x doesn't produce a short opcode for this. */
+ #define	MOV_MEM_TO_AL(x)	.byte 0xa0;  .word x
+@@ -151,7 +153,7 @@ real_start:
+ 	pushw	%dx
+ 
+ 	/* print a notification message on the screen */
+-	MSG(notification_string)
++	VMSG(notification_string)
+ 
+ 	/* do not probe LBA if the drive is a floppy */
+ 	testb	$STAGE1_BIOS_HD_FLAG, %dl
 diff --git a/stage2/Makefile.am b/stage2/Makefile.am
-index f8e6d42..e128bc2 100644
+index f8e6d42..477d129 100644
 --- a/stage2/Makefile.am
 +++ b/stage2/Makefile.am
 @@ -7,19 +7,23 @@ noinst_HEADERS = apic.h defs.h dir.h disk_inode.h disk_inode_ffs.h \
@@ -31613,9 +32784,10 @@ index f8e6d42..e128bc2 100644
  libgrub_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \
  	disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_iso9660.c \
  	fsys_jfs.c fsys_minix.c fsys_reiserfs.c fsys_ufs2.c \
- 	fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c stage2.c \
+-	fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c stage2.c \
 -	terminfo.c tparm.c
-+	terminfo.c tparm.c graphics.c
++	fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c sha256crypt.c \
++	sha512crypt.c stage2.c terminfo.c tparm.c graphics.c efistubs.c
  libgrub_a_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/lib \
  	-DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \
  	-DFSYS_ISO9660=1 -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 \
@@ -31677,15 +32849,15 @@ index f8e6d42..e128bc2 100644
  STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
 -	$(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS)
 +	$(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS) $(GRAPHICS_FLAGS)
- 
--STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000
++
 +libstage2_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \
 +	disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_iso9660.c \
 +	fsys_jfs.c fsys_minix.c fsys_reiserfs.c fsys_ufs2.c \
-+	fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c stage2.c \
-+	terminfo.c tparm.c
++	fsys_vstafs.c fsys_xfs.c gunzip.c md5.c serial.c sha256crypt.c \
++	sha512crypt.c stage2.c terminfo.c tparm.c efistubs.c
 +libstage2_a_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
-+
+ 
+-STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000
 +if !PLATFORM_EFI
 +
 +STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000 $(LOADER_LDFLAGS)
@@ -31697,8 +32869,8 @@ index f8e6d42..e128bc2 100644
  	fsys_fat.c fsys_ffs.c fsys_iso9660.c fsys_jfs.c fsys_minix.c \
  	fsys_reiserfs.c fsys_ufs2.c fsys_vstafs.c fsys_xfs.c gunzip.c \
 -	hercules.c md5.c serial.c smp-imps.c stage2.c terminfo.c tparm.c
-+	hercules.c md5.c serial.c smp-imps.c stage2.c terminfo.c tparm.c \
-+	graphics.c
++	hercules.c md5.c serial.c smp-imps.c sha256crypt.c sha512crypt.c \
++	stage2.c terminfo.c tparm.c graphics.c
  pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
  pre_stage2_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
  pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK)
@@ -35519,7 +36691,7 @@ index d0062bd..66e7465 100644
  
  stage2_size.h: pre_stage2
 diff --git a/stage2/asm.S b/stage2/asm.S
-index 34b6e7d..655e707 100644
+index 34b6e7d..5c4dd5e 100644
 --- a/stage2/asm.S
 +++ b/stage2/asm.S
 @@ -98,7 +98,7 @@ VARIABLE(version_string)
@@ -35531,12 +36703,77 @@ index 34b6e7d..655e707 100644
  #else   /* STAGE1_5 */
  	.long	0xffffffff
  	.string "/boot/grub/stage2"
-@@ -1651,7 +1651,30 @@ ENTRY(gateA20)
- 	jnz	3f
- 	ret
+@@ -1622,36 +1622,78 @@ ENTRY(set_vbe_mode)
+  */
  
--3:	/* use keyboard controller */
-+3:	/*
+ ENTRY(gateA20)
++	pushl	%ebx
++	pushl	%edx
++	call	testA20
++	jnz	1f
++	call	A20_BIOS
++	call	testA20
++	jnz	1f
++	call	A20_PORT92
++	call	testA20
++	jnz	1f
++	call	A20_KBDCTL
++	call	testA20
++	jnz	1f
++	movl	$0,%eax
++	jmp	2f
++1:
++	movl	$-1,%eax
++2:
++	popl	%edx
++	popl	%ebx
++	ret
++
++testA20:
++	movl	0x500,%eax
++	movl	0x100500,%ebx
++	notl	%eax
++	movl	%eax,0x100500
++	cmpl	%eax,0x500
++	pushfl
++	movl	%ebx,0x100500
++	notl	%eax
++	movl	%eax,0x500
++	popfl
++	ret
++
++A20_BIOS:
+ 	/* first, try a BIOS call */
+-	pushl	%ebp
+-	movl	8(%esp), %edx
+ 	
+ 	call	EXT_C(prot_to_real)
+ 	
+ 	.code16
+-	movw	$0x2400, %ax
+-	testw	%dx, %dx
+-	jz	1f
+-	incw	%ax
++	movw	$0x2401, %ax
+ 1:	stc
+ 	int	$0x15
+-	jnc	2f
+-
+-	/* set non-zero if failed */
+-	movb	$1, %ah
+-
+-	/* save the status */
+-2:	movb	%ah, %dl
+ 
+ 	DATA32	call	EXT_C(real_to_prot)
+ 	.code32
++	ret
+ 
+-	popl	%ebp
+-	testb	%dl, %dl
+-	jnz	3f
++A20_PORT92:
++	/*
 +	* try to switch gateA20 using PORT92, the "Fast A20 and Init"
 +	* register
 +	*/
@@ -35546,46 +36783,35 @@ index 34b6e7d..655e707 100644
 +	cmpb	$0xff, %al
 +	jz	6f
 +
-+	/* set or clear bit1, the ALT_A20_GATE bit */
-+	movb	4(%esp), %ah
-+	testb	%ah, %ah
-+	jz	4f
++	/* set bit1, the ALT_A20_GATE bit */
 +	orb	$2, %al
-+	jmp	5f
-+4:	and	$0xfd, %al
++	/*     	and     $0xfd, %al */
 +
 +	/* clear the INIT_NOW bit; don't accidently reset the machine */
-+5:	and	$0xfe, %al
++	and	$0xfe, %al
 +	outb	%al, %dx
-+
-+
-+6:	/* use keyboard controller */
++6:
+ 	ret
+ 
+-3:	/* use keyboard controller */
++A20_KBDCTL:
++	/* use keyboard controller */
  	pushl	%eax
  
  	call    gloop1
-@@ -1661,9 +1684,12 @@ ENTRY(gateA20)
- 
- gloopint1:
- 	inb	$K_STATUS
-+	cmpb	$0xff, %al
-+	jz	gloopint1_done
- 	andb	$K_IBUF_FUL, %al
+@@ -1665,11 +1707,7 @@ gloopint1:
  	jnz	gloopint1
  
-+gloopint1_done:
  	movb	$KB_OUTPUT_MASK, %al
- 	cmpb	$0, 0x8(%esp)
- 	jz	gdoit
-@@ -1684,6 +1710,8 @@ gdoit:
- 
- gloop1:
- 	inb	$K_STATUS
-+	cmpb	$0xff, %al
-+	jz	gloop2ret
- 	andb	$K_IBUF_FUL, %al
- 	jnz	gloop1
+-	cmpb	$0, 0x8(%esp)
+-	jz	gdoit
+-
+ 	orb	$KB_A20_ENABLE, %al
+-gdoit:
+ 	outb	$K_RDWR
  
-@@ -1994,8 +2022,25 @@ ENTRY(console_getkey)
+ 	call	gloop1
+@@ -1994,8 +2032,25 @@ ENTRY(console_getkey)
  	call	EXT_C(prot_to_real)
  	.code16
  
@@ -35611,7 +36837,7 @@ index 34b6e7d..655e707 100644
  	movw	%ax, %dx		/* real_to_prot uses %eax */
  	call	translate_keycode
  	call	remap_ascii_char
-@@ -2003,7 +2048,7 @@ ENTRY(console_getkey)
+@@ -2003,7 +2058,7 @@ ENTRY(console_getkey)
  	DATA32	call	EXT_C(real_to_prot)
  	.code32
  
@@ -35620,7 +36846,7 @@ index 34b6e7d..655e707 100644
  
  	pop	%ebp
  	ret
-@@ -2029,7 +2074,7 @@ ENTRY(console_checkkey)
+@@ -2029,7 +2084,7 @@ ENTRY(console_checkkey)
  	call	EXT_C(prot_to_real)	/* enter real mode */
  	.code16
  
@@ -35629,7 +36855,45 @@ index 34b6e7d..655e707 100644
  	int	$0x16
  
  	DATA32	jz	notpending
-@@ -2216,6 +2261,156 @@ ENTRY(console_setcursor)
+@@ -2051,6 +2106,37 @@ pending:
+ 	pop	%ebp
+ 	ret
+ 
++
++/*
++ * int console_keystatus (void)
++ * BIOS call "INT 16H Function 02H" to get keyboard modifier status
++ *	Call with	%ah = 0x2
++ *	Return:		%al = keyboard state:
++ *				bit 3: alt key down
++ *				bit 2: ctrl key down
++ *				bit 1: left shift key down
++ *				bit 0: right shift key down
++ */
++ENTRY(console_keystatus)
++	push	%ebp
++
++	call	EXT_C(prot_to_real)
++	.code16
++	
++	movb	$0x12, %ah
++	int	$0x16
++	movw	%ax, %dx
++
++	DATA32	call	EXT_C(real_to_prot)
++	.code32
++
++	movw	%dx, %ax
++	
++	/* Mask out numlock, capslock and insert state. */
++	andl	$0x0f0f, %eax
++	pop	%ebp
++	ret
++	
+ 	
+ /*
+  * int console_getxy (void)
+@@ -2216,6 +2302,156 @@ ENTRY(console_setcursor)
  	pop	%ebx
  	pop	%ebp
  	ret
@@ -35787,7 +37051,7 @@ index 34b6e7d..655e707 100644
  /*
   * getrtsecs()
 diff --git a/stage2/boot.c b/stage2/boot.c
-index 4185d23..ec25acf 100644
+index 4185d23..247b8c9 100644
 --- a/stage2/boot.c
 +++ b/stage2/boot.c
 @@ -25,10 +25,14 @@
@@ -35815,7 +37079,165 @@ index 4185d23..ec25acf 100644
    int len, i, exec_type = 0, align_4k = 1;
    entry_func real_entry_addr = 0;
    kernel_t type = KERNEL_TYPE_NONE;
-@@ -756,8 +763,10 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+@@ -221,6 +228,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+     {
+       int big_linux = 0;
+       int setup_sects = lh->setup_sects;
++      int cmdline_size = 0xff;
+ 
+       if (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0200)
+ 	{
+@@ -248,6 +256,14 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 	      lh->cl_offset = LINUX_CL_OFFSET;
+ 	      lh->setup_move_size = LINUX_SETUP_MOVE_SIZE;
+ 	    }
++
++	  if (lh->version >= 0x0206)
++	    {
++	      cmdline_size = lh->cmdline_size;
++	      if (cmdline_size > (LINUX_CL_END_OFFSET - LINUX_CL_OFFSET))
++		cmdline_size = LINUX_CL_END_OFFSET - LINUX_CL_OFFSET;
++	    }
++
+ 	}
+       else
+ 	{
+@@ -280,8 +296,12 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 	errnum = ERR_WONT_FIT;
+       else
+ 	{
+-	  grub_printf ("   [Linux-%s, setup=0x%x, size=0x%x]\n",
+-		       (big_linux ? "bzImage" : "zImage"), data_len, text_len);
++	  grub_verbose_printf ("   [Linux-%s, setup=0x%x, size=0x%x]\n",
++			       (big_linux ? "bzImage" : "zImage"),
++			       data_len, text_len);
++
++	  if (silent_grub)
++	    lh->vid_mode = 0x0f04;
+ 
+ 	  /* Video mode selection support. What a mess!  */
+ 	  /* NOTE: Even the word "mess" is not still enough to
+@@ -404,7 +424,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 	    char *src = skip_to (0, arg);
+ 	    char *dest = linux_data_tmp_addr + LINUX_CL_OFFSET;
+ 	
+-	    while (dest < linux_data_tmp_addr + LINUX_CL_END_OFFSET && *src)
++	    while (dest < linux_data_tmp_addr + LINUX_CL_OFFSET + cmdline_size && *src)
+ 	      *(dest++) = *(src++);
+ 	
+ 	    /* Old Linux kernels have problems determining the amount of
+@@ -425,7 +445,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 	    if (! grub_strstr (arg, "mem=")
+ 		&& ! (load_flags & KERNEL_LOAD_NO_MEM_OPTION)
+ 		&& lh->version < 0x0203		/* kernel version < 2.4.18 */
+-		&& dest + 15 < linux_data_tmp_addr + LINUX_CL_END_OFFSET)
++		&& dest + 15 < linux_data_tmp_addr + LINUX_CL_OFFSET + cmdline_size)
+ 	      {
+ 		*dest++ = ' ';
+ 		*dest++ = 'm';
+@@ -487,7 +507,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+   mbi.syms.a.addr = 0;
+   mbi.syms.a.pad = 0;
+ 
+-  printf ("   [%s-%s", str2, str);
++  verbose_printf ("   [%s-%s", str2, str);
+ 
+   str = "";
+ 
+@@ -496,7 +516,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+       if (flags & MULTIBOOT_AOUT_KLUDGE)
+ 	str = "-and-data";
+ 
+-      printf (", loadaddr=0x%x, text%s=0x%x", cur_addr, str, text_len);
++      verbose_printf (", loadaddr=0x%x, text%s=0x%x", cur_addr, str, text_len);
+ 
+       /* read text, then read data */
+       if (grub_read ((char *) RAW_ADDR (cur_addr), text_len) == text_len)
+@@ -509,9 +529,9 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 	      if (align_4k)
+ 		cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000;
+ 	      else
+-		printf (", C");
++		verbose_printf (", C");
+ 
+-	      printf (", data=0x%x", data_len);
++	      verbose_printf (", data=0x%x", data_len);
+ 
+ 	      if ((grub_read ((char *) RAW_ADDR (cur_addr), data_len)
+ 		   != data_len)
+@@ -525,7 +545,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 	      memset ((char *) RAW_ADDR (cur_addr), 0, bss_len);
+ 	      cur_addr += bss_len;
+ 
+-	      printf (", bss=0x%x", bss_len);
++	      verbose_printf (", bss=0x%x", bss_len);
+ 	    }
+ 	}
+       else if (!errnum)
+@@ -545,7 +565,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 	  *((int *) RAW_ADDR (cur_addr)) = pu.aout->a_syms;
+ 	  cur_addr += sizeof (int);
+ 	  
+-	  printf (", symtab=0x%x", pu.aout->a_syms);
++	  verbose_printf (", symtab=0x%x", pu.aout->a_syms);
+ 
+ 	  if (grub_read ((char *) RAW_ADDR (cur_addr), pu.aout->a_syms)
+ 	      == pu.aout->a_syms)
+@@ -562,7 +582,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 
+ 		  i -= sizeof (int);
+ 
+-		  printf (", strtab=0x%x", i);
++		  verbose_printf (", strtab=0x%x", i);
+ 
+ 		  symtab_err = (grub_read ((char *) RAW_ADDR (cur_addr), i)
+ 				!= i);
+@@ -576,7 +596,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 
+ 	  if (symtab_err)
+ 	    {
+-	      printf ("(bad)");
++	      verbose_printf ("(bad)");
+ 	      cur_addr = orig_addr;
+ 	      mbi.syms.a.tabsize = 0;
+ 	      mbi.syms.a.strsize = 0;
+@@ -630,7 +650,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 	      /* mark memory as used */
+ 	      if (cur_addr < memaddr + memsiz)
+ 		cur_addr = memaddr + memsiz;
+-	      printf (", <0x%x:0x%x:0x%x>", memaddr, filesiz,
++	      verbose_printf (", <0x%x:0x%x:0x%x>", memaddr, filesiz,
+ 		      memsiz - filesiz);
+ 	      /* increment number of segments */
+ 	      loaded++;
+@@ -676,7 +696,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 		  shdr = (Elf32_Shdr *) mbi.syms.e.addr;
+ 		  cur_addr += tab_size;
+ 		  
+-		  printf (", shtab=0x%x", cur_addr);
++		  verbose_printf (", shtab=0x%x", cur_addr);
+   		  
+ 		  for (i = 0; i < mbi.syms.e.num; i++)
+ 		    {
+@@ -718,7 +738,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 	      
+ 	      if (symtab_err) 
+ 		{
+-		  printf ("(bad)");
++		  verbose_printf ("(bad)");
+ 		  mbi.syms.e.num = 0;
+ 		  mbi.syms.e.size = 0;
+ 		  mbi.syms.e.addr = 0;
+@@ -733,7 +753,7 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
+ 
+   if (! errnum)
+     {
+-      grub_printf (", entry=0x%x]\n", (unsigned) entry_addr);
++      grub_verbose_printf (", entry=0x%x]\n", (unsigned) entry_addr);
+       
+       /* If the entry address is physically different from that of the ELF
+ 	 header, correct it here.  */
+@@ -756,8 +776,10 @@ load_image (char *kernel, char *arg, kernel_t suggested_type,
      }
    
    return type;
@@ -35826,7 +37248,16 @@ index 4185d23..ec25acf 100644
  int
  load_module (char *module, char *arg)
  {
-@@ -794,10 +803,17 @@ load_module (char *module, char *arg)
+@@ -776,7 +798,7 @@ load_module (char *module, char *arg)
+       return 0;
+     }
+ 
+-  printf ("   [Multiboot-module @ 0x%x, 0x%x bytes]\n", cur_addr, len);
++  verbose_printf ("   [Multiboot-module @ 0x%x, 0x%x bytes]\n", cur_addr, len);
+ 
+   /* these two simply need to be set if any modules are loaded at all */
+   mbi.flags |= MB_INFO_MODS;
+@@ -794,11 +816,19 @@ load_module (char *module, char *arg)
    grub_close ();
    return 1;
  }
@@ -35835,16 +37266,53 @@ index 4185d23..ec25acf 100644
  int
  load_initrd (char *initrd)
  {
+-  int len;
 +#ifdef PLATFORM_EFI
 +#ifndef NO_DECOMPRESSION
 +  no_decompression = 1;
 +#endif
 +  return grub_load_initrd (initrd);
 +#else
-   int len;
++  int len, next_addr;
++  char *singleimage, *pos;
    unsigned long moveto;
    unsigned long max_addr;
-@@ -824,8 +840,12 @@ load_initrd (char *initrd)
+   struct linux_kernel_header *lh
+@@ -807,16 +837,24 @@ load_initrd (char *initrd)
+ #ifndef NO_DECOMPRESSION
+   no_decompression = 1;
+ #endif
+-  
+-  if (! grub_open (initrd))
+-    goto fail;
++  len = 0;
++  next_addr = cur_addr;
+ 
+-  len = grub_read ((char *) cur_addr, -1);
+-  if (! len)
+-    {
+-      grub_close ();
+-      goto fail;
+-    }
++  /* loop over all initrd images and concatenate them in memory */
++  singleimage = strtok_r(initrd," \t",&pos);
++  while (singleimage) {
++    if (! grub_open (singleimage))
++      continue;
++
++    len += grub_read ((char *) next_addr, -1);
++    grub_close ();
++
++    next_addr = cur_addr + len;
++    singleimage = strtok_r(NULL," \t",&pos);
++  }
++
++  if (!len)
++    goto fail;
+ 
+   if (linux_mem_size)
+     moveto = linux_mem_size;
+@@ -824,8 +862,12 @@ load_initrd (char *initrd)
      moveto = (mbi.mem_upper + 0x400) << 10;
    
    moveto = (moveto - len) & 0xfffff000;
@@ -35857,7 +37325,22 @@ index 4185d23..ec25acf 100644
    if (moveto + len >= max_addr)
      moveto = (max_addr - len) & 0xfffff000;
    
-@@ -851,9 +871,11 @@ load_initrd (char *initrd)
+@@ -836,13 +878,12 @@ load_initrd (char *initrd)
+   moveto -= 0x10000;
+   memmove ((void *) RAW_ADDR (moveto), (void *) cur_addr, len);
+ 
+-  printf ("   [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len);
++  verbose_printf ("   [Linux-initrd @ 0x%x, 0x%x bytes]\n", moveto, len);
+ 
+   /* FIXME: Should check if the kernel supports INITRD.  */
+   lh->ramdisk_image = RAW_ADDR (moveto);
+   lh->ramdisk_size = len;
+ 
+-  grub_close ();
+ 
+  fail:
+   
+@@ -851,9 +892,11 @@ load_initrd (char *initrd)
  #endif
  
    return ! errnum;
@@ -35869,25 +37352,55 @@ index 4185d23..ec25acf 100644
  #ifdef GRUB_UTIL
  /* Dummy function to fake the *BSD boot.  */
  static void
-@@ -1018,3 +1040,5 @@ bsd_boot (kernel_t type, int bootdev, char *arg)
+@@ -1018,3 +1061,5 @@ bsd_boot (kernel_t type, int bootdev, char *arg)
  		     extended_memory, mbi.mem_lower);
      }
  }
 +#endif
 +
 diff --git a/stage2/builtins.c b/stage2/builtins.c
-index 3e08a86..3333ae3 100644
+index 3e08a86..c90c527 100644
 --- a/stage2/builtins.c
 +++ b/stage2/builtins.c
-@@ -56,6 +56,7 @@ static int bootdev;
+@@ -56,6 +56,9 @@ static int bootdev;
  /* True when the debug mode is turned on, and false
     when it is turned off.  */
  int debug = 0;
 +int debug_graphics = 0;
++/* Print what we're booting */
++int grub_verbose = 0;
  /* The default entry.  */
  int default_entry = 0;
  /* The fallback entry.  */
-@@ -131,62 +132,97 @@ disk_read_print_func (int sector, int offset, int length)
+@@ -117,6 +120,27 @@ check_password (char *entered, char* expected, password_t type)
+     case PASSWORD_MD5:
+       return check_md5_password (entered, expected);
+ #endif
++
++    case PASSWORD_ENCRYPTED:
++      if (grub_memcmp (expected, "$1$", 3) == 0)
++	return check_md5_password (entered, expected);
++      else if (grub_memcmp (expected, "$5$", 3) == 0)
++	{
++	  char *hashed;
++
++	  hashed = sha256_crypt (entered, expected);
++	  return hashed == NULL || strcmp (expected, hashed);
++	}
++      else if (grub_memcmp (expected, "$6$", 3) == 0)
++	{
++	  char *hashed;
++
++	  hashed = sha512_crypt (entered, expected);
++	  return hashed == NULL || strcmp (expected, hashed);
++	}
++      else
++	return strcmp (entered, expected);
++
+     default: 
+       /* unsupported password type: be secure */
+       return 1;
+@@ -131,62 +155,97 @@ disk_read_print_func (int sector, int offset, int length)
  }
  
  
@@ -35982,7 +37495,7 @@ index 3e08a86..3333ae3 100644
 -  int num_sectors = 0;
 -  int num_entries = 0;
 -  int last_length = 0;
--
+ 
 -  auto void disk_read_blocklist_func (int sector, int offset, int length);
 -  
 -  /* Collect contiguous blocks into one entry as many as possible,
@@ -36015,7 +37528,7 @@ index 3e08a86..3333ae3 100644
 -	      num_sectors = 0;
 -	    }
 -	}
- 
+-
 -      if (offset > 0)
 -	{
 -	  grub_printf("%s%d[%d-%d]", num_entries ? "," : "",
@@ -36035,7 +37548,7 @@ index 3e08a86..3333ae3 100644
  
    /* Open the file.  */
    if (! grub_open (arg))
-@@ -206,15 +242,15 @@ blocklist_func (char *arg, int flags)
+@@ -206,15 +265,15 @@ blocklist_func (char *arg, int flags)
    grub_printf (")");
  
    /* Read in the whole file to DUMMY.  */
@@ -36055,7 +37568,7 @@ index 3e08a86..3333ae3 100644
  
    grub_printf ("\n");
    
-@@ -237,12 +273,22 @@ static struct builtin builtin_blocklist =
+@@ -237,12 +296,25 @@ static struct builtin builtin_blocklist =
  static int
  boot_func (char *arg, int flags)
  {
@@ -36075,10 +37588,13 @@ index 3e08a86..3333ae3 100644
 +      current_term = term_table; /* assumption: console is first */
 +    }
 +
++  if (silent_grub)
++    setcursor(0);
++
  #ifdef SUPPORT_NETBOOT
    /* Shut down the networking.  */
    cleanup_net ();
-@@ -250,11 +296,13 @@ boot_func (char *arg, int flags)
+@@ -250,11 +322,13 @@ boot_func (char *arg, int flags)
    
    switch (kernel_type)
      {
@@ -36092,7 +37608,7 @@ index 3e08a86..3333ae3 100644
  
      case KERNEL_TYPE_LINUX:
        /* Linux */
-@@ -296,16 +344,25 @@ boot_func (char *arg, int flags)
+@@ -296,16 +370,25 @@ boot_func (char *arg, int flags)
        chain_stage1 (0, BOOTSEC_LOCATION, boot_part_addr);
        break;
  
@@ -36118,7 +37634,7 @@ index 3e08a86..3333ae3 100644
    return 0;
  }
  
-@@ -402,6 +459,10 @@ static struct builtin builtin_cat =
+@@ -402,6 +485,10 @@ static struct builtin builtin_cat =
  static int
  chainloader_func (char *arg, int flags)
  {
@@ -36129,7 +37645,7 @@ index 3e08a86..3333ae3 100644
    int force = 0;
    char *file = arg;
  
-@@ -458,6 +519,7 @@ chainloader_func (char *arg, int flags)
+@@ -458,6 +545,7 @@ chainloader_func (char *arg, int flags)
    errnum = ERR_NONE;
    
    return 0;
@@ -36137,7 +37653,7 @@ index 3e08a86..3333ae3 100644
  }
  
  static struct builtin builtin_chainloader =
-@@ -564,89 +626,88 @@ static struct builtin builtin_cmp =
+@@ -564,89 +652,88 @@ static struct builtin builtin_cmp =
  /* Set new colors used for the menu interface. Support two methods to
     specify a color name: a direct integer representation and a symbolic
     color name. An example of the latter is "blink-light-gray/blue".  */
@@ -36299,7 +37815,7 @@ index 3e08a86..3333ae3 100644
    normal = arg;
    highlight = skip_to (0, arg);
  
-@@ -690,7 +751,6 @@ static struct builtin builtin_color =
+@@ -690,7 +777,6 @@ static struct builtin builtin_color =
    " But only the first eight names can be used for BG. You can prefix"
    " \"blink-\" to FG if you want a blinking foreground color."
  };
@@ -36307,7 +37823,7 @@ index 3e08a86..3333ae3 100644
  
  /* configfile */
  static int
-@@ -737,14 +797,18 @@ static struct builtin builtin_configfile =
+@@ -737,14 +823,18 @@ static struct builtin builtin_configfile =
  static int
  debug_func (char *arg, int flags)
  {
@@ -36329,7 +37845,7 @@ index 3e08a86..3333ae3 100644
        grub_printf (" Debug mode is turned on\n");
      }
  
-@@ -755,17 +819,33 @@ static struct builtin builtin_debug =
+@@ -755,17 +845,61 @@ static struct builtin builtin_debug =
  {
    "debug",
    debug_func,
@@ -36340,6 +37856,34 @@ index 3e08a86..3333ae3 100644
  };
  
  
++/* verbose */
++static int
++verbose_func (char *arg, int flags)
++{
++  if (grub_verbose)
++    {
++      grub_verbose = 0;
++      grub_printf (" Verbose mode is turned off\n");
++    }
++  else
++    {
++      grub_verbose = 1;
++      grub_printf (" Verbose mode is turned on\n");
++    }
++
++  return 0;
++}
++
++static struct builtin builtin_verbose =
++{
++  "verbose",
++  verbose_func,
++  BUILTIN_CMDLINE | BUILTIN_MENU,
++  "verbose",
++  "Turn on/off verbose output."
++};
++
++
 +#if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL) && !defined(PLATFORM_EFI)
 +static int savedefault_helper(int);
 +#endif
@@ -36364,7 +37908,71 @@ index 3e08a86..3333ae3 100644
    if (grub_strcmp (arg, "saved") == 0)
      {
        default_entry = saved_entryno;
-@@ -852,6 +932,139 @@ static struct builtin builtin_dhcp =
+@@ -792,7 +926,7 @@ static struct builtin builtin_default =
+ };
+ 
+ 
+-#ifdef GRUB_UTIL
++#if defined(GRUB_UTIL) || defined(PLATFORM_EFI)
+ /* device */
+ static int
+ device_func (char *arg, int flags)
+@@ -800,16 +934,17 @@ device_func (char *arg, int flags)
+   char *drive = arg;
+   char *device;
+ 
+-  /* Get the drive number from DRIVE.  */
+-  if (! set_device (drive))
+-    return 1;
+-
+   /* Get the device argument.  */
+   device = skip_to (0, drive);
+-  
++
++  nul_terminate (drive);
+   /* Terminate DEVICE.  */
+   nul_terminate (device);
+ 
++  /* Get the drive number from DRIVE.  */
++  if (! set_device (drive))
++    return 1;
++
+   if (! *device || ! check_device (device))
+     {
+       errnum = ERR_FILE_NOT_FOUND;
+@@ -817,7 +952,7 @@ device_func (char *arg, int flags)
+     }
+ 
+   assign_device_name (current_drive, device);
+-  
++
+   return 0;
+ }
+ 
+@@ -828,9 +963,20 @@ static struct builtin builtin_device =
+   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+   "device DRIVE DEVICE",
+   "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This command"
+-  " can be used only in the grub shell."
++  " can be used only in the grub shell and in EFI."
+ };
+-#endif /* GRUB_UTIL */
++#endif /* defined(GRUB_UTIL) || defined(PLATFORM_EFI) */
++#ifdef PLATFORM_EFI
++static struct builtin builtin_efimap =
++{
++  "efimap",
++  device_func,
++  BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
++  "efimap DRIVE DEVICE",
++  "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This command"
++  " can be used only in EFI."
++};
++#endif /* PLATFORM_EFI */
+ 
+ 
+ #ifdef SUPPORT_NETBOOT
+@@ -852,6 +998,139 @@ static struct builtin builtin_dhcp =
  };
  #endif /* SUPPORT_NETBOOT */
  
@@ -36504,7 +38112,7 @@ index 3e08a86..3333ae3 100644
  
  /* displayapm */
  static int
-@@ -893,6 +1106,7 @@ static struct builtin builtin_displayapm =
+@@ -893,6 +1172,7 @@ static struct builtin builtin_displayapm =
    "displayapm",
    "Display APM BIOS information."
  };
@@ -36512,7 +38120,7 @@ index 3e08a86..3333ae3 100644
  
  
  /* displaymem */
-@@ -912,11 +1126,11 @@ displaymem_func (char *arg, int flags)
+@@ -912,11 +1192,11 @@ displaymem_func (char *arg, int flags)
    if (mbi.flags & MB_INFO_MEM_MAP)
      {
        struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr;
@@ -36526,7 +38134,7 @@ index 3e08a86..3333ae3 100644
  	{
  	  char *str;
  
-@@ -924,15 +1138,10 @@ displaymem_func (char *arg, int flags)
+@@ -924,15 +1204,10 @@ displaymem_func (char *arg, int flags)
  	    str = "Usable RAM";
  	  else
  	    str = "Reserved";
@@ -36546,7 +38154,7 @@ index 3e08a86..3333ae3 100644
  	}
      }
  
-@@ -1009,6 +1218,7 @@ static struct builtin builtin_dump =
+@@ -1009,6 +1284,7 @@ static struct builtin builtin_dump =
    };
  #endif /* GRUB_UTIL */
  
@@ -36554,7 +38162,7 @@ index 3e08a86..3333ae3 100644
  
  static char embed_info[32];
  /* embed */
-@@ -1143,6 +1353,7 @@ static struct builtin builtin_embed =
+@@ -1143,6 +1419,7 @@ static struct builtin builtin_embed =
    " is a drive, or in the \"bootloader\" area if DEVICE is a FFS partition."
    " Print the number of sectors which STAGE1_5 occupies if successful."
  };
@@ -36562,7 +38170,7 @@ index 3e08a86..3333ae3 100644
  
  
  /* fallback */
-@@ -1233,14 +1444,15 @@ find_func (char *arg, int flags)
+@@ -1233,14 +1510,15 @@ find_func (char *arg, int flags)
    for (drive = 0x80; drive < 0x88; drive++)
      {
        unsigned long part = 0xFFFFFF;
@@ -36581,7 +38189,7 @@ index 3e08a86..3333ae3 100644
  	{
  	  if (type != PC_SLICE_TYPE_NONE
  	      && ! IS_PC_SLICE_TYPE_BSD (type)
-@@ -1679,6 +1891,7 @@ static struct builtin builtin_ifconfig =
+@@ -1679,6 +1957,7 @@ static struct builtin builtin_ifconfig =
  };
  #endif /* SUPPORT_NETBOOT */
  
@@ -36589,7 +38197,7 @@ index 3e08a86..3333ae3 100644
  
  /* impsprobe */
  static int
-@@ -1706,6 +1919,7 @@ static struct builtin builtin_impsprobe =
+@@ -1706,6 +1985,7 @@ static struct builtin builtin_impsprobe =
    " configuration table and boot the various CPUs which are found into"
    " a tight loop."
  };
@@ -36597,7 +38205,7 @@ index 3e08a86..3333ae3 100644
  
  
  /* initrd */
-@@ -1738,8 +1952,82 @@ static struct builtin builtin_initrd =
+@@ -1738,8 +2018,82 @@ static struct builtin builtin_initrd =
    " appropriate parameters in the Linux setup area in memory."
  };
  
@@ -36680,7 +38288,7 @@ index 3e08a86..3333ae3 100644
  static int
  install_func (char *arg, int flags)
  {
-@@ -1747,8 +2035,12 @@ install_func (char *arg, int flags)
+@@ -1747,8 +2101,12 @@ install_func (char *arg, int flags)
    char *stage1_buffer = (char *) RAW_ADDR (0x100000);
    char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
    char *old_sect = stage2_buffer + SECTOR_SIZE;
@@ -36695,7 +38303,7 @@ index 3e08a86..3333ae3 100644
    /* XXX: Probably SECTOR_SIZE is reasonable.  */
    char *config_filename = stage2_second_buffer + SECTOR_SIZE;
    char *dummy = config_filename + SECTOR_SIZE;
-@@ -1757,10 +2049,11 @@ install_func (char *arg, int flags)
+@@ -1757,10 +2115,11 @@ install_func (char *arg, int flags)
    int src_drive, src_partition, src_part_start;
    int i;
    struct geometry dest_geom, src_geom;
@@ -36709,7 +38317,7 @@ index 3e08a86..3333ae3 100644
    /* Point to the location of the name of a configuration file in Stage 2.  */
    char *config_file_location;
    /* If FILE is a Stage 1.5?  */
-@@ -1769,68 +2062,18 @@ install_func (char *arg, int flags)
+@@ -1769,68 +2128,18 @@ install_func (char *arg, int flags)
    int is_open = 0;
    /* If LBA is forced?  */
    int is_force_lba = 0;
@@ -36783,7 +38391,7 @@ index 3e08a86..3333ae3 100644
    /* First, check the GNU-style long option.  */
    while (1)
      {
-@@ -1862,10 +2105,10 @@ install_func (char *arg, int flags)
+@@ -1862,10 +2171,10 @@ install_func (char *arg, int flags)
    addr = skip_to (0, file);
  
    /* Get the installation address.  */
@@ -36796,7 +38404,7 @@ index 3e08a86..3333ae3 100644
        ptr = addr;
        errnum = 0;
      }
-@@ -1961,17 +2204,17 @@ install_func (char *arg, int flags)
+@@ -1961,17 +2270,17 @@ install_func (char *arg, int flags)
        = 0x9090;
    
    /* Read the first sector of Stage 2.  */
@@ -36818,7 +38426,7 @@ index 3e08a86..3333ae3 100644
    
    /* Check for the version of Stage 2.  */
    if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
-@@ -1987,27 +2230,27 @@ install_func (char *arg, int flags)
+@@ -1987,27 +2296,27 @@ install_func (char *arg, int flags)
  
    /* If INSTALLADDR is not specified explicitly in the command-line,
       determine it by the Stage 2 id.  */
@@ -36853,7 +38461,7 @@ index 3e08a86..3333ae3 100644
  	  || (*((int *) (i - 4)) & 0x80000000)
  	  || *((unsigned short *) i) >= 0xA00
  	  || *((short *) (i + 2)) == 0)
-@@ -2021,13 +2264,13 @@ install_func (char *arg, int flags)
+@@ -2021,13 +2330,13 @@ install_func (char *arg, int flags)
        i -= 8;
      }
  
@@ -36870,7 +38478,7 @@ index 3e08a86..3333ae3 100644
    if (! grub_read (dummy, -1))
      goto fail;
    
-@@ -2110,7 +2353,7 @@ install_func (char *arg, int flags)
+@@ -2110,7 +2419,7 @@ install_func (char *arg, int flags)
  	  /* Skip the first sector.  */
  	  grub_seek (SECTOR_SIZE);
  	  
@@ -36879,7 +38487,7 @@ index 3e08a86..3333ae3 100644
  	  if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
  	    goto fail;
  	  
-@@ -2180,7 +2423,7 @@ install_func (char *arg, int flags)
+@@ -2180,7 +2489,7 @@ install_func (char *arg, int flags)
  	  else
  #endif /* GRUB_UTIL */
  	    {
@@ -36888,7 +38496,7 @@ index 3e08a86..3333ae3 100644
  		goto fail;
  	    }
  	}
-@@ -2202,7 +2445,7 @@ install_func (char *arg, int flags)
+@@ -2202,7 +2511,7 @@ install_func (char *arg, int flags)
  	  goto fail;
  	}
  
@@ -36897,7 +38505,7 @@ index 3e08a86..3333ae3 100644
  	{
  	  fclose (fp);
  	  errnum = ERR_WRITE;
-@@ -2229,7 +2472,7 @@ install_func (char *arg, int flags)
+@@ -2229,7 +2538,7 @@ install_func (char *arg, int flags)
  	goto fail;
  
        if (! devwrite (stage2_first_sector - src_part_start, 1,
@@ -36906,7 +38514,7 @@ index 3e08a86..3333ae3 100644
  	goto fail;
  
        if (! devwrite (stage2_second_sector - src_part_start, 1,
-@@ -2322,6 +2565,7 @@ static struct builtin builtin_ioprobe =
+@@ -2322,6 +2631,7 @@ static struct builtin builtin_ioprobe =
    "ioprobe DRIVE",
    "Probe I/O ports used for the drive DRIVE."
  };
@@ -36914,7 +38522,7 @@ index 3e08a86..3333ae3 100644
  
  
  /* kernel */
-@@ -2456,6 +2700,7 @@ static struct builtin builtin_makeactive =
+@@ -2456,6 +2766,7 @@ static struct builtin builtin_makeactive =
    " This command is limited to _primary_ PC partitions on a hard disk."
  };
  
@@ -36922,7 +38530,7 @@ index 3e08a86..3333ae3 100644
  
  /* map */
  /* Map FROM_DRIVE to TO_DRIVE.  */
-@@ -2519,6 +2764,7 @@ static struct builtin builtin_map =
+@@ -2519,6 +2830,7 @@ static struct builtin builtin_map =
    " when you chain-load some operating systems, such as DOS, if such an"
    " OS resides at a non-first drive."
  };
@@ -36930,7 +38538,7 @@ index 3e08a86..3333ae3 100644
  
  
  #ifdef USE_MD5_PASSWORDS
-@@ -2579,6 +2825,7 @@ static struct builtin builtin_md5crypt =
+@@ -2579,6 +2891,7 @@ static struct builtin builtin_md5crypt =
  };
  #endif /* USE_MD5_PASSWORDS */
  
@@ -36938,7 +38546,7 @@ index 3e08a86..3333ae3 100644
  
  /* module */
  static int
-@@ -2656,6 +2903,7 @@ static struct builtin builtin_modulenounzip =
+@@ -2656,6 +2969,7 @@ static struct builtin builtin_modulenounzip =
    "The same as `module', except that automatic decompression is"
    " disabled."
  };
@@ -36946,7 +38554,7 @@ index 3e08a86..3333ae3 100644
  
  
  /* pager [on|off] */
-@@ -2815,8 +3063,8 @@ parttype_func (char *arg, int flags)
+@@ -2815,8 +3129,8 @@ parttype_func (char *arg, int flags)
  {
    int new_type;
    unsigned long part = 0xFFFFFF;
@@ -36957,7 +38565,7 @@ index 3e08a86..3333ae3 100644
    char mbr[512];
  
    /* Get the drive and the partition.  */
-@@ -2853,8 +3101,15 @@ parttype_func (char *arg, int flags)
+@@ -2853,8 +3167,15 @@ parttype_func (char *arg, int flags)
    /* Look for the partition.  */
    while (next_partition (current_drive, 0xFFFFFF, &part, &type,
  			 &start, &len, &offset, &entry,
@@ -36974,7 +38582,38 @@ index 3e08a86..3333ae3 100644
        if (part == current_partition)
  	{
  	  /* Found.  */
-@@ -2982,8 +3237,8 @@ static struct builtin builtin_pause =
+@@ -2900,6 +3221,11 @@ password_func (char *arg, int flags)
+       arg = skip_to (0, arg);
+     }
+ #endif
++  else if (grub_memcmp (arg, "--encrypted", 5) == 0)
++    {
++      type = PASSWORD_ENCRYPTED;
++      arg = skip_to (0, arg);
++    }
+   if (grub_memcmp (arg, "--", 2) == 0)
+     {
+       type = PASSWORD_UNSUPPORTED;
+@@ -2947,7 +3273,7 @@ static struct builtin builtin_password =
+   "password",
+   password_func,
+   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
+-  "password [--md5] PASSWD [FILE]",
++  "password [--md5|--encrypted] PASSWD [FILE]",
+   "If used in the first section of a menu file, disable all"
+   " interactive editing control (menu entry editor and"
+   " command line). If the password PASSWD is entered, it loads the"
+@@ -2956,7 +3282,8 @@ static struct builtin builtin_password =
+   " instructions.  You can also use it in the script section, in"
+   " which case it will ask for the password, before continueing."
+   " The option --md5 tells GRUB that PASSWD is encrypted with"
+-  " md5crypt."
++  " md5crypt, --encrypted that PASSWD is encrypted (with algorithm"
++  " specified in PASSWD: supported is md5, sha-256, sha-512)."
+ };
+ 
+ 
+@@ -2982,8 +3309,8 @@ static struct builtin builtin_pause =
    "Print MESSAGE, then wait until a key is pressed."
  };
  
@@ -36984,7 +38623,7 @@ index 3e08a86..3333ae3 100644
  /* quit */
  static int
  quit_func (char *arg, int flags)
-@@ -3002,7 +3257,7 @@ static struct builtin builtin_quit =
+@@ -3002,7 +3329,7 @@ static struct builtin builtin_quit =
    "quit",
    "Exit from the GRUB shell."
  };
@@ -36993,7 +38632,17 @@ index 3e08a86..3333ae3 100644
  
  
  #ifdef SUPPORT_NETBOOT
-@@ -3217,146 +3472,179 @@ static struct builtin builtin_rootnoverify =
+@@ -3165,7 +3492,8 @@ real_root_func (char *arg, int attempt_mount)
+ 	return 1;
+       
+       /* Print the type of the filesystem.  */
+-      print_fsys_type ();
++      if (grub_verbose)
++	print_fsys_type ();
+     }
+   
+   return 0;
+@@ -3217,146 +3545,179 @@ static struct builtin builtin_rootnoverify =
  };
  
  
@@ -37294,7 +38943,7 @@ index 3e08a86..3333ae3 100644
  #else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
    errnum = ERR_UNRECOGNIZED;
    return 1;
-@@ -3368,10 +3656,14 @@ static struct builtin builtin_savedefault =
+@@ -3368,10 +3729,14 @@ static struct builtin builtin_savedefault =
    "savedefault",
    savedefault_func,
    BUILTIN_CMDLINE,
@@ -37313,7 +38962,7 @@ index 3e08a86..3333ae3 100644
  };
  
  
-@@ -3527,6 +3819,7 @@ static struct builtin builtin_serial =
+@@ -3527,6 +3892,7 @@ static struct builtin builtin_serial =
  };
  #endif /* SUPPORT_SERIAL */
  
@@ -37321,7 +38970,7 @@ index 3e08a86..3333ae3 100644
  
  /* setkey */
  struct keysym
-@@ -3612,50 +3905,47 @@ static struct keysym keysym_table[] =
+@@ -3612,50 +3978,47 @@ static struct keysym keysym_table[] =
    {"delete",		0,		0x7f,	0,	0x53}
  };
  
@@ -37406,7 +39055,26 @@ index 3e08a86..3333ae3 100644
    to_key = arg;
    from_key = skip_to (0, to_key);
  
-@@ -3973,7 +4263,7 @@ setup_func (char *arg, int flags)
+@@ -3830,15 +4193,15 @@ setup_func (char *arg, int flags)
+ 	{
+ 	  char tmp[16];
+ 	  grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF);
+-	  grub_strncat (device, tmp, 256);
++	  grub_strncat (device, tmp, 16);
+ 	}
+       if ((partition & 0x00FF00) != 0x00FF00)
+ 	{
+ 	  char tmp[16];
+ 	  grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF));
+-	  grub_strncat (device, tmp, 256);
++	  grub_strncat (device, tmp, 16);
+ 	}
+-      grub_strncat (device, ")", 256);
++      grub_strncat (device, ")", 16);
+     }
+   
+   int embed_stage1_5 (char *stage1_5, int drive, int partition)
+@@ -3973,7 +4336,7 @@ setup_func (char *arg, int flags)
  
    /* The prefix was determined.  */
    grub_sprintf (stage2, "%s%s", prefix, "/stage2");
@@ -37415,11 +39083,27 @@ index 3e08a86..3333ae3 100644
    *real_config_filename = 0;
  
    /* Check if stage2 exists.  */
-@@ -4083,9 +4373,10 @@ static struct builtin builtin_setup =
+@@ -4083,9 +4446,26 @@ static struct builtin builtin_setup =
    " partition where GRUB images reside, specify the option `--stage2'"
    " to tell GRUB the file name under your OS."
  };
 +#endif /* ! PLATFORM_EFI */
++
++
++static int
++silent_func (char *arg, int flags)
++{
++  silent_grub = 1;
++  return 0;
++}
++
++static struct builtin builtin_silent =
++{
++  "silent",
++  silent_func,
++  BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
++  "grub will attempt to avoid printing anything to the screen"
++};
  
  
 -#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES)
@@ -37427,7 +39111,7 @@ index 3e08a86..3333ae3 100644
  /* terminal */
  static int
  terminal_func (char *arg, int flags)
-@@ -4244,17 +4535,21 @@ terminal_func (char *arg, int flags)
+@@ -4244,17 +4624,21 @@ terminal_func (char *arg, int flags)
   end:
    current_term = term_table + default_term;
    current_term->flags = term_flags;
@@ -37454,7 +39138,7 @@ index 3e08a86..3333ae3 100644
    
    return 0;
  }
-@@ -4264,7 +4559,7 @@ static struct builtin builtin_terminal =
+@@ -4264,7 +4648,7 @@ static struct builtin builtin_terminal =
    "terminal",
    terminal_func,
    BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
@@ -37463,7 +39147,7 @@ index 3e08a86..3333ae3 100644
    "Select a terminal. When multiple terminals are specified, wait until"
    " you push any key to continue. If both console and serial are specified,"
    " the terminal to which you input a key first will be selected. If no"
-@@ -4276,7 +4571,7 @@ static struct builtin builtin_terminal =
+@@ -4276,7 +4660,7 @@ static struct builtin builtin_terminal =
    " seconds. The option --lines specifies the maximum number of lines."
    " The option --silent is used to suppress messages."
  };
@@ -37472,7 +39156,7 @@ index 3e08a86..3333ae3 100644
  
  
  #ifdef SUPPORT_SERIAL
-@@ -4462,6 +4757,7 @@ static struct builtin builtin_testload =
+@@ -4462,6 +4846,7 @@ static struct builtin builtin_testload =
    " step is to try loading a kernel."
  };
  
@@ -37480,7 +39164,7 @@ index 3e08a86..3333ae3 100644
  
  /* testvbe MODE */
  static int
-@@ -4566,6 +4862,7 @@ static struct builtin builtin_testvbe =
+@@ -4566,6 +4951,7 @@ static struct builtin builtin_testvbe =
    "testvbe MODE",
    "Test the VBE mode MODE. Hit any key to return."
  };
@@ -37488,7 +39172,7 @@ index 3e08a86..3333ae3 100644
  
  
  #ifdef SUPPORT_NETBOOT
-@@ -4598,6 +4895,15 @@ static struct builtin builtin_tftpserver =
+@@ -4598,6 +4984,15 @@ static struct builtin builtin_tftpserver =
  static int
  timeout_func (char *arg, int flags)
  {
@@ -37504,7 +39188,7 @@ index 3e08a86..3333ae3 100644
    if (! safe_parse_maxint (&arg, &grub_timeout))
      return 1;
  
-@@ -4661,6 +4967,7 @@ static struct builtin builtin_unhide =
+@@ -4661,6 +5056,7 @@ static struct builtin builtin_unhide =
    " partition type code."
  };
  
@@ -37512,12 +39196,32 @@ index 3e08a86..3333ae3 100644
  
  /* uppermem */
  static int
-@@ -4790,11 +5097,15 @@ static struct builtin builtin_vbeprobe =
+@@ -4790,11 +5186,34 @@ static struct builtin builtin_vbeprobe =
    "Probe VBE information. If the mode number MODE is specified, show only"
    " the information about only the mode."
  };
+-  
 +#endif /* ! PLATFORM_EFI */
-   
++
++
++/* version */
++static int
++version_func (char *arg, int flags)
++{
++  grub_printf ("\n    GNU GRUB  version %s  (%dK lower / %dK upper memory)\n\n",
++                version_string, mbi.mem_lower, mbi.mem_upper);
++  return 0;
++}
++
++static struct builtin builtin_version =
++{
++  "version",
++  version_func,
++  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
++  "version",
++  "Display grub version."
++};
++
  
  /* The table of builtin commands. Sorted in dictionary order.  */
  struct builtin *builtin_table[] =
@@ -37528,7 +39232,7 @@ index 3e08a86..3333ae3 100644
    &builtin_blocklist,
    &builtin_boot,
  #ifdef SUPPORT_NETBOOT
-@@ -4802,6 +5113,7 @@ struct builtin *builtin_table[] =
+@@ -4802,25 +5221,36 @@ struct builtin *builtin_table[] =
  #endif /* SUPPORT_NETBOOT */
    &builtin_cat,
    &builtin_chainloader,
@@ -37536,7 +39240,13 @@ index 3e08a86..3333ae3 100644
    &builtin_cmp,
    &builtin_color,
    &builtin_configfile,
-@@ -4813,14 +5125,21 @@ struct builtin *builtin_table[] =
+   &builtin_debug,
+   &builtin_default,
+-#ifdef GRUB_UTIL
++#if defined(GRUB_UTIL) || defined(PLATFORM_EFI)
+   &builtin_device,
+-#endif /* GRUB_UTIL */
++#endif /* defined(GRUB_UTIL) || defined(PLATFORM_EFI) */
  #ifdef SUPPORT_NETBOOT
    &builtin_dhcp,
  #endif /* SUPPORT_NETBOOT */
@@ -37547,6 +39257,9 @@ index 3e08a86..3333ae3 100644
  #ifdef GRUB_UTIL
    &builtin_dump,
  #endif /* GRUB_UTIL */
++#ifdef PLATFORM_EFI
++  &builtin_efimap,
++#endif
 +#ifndef PLATFORM_EFI
    &builtin_embed,
 +#endif
@@ -37558,7 +39271,7 @@ index 3e08a86..3333ae3 100644
    &builtin_fstest,
    &builtin_geometry,
    &builtin_halt,
-@@ -4830,27 +5149,35 @@ struct builtin *builtin_table[] =
+@@ -4830,27 +5260,35 @@ struct builtin *builtin_table[] =
  #ifdef SUPPORT_NETBOOT
    &builtin_ifconfig,
  #endif /* SUPPORT_NETBOOT */
@@ -37596,7 +39309,7 @@ index 3e08a86..3333ae3 100644
  #ifdef SUPPORT_NETBOOT
    &builtin_rarp,
  #endif /* SUPPORT_NETBOOT */
-@@ -4862,23 +5189,32 @@ struct builtin *builtin_table[] =
+@@ -4862,23 +5300,35 @@ struct builtin *builtin_table[] =
  #ifdef SUPPORT_SERIAL
    &builtin_serial,
  #endif /* SUPPORT_SERIAL */
@@ -37605,6 +39318,7 @@ index 3e08a86..3333ae3 100644
    &builtin_setup,
 -#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES)
 +#endif
++  &builtin_silent,
 +#ifdef SUPPORT_GRAPHICS
 +  &builtin_splashimage,
 +#endif /* SUPPORT_GRAPHICS */
@@ -37629,13 +39343,15 @@ index 3e08a86..3333ae3 100644
    &builtin_uppermem,
    &builtin_vbeprobe,
 +#endif
++  &builtin_verbose,
++  &builtin_version,
    0
  };
 diff --git a/stage2/char_io.c b/stage2/char_io.c
-index c86c240..f1313cb 100644
+index c86c240..073201a 100644
 --- a/stage2/char_io.c
 +++ b/stage2/char_io.c
-@@ -35,6 +35,7 @@ struct term_entry term_table[] =
+@@ -35,29 +35,37 @@ struct term_entry term_table[] =
      {
        "console",
        0,
@@ -37643,7 +39359,9 @@ index c86c240..f1313cb 100644
        console_putchar,
        console_checkkey,
        console_getkey,
-@@ -43,13 +44,16 @@ struct term_entry term_table[] =
++      console_keystatus,
+       console_getxy,
+       console_gotoxy,
        console_cls,
        console_setcolorstate,
        console_setcolor,
@@ -37661,7 +39379,9 @@ index c86c240..f1313cb 100644
        serial_putchar,
        serial_checkkey,
        serial_getkey,
-@@ -58,6 +62,8 @@ struct term_entry term_table[] =
++      0,
+       serial_getxy,
+       serial_gotoxy,
        serial_cls,
        serial_setcolorstate,
        0,
@@ -37670,7 +39390,7 @@ index c86c240..f1313cb 100644
        0
      },
  #endif /* SUPPORT_SERIAL */
-@@ -65,6 +71,7 @@ struct term_entry term_table[] =
+@@ -65,17 +73,39 @@ struct term_entry term_table[] =
      {
        "hercules",
        0,
@@ -37678,7 +39398,9 @@ index c86c240..f1313cb 100644
        hercules_putchar,
        console_checkkey,
        console_getkey,
-@@ -73,9 +80,28 @@ struct term_entry term_table[] =
++      console_keystatus,
+       hercules_getxy,
+       hercules_gotoxy,
        hercules_cls,
        hercules_setcolorstate,
        hercules_setcolor,
@@ -37695,6 +39417,7 @@ index c86c240..f1313cb 100644
 +      graphics_putchar, /* putchar */
 +      console_checkkey, /* checkkey */
 +      console_getkey, /* getkey */
++      console_keystatus, /* keystatus */
 +      graphics_getxy, /* getxy */
 +      graphics_gotoxy, /* gotoxy */
 +      graphics_cls, /* cls */
@@ -37708,7 +39431,7 @@ index c86c240..f1313cb 100644
      /* This must be the last entry.  */
      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
    };
-@@ -101,16 +127,16 @@ print_error (void)
+@@ -101,16 +131,16 @@ print_error (void)
  }
  
  char *
@@ -37728,7 +39451,7 @@ index c86c240..f1313cb 100644
      {
        num = (~num) + 1;
        *(ptr++) = '-';
-@@ -149,87 +175,223 @@ grub_putstr (const char *str)
+@@ -149,87 +179,266 @@ grub_putstr (const char *str)
      grub_putchar (*str++);
  }
  
@@ -37785,13 +39508,15 @@ index c86c240..f1313cb 100644
  }
  
 -#ifndef STAGE1_5
-+#define format_ascii(buf, val, is_hex, is_cap) ({                   \
++#define format_ascii(buf, val, is_hex, is_cap, num_pad_chars) ({    \
 +        int _n = sizeof ((buf)) - 2;                                \
 +        typeof(val) _nval = (val);                                  \
 +        int _negative = 0;                                          \
 +        int _mult = is_hex ? 16 : 10;                               \
 +        char _a = is_cap ? 'A' : 'a';                               \
-+        memset((buf), '\0', sizeof ((buf)));                        \
++	int _pad = num_pad_chars; \
++		    char hex[] = "0123456789abcdef"; \
++        memset((buf), '\0', sizeof ((buf)));			    \
 +        if (!(_nval > 0LL))                                         \
 +            _negative = 1;                                          \
 +        if (_nval == 0LL)                                           \
@@ -37801,12 +39526,15 @@ index c86c240..f1313cb 100644
 +        do {                                                        \
 +            int _dig = _nval % _mult;                               \
 +            (buf)[_n--] = ((_dig > 9) ? _dig + _a - 10 : '0'+_dig); \
++	    if (_pad > 0) _pad--; \
 +        } while (_nval /= _mult);                                   \
++	while (_pad--) \
++		(buf)[_n--] = '0'; \
 +        if (_negative)                                              \
 +            (buf)[_n--] = '-';                                      \
 +        _mult = 0;                                                  \
 +        _n++;                                                       \
-+        while (_n < sizeof ((buf)))                                 \
++        while (_n < sizeof ((buf)))				    \
 +            (buf)[_mult++] = (buf)[_n++];                           \
 +        if (_negative && _mult > 1)                                 \
 +            ((buf)[_mult-2])++;                                     \
@@ -37843,6 +39571,8 @@ index c86c240..f1313cb 100644
 +
 +    char *str_arg;
 +    int int_arg;
++    unsigned char uchar_arg;
++    unsigned ushort_arg;
 +    unsigned int uint_arg;
 +    signed long long_arg;
 +    unsigned long ulong_arg;
@@ -37853,7 +39583,9 @@ index c86c240..f1313cb 100644
 +    if (!c)
 +        return 0;
 +
-+    int is_fmt = 0, is_long = 0, is_signed = 1, is_cap = 0, restart = 1;
++    int is_fmt = 0, is_long = 0, is_signed = 1, is_cap = 0, is_zero_padded = 0;
++    int num_pad_chars = 0;
++    int restart = 1;
 +    do {
 +        if (restart) {
 +            restart = 0;
@@ -37861,6 +39593,8 @@ index c86c240..f1313cb 100644
 +            is_long = 0;
 +            is_cap = 0;
 +            is_signed = 1;
++	    is_zero_padded = 0;
++	    num_pad_chars = 0;
 +            buf[0] = '\0';
 +            pos = 0;
 +        }
@@ -37886,10 +39620,31 @@ index c86c240..f1313cb 100644
 +                write_char(&str, c, &count);
 +                restart = 1;
 +                continue;
++	    case '0':
++	    	if (!is_zero_padded) {
++		    	buf[pos++] = c;
++			buf[pos] = '\0';
++			is_zero_padded++;
++			continue;
++		}
++	    case '1':
++	    case '2':
++	    case '3':
++	    case '4':
++	    case '5':
++	    case '6':
++	    case '7':
++	    case '8':
++	    case '9':
++		buf[pos++] = c;
++		buf[pos] = '\0';
++		num_pad_chars *= 10;
++		num_pad_chars += c - '0';
++		continue;
 +            case 'l':
 +                buf[pos++] = c;
 +                buf[pos] = '\0';
-+                is_long ++;
++                is_long++;
 +                continue;
 +            case 'L':
 +                buf[pos++] = c;
@@ -37911,13 +39666,13 @@ index c86c240..f1313cb 100644
 +            case 'd':
 +                if (is_long == 0) {
 +                    int_arg = va_arg(args, signed int);
-+                    format_ascii(buf, int_arg, 0, 0);
++                    format_ascii(buf, int_arg, 0, 0, 0);
 +                } else if (is_long == 1) {
 +                    long_arg = va_arg(args, signed long);
-+                    format_ascii(buf, long_arg, 0, 0);
++                    format_ascii(buf, long_arg, 0, 0, 0);
 +                } else {
 +                    longlong_arg = va_arg(args, signed long long);
-+                    format_ascii(buf, longlong_arg, 0, 0);
++                    format_ascii(buf, longlong_arg, 0, 0, 0);
 +                }
 +                write_str(&str, buf, &count);
 +                restart = 1;
@@ -37931,13 +39686,13 @@ index c86c240..f1313cb 100644
 +            case 'U':
 +                if (is_long == 0) {
 +                    uint_arg = va_arg(args, unsigned int);
-+                    format_ascii(buf, uint_arg, 0, 0);
++                    format_ascii(buf, uint_arg, 0, 0, 0);
 +                } else if (is_long == 1) {
 +                    ulong_arg = va_arg(args, unsigned long);
-+                    format_ascii(buf, ulong_arg, 0, 0);
++                    format_ascii(buf, ulong_arg, 0, 0, 0);
 +                } else {
 +                    ulonglong_arg = va_arg(args, unsigned long long);
-+                    format_ascii(buf, ulonglong_arg, 0, 0);
++                    format_ascii(buf, ulonglong_arg, 0, 0, 0);
 +                }
 +                write_str(&str, buf, &count);
 +                restart = 1;
@@ -37946,7 +39701,8 @@ index c86c240..f1313cb 100644
 +                is_cap = 1;
 +            case 'p':
 +                ulong_arg = va_arg(args, unsigned long);
-+                format_ascii(buf, ulong_arg, 1, is_cap);
++		is_zero_padded = 1;
++                format_ascii(buf, ulong_arg, 1, is_cap, sizeof(ulong_arg));
 +                write_str(&str, is_cap ? "0X" : "0x", &count);
 +                write_str(&str, buf, &count);
 +                restart = 1;
@@ -37954,15 +39710,25 @@ index c86c240..f1313cb 100644
 +            case 'X':
 +                is_cap = 1;
 +            case 'x':
-+                if (is_long == 0) {
++	    	if (num_pad_chars == 2) {
++		    int i;
++		    char hex[] = "0123456789abcdef";
++		    uint_arg = va_arg(args, unsigned int);
++		    uchar_arg = uint_arg & 0xff;
++		    format_ascii(buf, uchar_arg, 1, is_cap, num_pad_chars);
++		} else if (num_pad_chars == 4) {
++		    uint_arg = va_arg(args, unsigned int);
++		    ushort_arg = uint_arg & 0xffff;
++		    format_ascii(buf, ushort_arg, 1, is_cap, num_pad_chars);
++		} else if (is_long == 0) {
 +                    uint_arg = va_arg(args, unsigned int);
-+                    format_ascii(buf, uint_arg, 1, is_cap);
++                    format_ascii(buf, uint_arg, 1, is_cap, num_pad_chars);
 +                } else if (is_long == 1) {
 +                    ulong_arg = va_arg(args, unsigned long);
-+                    format_ascii(buf, ulong_arg, 1, is_cap);
++                    format_ascii(buf, ulong_arg, 1, is_cap, num_pad_chars);
 +                } else {
 +                    ulonglong_arg = va_arg(args, unsigned long long);
-+                    format_ascii(buf, ulonglong_arg, 1, is_cap);
++                    format_ascii(buf, ulonglong_arg, 1, is_cap, num_pad_chars);
 +                }
 +                write_str(&str, buf, &count);
 +                restart = 1;
@@ -38021,7 +39787,40 @@ index c86c240..f1313cb 100644
  }
  
  
-@@ -1046,13 +1208,15 @@ grub_putchar (int c)
+@@ -898,7 +1107,6 @@ safe_parse_maxint (char **str_ptr, int *myint_ptr)
+ }
+ #endif /* STAGE1_5 */
+ 
+-#if !defined(STAGE1_5) || defined(FSYS_FAT)
+ int
+ grub_tolower (int c)
+ {
+@@ -907,7 +1115,6 @@ grub_tolower (int c)
+ 
+   return c;
+ }
+-#endif /* ! STAGE1_5 || FSYS_FAT */
+ 
+ int
+ grub_isspace (int c)
+@@ -1004,6 +1211,16 @@ checkkey (void)
+ {
+   return current_term->checkkey ();
+ }
++
++/* Return keyboard modifier status. */
++int
++keystatus (void)
++{
++  if (current_term->keystatus)
++    return current_term->keystatus ();
++  else 
++    return 0;
++}
+ #endif /* ! STAGE1_5 */
+ 
+ /* Display an ASCII character.  */
+@@ -1046,13 +1263,15 @@ grub_putchar (int c)
  		 the following grub_printf call will print newlines.  */
  	      count_lines = -1;
  
@@ -38038,7 +39837,7 @@ index c86c240..f1313cb 100644
  	      
  	      do
  		{
-@@ -1090,7 +1254,7 @@ void
+@@ -1090,7 +1309,7 @@ void
  cls (void)
  {
    /* If the terminal is dumb, there is no way to clean the terminal.  */
@@ -38047,20 +39846,185 @@ index c86c240..f1313cb 100644
      grub_putchar ('\n');
    else
      current_term->cls ();
-@@ -1174,39 +1338,41 @@ grub_strlen (const char *str)
+@@ -1125,6 +1344,26 @@ substring (const char *s1, const char *s2)
+   return 1;
  }
- #endif /* ! STAGE1_5 */
  
--int
++int
++subcasestring (const char *s1, const char *s2)
++{
++  while (tolower(*s1) == tolower(*s2))
++    {
++      /* The strings match exactly. */
++      if (! *(s1++))
++	return 0;
++      s2 ++;
++    }
++
++  /* S1 is a substring of S2. */
++  if (*s1 == 0)
++    return -1;
++
++  /* S1 isn't a substring. */
++  return 1;
++}
++
++
+ #ifndef STAGE1_5
+ /* Terminate the string STR with NUL.  */
+ int
+@@ -1172,41 +1411,180 @@ grub_strlen (const char *str)
+ 
+   return len;
+ }
+-#endif /* ! STAGE1_5 */
+ 
++/* this function "borrowed" from dietlibc */
+ int
 -memcheck (int addr, int len)
--{
- #ifdef GRUB_UTIL
++grub_strspn(const char *s, const char *accept)
+ {
+-#ifdef GRUB_UTIL
 -  auto int start_addr (void);
 -  auto int end_addr (void);
 -  
 -  auto int start_addr (void)
--    {
++  int l=0;
++  int a=1,i,al=grub_strlen(accept);
++
++  while((a)&&(*s))
++  {
++    for(a=i=0;(!a)&&(i<al);i++)
++      if (*s==accept[i]) a=1;
++    if (a) l++;
++    s++;
++  }
++  return l;
++}
++
++/* this function "borrowed" from dietlibc */
++int
++grub_strcspn(const char *s, const char *reject)
++{
++  int l=0;
++  int a=1,i,al=grub_strlen(reject);
++
++  while((a)&&(*s))
++  {
++    for(i=0;(a)&&(i<al);i++)
++      if (*s==reject[i]) a=0;
++    if (a) l++;
++    s++;
++  }
++  return l;
++}
++
++/* this function "borrowed" from dietlibc */
++char *
++grub_strtok_r(char *s, const char *delim, char **ptrptr) {
++  char *tmp=0;
++
++  if (s==0) s=*ptrptr;
++  s+=grub_strspn(s,delim);           /* overread leading delimiter */
++  if (*s) {
++    tmp=s;
++    s+=grub_strcspn(s,delim);
++    if (*s) *s++=0;   /* not the end ? => terminate it */
++  }
++  *ptrptr=s;
++  return tmp;
++}
++
++char *
++grub_strchr (const char *s, int c)
++{
++  while (*s)
+     {
 -      int ret;
++      if (*s == c)
++	return (char *) s;
++      s++;
++    }
++
++  return 0;
++}
++
++char *
++grub_strnchr (const char *s, int c)
++{
++  while (*s)
++    {
++      if (*s != c)
++	return (char *) s;
++      s++;
++    }
++
++  return 0;
++}
++
++char *
++grub_strrchr (const char *s, int c)
++{
++  char *p = 0;
++
++  while (*s)
++    {
++      if (*s == c)
++	p = (char *) s;
++      s++;
++    }
++
++  return p;
++}
++
++int
++grub_strnlen (const char *s, int n)
++{
++  int i;
++
++  if (n == 0)
++    return 0;
++
++  for (i = 0; s[i] != '\0' && i < n; i++)
++    ;
++  return i;
++}
++
++char *
++grub_strncpy(char *new, const char *s, int n)
++{
++  int i;
++
++  for (i = 0; s[i] != '\0' && i < n; i++)
++    new[i] = s[i];
++  return new;
++}
++
++int
++grub_strncasecmp(const char *s0, const char *s1, int n)
++{
++  int c0, c1;
++
++  if (s0 == s1 || n == 0)
++    return 0;
++
++  do {
++    c0 = *s0 & ~0x20;
++    c1 = *s1 & ~0x20;
++
++    if (--n == 0 || c0 == '\0')
++      break;
++
++    *s0++;
++    *s1++;
++  } while (c0 == c1);
++
++  return (c0 > c1 ? 1 : c0 < c1 ? -1 : 0);
++}
++
++#endif /* ! STAGE1_5 */
++
++#ifdef GRUB_UTIL
 +static int memcheck_start_addr (void)
 +{
 +  int ret;
@@ -38110,7 +40074,7 @@ index c86c240..f1313cb 100644
    if ((addr < RAW_ADDR (0x1000))
        || (addr < RAW_ADDR (0x100000)
  	  && RAW_ADDR (mbi.mem_lower * 1024) < (addr + len))
-@@ -1215,12 +1381,23 @@ memcheck (int addr, int len)
+@@ -1215,12 +1593,23 @@ memcheck (int addr, int len)
      errnum = ERR_WONT_FIT;
  
    return ! errnum;
@@ -38135,7 +40099,7 @@ index c86c240..f1313cb 100644
       {
         /* This assembly code is stolen from
  	  linux-2.2.2/include/asm-i386/string.h. This is not very fast
-@@ -1258,7 +1435,7 @@ grub_memset (void *start, int c, int len)
+@@ -1258,7 +1647,7 @@ grub_memset (void *start, int c, int len)
  {
    char *p = start;
  
@@ -38144,8 +40108,35 @@ index c86c240..f1313cb 100644
      {
        while (len -- > 0)
  	*p ++ = c;
+@@ -1274,6 +1663,26 @@ grub_strcpy (char *dest, const char *src)
+   grub_memmove (dest, src, grub_strlen (src) + 1);
+   return dest;
+ }
++
++char *
++grub_stpncpy (char *dest, const char *src, int n)
++{
++  char *res;
++
++  res = NULL;
++  while (n != 0) {
++    *dest = *src;
++    if (*src != 0)
++      src++;
++    else if (res == NULL)
++      res = dest;
++    dest++;
++    n--;
++  }
++  if (res == NULL)
++    res = dest;
++  return res;
++}
+ #endif /* ! STAGE1_5 */
+ 
+ #ifndef GRUB_UTIL
 diff --git a/stage2/cmdline.c b/stage2/cmdline.c
-index a6ee309..044fd02 100644
+index a6ee309..cb41eda 100644
 --- a/stage2/cmdline.c
 +++ b/stage2/cmdline.c
 @@ -48,12 +48,17 @@ skip_to (int after_equal, char *cmdline)
@@ -38187,10 +40178,34 @@ index a6ee309..044fd02 100644
        if (! *heap)
  	{
  	  /* If there is no more command in SCRIPT...  */
+@@ -232,12 +237,12 @@ run_script (char *script, char *heap)
+       builtin = find_command (heap);
+       if (! builtin)
+ 	{
+-	  grub_printf ("%s\n", old_entry);
++	  grub_verbose_printf ("%s\n", old_entry);
+ 	  continue;
+ 	}
+ 
+       if (! (builtin->flags & BUILTIN_NO_ECHO))
+-	grub_printf ("%s\n", old_entry);
++	grub_verbose_printf ("%s\n", old_entry);
+ 
+       /* If BUILTIN cannot be run in the command-line, skip it.  */
+       if (! (builtin->flags & BUILTIN_CMDLINE))
 diff --git a/stage2/common.c b/stage2/common.c
-index 09f9e31..21c07f2 100644
+index 09f9e31..e96bec2 100644
 --- a/stage2/common.c
 +++ b/stage2/common.c
+@@ -32,7 +32,7 @@
+ struct multiboot_info mbi;
+ unsigned long saved_drive;
+ unsigned long saved_partition;
+-unsigned long cdrom_drive;
++unsigned long cdrom_drive = 0x100;
+ #ifndef STAGE1_5
+ unsigned long saved_mem_upper;
+ 
 @@ -114,7 +114,7 @@ mmap_avail_at (unsigned long bottom)
      {
        for (cont = 0, addr = mbi.mmap_addr;
@@ -38243,10 +40258,10 @@ index 09f9e31..21c07f2 100644
    
    /* Start main routine here.  */
 diff --git a/stage2/disk_io.c b/stage2/disk_io.c
-index b9bc526..622bdbb 100644
+index b9bc526..d54864f 100644
 --- a/stage2/disk_io.c
 +++ b/stage2/disk_io.c
-@@ -21,6 +21,7 @@
+@@ -21,12 +21,17 @@
  
  #include <shared.h>
  #include <filesys.h>
@@ -38254,7 +40269,27 @@ index b9bc526..622bdbb 100644
  
  #ifdef SUPPORT_NETBOOT
  # define GRUB	1
-@@ -127,8 +128,8 @@ struct geometry buf_geom;
+ # include <etherboot.h>
+ #endif
+ 
++#ifdef PLATFORM_EFI
++#include "efistubs.h"
++#endif
++
+ #ifdef GRUB_UTIL
+ # include <device.h>
+ #endif
+@@ -48,6 +53,9 @@ int fsmax;
+ struct fsys_entry fsys_table[NUM_FSYS + 1] =
+ {
+   /* TFTP should come first because others don't handle net device.  */
++# ifdef PLATFORM_EFI
++  {"efitftp", efi_tftp_mount, efi_tftp_read, efi_tftp_dir, efi_tftp_close, 0},
++# endif
+ # ifdef FSYS_TFTP
+   {"tftp", tftp_mount, tftp_read, tftp_dir, tftp_close, 0},
+ # endif
+@@ -127,8 +135,8 @@ struct geometry buf_geom;
  int filepos;
  int filemax;
  
@@ -38265,7 +40300,7 @@ index b9bc526..622bdbb 100644
  {
    asm volatile ("bsfl %1,%0"
  		: "=r" (word)
-@@ -140,7 +141,7 @@ int
+@@ -140,7 +148,7 @@ int
  rawread (int drive, int sector, int byte_offset, int byte_len, char *buf)
  {
    int slen, sectors_per_vtrack;
@@ -38274,7 +40309,7 @@ index b9bc526..622bdbb 100644
  
    if (byte_len <= 0)
      return 1;
-@@ -163,7 +164,7 @@ rawread (int drive, int sector, int byte_offset, int byte_len, char *buf)
+@@ -163,7 +171,7 @@ rawread (int drive, int sector, int byte_offset, int byte_len, char *buf)
  	    }
  	  buf_drive = drive;
  	  buf_track = -1;
@@ -38283,7 +40318,7 @@ index b9bc526..622bdbb 100644
  	}
  
        /* Make sure that SECTOR is valid.  */
-@@ -502,8 +503,8 @@ int
+@@ -502,8 +510,8 @@ int
  set_partition_hidden_flag (int hidden)
  {
    unsigned long part = 0xFFFFFF;
@@ -38294,7 +40329,7 @@ index b9bc526..622bdbb 100644
    char mbr[512];
    
    /* The drive must be a hard disk.  */
-@@ -524,8 +525,15 @@ set_partition_hidden_flag (int hidden)
+@@ -524,8 +532,15 @@ set_partition_hidden_flag (int hidden)
    /* Look for the partition.  */
    while (next_partition (current_drive, 0xFFFFFF, &part, &type,           
  			 &start, &len, &offset, &entry,
@@ -38312,7 +40347,7 @@ index b9bc526..622bdbb 100644
        if (part == current_partition)
  	{
  	  /* Found.  */
-@@ -577,11 +585,14 @@ next_partition (unsigned long drive, unsigned long dest,
+@@ -577,11 +592,14 @@ next_partition (unsigned long drive, unsigned long dest,
  		unsigned long *partition, int *type,
  		unsigned long *start, unsigned long *len,
  		unsigned long *offset, int *entry,
@@ -38328,7 +40363,7 @@ index b9bc526..622bdbb 100644
  
    /* Get next BSD partition in current PC slice.  */
    int next_bsd_partition (void)
-@@ -666,6 +677,40 @@ next_partition (unsigned long drive, unsigned long dest,
+@@ -666,6 +684,40 @@ next_partition (unsigned long drive, unsigned long dest,
  	  return 0;
  	}
  
@@ -38369,7 +40404,7 @@ index b9bc526..622bdbb 100644
        /* Increase the entry number.  */
        (*entry)++;
  
-@@ -710,6 +755,43 @@ next_partition (unsigned long drive, unsigned long dest,
+@@ -710,6 +762,43 @@ next_partition (unsigned long drive, unsigned long dest,
        return 1;
      }
  
@@ -38413,7 +40448,7 @@ index b9bc526..622bdbb 100644
    /* Start the body of this function.  */
    
  #ifndef STAGE1_5
-@@ -717,6 +799,9 @@ next_partition (unsigned long drive, unsigned long dest,
+@@ -717,6 +806,9 @@ next_partition (unsigned long drive, unsigned long dest,
      return 0;
  #endif
  
@@ -38423,7 +40458,7 @@ index b9bc526..622bdbb 100644
    /* If previous partition is a BSD partition or a PC slice which
       contains BSD partitions...  */
    if ((*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_BSD (*type & 0xff))
-@@ -755,6 +840,9 @@ real_open_partition (int flags)
+@@ -755,6 +847,9 @@ real_open_partition (int flags)
    unsigned long dest_partition = current_partition;
    unsigned long part_offset;
    unsigned long ext_offset;
@@ -38433,7 +40468,7 @@ index b9bc526..622bdbb 100644
    int entry;
    char buf[SECTOR_SIZE];
    int bsd_part, pc_slice;
-@@ -766,7 +854,8 @@ real_open_partition (int flags)
+@@ -766,7 +861,8 @@ real_open_partition (int flags)
        int ret = next_partition (current_drive, dest_partition,
  				&current_partition, &current_slice,
  				&part_start, &part_length,
@@ -38443,6 +40478,78 @@ index b9bc526..622bdbb 100644
        bsd_part = (current_partition >> 8) & 0xFF;
        pc_slice = current_partition >> 16;
        return ret;
+@@ -978,7 +1074,7 @@ set_device (char *device)
+       if (*device != ',' && *device != ')')
+ 	{
+ 	  char ch = *device;
+-#ifdef SUPPORT_NETBOOT
++#if defined(SUPPORT_NETBOOT) || defined(PLATFORM_EFI)
+ 	  if (*device == 'f' || *device == 'h'
+ 	      || (*device == 'n' && network_ready)
+ 	      || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
+@@ -1002,14 +1098,14 @@ set_device (char *device)
+ 
+ 	  if ((*device == 'f'
+ 	       || *device == 'h'
+-#ifdef SUPPORT_NETBOOT
++#if defined(SUPPORT_NETBOOT) || defined(PLATFORM_EFI)
+ 	       || (*device == 'n' && network_ready)
+ #endif
+ 	       || (*device == 'c' && cdrom_drive != GRUB_INVALID_DRIVE))
+ 	      && (device += 2, (*(device - 1) != 'd')))
+ 	    errnum = ERR_NUMBER_PARSING;
+-	  
+-#ifdef SUPPORT_NETBOOT
++
++#if defined(SUPPORT_NETBOOT) || defined(PLATFORM_EFI)
+ 	  if (ch == 'n' && network_ready)
+ 	    current_drive = NETWORK_DRIVE;
+ 	  else
+@@ -1376,7 +1472,7 @@ print_completions (int is_filename, int is_completion)
+ 
+ 	      if (!ptr
+ 		  || *(ptr-1) != 'd'
+-#ifdef SUPPORT_NETBOOT
++#if defined(SUPPORT_NETBOOT) || defined(PLATFORM_EFI)
+ 		  || *(ptr-2) != 'n'
+ #endif /* SUPPORT_NETBOOT */
+ 		  || *(ptr-2) != 'c')
+@@ -1407,7 +1503,7 @@ print_completions (int is_filename, int is_completion)
+ 		      || (*(ptr-1) == 'd' && *(ptr-2) == 'c')))
+ 		print_a_completion ("cd");
+ 
+-# ifdef SUPPORT_NETBOOT
++# if defined(SUPPORT_NETBOOT) || defined(PLATFORM_EFI)
+ 	      if (network_ready
+ 		  && (disk_choice || NETWORK_DRIVE == current_drive)
+ 		  && (!ptr
+diff --git a/stage2/efistubs.c b/stage2/efistubs.c
+new file mode 100644
+index 0000000..29b086a
+--- /dev/null
++++ b/stage2/efistubs.c
+@@ -0,0 +1,7 @@
++
++#include "shared.h"
++#include "efistubs.h"
++
++#if defined(PLATFORM_EFI)
++int network_ready = 0;
++#endif /* defined(PLATFORM_EFI) */
+diff --git a/stage2/efistubs.h b/stage2/efistubs.h
+new file mode 100644
+index 0000000..97e407d
+--- /dev/null
++++ b/stage2/efistubs.h
+@@ -0,0 +1,8 @@
++#ifndef EFISTUBS_H
++#define EFISTUBS_H 1
++
++#if defined(PLATFORM_EFI)
++extern int network_ready;
++#endif /* defined(PLATFORM_EFI) */
++
++#endif /* EFISTUBS_H */
 diff --git a/stage2/fat.h b/stage2/fat.h
 index 7fed6ba..f154eed 100644
 --- a/stage2/fat.h
@@ -38457,10 +40564,37 @@ index 7fed6ba..f154eed 100644
  #define FAT_LONGDIR_ID(entry) \
    (*((unsigned char *) (entry)))
 diff --git a/stage2/filesys.h b/stage2/filesys.h
-index bbad8b9..4ea0728 100644
+index bbad8b9..4295e45 100644
 --- a/stage2/filesys.h
 +++ b/stage2/filesys.h
-@@ -137,8 +137,8 @@ int iso9660_dir (char *dirname);
+@@ -115,6 +115,17 @@ void tftp_close (void);
+ #define FSYS_TFTP_NUM 0
+ #endif
+ 
++#ifdef PLATFORM_EFI
++#define FSYS_EFI_TFTP_NUM 1
++int efi_tftp_mount (void);
++int efi_tftp_read (char *buf, int len);
++int efi_tftp_dir (char *dirname);
++void efi_tftp_close (void);
++#else
++#define FSYS_EFI_TFTP_NUM 0
++#endif
++
++
+ #ifdef FSYS_ISO9660
+ #define FSYS_ISO9660_NUM 1
+ int iso9660_mount (void);
+@@ -128,7 +139,7 @@ int iso9660_dir (char *dirname);
+ #define NUM_FSYS	\
+   (FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_EXT2FS_NUM + FSYS_MINIX_NUM	\
+    + FSYS_REISERFS_NUM + FSYS_VSTAFS_NUM + FSYS_JFS_NUM + FSYS_XFS_NUM	\
+-   + FSYS_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM)
++   + FSYS_TFTP_NUM + FSYS_EFI_TFTP_NUM + FSYS_ISO9660_NUM + FSYS_UFS2_NUM)
+ #endif
+ 
+ /* defines for the block filesystem info area */
+@@ -137,8 +148,8 @@ int iso9660_dir (char *dirname);
  #define BLK_CUR_BLKLIST      (*((int*)(FSYS_BUF+4)))
  #define BLK_CUR_BLKNUM       (*((int*)(FSYS_BUF+8)))
  #define BLK_MAX_ADDR         (FSYS_BUF+0x7FF9)
@@ -38472,14 +40606,54 @@ index bbad8b9..4ea0728 100644
  #define BLK_BLKLIST_INC_VAL  8
  #endif /* NO_BLOCK_FILES */
 diff --git a/stage2/fsys_ext2fs.c b/stage2/fsys_ext2fs.c
-index 560048f..1c07035 100644
+index 560048f..810ac5f 100644
 --- a/stage2/fsys_ext2fs.c
 +++ b/stage2/fsys_ext2fs.c
-@@ -79,7 +79,52 @@ struct ext2_super_block
+@@ -41,6 +41,7 @@ typedef __signed__ short __s16;
+ typedef unsigned short __u16;
+ typedef __signed__ int __s32;
+ typedef unsigned int __u32;
++typedef unsigned long long __u64;
+ 
+ /*
+  * Constants relative to the data blocks, from ext2_fs.h
+@@ -51,7 +52,7 @@ typedef unsigned int __u32;
+ #define EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)
+ #define EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)
+ 
+-/* include/linux/ext2_fs.h */
++/* lib/ext2fs/ext2_fs.h from e2fsprogs */
+ struct ext2_super_block
+   {
+     __u32 s_inodes_count;	/* Inodes count */
+@@ -61,9 +62,9 @@ struct ext2_super_block
+     __u32 s_free_inodes_count;	/* Free inodes count */
+     __u32 s_first_data_block;	/* First Data Block */
+     __u32 s_log_block_size;	/* Block size */
+-    __s32 s_log_frag_size;	/* Fragment size */
++    __s32 s_obso_log_frag_size;	/* Obsoleted Fragment size */
+     __u32 s_blocks_per_group;	/* # Blocks per group */
+-    __u32 s_frags_per_group;	/* # Fragments per group */
++    __u32 s_obso_frags_per_group;	/* Obsoleted Fragments per group */
+     __u32 s_inodes_per_group;	/* # Inodes per group */
+     __u32 s_mtime;		/* Mount time */
+     __u32 s_wtime;		/* Write time */
+@@ -72,17 +73,76 @@ struct ext2_super_block
+     __u16 s_magic;		/* Magic signature */
+     __u16 s_state;		/* File system state */
+     __u16 s_errors;		/* Behaviour when detecting errors */
+-    __u16 s_pad;
++    __u16 s_minor_rev_level;	/* minor revision level */
+     __u32 s_lastcheck;		/* time of last check */
+     __u32 s_checkinterval;	/* max. time between checks */
+     __u32 s_creator_os;		/* OS */
      __u32 s_rev_level;		/* Revision level */
      __u16 s_def_resuid;		/* Default uid for reserved blocks */
      __u16 s_def_resgid;		/* Default gid for reserved blocks */
 -    __u32 s_reserved[235];	/* Padding to the end of the block */
+-  };
+-
+-struct ext2_group_desc
 +    /*
 +     * These fields are for EXT2_DYNAMIC_REV superblocks only.
 +     *
@@ -38520,16 +40694,183 @@ index 560048f..1c07035 100644
 +    __u32 s_hash_seed[4];	/* HTREE hash seed */
 +    __u8  s_def_hash_version;	/* Default hash version to use */
 +    __u8  s_jnl_backup_type; 	/* Default type of journal backup */
-+    __u16 s_reserved_word_pad;
++    __u16 s_desc_size;		/* size of group descriptor */
 +    __u32 s_default_mount_opts;
 +    __u32 s_first_meta_bg;	/* First metablock group */
 +    __u32 s_mkfs_time;		/* When the filesystem was created */
 +    __u32 s_jnl_blocks[17]; 	/* Backup of the journal inode */
-+    __u32 s_reserved[172];	/* Padding to the end of the block */
++    /* 64bit desc support valid if EXT4_FEATURE_INCOMPAT_64BIT */
++    __u32 s_blocks_count_hi;	/* Blocks count */
++    __u32 s_r_blocks_count_hi;	/* Reserved blocks count */
++    __u32 s_free_blocks_count_hi; /* Free blocks count */
++    __u16 s_min_extra_isize;	/* All inodes have at least # bytes */
++    __u16 s_max_extra_isize;	/* New inodes should reverve # bytes */
++    __u32 s_flags;		/* Miscellaneous flags */
++    __u16 s_raid_stride;	/* Raid stride */
++    __u16 s_mmp_interval;	/* # seconds to wait MMP checking */
++    __u64 s_mmp_block;		/* Block for multi-mount protection */
++    __u32 s_raid_stripe_width;	/* Blocks on all data disks (N*stride)*/
++    __u8  s_log_groups_per_flex;/* FLEX_BG group size*/
++    __u8  s_reserved_char_pad;
++    __u16 s_reserved_pad;
++    __u32 s_reserved[162];	/* Padding to the end of the block */
++};
++
++struct ext4_group_desc
+   {
+     __u32 bg_block_bitmap;	/* Blocks bitmap block */
+     __u32 bg_inode_bitmap;	/* Inodes bitmap block */
+@@ -90,8 +150,18 @@ struct ext2_group_desc
+     __u16 bg_free_blocks_count;	/* Free blocks count */
+     __u16 bg_free_inodes_count;	/* Free inodes count */
+     __u16 bg_used_dirs_count;	/* Directories count */
+-    __u16 bg_pad;
+-    __u32 bg_reserved[3];
++    __u16 bg_flags;		/* EXT4_BG_flags (INODE_UNINIT, etc) */
++    __u32 bg_reserved[2];		/* Likely block/inode bitmap checksum */
++    __u16 bg_itable_unused;	/* Unused inodes count */
++    __u16 bg_checksum;		/* crc16(sb_uuid+group+desc) */
++    __u32 bg_block_bitmap_hi;	/* Blocks bitmap block MSB */
++    __u32 bg_inode_bitmap_hi;	/* Inodes bitmap block MSB */
++    __u32 bg_inode_table_hi;	/* Inodes table block MSB */
++    __u16 bg_free_blocks_count_hi;/* Free blocks count MSB */
++    __u16 bg_free_inodes_count_hi;/* Free inodes count MSB */
++    __u16 bg_used_dirs_count_hi;	/* Directories count MSB */
++    __u16 bg_itable_unused_hi;	/* Unused inodes count MSB */
++    __u32 bg_reserved2[3];
+   };
+ 
+ struct ext2_inode
+@@ -129,22 +199,22 @@ struct ext2_inode
+     __u32 i_block[EXT2_N_BLOCKS];	/* 40: Pointers to blocks */
+     __u32 i_version;		/* File version (for NFS) */
+     __u32 i_file_acl;		/* File ACL */
+-    __u32 i_dir_acl;		/* Directory ACL */
+-    __u32 i_faddr;		/* Fragment address */
++    __u32 i_size_high;
++    __u32 i_obso_faddr;		/* Obsoleted fragment address */
+     union
+       {
+ 	struct
+ 	  {
+-	    __u8 l_i_frag;	/* Fragment number */
+-	    __u8 l_i_fsize;	/* Fragment size */
+-	    __u16 i_pad1;
+-	    __u32 l_i_reserved2[2];
++		__u16	l_i_blocks_high; /* were l_i_reserved1 */
++		__u16	l_i_file_acl_high;
++		__u16	l_i_uid_high;	/* these 2 fields */
++		__u16	l_i_gid_high;	/* were reserved2[0] */
++		__u32	l_i_reserved2;
+ 	  }
+ 	linux2;
+ 	struct
+ 	  {
+-	    __u8 h_i_frag;	/* Fragment number */
+-	    __u8 h_i_fsize;	/* Fragment size */
++		__u16	h_i_reserved1;	/* Obsoleted fragment number/size which are removed in ext4 */
+ 	    __u16 h_i_mode_high;
+ 	    __u16 h_i_uid_high;
+ 	    __u16 h_i_gid_high;
+@@ -153,16 +223,36 @@ struct ext2_inode
+ 	hurd2;
+ 	struct
+ 	  {
+-	    __u8 m_i_frag;	/* Fragment number */
+-	    __u8 m_i_fsize;	/* Fragment size */
+-	    __u16 m_pad1;
++		__u16	h_i_reserved1;	/* Obsoleted fragment number/size which are removed in ext4 */
++		__u16	m_i_file_acl_high;
+ 	    __u32 m_i_reserved2[2];
+ 	  }
+ 	masix2;
+       }
+     osd2;			/* OS dependent 2 */
++	__u16	i_extra_isize;
++	__u16	i_pad1;
++	__u32  i_ctime_extra;  /* extra Change time      (nsec << 2 | epoch) */
++	__u32  i_mtime_extra;  /* extra Modification time(nsec << 2 | epoch) */
++	__u32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
++	__u32  i_crtime;       /* File Creation time */
++	__u32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
++	__u32  i_version_hi;	/* high 32 bits for 64-bit version */
    };
  
- struct ext2_group_desc
-@@ -206,18 +251,21 @@ struct ext2_dir_entry
++#define EXT4_FEATURE_INCOMPAT_EXTENTS		0x0040 /* extents support */
++#define EXT4_FEATURE_INCOMPAT_64BIT			0x0080 /* grub not supported*/
++#define EXT4_FEATURE_INCOMPAT_MMP           0x0100
++#define EXT4_FEATURE_INCOMPAT_FLEX_BG		0x0200
++
++#define EXT4_HAS_INCOMPAT_FEATURE(sb,mask)			\
++	( sb->s_feature_incompat & mask )
++
++#define EXT4_EXTENTS_FL		0x00080000 /* Inode uses extents */
++#define EXT4_HUGE_FILE_FL	0x00040000 /* Set to each huge file */
++
++#define EXT4_MIN_DESC_SIZE			32
++
+ /* linux/limits.h */
+ #define NAME_MAX         255	/* # chars in a file name */
+ 
+@@ -180,6 +270,57 @@ struct ext2_dir_entry
+     char name[EXT2_NAME_LEN];	/* File name */
+   };
+ 
++/* linux/ext4_fs_extents.h */
++/* This is the extent on-disk structure.
++ * It's used at the bottom of the tree.
++ */
++struct ext4_extent
++  {
++	__u32  ee_block;   /* first logical block extent covers */
++	__u16  ee_len;     /* number of blocks covered by extent */
++	__u16  ee_start_hi;    /* high 16 bits of physical block */
++	__u32  ee_start_lo;    /* low 32 bits of physical block */
++  };
++
++/*
++ * This is index on-disk structure.
++ * It's used at all the levels except the bottom.
++ */
++struct ext4_extent_idx
++  {
++    __u32  ei_block;   /* index covers logical blocks from 'block' */
++    __u32  ei_leaf_lo; /* pointer to the physical block of the next *
++	                     * level. leaf or next index could be there */
++    __u16  ei_leaf_hi; /* high 16 bits of physical block */
++    __u16  ei_unused;
++  };
++
++/*
++ * Each block (leaves and indexes), even inode-stored has header.
++ */
++struct ext4_extent_header
++  {
++    __u16  eh_magic;   /* probably will support different formats */
++    __u16  eh_entries; /* number of valid entries */
++    __u16  eh_max;     /* capacity of store in entries */
++    __u16  eh_depth;   /* has tree real underlying blocks? */
++    __u32  eh_generation;  /* generation of the tree */
++  };
++
++#define EXT4_EXT_MAGIC      (0xf30a)
++#define EXT_FIRST_EXTENT(__hdr__) \
++    ((struct ext4_extent *) (((char *) (__hdr__)) +     \
++                 sizeof(struct ext4_extent_header)))
++#define EXT_FIRST_INDEX(__hdr__) \
++    ((struct ext4_extent_idx *) (((char *) (__hdr__)) + \
++                 sizeof(struct ext4_extent_header)))
++#define EXT_LAST_EXTENT(__hdr__) \
++    (EXT_FIRST_EXTENT((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1)
++#define EXT_LAST_INDEX(__hdr__) \
++    (EXT_FIRST_INDEX((__hdr__)) + (__u16)((__hdr__)->eh_entries) - 1)
++
++
++
+ /* linux/ext2fs.h */
+ /*
+  * EXT2_DIR_PAD defines the directory entries boundaries
+@@ -206,25 +347,37 @@ struct ext2_dir_entry
      ((struct ext2_super_block *)(FSYS_BUF))
  #define GROUP_DESC \
      ((struct ext2_group_desc *) \
@@ -38555,7 +40896,24 @@ index 560048f..1c07035 100644
  /* linux/ext2_fs.h */
  #define EXT2_BLOCK_SIZE_BITS(s)        ((s)->s_log_block_size + 10)
  /* kind of from ext2/super.c */
-@@ -239,8 +287,8 @@ struct ext2_dir_entry
+ #define EXT2_BLOCK_SIZE(s)	(1 << EXT2_BLOCK_SIZE_BITS(s))
+ /* linux/ext2fs.h */
++/* sizeof(struct ext2_group_desc) is changed in ext4
++ * in kernel code, ext2/3 uses sizeof(struct ext2_group_desc) to calculate
++ * number of desc per block, while ext4 uses superblock->s_desc_size in stead
++ * superblock->s_desc_size is not available in ext2/3
++ * */
++#define EXT2_DESC_SIZE(s) \
++	(EXT4_HAS_INCOMPAT_FEATURE(s,EXT4_FEATURE_INCOMPAT_64BIT)? \
++	s->s_desc_size : EXT4_MIN_DESC_SIZE)
+ #define EXT2_DESC_PER_BLOCK(s) \
+-     (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
++	(EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s))
++
+ /* linux/stat.h */
+ #define S_IFMT  00170000
+ #define S_IFLNK  0120000
+@@ -239,8 +392,8 @@ struct ext2_dir_entry
   * ffz = Find First Zero in word. Undefined if no zero exists,
   * so code should check against ~0UL first..
   */
@@ -38566,7 +40924,7 @@ index 560048f..1c07035 100644
  {
    __asm__ ("bsfl %1,%0"
  :	   "=r" (word)
-@@ -276,7 +324,7 @@ ext2_rdfsb (int fsblock, int buffer)
+@@ -276,7 +429,7 @@ ext2_rdfsb (int fsblock, int buffer)
    printf ("fsblock %d buffer %d\n", fsblock, buffer);
  #endif /* E2DEBUG */
    return devread (fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0,
@@ -38575,7 +40933,151 @@ index 560048f..1c07035 100644
  }
  
  /* from
-@@ -546,18 +594,18 @@ ext2fs_dir (char *dirname)
+@@ -386,6 +539,122 @@ ext2fs_block_map (int logical_block)
+     [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
+ }
+ 
++/* extent binary search index
++ * find closest index in the current level extent tree
++ * kind of from ext4_ext_binsearch_idx in ext4/extents.c
++ */
++static struct ext4_extent_idx*
++ext4_ext_binsearch_idx(struct ext4_extent_header* eh, int logical_block)
++{
++  struct ext4_extent_idx *r, *l, *m;
++  l = EXT_FIRST_INDEX(eh) + 1;
++  r = EXT_LAST_INDEX(eh);
++  while (l <= r)
++    {
++	  m = l + (r - l) / 2;
++	  if (logical_block < m->ei_block)
++		  r = m - 1;
++	  else
++		  l = m + 1;
++	}
++  return (struct ext4_extent_idx*)(l - 1);
++}
++
++/* extent binary search
++ * find closest extent in the leaf level
++ * kind of from ext4_ext_binsearch in ext4/extents.c
++ */
++static struct ext4_extent*
++ext4_ext_binsearch(struct ext4_extent_header* eh, int logical_block)
++{
++  struct ext4_extent *r, *l, *m;
++  l = EXT_FIRST_EXTENT(eh) + 1;
++  r = EXT_LAST_EXTENT(eh);
++  while (l <= r)
++    {
++	  m = l + (r - l) / 2;
++	  if (logical_block < m->ee_block)
++		  r = m - 1;
++	  else
++		  l = m + 1;
++	}
++  return (struct ext4_extent*)(l - 1);
++}
++
++/* Maps extents enabled logical block into physical block via an inode.
++ * EXT4_HUGE_FILE_FL should be checked before calling this.
++ */
++static int
++ext4fs_block_map (int logical_block)
++{
++  struct ext4_extent_header *eh;
++  struct ext4_extent *ex, *extent;
++  struct ext4_extent_idx *ei, *index;
++  int depth;
++  int i;
++
++#ifdef E2DEBUG
++  unsigned char *i;
++  for (i = (unsigned char *) INODE;
++       i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
++       i++)
++    {
++      printf ("%c", "0123456789abcdef"[*i >> 4]);
++      printf ("%c", "0123456789abcdef"[*i % 16]);
++      if (!((i + 1 - (unsigned char *) INODE) % 16))
++	{
++	  printf ("\n");
++	}
++      else
++	{
++	  printf (" ");
++	}
++    }
++  printf ("logical block %d\n", logical_block);
++#endif /* E2DEBUG */
++  eh = (struct ext4_extent_header*)INODE->i_block;
++  if (eh->eh_magic != EXT4_EXT_MAGIC)
++  {
++          errnum = ERR_FSYS_CORRUPT;
++          return -1;
++  }
++  while((depth = eh->eh_depth) != 0)
++  	{ /* extent index */
++	  if (eh->eh_magic != EXT4_EXT_MAGIC)
++	  {
++	          errnum = ERR_FSYS_CORRUPT;
++		  return -1;
++	  }
++	  ei = ext4_ext_binsearch_idx(eh, logical_block);
++	  if (ei->ei_leaf_hi)
++	{/* 64bit physical block number not supported */
++	  errnum = ERR_FILELENGTH;
++	  return -1;
++	}
++	  if (!ext2_rdfsb(ei->ei_leaf_lo, DATABLOCK1))
++	{
++	  errnum = ERR_FSYS_CORRUPT;
++	  return -1;
++	}
++	  eh = (struct ext4_extent_header*)DATABLOCK1;
++  	}
++
++  /* depth==0, we come to the leaf */
++  ex = ext4_ext_binsearch(eh, logical_block);
++  if (ex->ee_start_hi)
++	{/* 64bit physical block number not supported */
++	  errnum = ERR_FILELENGTH;
++	  return -1;
++	}
++  if ((ex->ee_block + ex->ee_len) < logical_block)
++	{
++	  errnum = ERR_FSYS_CORRUPT;
++	  return -1;
++	}
++  return ex->ee_start_lo + logical_block - ex->ee_block;
++
++}
++
+ /* preconditions: all preconds of ext2fs_block_map */
+ int
+ ext2fs_read (char *buf, int len)
+@@ -420,6 +689,11 @@ ext2fs_read (char *buf, int len)
+       /* find the (logical) block component of our location */
+       logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
+       offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
++      /* map extents enabled logical block number to physical fs on-disk block number */
++      if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS)
++                    && INODE->i_flags & EXT4_EXTENTS_FL)
++          map = ext4fs_block_map (logical_block);
++      else
+       map = ext2fs_block_map (logical_block);
+ #ifdef E2DEBUG
+       printf ("map=%d\n", map);
+@@ -504,7 +778,7 @@ ext2fs_dir (char *dirname)
+   int desc;			/* index within that group */
+   int ino_blk;			/* fs pointer of the inode's information */
+   int str_chk = 0;		/* used to hold the results of a string compare */
+-  struct ext2_group_desc *gdp;
++  struct ext4_group_desc *ext4_gdp;
+   struct ext2_inode *raw_inode;	/* inode info corresponding to current_ino */
+ 
+   char linkbuf[PATH_MAX];	/* buffer for following symbolic links */
+@@ -546,18 +820,25 @@ ext2fs_dir (char *dirname)
  #endif /* E2DEBUG */
        if (!ext2_rdfsb (
  			(WHICH_SUPER + group_desc + SUPERBLOCK->s_first_data_block),
@@ -38584,8 +41086,17 @@ index 560048f..1c07035 100644
  	{
  	  return 0;
  	}
-       gdp = GROUP_DESC;
-       ino_blk = gdp[desc].bg_inode_table +
+-      gdp = GROUP_DESC;
+-      ino_blk = gdp[desc].bg_inode_table +
++	  ext4_gdp = (struct ext4_group_desc *)( (__u8*)GROUP_DESC +
++			  		desc * EXT2_DESC_SIZE(SUPERBLOCK));
++	  if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK, EXT4_FEATURE_INCOMPAT_64BIT)
++		&& (! ext4_gdp->bg_inode_table_hi))
++	{/* 64bit itable not supported */
++	  errnum = ERR_FILELENGTH;
++	  return -1;
++	}
++      ino_blk = ext4_gdp->bg_inode_table +
  	(((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group))
 -	 >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)));
 +	 >> log2 (EXT2_INODES_PER_BLOCK (SUPERBLOCK)));
@@ -38597,7 +41108,7 @@ index 560048f..1c07035 100644
  	{
  	  return 0;
  	}
-@@ -565,13 +613,12 @@ ext2fs_dir (char *dirname)
+@@ -565,13 +846,12 @@ ext2fs_dir (char *dirname)
        /* reset indirect blocks! */
        mapblock2 = mapblock1 = -1;
  
@@ -38615,8 +41126,75 @@ index 560048f..1c07035 100644
        printf ("inode=%x, raw_inode=%x\n", INODE, raw_inode);
        printf ("offset into inode table block=%d\n", (int) raw_inode - (int) INODE);
        for (i = (unsigned char *) INODE; i <= (unsigned char *) raw_inode;
+@@ -629,7 +909,10 @@ ext2fs_dir (char *dirname)
+ 	    }
+ 	  linkbuf[filemax + len] = '\0';
+ 
+-	  /* Read the symlink data. */
++	  /* Read the symlink data.
++	   * Slow symlink is extents enabled
++	   * But since grub_read invokes ext2fs_read, nothing to change here
++	   */
+ 	  if (! ext2_is_fast_symlink ())
+ 	    {
+ 	      /* Read the necessary blocks, and reset the file pointer. */
+@@ -640,7 +923,9 @@ ext2fs_dir (char *dirname)
+ 	    }
+ 	  else
+ 	    {
+-	      /* Copy the data directly from the inode. */
++	      /* Copy the data directly from the inode.
++	       * Fast symlink is not extents enabled
++	       */
+ 	      len = filemax;
+ 	      memmove (linkbuf, (char *) INODE->i_block, len);
+ 	    }
+@@ -674,6 +959,13 @@ ext2fs_dir (char *dirname)
+ 	      errnum = ERR_BAD_FILETYPE;
+ 	      return 0;
+ 	    }
++	  /* if file is too large, just stop and report an error*/
++	  if ( (INODE->i_flags & EXT4_HUGE_FILE_FL) && !(INODE->i_size_high))
++	    {
++		  /* file too large, stop reading */
++		  errnum = ERR_FILELENGTH;
++		  return 0;
++	    }
+ 
+ 	  filemax = (INODE->i_size);
+ 	  return 1;
+@@ -728,17 +1020,28 @@ ext2fs_dir (char *dirname)
+ 	    }
+ 
+ 	  /* else, find the (logical) block component of our location */
++	  /* ext4 logical block number the same as ext2/3 */
+ 	  blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
+ 
+ 	  /* we know which logical block of the directory entry we are looking
+ 	     for, now we have to translate that to the physical (fs) block on
+ 	     the disk */
++	  /* map extents enabled logical block number to physical fs on-disk block number */
++	  if (EXT4_HAS_INCOMPAT_FEATURE(SUPERBLOCK,EXT4_FEATURE_INCOMPAT_EXTENTS)
++                        && INODE->i_flags & EXT4_EXTENTS_FL)
++              map = ext4fs_block_map (blk);
++	  else
+ 	  map = ext2fs_block_map (blk);
+ #ifdef E2DEBUG
+ 	  printf ("fs block=%d\n", map);
+ #endif /* E2DEBUG */
+ 	  mapblock2 = -1;
+-	  if ((map < 0) || !ext2_rdfsb (map, DATABLOCK2))
++	  if (map < 0)
++	  {
++	      *rest = ch;
++	      return 0;
++	  }
++          if (!ext2_rdfsb (map, DATABLOCK2))
+ 	    {
+ 	      errnum = ERR_FSYS_CORRUPT;
+ 	      *rest = ch;
 diff --git a/stage2/fsys_fat.c b/stage2/fsys_fat.c
-index f40e658..57a556c 100644
+index f40e658..266ec03 100644
 --- a/stage2/fsys_fat.c
 +++ b/stage2/fsys_fat.c
 @@ -54,8 +54,8 @@ struct fat_superblock
@@ -38661,6 +41239,33 @@ index f40e658..57a556c 100644
    
    *rest = 0;
    
+@@ -432,7 +435,7 @@ fat_dir (char *dirname)
+ 		goto print_filename;
+ # endif /* STAGE1_5 */
+ 	      
+-	      if (substring (dirname, filename) == 0)
++	      if (subcasestring (dirname, filename) == 0)
+ 		break;
+ 	    }
+ 	}
+@@ -459,7 +462,7 @@ fat_dir (char *dirname)
+       if (do_possibilities)
+ 	{
+ 	print_filename:
+-	  if (substring (dirname, filename) <= 0)
++	  if (subcasestring (dirname, filename) <= 0)
+ 	    {
+ 	      if (print_possibilities > 0)
+ 		print_possibilities = -print_possibilities;
+@@ -469,7 +472,7 @@ fat_dir (char *dirname)
+ 	}
+ # endif /* STAGE1_5 */
+       
+-      if (substring (dirname, filename) == 0)
++      if (subcasestring (dirname, filename) == 0)
+ 	break;
+     }
+   
 diff --git a/stage2/fsys_iso9660.c b/stage2/fsys_iso9660.c
 index 90e4aa8..4d8a300 100644
 --- a/stage2/fsys_iso9660.c
@@ -38869,10 +41474,10 @@ index a116717..652e784 100644
      }
    
 diff --git a/stage2/fsys_xfs.c b/stage2/fsys_xfs.c
-index 76c4c13..1c01c3b 100644
+index 76c4c13..d5214d3 100644
 --- a/stage2/fsys_xfs.c
 +++ b/stage2/fsys_xfs.c
-@@ -97,8 +97,8 @@ ino2offset (xfs_ino_t ino)
+@@ -97,19 +97,23 @@ ino2offset (xfs_ino_t ino)
  	return ino & XFS_INO_MASK(XFS_INO_OFFSET_BITS);
  }
  
@@ -38881,10 +41486,14 @@ index 76c4c13..1c01c3b 100644
 +static inline xfs_uint16_t __attribute__((__const__))
 +le16 (xfs_uint16_t x) 
  {
++#if 1
++	return ((x & 0xff00) >> 8) | ((x & 0xff) << 8);
++#else
  	__asm__("xchgb %b0,%h0"	\
  		: "=q" (x) \
-@@ -106,10 +106,10 @@ le16 (xfs_uint16_t x)
+ 		:  "0" (x)); \
  		return x;
++#endif
  }
  
 -static inline __const__ xfs_uint32_t
@@ -38896,7 +41505,7 @@ index 76c4c13..1c01c3b 100644
          /* 386 doesn't have bswap.  */
  	__asm__("bswap %0" : "=r" (x) : "0" (x));
  #else
-@@ -122,7 +122,7 @@ le32 (xfs_uint32_t x)
+@@ -122,7 +126,7 @@ le32 (xfs_uint32_t x)
  	return x;
  }
  
@@ -38905,7 +41514,7 @@ index 76c4c13..1c01c3b 100644
  le64 (xfs_uint64_t x)
  {
  	xfs_uint32_t h = x >> 32;
-@@ -187,12 +187,12 @@ fsb2daddr (xfs_fsblock_t fsbno)
+@@ -187,12 +191,12 @@ fsb2daddr (xfs_fsblock_t fsbno)
  }
  
  #undef offsetof
@@ -38921,15 +41530,6 @@ index 76c4c13..1c01c3b 100644
  
  	return (tmp - sizeof(xfs_bmdr_block_t) - offsetof(xfs_dinode_t, di_u)) /
  		(sizeof (xfs_bmbt_key_t) + sizeof (xfs_bmbt_ptr_t));
-@@ -334,7 +334,7 @@ next_dentry (xfs_ino_t *ino)
- {
- 	int namelen = 1;
- 	int toread;
--	static char usual[2][3] = {".", ".."};
-+	static char *usual[2] = {".", ".."};
- 	static xfs_dir2_sf_entry_t *sfe;
- 	char *name = usual[0];
- 
 diff --git a/stage2/gpt.h b/stage2/gpt.h
 new file mode 100644
 index 0000000..71ed0b8
@@ -39006,7 +41606,7 @@ index 0000000..71ed0b8
 +#endif /* _GPT_H */
 diff --git a/stage2/graphics.c b/stage2/graphics.c
 new file mode 100644
-index 0000000..7f943f7
+index 0000000..81109ae
 --- /dev/null
 +++ b/stage2/graphics.c
 @@ -0,0 +1,573 @@
@@ -39552,10 +42152,10 @@ index 0000000..7f943f7
 +                offset += 80;
 +            }
 +            else {
-+                chr[i     ] = mask;
-+                chr[16 + i] = mask;
-+                chr[32 + i] = mask;
-+                chr[48 + i] = mask;
++                chr[i     ] = ~mask;
++                chr[16 + i] = ~mask;
++                chr[32 + i] = ~mask;
++                chr[48 + i] = ~mask;
 +            }
 +        }
 +    }
@@ -39715,7 +42315,7 @@ index 1e1e63b..3a8dcfb 100644
    /* unspecified optional padding... */
  } __attribute__ ((packed));
 diff --git a/stage2/pc_slice.h b/stage2/pc_slice.h
-index a38d97f..755e318 100644
+index a38d97f..2206e82 100644
 --- a/stage2/pc_slice.h
 +++ b/stage2/pc_slice.h
 @@ -38,50 +38,50 @@
@@ -39781,15 +42381,26 @@ index a38d97f..755e318 100644
  			  + (part << 4)) ) )
  
  
-@@ -115,6 +115,7 @@
+@@ -115,6 +115,8 @@
  #define PC_SLICE_TYPE_LINUX_EXTENDED	0x85
  #define PC_SLICE_TYPE_VSTAFS		0x9e
  #define PC_SLICE_TYPE_DELL_UTIL		0xde
 +#define PC_SLICE_TYPE_GPT              0xee
++#define PC_SLICE_TYPE_EFI		0xef
  #define PC_SLICE_TYPE_LINUX_RAID	0xfd
  
  
-@@ -177,40 +178,40 @@
+@@ -129,7 +131,8 @@
+      || _type == PC_SLICE_TYPE_FAT16_LBA \
+      || _type == PC_SLICE_TYPE_FAT32 \
+      || _type == PC_SLICE_TYPE_FAT32_LBA \
+-     || _type == PC_SLICE_TYPE_DELL_UTIL; })
++     || _type == PC_SLICE_TYPE_DELL_UTIL \
++     || _type == PC_SLICE_TYPE_EFI; })
+ 
+ #define IS_PC_SLICE_TYPE_EXTENDED(type)	\
+   (((type) == PC_SLICE_TYPE_EXTENDED)	\
+@@ -177,40 +180,40 @@
   */
  
  #define BSD_LABEL_CHECK_MAG(l_ptr) \
@@ -39863,8 +42474,1538 @@ index 16c376f..37b9532 100644
  
  
  /* Generic definitions.  */
+diff --git a/stage2/sha256crypt.c b/stage2/sha256crypt.c
+new file mode 100644
+index 0000000..db168a2
+--- /dev/null
++++ b/stage2/sha256crypt.c
+@@ -0,0 +1,723 @@
++/* SHA256-based Unix crypt implementation.
++   Released into the Public Domain by Ulrich Drepper <drepper at redhat.com>.
++   Adapted for grub by Miloslav Trmac <mitr at redhat.com>. */
++
++#include <stdbool.h>
++#include <stddef.h>
++
++#include <shared.h>
++
++typedef unsigned int uint32_t;
++typedef size_t uintptr_t;
++#define alloca(SIZE) (__builtin_alloca (SIZE))
++#define MIN(A, B) ((A) < (B) ? (A) : (B))
++#define MAX(A, B) ((A) > (B) ? (A) : (B))
++
++/* Structure to save state of computation between the single steps.  */
++struct sha256_ctx
++{
++  uint32_t H[8];
++
++  uint32_t total[2];
++  uint32_t buflen;
++  char buffer[128];	/* NB: always correctly aligned for uint32_t.  */
++};
++
++
++#if 1 /* __BYTE_ORDER == __LITTLE_ENDIAN */
++# define SWAP(n) \
++    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
++#else
++# define SWAP(n) (n)
++#endif
++
++
++/* This array contains the bytes used to pad the buffer to the next
++   64-byte boundary.  (FIPS 180-2:5.1.1)  */
++static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };
++
++
++/* Constants for SHA256 from FIPS 180-2:4.2.2.  */
++static const uint32_t K[64] =
++  {
++    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
++    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
++    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
++    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
++    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
++    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
++    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
++    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
++    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
++    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
++    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
++    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
++    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
++    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
++    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
++    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
++  };
++
++
++/* Process LEN bytes of BUFFER, accumulating context into CTX.
++   It is assumed that LEN % 64 == 0.  */
++static void
++sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx)
++{
++  const uint32_t *words = buffer;
++  size_t nwords = len / sizeof (uint32_t);
++  uint32_t a = ctx->H[0];
++  uint32_t b = ctx->H[1];
++  uint32_t c = ctx->H[2];
++  uint32_t d = ctx->H[3];
++  uint32_t e = ctx->H[4];
++  uint32_t f = ctx->H[5];
++  uint32_t g = ctx->H[6];
++  uint32_t h = ctx->H[7];
++
++  /* First increment the byte count.  FIPS 180-2 specifies the possible
++     length of the file up to 2^64 bits.  Here we only compute the
++     number of bytes.  Do a double word increment.  */
++  ctx->total[0] += len;
++  if (ctx->total[0] < len)
++    ++ctx->total[1];
++
++  /* Process all bytes in the buffer with 64 bytes in each round of
++     the loop.  */
++  while (nwords > 0)
++    {
++      uint32_t W[64];
++      uint32_t a_save = a;
++      uint32_t b_save = b;
++      uint32_t c_save = c;
++      uint32_t d_save = d;
++      uint32_t e_save = e;
++      uint32_t f_save = f;
++      uint32_t g_save = g;
++      uint32_t h_save = h;
++      unsigned int t;
++
++      /* Operators defined in FIPS 180-2:4.1.2.  */
++#define Ch(x, y, z) ((x & y) ^ (~x & z))
++#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
++#define S0(x) (CYCLIC (x, 2) ^ CYCLIC (x, 13) ^ CYCLIC (x, 22))
++#define S1(x) (CYCLIC (x, 6) ^ CYCLIC (x, 11) ^ CYCLIC (x, 25))
++#define R0(x) (CYCLIC (x, 7) ^ CYCLIC (x, 18) ^ (x >> 3))
++#define R1(x) (CYCLIC (x, 17) ^ CYCLIC (x, 19) ^ (x >> 10))
++
++      /* It is unfortunate that C does not provide an operator for
++	 cyclic rotation.  Hope the C compiler is smart enough.  */
++#define CYCLIC(w, s) ((w >> s) | (w << (32 - s)))
++
++      /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2.  */
++      for (t = 0; t < 16; ++t)
++	{
++	  W[t] = SWAP (*words);
++	  ++words;
++	}
++      for (t = 16; t < 64; ++t)
++	W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16];
++
++      /* The actual computation according to FIPS 180-2:6.2.2 step 3.  */
++      for (t = 0; t < 64; ++t)
++	{
++	  uint32_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t];
++	  uint32_t T2 = S0 (a) + Maj (a, b, c);
++	  h = g;
++	  g = f;
++	  f = e;
++	  e = d + T1;
++	  d = c;
++	  c = b;
++	  b = a;
++	  a = T1 + T2;
++	}
++
++      /* Add the starting values of the context according to FIPS 180-2:6.2.2
++	 step 4.  */
++      a += a_save;
++      b += b_save;
++      c += c_save;
++      d += d_save;
++      e += e_save;
++      f += f_save;
++      g += g_save;
++      h += h_save;
++
++      /* Prepare for the next round.  */
++      nwords -= 16;
++    }
++
++  /* Put checksum in context given as argument.  */
++  ctx->H[0] = a;
++  ctx->H[1] = b;
++  ctx->H[2] = c;
++  ctx->H[3] = d;
++  ctx->H[4] = e;
++  ctx->H[5] = f;
++  ctx->H[6] = g;
++  ctx->H[7] = h;
++}
++
++
++/* Initialize structure containing state of computation.
++   (FIPS 180-2:5.3.2)  */
++static void
++sha256_init_ctx (struct sha256_ctx *ctx)
++{
++  ctx->H[0] = 0x6a09e667;
++  ctx->H[1] = 0xbb67ae85;
++  ctx->H[2] = 0x3c6ef372;
++  ctx->H[3] = 0xa54ff53a;
++  ctx->H[4] = 0x510e527f;
++  ctx->H[5] = 0x9b05688c;
++  ctx->H[6] = 0x1f83d9ab;
++  ctx->H[7] = 0x5be0cd19;
++
++  ctx->total[0] = ctx->total[1] = 0;
++  ctx->buflen = 0;
++}
++
++
++/* Process the remaining bytes in the internal buffer and the usual
++   prolog according to the standard and write the result to RESBUF.
++
++   IMPORTANT: On some systems it is required that RESBUF is correctly
++   aligned for a 32 bits value.  */
++static void *
++sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf)
++{
++  /* Take yet unprocessed bytes into account.  */
++  uint32_t bytes = ctx->buflen;
++  size_t pad;
++  unsigned int i;
++
++  /* Now count remaining bytes.  */
++  ctx->total[0] += bytes;
++  if (ctx->total[0] < bytes)
++    ++ctx->total[1];
++
++  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
++  memcpy (&ctx->buffer[bytes], fillbuf, pad);
++
++  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
++  *(uint32_t *) &ctx->buffer[bytes + pad + 4] = SWAP (ctx->total[0] << 3);
++  *(uint32_t *) &ctx->buffer[bytes + pad] = SWAP ((ctx->total[1] << 3) |
++						  (ctx->total[0] >> 29));
++
++  /* Process last bytes.  */
++  sha256_process_block (ctx->buffer, bytes + pad + 8, ctx);
++
++  /* Put result from CTX in first 32 bytes following RESBUF.  */
++  for (i = 0; i < 8; ++i)
++    ((uint32_t *) resbuf)[i] = SWAP (ctx->H[i]);
++
++  return resbuf;
++}
++
++
++static void
++sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx)
++{
++  /* When we already have some bits in our internal buffer concatenate
++     both inputs first.  */
++  if (ctx->buflen != 0)
++    {
++      size_t left_over = ctx->buflen;
++      size_t add = 128 - left_over > len ? len : 128 - left_over;
++
++      memcpy (&ctx->buffer[left_over], buffer, add);
++      ctx->buflen += add;
++
++      if (ctx->buflen > 64)
++	{
++	  sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
++
++	  ctx->buflen &= 63;
++	  /* The regions in the following copy operation cannot overlap.  */
++	  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
++		  ctx->buflen);
++	}
++
++      buffer = (const char *) buffer + add;
++      len -= add;
++    }
++
++  /* Process available complete blocks.  */
++  if (len >= 64)
++    {
++/* To check alignment gcc has an appropriate operator.  Other
++   compilers don't.  */
++#if __GNUC__ >= 2
++# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__ (uint32_t) != 0)
++#else
++# define UNALIGNED_P(p) (((uintptr_t) p) % sizeof (uint32_t) != 0)
++#endif
++      if (UNALIGNED_P (buffer))
++	while (len > 64)
++	  {
++	    sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
++	    buffer = (const char *) buffer + 64;
++	    len -= 64;
++	  }
++      else
++	{
++	  sha256_process_block (buffer, len & ~63, ctx);
++	  buffer = (const char *) buffer + (len & ~63);
++	  len &= 63;
++	}
++    }
++
++  /* Move remaining bytes into internal buffer.  */
++  if (len > 0)
++    {
++      size_t left_over = ctx->buflen;
++
++      memcpy (&ctx->buffer[left_over], buffer, len);
++      left_over += len;
++      if (left_over >= 64)
++	{
++	  sha256_process_block (ctx->buffer, 64, ctx);
++	  left_over -= 64;
++	  memcpy (ctx->buffer, &ctx->buffer[64], left_over);
++	}
++      ctx->buflen = left_over;
++    }
++}
++
++
++/* Define our magic string to mark salt for SHA256 "encryption"
++   replacement.  */
++static const char sha256_salt_prefix[] = "$5$";
++
++/* Prefix for optional rounds specification.  */
++static const char sha256_rounds_prefix[] = "rounds=";
++
++/* Maximum salt string length.  */
++#define SALT_LEN_MAX 16
++/* Default number of rounds if not explicitly specified.  */
++#define ROUNDS_DEFAULT 5000
++/* Minimum number of rounds.  */
++#define ROUNDS_MIN 1000
++/* Maximum number of rounds.  */
++#define ROUNDS_MAX 999999999
++
++/* Table with characters for base64 transformation.  */
++static const char b64t[64] =
++"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
++
++
++static char *
++sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
++{
++  unsigned char alt_result[32]
++    __attribute__ ((__aligned__ (__alignof__ (uint32_t))));
++  unsigned char temp_result[32]
++    __attribute__ ((__aligned__ (__alignof__ (uint32_t))));
++  struct sha256_ctx ctx;
++  struct sha256_ctx alt_ctx;
++  size_t salt_len;
++  size_t key_len;
++  size_t cnt;
++  char *cp;
++  char *copied_key = NULL;
++  char *copied_salt = NULL;
++  char *p_bytes;
++  char *s_bytes;
++  /* Default number of rounds.  */
++  size_t rounds = ROUNDS_DEFAULT;
++  bool rounds_custom = false;
++
++  /* Find beginning of salt string.  The prefix should normally always
++     be present.  Just in case it is not.  */
++  if (grub_memcmp (sha256_salt_prefix, salt,
++		   sizeof (sha256_salt_prefix) - 1) == 0)
++    /* Skip salt prefix.  */
++    salt += sizeof (sha256_salt_prefix) - 1;
++
++  if (grub_memcmp (salt, sha256_rounds_prefix,
++		   sizeof (sha256_rounds_prefix) - 1) == 0)
++    {
++      const char *num = salt + sizeof (sha256_rounds_prefix) - 1;
++      char *endp = (char *)num;
++      int srounds = 0;
++      if (*endp == '0' && tolower (endp[1]) == 'x')
++	/* This would be interpreted as hexadecimal by safe_parse_maxint(). */
++	endp++;
++      else
++	/* On error, endp and srounds is not changed. */
++	safe_parse_maxint(&endp, &srounds);
++      if (*endp == '$')
++	{
++	  salt = endp + 1;
++	  rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
++	  rounds_custom = true;
++	}
++    }
++
++  salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
++  key_len = strlen (key);
++
++  if ((key - (char *) 0) % __alignof__ (uint32_t) != 0)
++    {
++      char *tmp = (char *) alloca (key_len + __alignof__ (uint32_t));
++      key = copied_key =
++	memcpy (tmp + __alignof__ (uint32_t)
++		- (tmp - (char *) 0) % __alignof__ (uint32_t),
++		key, key_len);
++    }
++
++  if ((salt - (char *) 0) % __alignof__ (uint32_t) != 0)
++    {
++      char *tmp = (char *) alloca (salt_len + __alignof__ (uint32_t));
++      salt = copied_salt =
++	memcpy (tmp + __alignof__ (uint32_t)
++		- (tmp - (char *) 0) % __alignof__ (uint32_t),
++		salt, salt_len);
++    }
++
++  /* Prepare for the real work.  */
++  sha256_init_ctx (&ctx);
++
++  /* Add the key string.  */
++  sha256_process_bytes (key, key_len, &ctx);
++
++  /* The last part is the salt string.  This must be at most 16
++     characters and it ends at the first `$' character (for
++     compatibility with existing implementations).  */
++  sha256_process_bytes (salt, salt_len, &ctx);
++
++
++  /* Compute alternate SHA256 sum with input KEY, SALT, and KEY.  The
++     final result will be added to the first context.  */
++  sha256_init_ctx (&alt_ctx);
++
++  /* Add key.  */
++  sha256_process_bytes (key, key_len, &alt_ctx);
++
++  /* Add salt.  */
++  sha256_process_bytes (salt, salt_len, &alt_ctx);
++
++  /* Add key again.  */
++  sha256_process_bytes (key, key_len, &alt_ctx);
++
++  /* Now get result of this (32 bytes) and add it to the other
++     context.  */
++  sha256_finish_ctx (&alt_ctx, alt_result);
++
++  /* Add for any character in the key one byte of the alternate sum.  */
++  for (cnt = key_len; cnt > 32; cnt -= 32)
++    sha256_process_bytes (alt_result, 32, &ctx);
++  sha256_process_bytes (alt_result, cnt, &ctx);
++
++  /* Take the binary representation of the length of the key and for every
++     1 add the alternate sum, for every 0 the key.  */
++  for (cnt = key_len; cnt > 0; cnt >>= 1)
++    if ((cnt & 1) != 0)
++      sha256_process_bytes (alt_result, 32, &ctx);
++    else
++      sha256_process_bytes (key, key_len, &ctx);
++
++  /* Create intermediate result.  */
++  sha256_finish_ctx (&ctx, alt_result);
++
++  /* Start computation of P byte sequence.  */
++  sha256_init_ctx (&alt_ctx);
++
++  /* For every character in the password add the entire password.  */
++  for (cnt = 0; cnt < key_len; ++cnt)
++    sha256_process_bytes (key, key_len, &alt_ctx);
++
++  /* Finish the digest.  */
++  sha256_finish_ctx (&alt_ctx, temp_result);
++
++  /* Create byte sequence P.  */
++  cp = p_bytes = alloca (key_len);
++  for (cnt = key_len; cnt >= 32; cnt -= 32)
++    {
++      memcpy (cp, temp_result, 32);
++      cp += 32;
++    }
++  memcpy (cp, temp_result, cnt);
++
++  /* Start computation of S byte sequence.  */
++  sha256_init_ctx (&alt_ctx);
++
++  /* For every character in the password add the entire password.  */
++  for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
++    sha256_process_bytes (salt, salt_len, &alt_ctx);
++
++  /* Finish the digest.  */
++  sha256_finish_ctx (&alt_ctx, temp_result);
++
++  /* Create byte sequence S.  */
++  cp = s_bytes = alloca (salt_len);
++  for (cnt = salt_len; cnt >= 32; cnt -= 32)
++    {
++      memcpy (cp, temp_result, 32);
++      cp += 32;
++    }
++  memcpy (cp, temp_result, cnt);
++
++  /* Repeatedly run the collected hash value through SHA256 to burn
++     CPU cycles.  */
++  for (cnt = 0; cnt < rounds; ++cnt)
++    {
++      /* New context.  */
++      sha256_init_ctx (&ctx);
++
++      /* Add key or last result.  */
++      if ((cnt & 1) != 0)
++	sha256_process_bytes (p_bytes, key_len, &ctx);
++      else
++	sha256_process_bytes (alt_result, 32, &ctx);
++
++      /* Add salt for numbers not divisible by 3.  */
++      if (cnt % 3 != 0)
++	sha256_process_bytes (s_bytes, salt_len, &ctx);
++
++      /* Add key for numbers not divisible by 7.  */
++      if (cnt % 7 != 0)
++	sha256_process_bytes (p_bytes, key_len, &ctx);
++
++      /* Add key or last result.  */
++      if ((cnt & 1) != 0)
++	sha256_process_bytes (alt_result, 32, &ctx);
++      else
++	sha256_process_bytes (p_bytes, key_len, &ctx);
++
++      /* Create intermediate result.  */
++      sha256_finish_ctx (&ctx, alt_result);
++    }
++
++  /* Now we can construct the result string.  It consists of three
++     parts.  */
++  cp = stpncpy (buffer, sha256_salt_prefix, MAX (0, buflen));
++  buflen -= sizeof (sha256_salt_prefix) - 1;
++
++  if (rounds_custom)
++    {
++      char sbuf[64];
++      grub_sprintf (sbuf, "%s%llu$", sha256_rounds_prefix,
++		    (unsigned long long)rounds);
++      size_t n = strlen (sbuf);
++      memcpy (cp, sbuf, MIN (MAX (0, buflen), n));
++      cp += n;
++      buflen -= n;
++    }
++
++  cp = stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
++  buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
++
++  if (buflen > 0)
++    {
++      *cp++ = '$';
++      --buflen;
++    }
++
++#define b64_from_24bit(B2, B1, B0, N)					      \
++  do {									      \
++    unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0);			      \
++    int n = (N);							      \
++    while (n-- > 0 && buflen > 0)					      \
++      {									      \
++	*cp++ = b64t[w & 0x3f];						      \
++	--buflen;							      \
++	w >>= 6;							      \
++      }									      \
++  } while (0)
++
++  b64_from_24bit (alt_result[0], alt_result[10], alt_result[20], 4);
++  b64_from_24bit (alt_result[21], alt_result[1], alt_result[11], 4);
++  b64_from_24bit (alt_result[12], alt_result[22], alt_result[2], 4);
++  b64_from_24bit (alt_result[3], alt_result[13], alt_result[23], 4);
++  b64_from_24bit (alt_result[24], alt_result[4], alt_result[14], 4);
++  b64_from_24bit (alt_result[15], alt_result[25], alt_result[5], 4);
++  b64_from_24bit (alt_result[6], alt_result[16], alt_result[26], 4);
++  b64_from_24bit (alt_result[27], alt_result[7], alt_result[17], 4);
++  b64_from_24bit (alt_result[18], alt_result[28], alt_result[8], 4);
++  b64_from_24bit (alt_result[9], alt_result[19], alt_result[29], 4);
++  b64_from_24bit (0, alt_result[31], alt_result[30], 3);
++  if (buflen <= 0)
++    buffer = NULL;
++  else
++    *cp = '\0';		/* Terminate the string.  */
++
++  /* Clear the buffer for the intermediate result so that people
++     attaching to processes or reading core dumps cannot get any
++     information.  We do it in this way to clear correct_words[]
++     inside the SHA256 implementation as well.  */
++  sha256_init_ctx (&ctx);
++  sha256_finish_ctx (&ctx, alt_result);
++  memset (temp_result, '\0', sizeof (temp_result));
++  memset (p_bytes, '\0', key_len);
++  memset (s_bytes, '\0', salt_len);
++  memset (&ctx, '\0', sizeof (ctx));
++  memset (&alt_ctx, '\0', sizeof (alt_ctx));
++  if (copied_key != NULL)
++    memset (copied_key, '\0', key_len);
++  if (copied_salt != NULL)
++    memset (copied_salt, '\0', salt_len);
++
++  return buffer;
++}
++
++
++/* This entry point is equivalent to the `crypt' function in Unix
++   libcs.  */
++char *
++sha256_crypt (const char *key, const char *salt)
++{
++  static char buffer[sizeof (sha256_salt_prefix) - 1
++		     + sizeof (sha256_rounds_prefix) + 9 + 1
++		     + 256 + 1 + 43 + 1]; /* 256 bytes for salt */
++  int needed = (sizeof (sha256_salt_prefix) - 1
++		+ sizeof (sha256_rounds_prefix) + 9 + 1
++		+ strlen (salt) + 1 + 43 + 1);
++
++  if (sizeof (buffer) < needed)
++    return NULL;
++
++  return sha256_crypt_r (key, salt, buffer, sizeof (buffer));
++}
++
++
++#ifdef TEST
++static const struct
++{
++  const char *input;
++  const char result[32];
++} tests[] =
++  {
++    /* Test vectors from FIPS 180-2: appendix B.1.  */
++    { "abc",
++      "\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23"
++      "\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad" },
++    /* Test vectors from FIPS 180-2: appendix B.2.  */
++    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
++      "\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39"
++      "\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1" },
++    /* Test vectors from the NESSIE project.  */
++    { "",
++      "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24"
++      "\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55" },
++    { "a",
++      "\xca\x97\x81\x12\xca\x1b\xbd\xca\xfa\xc2\x31\xb3\x9a\x23\xdc\x4d"
++      "\xa7\x86\xef\xf8\x14\x7c\x4e\x72\xb9\x80\x77\x85\xaf\xee\x48\xbb" },
++    { "message digest",
++      "\xf7\x84\x6f\x55\xcf\x23\xe1\x4e\xeb\xea\xb5\xb4\xe1\x55\x0c\xad"
++      "\x5b\x50\x9e\x33\x48\xfb\xc4\xef\xa3\xa1\x41\x3d\x39\x3c\xb6\x50" },
++    { "abcdefghijklmnopqrstuvwxyz",
++      "\x71\xc4\x80\xdf\x93\xd6\xae\x2f\x1e\xfa\xd1\x44\x7c\x66\xc9\x52"
++      "\x5e\x31\x62\x18\xcf\x51\xfc\x8d\x9e\xd8\x32\xf2\xda\xf1\x8b\x73" },
++    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
++      "\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39"
++      "\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1" },
++    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
++      "\xdb\x4b\xfc\xbd\x4d\xa0\xcd\x85\xa6\x0c\x3c\x37\xd3\xfb\xd8\x80"
++      "\x5c\x77\xf1\x5f\xc6\xb1\xfd\xfe\x61\x4e\xe0\xa7\xc8\xfd\xb4\xc0" },
++    { "123456789012345678901234567890123456789012345678901234567890"
++      "12345678901234567890",
++      "\xf3\x71\xbc\x4a\x31\x1f\x2b\x00\x9e\xef\x95\x2d\xd8\x3c\xa8\x0e"
++      "\x2b\x60\x02\x6c\x8e\x93\x55\x92\xd0\xf9\xc3\x08\x45\x3c\x81\x3e" }
++  };
++#define ntests (sizeof (tests) / sizeof (tests[0]))
++
++
++static const struct
++{
++  const char *salt;
++  const char *input;
++  const char *expected;
++} tests2[] =
++{
++  { "$5$saltstring", "Hello world!",
++    "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5" },
++  { "$5$rounds=10000$saltstringsaltstring", "Hello world!",
++    "$5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2."
++    "opqey6IcA" },
++  { "$5$rounds=5000$toolongsaltstring", "This is just a test",
++    "$5$rounds=5000$toolongsaltstrin$Un/5jzAHMgOGZ5.mWJpuVolil07guHPvOW8"
++    "mGRcvxa5" },
++  { "$5$rounds=1400$anotherlongsaltstring",
++    "a very much longer text to encrypt.  This one even stretches over more"
++    "than one line.",
++    "$5$rounds=1400$anotherlongsalts$Rx.j8H.h8HjEDGomFU8bDkXm3XIUnzyxf12"
++    "oP84Bnq1" },
++  { "$5$rounds=77777$short",
++    "we have a short salt string but not a short password",
++    "$5$rounds=77777$short$JiO1O3ZpDAxGJeaDIuqCoEFysAe1mZNJRs3pw0KQRd/" },
++  { "$5$rounds=123456$asaltof16chars..", "a short string",
++    "$5$rounds=123456$asaltof16chars..$gP3VQ/6X7UUEW3HkBn2w1/Ptq2jxPyzV/"
++    "cZKmF/wJvD" },
++  { "$5$rounds=10$roundstoolow", "the minimum number is still observed",
++    "$5$rounds=1000$roundstoolow$yfvwcWrQ8l/K0DAWyuPMDNHpIVlTQebY9l/gL97"
++    "2bIC" },
++};
++#define ntests2 (sizeof (tests2) / sizeof (tests2[0]))
++
++
++int
++sha256_test (void)
++{
++  struct sha256_ctx ctx;
++  char sum[32];
++  int result = 0;
++  int cnt, i;
++
++  for (cnt = 0; cnt < (int) ntests; ++cnt)
++    {
++      sha256_init_ctx (&ctx);
++      sha256_process_bytes (tests[cnt].input, strlen (tests[cnt].input), &ctx);
++      sha256_finish_ctx (&ctx, sum);
++      if (memcmp (tests[cnt].result, sum, 32) != 0)
++	{
++	  printf ("test %d run %d failed\n", cnt, 1);
++	  result = 1;
++	}
++
++      sha256_init_ctx (&ctx);
++      for (i = 0; tests[cnt].input[i] != '\0'; ++i)
++	sha256_process_bytes (&tests[cnt].input[i], 1, &ctx);
++      sha256_finish_ctx (&ctx, sum);
++      if (memcmp (tests[cnt].result, sum, 32) != 0)
++	{
++	  printf ("test %d run %d failed\n", cnt, 2);
++	  result = 1;
++	}
++    }
++
++  /* Test vector from FIPS 180-2: appendix B.3.  */
++  char buf[1000];
++  memset (buf, 'a', sizeof (buf));
++  sha256_init_ctx (&ctx);
++  for (i = 0; i < 1000; ++i)
++    sha256_process_bytes (buf, sizeof (buf), &ctx);
++  sha256_finish_ctx (&ctx, sum);
++  static const char expected[32] =
++    "\xcd\xc7\x6e\x5c\x99\x14\xfb\x92\x81\xa1\xc7\xe2\x84\xd7\x3e\x67"
++    "\xf1\x80\x9a\x48\xa4\x97\x20\x0e\x04\x6d\x39\xcc\xc7\x11\x2c\xd0";
++  if (memcmp (expected, sum, 32) != 0)
++    {
++      printf ("test %d failed\n", cnt);
++      result = 1;
++    }
++
++  for (cnt = 0; cnt < ntests2; ++cnt)
++    {
++      char *cp = sha256_crypt (tests2[cnt].input, tests2[cnt].salt);
++
++      if (strcmp (cp, tests2[cnt].expected) != 0)
++	{
++	  printf ("test %d: expected \"%s\", got \"%s\"\n",
++		  cnt, tests2[cnt].expected, cp);
++	  result = 1;
++	}
++    }
++
++  if (result == 0)
++    printf ("all tests OK\n");
++
++  return result;
++}
++#endif
+diff --git a/stage2/sha512crypt.c b/stage2/sha512crypt.c
+new file mode 100644
+index 0000000..ff6cd26
+--- /dev/null
++++ b/stage2/sha512crypt.c
+@@ -0,0 +1,795 @@
++/* SHA512-based Unix crypt implementation.
++   Released into the Public Domain by Ulrich Drepper <drepper at redhat.com>.
++   Adapted for grub by Miloslav Trmac <mitr at redhat.com>. */
++
++#include <stdbool.h>
++#include <stddef.h>
++
++#include <shared.h>
++
++typedef unsigned long long uint64_t;
++typedef size_t uintptr_t;
++#define alloca(SIZE) (__builtin_alloca (SIZE))
++#define UINT64_C(X) X ## ULL
++#define MIN(a, b) ((a) < (b) ? (a) : (b))
++#define MAX(a, b) ((a) > (b) ? (a) : (b))
++
++/* Structure to save state of computation between the single steps.  */
++struct sha512_ctx
++{
++  uint64_t H[8];
++
++  uint64_t total[2];
++  uint64_t buflen;
++  char buffer[256];	/* NB: always correctly aligned for uint64_t.  */
++};
++
++
++#if 1 /* __BYTE_ORDER == __LITTLE_ENDIAN */
++# define SWAP(n) \
++  (((n) << 56)					\
++   | (((n) & 0xff00) << 40)			\
++   | (((n) & 0xff0000) << 24)			\
++   | (((n) & 0xff000000) << 8)			\
++   | (((n) >> 8) & 0xff000000)			\
++   | (((n) >> 24) & 0xff0000)			\
++   | (((n) >> 40) & 0xff00)			\
++   | ((n) >> 56))
++#else
++# define SWAP(n) (n)
++#endif
++
++
++/* This array contains the bytes used to pad the buffer to the next
++   64-byte boundary.  (FIPS 180-2:5.1.2)  */
++static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ...  */ };
++
++
++/* Constants for SHA512 from FIPS 180-2:4.2.3.  */
++static const uint64_t K[80] =
++  {
++    UINT64_C (0x428a2f98d728ae22), UINT64_C (0x7137449123ef65cd),
++    UINT64_C (0xb5c0fbcfec4d3b2f), UINT64_C (0xe9b5dba58189dbbc),
++    UINT64_C (0x3956c25bf348b538), UINT64_C (0x59f111f1b605d019),
++    UINT64_C (0x923f82a4af194f9b), UINT64_C (0xab1c5ed5da6d8118),
++    UINT64_C (0xd807aa98a3030242), UINT64_C (0x12835b0145706fbe),
++    UINT64_C (0x243185be4ee4b28c), UINT64_C (0x550c7dc3d5ffb4e2),
++    UINT64_C (0x72be5d74f27b896f), UINT64_C (0x80deb1fe3b1696b1),
++    UINT64_C (0x9bdc06a725c71235), UINT64_C (0xc19bf174cf692694),
++    UINT64_C (0xe49b69c19ef14ad2), UINT64_C (0xefbe4786384f25e3),
++    UINT64_C (0x0fc19dc68b8cd5b5), UINT64_C (0x240ca1cc77ac9c65),
++    UINT64_C (0x2de92c6f592b0275), UINT64_C (0x4a7484aa6ea6e483),
++    UINT64_C (0x5cb0a9dcbd41fbd4), UINT64_C (0x76f988da831153b5),
++    UINT64_C (0x983e5152ee66dfab), UINT64_C (0xa831c66d2db43210),
++    UINT64_C (0xb00327c898fb213f), UINT64_C (0xbf597fc7beef0ee4),
++    UINT64_C (0xc6e00bf33da88fc2), UINT64_C (0xd5a79147930aa725),
++    UINT64_C (0x06ca6351e003826f), UINT64_C (0x142929670a0e6e70),
++    UINT64_C (0x27b70a8546d22ffc), UINT64_C (0x2e1b21385c26c926),
++    UINT64_C (0x4d2c6dfc5ac42aed), UINT64_C (0x53380d139d95b3df),
++    UINT64_C (0x650a73548baf63de), UINT64_C (0x766a0abb3c77b2a8),
++    UINT64_C (0x81c2c92e47edaee6), UINT64_C (0x92722c851482353b),
++    UINT64_C (0xa2bfe8a14cf10364), UINT64_C (0xa81a664bbc423001),
++    UINT64_C (0xc24b8b70d0f89791), UINT64_C (0xc76c51a30654be30),
++    UINT64_C (0xd192e819d6ef5218), UINT64_C (0xd69906245565a910),
++    UINT64_C (0xf40e35855771202a), UINT64_C (0x106aa07032bbd1b8),
++    UINT64_C (0x19a4c116b8d2d0c8), UINT64_C (0x1e376c085141ab53),
++    UINT64_C (0x2748774cdf8eeb99), UINT64_C (0x34b0bcb5e19b48a8),
++    UINT64_C (0x391c0cb3c5c95a63), UINT64_C (0x4ed8aa4ae3418acb),
++    UINT64_C (0x5b9cca4f7763e373), UINT64_C (0x682e6ff3d6b2b8a3),
++    UINT64_C (0x748f82ee5defb2fc), UINT64_C (0x78a5636f43172f60),
++    UINT64_C (0x84c87814a1f0ab72), UINT64_C (0x8cc702081a6439ec),
++    UINT64_C (0x90befffa23631e28), UINT64_C (0xa4506cebde82bde9),
++    UINT64_C (0xbef9a3f7b2c67915), UINT64_C (0xc67178f2e372532b),
++    UINT64_C (0xca273eceea26619c), UINT64_C (0xd186b8c721c0c207),
++    UINT64_C (0xeada7dd6cde0eb1e), UINT64_C (0xf57d4f7fee6ed178),
++    UINT64_C (0x06f067aa72176fba), UINT64_C (0x0a637dc5a2c898a6),
++    UINT64_C (0x113f9804bef90dae), UINT64_C (0x1b710b35131c471b),
++    UINT64_C (0x28db77f523047d84), UINT64_C (0x32caab7b40c72493),
++    UINT64_C (0x3c9ebe0a15c9bebc), UINT64_C (0x431d67c49c100d4c),
++    UINT64_C (0x4cc5d4becb3e42b6), UINT64_C (0x597f299cfc657e2a),
++    UINT64_C (0x5fcb6fab3ad6faec), UINT64_C (0x6c44198c4a475817)
++  };
++
++
++/* Process LEN bytes of BUFFER, accumulating context into CTX.
++   It is assumed that LEN % 128 == 0.  */
++static void
++sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx)
++{
++  const uint64_t *words = buffer;
++  size_t nwords = len / sizeof (uint64_t);
++  uint64_t a = ctx->H[0];
++  uint64_t b = ctx->H[1];
++  uint64_t c = ctx->H[2];
++  uint64_t d = ctx->H[3];
++  uint64_t e = ctx->H[4];
++  uint64_t f = ctx->H[5];
++  uint64_t g = ctx->H[6];
++  uint64_t h = ctx->H[7];
++
++  /* First increment the byte count.  FIPS 180-2 specifies the possible
++     length of the file up to 2^128 bits.  Here we only compute the
++     number of bytes.  Do a double word increment.  */
++  ctx->total[0] += len;
++  if (ctx->total[0] < len)
++    ++ctx->total[1];
++
++  /* Process all bytes in the buffer with 128 bytes in each round of
++     the loop.  */
++  while (nwords > 0)
++    {
++      uint64_t W[80];
++      uint64_t a_save = a;
++      uint64_t b_save = b;
++      uint64_t c_save = c;
++      uint64_t d_save = d;
++      uint64_t e_save = e;
++      uint64_t f_save = f;
++      uint64_t g_save = g;
++      uint64_t h_save = h;
++      unsigned int t;
++
++      /* Operators defined in FIPS 180-2:4.1.2.  */
++#define Ch(x, y, z) ((x & y) ^ (~x & z))
++#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
++#define S0(x) (CYCLIC (x, 28) ^ CYCLIC (x, 34) ^ CYCLIC (x, 39))
++#define S1(x) (CYCLIC (x, 14) ^ CYCLIC (x, 18) ^ CYCLIC (x, 41))
++#define R0(x) (CYCLIC (x, 1) ^ CYCLIC (x, 8) ^ (x >> 7))
++#define R1(x) (CYCLIC (x, 19) ^ CYCLIC (x, 61) ^ (x >> 6))
++
++      /* It is unfortunate that C does not provide an operator for
++	 cyclic rotation.  Hope the C compiler is smart enough.  */
++#define CYCLIC(w, s) ((w >> s) | (w << (64 - s)))
++
++      /* Compute the message schedule according to FIPS 180-2:6.3.2 step 2.  */
++      for (t = 0; t < 16; ++t)
++	{
++	  W[t] = SWAP (*words);
++	  ++words;
++	}
++      for (t = 16; t < 80; ++t)
++	W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16];
++
++      /* The actual computation according to FIPS 180-2:6.3.2 step 3.  */
++      for (t = 0; t < 80; ++t)
++	{
++	  uint64_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t];
++	  uint64_t T2 = S0 (a) + Maj (a, b, c);
++	  h = g;
++	  g = f;
++	  f = e;
++	  e = d + T1;
++	  d = c;
++	  c = b;
++	  b = a;
++	  a = T1 + T2;
++	}
++
++      /* Add the starting values of the context according to FIPS 180-2:6.3.2
++	 step 4.  */
++      a += a_save;
++      b += b_save;
++      c += c_save;
++      d += d_save;
++      e += e_save;
++      f += f_save;
++      g += g_save;
++      h += h_save;
++
++      /* Prepare for the next round.  */
++      nwords -= 16;
++    }
++
++  /* Put checksum in context given as argument.  */
++  ctx->H[0] = a;
++  ctx->H[1] = b;
++  ctx->H[2] = c;
++  ctx->H[3] = d;
++  ctx->H[4] = e;
++  ctx->H[5] = f;
++  ctx->H[6] = g;
++  ctx->H[7] = h;
++}
++
++
++/* Initialize structure containing state of computation.
++   (FIPS 180-2:5.3.3)  */
++static void
++sha512_init_ctx (struct sha512_ctx *ctx)
++{
++  ctx->H[0] = UINT64_C (0x6a09e667f3bcc908);
++  ctx->H[1] = UINT64_C (0xbb67ae8584caa73b);
++  ctx->H[2] = UINT64_C (0x3c6ef372fe94f82b);
++  ctx->H[3] = UINT64_C (0xa54ff53a5f1d36f1);
++  ctx->H[4] = UINT64_C (0x510e527fade682d1);
++  ctx->H[5] = UINT64_C (0x9b05688c2b3e6c1f);
++  ctx->H[6] = UINT64_C (0x1f83d9abfb41bd6b);
++  ctx->H[7] = UINT64_C (0x5be0cd19137e2179);
++
++  ctx->total[0] = ctx->total[1] = 0;
++  ctx->buflen = 0;
++}
++
++
++/* Process the remaining bytes in the internal buffer and the usual
++   prolog according to the standard and write the result to RESBUF.
++
++   IMPORTANT: On some systems it is required that RESBUF is correctly
++   aligned for a 32 bits value.  */
++static void *
++sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf)
++{
++  /* Take yet unprocessed bytes into account.  */
++  uint64_t bytes = ctx->buflen;
++  size_t pad;
++  unsigned int i;
++
++  /* Now count remaining bytes.  */
++  ctx->total[0] += bytes;
++  if (ctx->total[0] < bytes)
++    ++ctx->total[1];
++
++  pad = bytes >= 112 ? 128 + 112 - bytes : 112 - bytes;
++  memcpy (&ctx->buffer[bytes], fillbuf, pad);
++
++  /* Put the 128-bit file length in *bits* at the end of the buffer.  */
++  *(uint64_t *) &ctx->buffer[bytes + pad + 8] = SWAP (ctx->total[0] << 3);
++  *(uint64_t *) &ctx->buffer[bytes + pad] = SWAP ((ctx->total[1] << 3) |
++						  (ctx->total[0] >> 61));
++
++  /* Process last bytes.  */
++  sha512_process_block (ctx->buffer, bytes + pad + 16, ctx);
++
++  /* Put result from CTX in first 64 bytes following RESBUF.  */
++  for (i = 0; i < 8; ++i)
++    ((uint64_t *) resbuf)[i] = SWAP (ctx->H[i]);
++
++  return resbuf;
++}
++
++
++static void
++sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx)
++{
++  /* When we already have some bits in our internal buffer concatenate
++     both inputs first.  */
++  if (ctx->buflen != 0)
++    {
++      size_t left_over = ctx->buflen;
++      size_t add = 256 - left_over > len ? len : 256 - left_over;
++
++      memcpy (&ctx->buffer[left_over], buffer, add);
++      ctx->buflen += add;
++
++      if (ctx->buflen > 128)
++	{
++	  sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx);
++
++	  ctx->buflen &= 127;
++	  /* The regions in the following copy operation cannot overlap.  */
++	  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~127],
++		  ctx->buflen);
++	}
++
++      buffer = (const char *) buffer + add;
++      len -= add;
++    }
++
++  /* Process available complete blocks.  */
++  if (len >= 128)
++    {
++/* To check alignment gcc has an appropriate operator.  Other
++   compilers don't.  */
++# if __GNUC__ >= 2
++#  define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__ (uint64_t) != 0)
++# else
++#  define UNALIGNED_P(p) (((uintptr_t) p) % sizeof (uint64_t) != 0)
++# endif
++      if (UNALIGNED_P (buffer))
++	while (len > 128)
++	  {
++	    sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128,
++				    ctx);
++	    buffer = (const char *) buffer + 128;
++	    len -= 128;
++	  }
++      else
++	{
++	  sha512_process_block (buffer, len & ~127, ctx);
++	  buffer = (const char *) buffer + (len & ~127);
++	  len &= 127;
++	}
++    }
++
++  /* Move remaining bytes into internal buffer.  */
++  if (len > 0)
++    {
++      size_t left_over = ctx->buflen;
++
++      memcpy (&ctx->buffer[left_over], buffer, len);
++      left_over += len;
++      if (left_over >= 128)
++	{
++	  sha512_process_block (ctx->buffer, 128, ctx);
++	  left_over -= 128;
++	  memcpy (ctx->buffer, &ctx->buffer[128], left_over);
++	}
++      ctx->buflen = left_over;
++    }
++}
++
++
++/* Define our magic string to mark salt for SHA512 "encryption"
++   replacement.  */
++static const char sha512_salt_prefix[] = "$6$";
++
++/* Prefix for optional rounds specification.  */
++static const char sha512_rounds_prefix[] = "rounds=";
++
++/* Maximum salt string length.  */
++#define SALT_LEN_MAX 16
++/* Default number of rounds if not explicitly specified.  */
++#define ROUNDS_DEFAULT 5000
++/* Minimum number of rounds.  */
++#define ROUNDS_MIN 1000
++/* Maximum number of rounds.  */
++#define ROUNDS_MAX 999999999
++
++/* Table with characters for base64 transformation.  */
++static const char b64t[64] =
++"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
++
++
++static char *
++sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
++{
++  unsigned char alt_result[64]
++    __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
++  unsigned char temp_result[64]
++    __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
++  struct sha512_ctx ctx;
++  struct sha512_ctx alt_ctx;
++  size_t salt_len;
++  size_t key_len;
++  size_t cnt;
++  char *cp;
++  char *copied_key = NULL;
++  char *copied_salt = NULL;
++  char *p_bytes;
++  char *s_bytes;
++  /* Default number of rounds.  */
++  size_t rounds = ROUNDS_DEFAULT;
++  bool rounds_custom = false;
++
++  /* Find beginning of salt string.  The prefix should normally always
++     be present.  Just in case it is not.  */
++  if (grub_memcmp (sha512_salt_prefix, salt,
++		   sizeof (sha512_salt_prefix) - 1) == 0)
++    /* Skip salt prefix.  */
++    salt += sizeof (sha512_salt_prefix) - 1;
++
++  if (grub_memcmp (salt, sha512_rounds_prefix,
++		   sizeof (sha512_rounds_prefix) - 1) == 0)
++    {
++      const char *num = salt + sizeof (sha512_rounds_prefix) - 1;
++      char *endp = (char *)num;
++      int srounds = 0;
++      if (*endp == '0' && tolower (endp[1]) == 'x')
++	/* This would be interpreted as hexadecimal by safe_parse_maxint(). */
++	endp++;
++      else
++	/* On error, endp and srounds is not changed. */
++	safe_parse_maxint(&endp, &srounds);
++      if (*endp == '$')
++	{
++	  salt = endp + 1;
++	  rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
++	  rounds_custom = true;
++	}
++    }
++
++  salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
++  key_len = strlen (key);
++
++  if ((key - (char *) 0) % __alignof__ (uint64_t) != 0)
++    {
++      char *tmp = (char *) alloca (key_len + __alignof__ (uint64_t));
++      key = copied_key =
++	memcpy (tmp + __alignof__ (uint64_t)
++		- (tmp - (char *) 0) % __alignof__ (uint64_t),
++		key, key_len);
++    }
++
++  if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0)
++    {
++      char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t));
++      salt = copied_salt =
++	memcpy (tmp + __alignof__ (uint64_t)
++		- (tmp - (char *) 0) % __alignof__ (uint64_t),
++		salt, salt_len);
++    }
++
++  /* Prepare for the real work.  */
++  sha512_init_ctx (&ctx);
++
++  /* Add the key string.  */
++  sha512_process_bytes (key, key_len, &ctx);
++
++  /* The last part is the salt string.  This must be at most 16
++     characters and it ends at the first `$' character (for
++     compatibility with existing implementations).  */
++  sha512_process_bytes (salt, salt_len, &ctx);
++
++
++  /* Compute alternate SHA512 sum with input KEY, SALT, and KEY.  The
++     final result will be added to the first context.  */
++  sha512_init_ctx (&alt_ctx);
++
++  /* Add key.  */
++  sha512_process_bytes (key, key_len, &alt_ctx);
++
++  /* Add salt.  */
++  sha512_process_bytes (salt, salt_len, &alt_ctx);
++
++  /* Add key again.  */
++  sha512_process_bytes (key, key_len, &alt_ctx);
++
++  /* Now get result of this (64 bytes) and add it to the other
++     context.  */
++  sha512_finish_ctx (&alt_ctx, alt_result);
++
++  /* Add for any character in the key one byte of the alternate sum.  */
++  for (cnt = key_len; cnt > 64; cnt -= 64)
++    sha512_process_bytes (alt_result, 64, &ctx);
++  sha512_process_bytes (alt_result, cnt, &ctx);
++
++  /* Take the binary representation of the length of the key and for every
++     1 add the alternate sum, for every 0 the key.  */
++  for (cnt = key_len; cnt > 0; cnt >>= 1)
++    if ((cnt & 1) != 0)
++      sha512_process_bytes (alt_result, 64, &ctx);
++    else
++      sha512_process_bytes (key, key_len, &ctx);
++
++  /* Create intermediate result.  */
++  sha512_finish_ctx (&ctx, alt_result);
++
++  /* Start computation of P byte sequence.  */
++  sha512_init_ctx (&alt_ctx);
++
++  /* For every character in the password add the entire password.  */
++  for (cnt = 0; cnt < key_len; ++cnt)
++    sha512_process_bytes (key, key_len, &alt_ctx);
++
++  /* Finish the digest.  */
++  sha512_finish_ctx (&alt_ctx, temp_result);
++
++  /* Create byte sequence P.  */
++  cp = p_bytes = alloca (key_len);
++  for (cnt = key_len; cnt >= 64; cnt -= 64)
++    {
++      memcpy (cp, temp_result, 64);
++      cp += 64;
++    }
++  memcpy (cp, temp_result, cnt);
++
++  /* Start computation of S byte sequence.  */
++  sha512_init_ctx (&alt_ctx);
++
++  /* For every character in the password add the entire password.  */
++  for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
++    sha512_process_bytes (salt, salt_len, &alt_ctx);
++
++  /* Finish the digest.  */
++  sha512_finish_ctx (&alt_ctx, temp_result);
++
++  /* Create byte sequence S.  */
++  cp = s_bytes = alloca (salt_len);
++  for (cnt = salt_len; cnt >= 64; cnt -= 64)
++    {
++      memcpy (cp, temp_result, 64);
++      cp += 64;
++    }
++  memcpy (cp, temp_result, cnt);
++
++  /* Repeatedly run the collected hash value through SHA512 to burn
++     CPU cycles.  */
++  for (cnt = 0; cnt < rounds; ++cnt)
++    {
++      /* New context.  */
++      sha512_init_ctx (&ctx);
++
++      /* Add key or last result.  */
++      if ((cnt & 1) != 0)
++	sha512_process_bytes (p_bytes, key_len, &ctx);
++      else
++	sha512_process_bytes (alt_result, 64, &ctx);
++
++      /* Add salt for numbers not divisible by 3.  */
++      if (cnt % 3 != 0)
++	sha512_process_bytes (s_bytes, salt_len, &ctx);
++
++      /* Add key for numbers not divisible by 7.  */
++      if (cnt % 7 != 0)
++	sha512_process_bytes (p_bytes, key_len, &ctx);
++
++      /* Add key or last result.  */
++      if ((cnt & 1) != 0)
++	sha512_process_bytes (alt_result, 64, &ctx);
++      else
++	sha512_process_bytes (p_bytes, key_len, &ctx);
++
++      /* Create intermediate result.  */
++      sha512_finish_ctx (&ctx, alt_result);
++    }
++
++  /* Now we can construct the result string.  It consists of three
++     parts.  */
++  cp = stpncpy (buffer, sha512_salt_prefix, MAX (0, buflen));
++  buflen -= sizeof (sha512_salt_prefix) - 1;
++
++  if (rounds_custom)
++    {
++      char sbuf[64];
++      grub_sprintf (sbuf, "%s%llu$", sha512_rounds_prefix,
++		    (unsigned long long)rounds);
++      size_t n = strlen (sbuf);
++      memcpy (cp, sbuf, MIN (MAX (0, buflen), n));
++      cp += n;
++      buflen -= n;
++    }
++
++  cp = stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
++  buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
++
++  if (buflen > 0)
++    {
++      *cp++ = '$';
++      --buflen;
++    }
++
++#define b64_from_24bit(B2, B1, B0, N)					      \
++  do {									      \
++    unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0);			      \
++    int n = (N);							      \
++    while (n-- > 0 && buflen > 0)					      \
++      {									      \
++	*cp++ = b64t[w & 0x3f];						      \
++	--buflen;							      \
++	w >>= 6;							      \
++      }									      \
++  } while (0)
++
++  b64_from_24bit (alt_result[0], alt_result[21], alt_result[42], 4);
++  b64_from_24bit (alt_result[22], alt_result[43], alt_result[1], 4);
++  b64_from_24bit (alt_result[44], alt_result[2], alt_result[23], 4);
++  b64_from_24bit (alt_result[3], alt_result[24], alt_result[45], 4);
++  b64_from_24bit (alt_result[25], alt_result[46], alt_result[4], 4);
++  b64_from_24bit (alt_result[47], alt_result[5], alt_result[26], 4);
++  b64_from_24bit (alt_result[6], alt_result[27], alt_result[48], 4);
++  b64_from_24bit (alt_result[28], alt_result[49], alt_result[7], 4);
++  b64_from_24bit (alt_result[50], alt_result[8], alt_result[29], 4);
++  b64_from_24bit (alt_result[9], alt_result[30], alt_result[51], 4);
++  b64_from_24bit (alt_result[31], alt_result[52], alt_result[10], 4);
++  b64_from_24bit (alt_result[53], alt_result[11], alt_result[32], 4);
++  b64_from_24bit (alt_result[12], alt_result[33], alt_result[54], 4);
++  b64_from_24bit (alt_result[34], alt_result[55], alt_result[13], 4);
++  b64_from_24bit (alt_result[56], alt_result[14], alt_result[35], 4);
++  b64_from_24bit (alt_result[15], alt_result[36], alt_result[57], 4);
++  b64_from_24bit (alt_result[37], alt_result[58], alt_result[16], 4);
++  b64_from_24bit (alt_result[59], alt_result[17], alt_result[38], 4);
++  b64_from_24bit (alt_result[18], alt_result[39], alt_result[60], 4);
++  b64_from_24bit (alt_result[40], alt_result[61], alt_result[19], 4);
++  b64_from_24bit (alt_result[62], alt_result[20], alt_result[41], 4);
++  b64_from_24bit (0, 0, alt_result[63], 2);
++
++  if (buflen <= 0)
++    buffer = NULL;
++  else
++    *cp = '\0';		/* Terminate the string.  */
++
++  /* Clear the buffer for the intermediate result so that people
++     attaching to processes or reading core dumps cannot get any
++     information.  We do it in this way to clear correct_words[]
++     inside the SHA512 implementation as well.  */
++  sha512_init_ctx (&ctx);
++  sha512_finish_ctx (&ctx, alt_result);
++  memset (temp_result, '\0', sizeof (temp_result));
++  memset (p_bytes, '\0', key_len);
++  memset (s_bytes, '\0', salt_len);
++  memset (&ctx, '\0', sizeof (ctx));
++  memset (&alt_ctx, '\0', sizeof (alt_ctx));
++  if (copied_key != NULL)
++    memset (copied_key, '\0', key_len);
++  if (copied_salt != NULL)
++    memset (copied_salt, '\0', salt_len);
++
++  return buffer;
++}
++
++
++/* This entry point is equivalent to the `crypt' function in Unix
++   libcs.  */
++char *
++sha512_crypt (const char *key, const char *salt)
++{
++  /* We don't want to have an arbitrary limit in the size of the
++     password.  We can compute an upper bound for the size of the
++     result in advance and so we can prepare the buffer we pass to
++     `sha512_crypt_r'.  */
++  static char buffer[sizeof (sha512_salt_prefix) - 1
++		     + sizeof (sha512_rounds_prefix) + 9 + 1
++		     + 256 + 1 + 86 + 1]; /* 256 bytes for salt */
++  int needed = (sizeof (sha512_salt_prefix) - 1
++		+ sizeof (sha512_rounds_prefix) + 9 + 1
++		+ strlen (salt) + 1 + 86 + 1);
++
++  if (sizeof (buffer) < needed)
++    return NULL;
++
++  return sha512_crypt_r (key, salt, buffer, sizeof (buffer));
++}
++
++
++#ifdef TEST
++static const struct
++{
++  const char *input;
++  const char result[64];
++} tests[] =
++  {
++    /* Test vectors from FIPS 180-2: appendix C.1.  */
++    { "abc",
++      "\xdd\xaf\x35\xa1\x93\x61\x7a\xba\xcc\x41\x73\x49\xae\x20\x41\x31"
++      "\x12\xe6\xfa\x4e\x89\xa9\x7e\xa2\x0a\x9e\xee\xe6\x4b\x55\xd3\x9a"
++      "\x21\x92\x99\x2a\x27\x4f\xc1\xa8\x36\xba\x3c\x23\xa3\xfe\xeb\xbd"
++      "\x45\x4d\x44\x23\x64\x3c\xe8\x0e\x2a\x9a\xc9\x4f\xa5\x4c\xa4\x9f" },
++    /* Test vectors from FIPS 180-2: appendix C.2.  */
++    { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
++      "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
++      "\x8e\x95\x9b\x75\xda\xe3\x13\xda\x8c\xf4\xf7\x28\x14\xfc\x14\x3f"
++      "\x8f\x77\x79\xc6\xeb\x9f\x7f\xa1\x72\x99\xae\xad\xb6\x88\x90\x18"
++      "\x50\x1d\x28\x9e\x49\x00\xf7\xe4\x33\x1b\x99\xde\xc4\xb5\x43\x3a"
++      "\xc7\xd3\x29\xee\xb6\xdd\x26\x54\x5e\x96\xe5\x5b\x87\x4b\xe9\x09" },
++    /* Test vectors from the NESSIE project.  */
++    { "",
++      "\xcf\x83\xe1\x35\x7e\xef\xb8\xbd\xf1\x54\x28\x50\xd6\x6d\x80\x07"
++      "\xd6\x20\xe4\x05\x0b\x57\x15\xdc\x83\xf4\xa9\x21\xd3\x6c\xe9\xce"
++      "\x47\xd0\xd1\x3c\x5d\x85\xf2\xb0\xff\x83\x18\xd2\x87\x7e\xec\x2f"
++      "\x63\xb9\x31\xbd\x47\x41\x7a\x81\xa5\x38\x32\x7a\xf9\x27\xda\x3e" },
++    { "a",
++      "\x1f\x40\xfc\x92\xda\x24\x16\x94\x75\x09\x79\xee\x6c\xf5\x82\xf2"
++      "\xd5\xd7\xd2\x8e\x18\x33\x5d\xe0\x5a\xbc\x54\xd0\x56\x0e\x0f\x53"
++      "\x02\x86\x0c\x65\x2b\xf0\x8d\x56\x02\x52\xaa\x5e\x74\x21\x05\x46"
++      "\xf3\x69\xfb\xbb\xce\x8c\x12\xcf\xc7\x95\x7b\x26\x52\xfe\x9a\x75" },
++    { "message digest",
++      "\x10\x7d\xbf\x38\x9d\x9e\x9f\x71\xa3\xa9\x5f\x6c\x05\x5b\x92\x51"
++      "\xbc\x52\x68\xc2\xbe\x16\xd6\xc1\x34\x92\xea\x45\xb0\x19\x9f\x33"
++      "\x09\xe1\x64\x55\xab\x1e\x96\x11\x8e\x8a\x90\x5d\x55\x97\xb7\x20"
++      "\x38\xdd\xb3\x72\xa8\x98\x26\x04\x6d\xe6\x66\x87\xbb\x42\x0e\x7c" },
++    { "abcdefghijklmnopqrstuvwxyz",
++      "\x4d\xbf\xf8\x6c\xc2\xca\x1b\xae\x1e\x16\x46\x8a\x05\xcb\x98\x81"
++      "\xc9\x7f\x17\x53\xbc\xe3\x61\x90\x34\x89\x8f\xaa\x1a\xab\xe4\x29"
++      "\x95\x5a\x1b\xf8\xec\x48\x3d\x74\x21\xfe\x3c\x16\x46\x61\x3a\x59"
++      "\xed\x54\x41\xfb\x0f\x32\x13\x89\xf7\x7f\x48\xa8\x79\xc7\xb1\xf1" },
++    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
++      "\x20\x4a\x8f\xc6\xdd\xa8\x2f\x0a\x0c\xed\x7b\xeb\x8e\x08\xa4\x16"
++      "\x57\xc1\x6e\xf4\x68\xb2\x28\xa8\x27\x9b\xe3\x31\xa7\x03\xc3\x35"
++      "\x96\xfd\x15\xc1\x3b\x1b\x07\xf9\xaa\x1d\x3b\xea\x57\x78\x9c\xa0"
++      "\x31\xad\x85\xc7\xa7\x1d\xd7\x03\x54\xec\x63\x12\x38\xca\x34\x45" },
++    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
++      "\x1e\x07\xbe\x23\xc2\x6a\x86\xea\x37\xea\x81\x0c\x8e\xc7\x80\x93"
++      "\x52\x51\x5a\x97\x0e\x92\x53\xc2\x6f\x53\x6c\xfc\x7a\x99\x96\xc4"
++      "\x5c\x83\x70\x58\x3e\x0a\x78\xfa\x4a\x90\x04\x1d\x71\xa4\xce\xab"
++      "\x74\x23\xf1\x9c\x71\xb9\xd5\xa3\xe0\x12\x49\xf0\xbe\xbd\x58\x94" },
++    { "123456789012345678901234567890123456789012345678901234567890"
++      "12345678901234567890",
++      "\x72\xec\x1e\xf1\x12\x4a\x45\xb0\x47\xe8\xb7\xc7\x5a\x93\x21\x95"
++      "\x13\x5b\xb6\x1d\xe2\x4e\xc0\xd1\x91\x40\x42\x24\x6e\x0a\xec\x3a"
++      "\x23\x54\xe0\x93\xd7\x6f\x30\x48\xb4\x56\x76\x43\x46\x90\x0c\xb1"
++      "\x30\xd2\xa4\xfd\x5d\xd1\x6a\xbb\x5e\x30\xbc\xb8\x50\xde\xe8\x43" }
++  };
++#define ntests (sizeof (tests) / sizeof (tests[0]))
++
++
++static const struct
++{
++  const char *salt;
++  const char *input;
++  const char *expected;
++} tests2[] =
++{
++  { "$6$saltstring", "Hello world!",
++    "$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu"
++    "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1" },
++  { "$6$rounds=10000$saltstringsaltstring", "Hello world!",
++    "$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sb"
++    "HbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v." },
++  { "$6$rounds=5000$toolongsaltstring", "This is just a test",
++    "$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQ"
++    "zQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0" },
++  { "$6$rounds=1400$anotherlongsaltstring",
++    "a very much longer text to encrypt.  This one even stretches over more"
++    "than one line.",
++    "$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wP"
++    "vMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1" },
++  { "$6$rounds=77777$short",
++    "we have a short salt string but not a short password",
++    "$6$rounds=77777$short$WuQyW2YR.hBNpjjRhpYD/ifIw05xdfeEyQoMxIXbkvr0g"
++    "ge1a1x3yRULJ5CCaUeOxFmtlcGZelFl5CxtgfiAc0" },
++  { "$6$rounds=123456$asaltof16chars..", "a short string",
++    "$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwc"
++    "elCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1" },
++  { "$6$rounds=10$roundstoolow", "the minimum number is still observed",
++    "$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1x"
++    "hLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX." },
++};
++#define ntests2 (sizeof (tests2) / sizeof (tests2[0]))
++
++
++int
++sha512_test (void)
++{
++  struct sha512_ctx ctx;
++  char sum[64];
++  int result = 0;
++  int cnt, i;
++
++  for (cnt = 0; cnt < (int) ntests; ++cnt)
++    {
++      sha512_init_ctx (&ctx);
++      sha512_process_bytes (tests[cnt].input, strlen (tests[cnt].input), &ctx);
++      sha512_finish_ctx (&ctx, sum);
++      if (memcmp (tests[cnt].result, sum, 64) != 0)
++	{
++	  printf ("test %d run %d failed\n", cnt, 1);
++	  result = 1;
++	}
++
++      sha512_init_ctx (&ctx);
++      for (i = 0; tests[cnt].input[i] != '\0'; ++i)
++	sha512_process_bytes (&tests[cnt].input[i], 1, &ctx);
++      sha512_finish_ctx (&ctx, sum);
++      if (memcmp (tests[cnt].result, sum, 64) != 0)
++	{
++	  printf ("test %d run %d failed\n", cnt, 2);
++	  result = 1;
++	}
++    }
++
++  /* Test vector from FIPS 180-2: appendix C.3.  */
++  char buf[1000];
++  memset (buf, 'a', sizeof (buf));
++  sha512_init_ctx (&ctx);
++  for (i = 0; i < 1000; ++i)
++    sha512_process_bytes (buf, sizeof (buf), &ctx);
++  sha512_finish_ctx (&ctx, sum);
++  static const char expected[64] =
++    "\xe7\x18\x48\x3d\x0c\xe7\x69\x64\x4e\x2e\x42\xc7\xbc\x15\xb4\x63"
++    "\x8e\x1f\x98\xb1\x3b\x20\x44\x28\x56\x32\xa8\x03\xaf\xa9\x73\xeb"
++    "\xde\x0f\xf2\x44\x87\x7e\xa6\x0a\x4c\xb0\x43\x2c\xe5\x77\xc3\x1b"
++    "\xeb\x00\x9c\x5c\x2c\x49\xaa\x2e\x4e\xad\xb2\x17\xad\x8c\xc0\x9b";
++  if (memcmp (expected, sum, 64) != 0)
++    {
++      printf ("test %d failed\n", cnt);
++      result = 1;
++    }
++
++  for (cnt = 0; cnt < ntests2; ++cnt)
++    {
++      char *cp = sha512_crypt (tests2[cnt].input, tests2[cnt].salt);
++
++      if (strcmp (cp, tests2[cnt].expected) != 0)
++	{
++	  printf ("test %d: expected \"%s\", got \"%s\"\n",
++		  cnt, tests2[cnt].expected, cp);
++	  result = 1;
++	}
++    }
++
++  if (result == 0)
++    printf ("all tests OK\n");
++
++  return result;
++}
++#endif
 diff --git a/stage2/shared.h b/stage2/shared.h
-index 77eef11..829a25f 100644
+index 77eef11..9405556 100644
 --- a/stage2/shared.h
 +++ b/stage2/shared.h
 @@ -35,9 +35,10 @@
@@ -39881,6 +44022,17 @@ index 77eef11..829a25f 100644
  # define RAW_SEG(x) (RAW_ADDR ((x) << 4) >> 4)
  #else
  # define RAW_ADDR(x) (x)
+@@ -160,8 +161,8 @@ extern char *grub_scratch_mem;
+ #define LINUX_VID_MODE_ASK		0xFFFD
+ 
+ #define LINUX_CL_OFFSET			0x9000
+-#define LINUX_CL_END_OFFSET		0x90FF
+-#define LINUX_SETUP_MOVE_SIZE		0x9100
++#define LINUX_CL_END_OFFSET		0x97FF
++#define LINUX_SETUP_MOVE_SIZE		0x9800
+ #define LINUX_CL_MAGIC			0xA33F
+ 
+ /*
 @@ -200,6 +201,8 @@ extern char *grub_scratch_mem;
  #define STAGE2_FORCE_LBA	0x11
  #define STAGE2_VER_STR_OFFS	0x12
@@ -39890,7 +44042,24 @@ index 77eef11..829a25f 100644
  /* Stage 2 identifiers */
  #define STAGE2_ID_STAGE2		0
  #define STAGE2_ID_FFS_STAGE1_5		1
-@@ -379,6 +382,8 @@ extern char *grub_scratch_mem;
+@@ -371,14 +374,24 @@ extern char *grub_scratch_mem;
+ #define tolower grub_tolower
+ #define strlen grub_strlen
+ #define strcpy grub_strcpy
++#define stpncpy grub_stpncpy
++#define strspn grub_strspn
++#define strcspn grub_strcspn
++#define strtok_r grub_strtok_r
++#define strchr grub_strchr
++#define strrchr grub_strrchr
++#define strnchr grub_strnchr
++#define strncpy grub_strncpy
++#define strncasecmp grub_strncasecmp
+ #endif /* WITHOUT_LIBC_STUBS */
+ 
+-
+ #ifndef ASM_FILE
+ /*
   *  Below this should be ONLY defines and other constructs for C code.
   */
  
@@ -39899,7 +44068,7 @@ index 77eef11..829a25f 100644
  /* multiboot stuff */
  
  #include "mb_header.h"
-@@ -400,30 +405,30 @@ struct linux_kernel_header
+@@ -400,30 +413,33 @@ struct linux_kernel_header
    unsigned short root_dev;		/* Default root device number */
    unsigned short boot_flag;		/* 0xAA55 magic number */
    unsigned short jump;			/* Jump instruction */
@@ -39926,6 +44095,9 @@ index 77eef11..829a25f 100644
    char *cmd_line_ptr;			/* Points to the kernel command line */
 -  unsigned long initrd_addr_max;	/* The highest address of initrd */
 +  unsigned int initrd_addr_max;		/* The highest address of initrd */
++  unsigned int kernel_alignment;	/* Physical addr alignment required for kernel */
++  unsigned int relocatable_kernel;	/* Whether kernel is relocatable or not */
++  unsigned int cmdline_size;		/* Maximum size of the kernel command line */
  } __attribute__ ((packed));
  
  /* Memory map address range descriptor used by GET_MMAP_ENTRY. */
@@ -39940,15 +44112,52 @@ index 77eef11..829a25f 100644
  } __attribute__ ((packed));
  
  /* VBE controller information.  */
-@@ -627,6 +632,7 @@ extern void (*disk_read_func) (int, int, int);
+@@ -600,6 +616,7 @@ typedef enum
+ {
+   PASSWORD_PLAIN,
+   PASSWORD_MD5,
++  PASSWORD_ENCRYPTED,
+   PASSWORD_UNSUPPORTED
+ }
+ password_t;
+@@ -627,8 +644,16 @@ extern void (*disk_read_func) (int, int, int);
  #ifndef STAGE1_5
  /* The flag for debug mode.  */
  extern int debug;
 +extern int debug_graphics;
  #endif /* STAGE1_5 */
  
++/* Verbose mode flag. */
++extern int grub_verbose;
++#define verbose_printf(format...) \
++  do { if (grub_verbose) printf(format); } while (0)
++#define grub_verbose_printf(format...) \
++  do { if (grub_verbose) grub_printf(format); } while (0)
++
  extern unsigned long current_drive;
-@@ -860,17 +866,25 @@ void init_builtins (void);
+ extern unsigned long current_partition;
+ 
+@@ -666,6 +691,8 @@ extern struct geometry buf_geom;
+ extern int filepos;
+ extern int filemax;
+ 
++extern int silent_grub;
++
+ /*
+  *  Common BIOS/boot data.
+  */
+@@ -804,6 +831,10 @@ int getkey (void);
+    available. */
+ int checkkey (void);
+ 
++/* Return keyboard modifier status. */
++int
++keystatus (void);
++
+ /* Low-level disk I/O */
+ int get_diskinfo (int drive, struct geometry *geometry);
+ int biosdisk (int subfunc, int drive, struct geometry *geometry,
+@@ -860,17 +891,25 @@ void init_builtins (void);
  void init_config (void);
  char *skip_to (int after_equal, char *cmdline);
  struct builtin *find_command (char *command);
@@ -39976,8 +44185,20 @@ index 77eef11..829a25f 100644
  void *grub_memmove (void *to, const void *from, int len);
  void *grub_memset (void *start, int c, int len);
  int grub_strncat (char *s1, const char *s2, int n);
-@@ -881,7 +895,7 @@ int grub_strlen (const char *str);
+@@ -879,9 +918,19 @@ int grub_memcmp (const char *s1, const char *s2, int n);
+ int grub_strcmp (const char *s1, const char *s2);
+ int grub_strlen (const char *str);
  char *grub_strcpy (char *dest, const char *src);
++char *grub_stpncpy (char *dest, const char *src, int n);
++int grub_strspn(const char *s, const char *accept);
++int grub_strcspn(const char *s, const char *reject);
++char *grub_strtok_r(char *s, const char *delim, char **ptrptr);
++char *grub_strchr (const char *s, int c);
++char *grub_strrchr (const char *s, int c);
++char *grub_strnchr (const char *s, int c);
++int grub_strnlen (const char *s, int n);
++char *grub_strncpy (char *new, const char *s, int n);
++int grub_strncasecmp(const char *s0, const char *s1, int n);
  
  #ifndef GRUB_UTIL
 -typedef unsigned long grub_jmp_buf[6];
@@ -39985,7 +44206,7 @@ index 77eef11..829a25f 100644
  #else
  /* In the grub shell, use the libc jmp_buf instead.  */
  # include <setjmp.h>
-@@ -904,7 +918,7 @@ extern grub_jmp_buf restart_cmdline_env;
+@@ -904,10 +953,11 @@ extern grub_jmp_buf restart_cmdline_env;
  /* misc */
  void init_page (void);
  void print_error (void);
@@ -39994,7 +44215,11 @@ index 77eef11..829a25f 100644
  int get_cmdline (char *prompt, char *cmdline, int maxlen,
  		 int echo_char, int history);
  int substring (const char *s1, const char *s2);
-@@ -934,7 +948,9 @@ int next_partition (unsigned long drive, unsigned long dest,
++int subcasestring (const char *s1, const char *s2);
+ int nul_terminate (char *str);
+ int get_based_digit (int c, int base);
+ int safe_parse_maxint (char **str_ptr, int *myint_ptr);
+@@ -934,7 +984,9 @@ int next_partition (unsigned long drive, unsigned long dest,
  		    unsigned long *partition, int *type,
  		    unsigned long *start, unsigned long *len,
  		    unsigned long *offset, int *entry,
@@ -40005,13 +44230,22 @@ index 77eef11..829a25f 100644
  
  /* Sets device to the one represented by the SAVED_* parameters. */
  int make_saved_active (void);
-@@ -991,6 +1007,13 @@ int check_password(char *entered, char* expected, password_t type);
+@@ -987,10 +1039,22 @@ int load_module (char *module, char *arg);
+ int load_initrd (char *initrd);
+ 
+ int check_password(char *entered, char* expected, password_t type);
++
++char *sha256_crypt (const char *key, const char *salt);
++char *sha512_crypt (const char *key, const char *salt);
+ #endif
  
  void init_bios_info (void);
  
 +#ifdef PLATFORM_EFI
 +void grub_set_config_file (char *path_name);
 +int grub_save_saved_default (int new_default);
++extern int check_device (const char *device);
++extern void assign_device_name (int drive, const char *device);
 +#endif
 +int grub_load_linux (char *kernel, char *arg);
 +int grub_load_initrd (char *initrd);
@@ -40031,49 +44265,95 @@ index c0fdce3..bae9b77 100644
  /*
   *  Defines that use variables
   */
+diff --git a/stage2/stage1_5.c b/stage2/stage1_5.c
+index 5c45d4c..c2d9632 100644
+--- a/stage2/stage1_5.c
++++ b/stage2/stage1_5.c
+@@ -30,7 +30,8 @@ disk_read_savesect_func (int sector, int offset, int length)
+ void
+ cmain (void)
+ {
+-  grub_printf ("\n\nGRUB loading, please wait...\n");
++  if (0)
++    grub_printf ("\n\nGRUB loading, please wait...\n");
+ 
+   /*
+    *  Here load the true second-stage boot-loader.
 diff --git a/stage2/stage2.c b/stage2/stage2.c
-index 4dbf6f5..f8bccf8 100644
+index 4dbf6f5..cca4332 100644
 --- a/stage2/stage2.c
 +++ b/stage2/stage2.c
-@@ -233,6 +233,9 @@ run_menu (char *menu_entries, char *config_entries, int num_entries,
+@@ -22,6 +22,8 @@
+ 
+ grub_jmp_buf restart_env;
+ 
++int silent_grub = 0;
++
+ #if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS)
+ 
+ # if defined(PRESET_MENU_STRING)
+@@ -233,6 +235,10 @@ run_menu (char *menu_entries, char *config_entries, int num_entries,
  {
    int c, time1, time2 = -1, first_entry = 0;
    char *cur_entry = 0;
 +  struct term_entry *prev_term = NULL;
 +
-+  cls();
++  if (grub_verbose)
++    cls();
  
    /*
     *  Main loop for menu UI.
-@@ -261,14 +264,16 @@ restart:
+@@ -254,18 +260,33 @@ restart:
+      interface. */
+   if (grub_timeout < 0)
+     show_menu = 1;
+-  
++
+   /* If SHOW_MENU is false, don't display the menu until ESC is pressed.  */
+   if (! show_menu)
+     {
++      /* Don't show the "Booting in blah seconds message" if the timeout is 0 */
++      int print_message = grub_timeout != 0;
++
        /* Get current time.  */
        while ((time1 = getrtsecs ()) == 0xFF)
  	;
-+      grub_printf("\rPress any key to enter the menu\n\n\n");
  
++      if (print_message)
++	grub_printf("\rPress any key to enter the menu\n\n\n");
++
        while (1)
  	{
- 	  /* Check if ESC is pressed.  */
+-	  /* Check if ESC is pressed.  */
 -	  if (checkkey () != -1 && ASCII_CHAR (getkey ()) == '\e')
++	  /* Check if any key is pressed */
 +	  if (checkkey () != -1)
++	    {
++	      grub_timeout = -1;
++	      show_menu = 1;
++	      getkey ();
++	      break;
++	    }
++
++	  /* See if a modifier key is held down.  */
++	  if (keystatus () != 0)
  	    {
  	      grub_timeout = -1;
  	      show_menu = 1;
-+	      getkey ();
- 	      break;
- 	    }
- 
-@@ -287,7 +292,8 @@ restart:
+@@ -287,8 +308,10 @@ restart:
  	      grub_timeout--;
  	      
  	      /* Print a message.  */
 -	      grub_printf ("\rPress `ESC' to enter the menu... %d   ",
-+	      grub_printf ("\rBooting %s in %d seconds...",
-+			   get_entry(menu_entries, first_entry + entryno, 0),
- 			   grub_timeout);
+-			   grub_timeout);
++	      if (print_message)
++		grub_printf ("\rBooting %s in %d seconds...",
++		             get_entry(menu_entries, first_entry + entryno, 0),
++		             grub_timeout);
  	    }
  	}
-@@ -319,7 +325,8 @@ restart:
+     }
+@@ -319,7 +342,8 @@ restart:
  	  if (config_entries)
  	    printf ("\
        Press enter to boot the selected OS, \'e\' to edit the\n\
@@ -40083,7 +44363,7 @@ index 4dbf6f5..f8bccf8 100644
  	  else
  	    printf ("\
        Press \'b\' to boot, \'e\' to edit the selected command in the\n\
-@@ -514,7 +521,7 @@ restart:
+@@ -514,7 +538,7 @@ restart:
  		  if (c == 'O')
  		    {
  		      grub_memmove (cur_entry + 2, cur_entry,
@@ -40092,7 +44372,7 @@ index 4dbf6f5..f8bccf8 100644
  
  		      cur_entry[0] = ' ';
  		      cur_entry[1] = 0;
-@@ -530,8 +537,8 @@ restart:
+@@ -530,8 +554,8 @@ restart:
  					    0);
  
  		      grub_memmove (cur_entry, ptr,
@@ -40103,7 +44383,7 @@ index 4dbf6f5..f8bccf8 100644
  
  		      num_entries--;
  
-@@ -655,7 +662,7 @@ restart:
+@@ -655,7 +679,7 @@ restart:
  		  else
  		    {
  		      cls ();
@@ -40112,7 +44392,7 @@ index 4dbf6f5..f8bccf8 100644
  
  		      new_heap = heap + NEW_HEAPSIZE + 1;
  
-@@ -681,7 +688,7 @@ restart:
+@@ -681,7 +705,7 @@ restart:
  
  			  /* align rest of commands properly */
  			  grub_memmove (cur_entry + j, cur_entry + i,
@@ -40121,7 +44401,7 @@ index 4dbf6f5..f8bccf8 100644
  
  			  /* copy command to correct area */
  			  grub_memmove (cur_entry, new_heap, j);
-@@ -697,6 +704,98 @@ restart:
+@@ -697,6 +721,98 @@ restart:
  		  enter_cmdline (heap, 0);
  		  goto restart;
  		}
@@ -40220,10 +44500,17 @@ index 4dbf6f5..f8bccf8 100644
  #ifdef GRUB_UTIL
  	      if (c == 'q')
  		{
-@@ -714,6 +813,15 @@ restart:
+@@ -712,16 +828,31 @@ restart:
+   
+  boot_entry:
    
-   cls ();
-   setcursor (1);
+-  cls ();
+-  setcursor (1);
++  if (grub_verbose || show_menu)
++    {
++      cls ();
++      setcursor (1);
++    }
 +  /* if our terminal needed initialization, we should shut it down
 +   * before booting the kernel, but we want to save what it was so
 +   * we can come back if needed */
@@ -40233,10 +44520,23 @@ index 4dbf6f5..f8bccf8 100644
 +      (*current_term->shutdown)();
 +      current_term = term_table; /* assumption: console is first */
 +    }
++
++  if (silent_grub)
++    setcursor(0);
    
    while (1)
      {
-@@ -748,6 +856,13 @@ restart:
+       if (config_entries)
+-	printf ("  Booting \'%s\'\n\n",
++	verbose_printf ("  Booting \'%s\'\n\n",
+ 		get_entry (menu_entries, first_entry + entryno, 0));
+       else
+-	printf ("  Booting command-list\n\n");
++	verbose_printf ("  Booting command-list\n\n");
+ 
+       if (! cur_entry)
+ 	cur_entry = get_entry (config_entries, first_entry + entryno, 1);
+@@ -748,6 +879,13 @@ restart:
  	break;
      }
  
@@ -40250,7 +44550,7 @@ index 4dbf6f5..f8bccf8 100644
    show_menu = 1;
    goto restart;
  }
-@@ -867,38 +982,8 @@ cmain (void)
+@@ -867,38 +1005,8 @@ cmain (void)
        if (use_config_file)
  #endif /* GRUB_UTIL */
  	{
@@ -40289,7 +44589,7 @@ index 4dbf6f5..f8bccf8 100644
  	  do
  	    {
  	      /* STATE 0:  Before any title command.
-@@ -1050,6 +1135,10 @@ cmain (void)
+@@ -1050,11 +1158,16 @@ cmain (void)
  	  while (is_preset);
  	}
  
@@ -40300,11 +44600,76 @@ index 4dbf6f5..f8bccf8 100644
        if (! num_entries)
  	{
  	  /* If no acceptable config file, goto command-line, starting
+ 	     heap from where the config entries would have been stored
+ 	     if there were any.  */
++	  grub_verbose = 1;
+ 	  enter_cmdline (config_entries, 1);
+ 	}
+       else
+diff --git a/stage2/start.S b/stage2/start.S
+index 9a7d504..7a6652f 100644
+--- a/stage2/start.S
++++ b/stage2/start.S
+@@ -39,6 +39,9 @@
+ 	
+ 	/* Print message string */
+ #define MSG(x)	movw $ABS(x), %si; call message
++	
++	/* Print verbose message string */
++#define VMSG(x)
+ 
+ 	.file	"start.S"
+ 
+@@ -67,9 +70,9 @@ _start:
+ 
+ 	/* print a notification message on the screen */
+ 	pushw	%si
+-	MSG(notification_string)
++	VMSG(notification_string)
+ 	popw	%si
+-	
++
+ 	/* this sets up for the first run through "bootloop" */
+ 	movw	$ABS(firstlist - BOOTSEC_LISTSIZE), %di
+ 
+@@ -291,9 +294,9 @@ copy_buffer:
+ 	movsb		/* this runs the actual copy */
+ 
+ 	/* restore addressing regs and print a dot with correct DS 
+-	   (MSG modifies SI, which is saved, and unused AX and BX) */
++	   (VMSG modifies SI, which is saved, and unused AX and BX) */
+ 	popw	%ds
+-	MSG(notification_step)
++	VMSG(notification_step)
+ 	popa
+ 
+ 	/* check if finished with this dataset */
+@@ -310,7 +313,7 @@ copy_buffer:
+ 
+ bootit:
+ 	/* print a newline */
+-	MSG(notification_done)
++	VMSG(notification_done)
+ 	popw	%dx	/* this makes sure %dl is our "boot" drive */
+ #ifdef STAGE1_5
+ 	ljmp	$0, $0x2200
 diff --git a/stage2/term.h b/stage2/term.h
-index 8261c7c..8ed8b9d 100644
+index 8261c7c..803de58 100644
 --- a/stage2/term.h
 +++ b/stage2/term.h
-@@ -60,6 +60,8 @@ struct term_entry
+@@ -54,18 +54,28 @@ typedef enum
+ /* Set when the terminal needs to be initialized.  */
+ #define TERM_NEED_INIT		(1 << 16)
+ 
++/* Bitmasks for modifier keys returned by term->keystatus(). */
++#define TERM_STATUS_ALT		(1 << 3)
++#define TERM_STATUS_CTRL	(1 << 2)
++#define TERM_STATUS_LEFT_SHIFT	(1 << 1)
++#define TERM_STATUS_RIGHT_SHIFT	(1 << 0)
++
+ struct term_entry
+ {
+   /* The name of a terminal.  */
    const char *name;
    /* The feature flags defined above.  */
    unsigned long flags;
@@ -40313,7 +44678,15 @@ index 8261c7c..8ed8b9d 100644
    /* Put a character.  */
    void (*putchar) (int c);
    /* Check if any input character is available.  */
-@@ -79,6 +81,11 @@ struct term_entry
+   int (*checkkey) (void);
+   /* Get a character.  */
+   int (*getkey) (void);
++  /* Get keyboard modifier status.  */
++  int (*keystatus) (void);
+   /* Get the cursor position. The return value is ((X << 8) | Y).  */
+   int (*getxy) (void);
+   /* Go to the position (X, Y).  */
+@@ -79,6 +89,11 @@ struct term_entry
    void (*setcolor) (int normal_color, int highlight_color);
    /* Turn on/off the cursor.  */
    int (*setcursor) (int on);
@@ -40325,7 +44698,15 @@ index 8261c7c..8ed8b9d 100644
  };
  
  /* This lists up available terminals.  */
-@@ -124,4 +131,23 @@ void hercules_setcolor (int normal_color, int highlight_color);
+@@ -96,6 +111,7 @@ void console_putchar (int c);
+ #ifndef STAGE1_5
+ int console_checkkey (void);
+ int console_getkey (void);
++int console_keystatus (void);
+ int console_getxy (void);
+ void console_gotoxy (int x, int y);
+ void console_cls (void);
+@@ -124,4 +140,23 @@ void hercules_setcolor (int normal_color, int highlight_color);
  int hercules_setcursor (int on);
  #endif
  
@@ -40398,7 +44779,7 @@ index 0000000..b182379
 @@ -0,0 +1 @@
 +fo of fo
 diff --git a/util/Makefile.am b/util/Makefile.am
-index 2e04711..a18ec35 100644
+index 2e04711..fa545b1 100644
 --- a/util/Makefile.am
 +++ b/util/Makefile.am
 @@ -1,6 +1,7 @@
@@ -40407,7 +44788,7 @@ index 2e04711..a18ec35 100644
  bin_PROGRAMS = mbchk
 -sbin_SCRIPTS = grub-install grub-md5-crypt grub-terminfo \
 -	grub-set-default
-+sbin_SCRIPTS = grub-install grub-md5-crypt grub-terminfo
++sbin_SCRIPTS = grub-install grub-md5-crypt grub-terminfo grub-crypt
  noinst_SCRIPTS = grub-image mkbimage
  
  EXTRA_DIST = mkbimage
@@ -40418,7 +44799,7 @@ index 2e04711..a18ec35 100644
 +
 +else
 +
-+sbin_SCRIPTS = grub-md5-crypt grub-terminfo
++sbin_SCRIPTS = grub-md5-crypt grub-terminfo grub-crypt
 +
 +endif
 diff --git a/util/Makefile.in b/util/Makefile.in
@@ -40757,8 +45138,94 @@ index e700cf7..aa5a12e 100644
  
  # Tell versions [3.59,3.63) of GNU make to not export all variables.
  # Otherwise a system limit (for SysV at least) may be exceeded.
+diff --git a/util/grub-crypt.in b/util/grub-crypt.in
+new file mode 100644
+index 0000000..e8783c8
+--- /dev/null
++++ b/util/grub-crypt.in
+@@ -0,0 +1,80 @@
++#! /usr/bin/python
++
++'''Generate encrypted passwords for GRUB.'''
++
++import crypt
++import getopt
++import getpass
++import sys
++
++def usage():
++    '''Output usage message to stderr and exit.'''
++    print >> sys.stderr, 'Usage: grub-crypt [OPTION]...'
++    print >> sys.stderr, 'Try `$progname --help\' for more information.'
++    sys.exit(1)
++
++def gen_salt():
++    '''Generate a random salt.'''
++    ret = ''
++    with open('/dev/urandom', 'rb') as urandom:
++        while True:
++            byte = urandom.read(1)
++            if byte in ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
++                        './0123456789'):
++                ret += byte
++                if len(ret) == 16:
++                    break
++    return ret
++
++def main():
++    '''Top level.'''
++    crypt_type = '$6$' # SHA-256
++    try:
++        opts, args = getopt.getopt(sys.argv[1:], 'hv',
++                                   ('help', 'version', 'md5', 'sha-256',
++                                    'sha-512'))
++    except getopt.GetoptError, err:
++        print >> sys.stderr, str(err)
++        usage()
++    if args:
++        print >> sys.stderr, 'Unexpected argument `%s\'' % (args[0],)
++        usage()
++    for (opt, _) in opts:
++        if opt in ('-h', '--help'):
++            print (
++'''Usage: grub-crypt [OPTION]...
++Encrypt a password.
++
++  -h, --help              Print this message and exit
++  -v, --version           Print the version information and exit
++  --md5                   Use MD5 to encrypt the password
++  --sha-256               Use SHA-256 to encrypt the password
++  --sha-512               Use SHA-512 to encrypt the password (default)
++
++Report bugs to <bug-grub at gnu.org>.
++EOF''')
++            sys.exit(0)
++        elif opt in ('-v', '--version'):
++            print 'grub-crypt (GNU GRUB @VERSION@)'
++            sys.exit(0)
++        elif opt == '--md5':
++            crypt_type = '$1$'
++        elif opt == '--sha-256':
++            crypt_type = '$5$'
++        elif opt == '--sha-512':
++            crypt_type = '$6$'
++        else:
++            assert False, 'Unhandled option'
++    password = getpass.getpass('Password: ')
++    password2 = getpass.getpass('Retype password: ')
++    if not password:
++        print >> sys.stderr, 'Empty password is not permitted.'
++        sys.exit(1)
++    if password != password2:
++        print >> sys.stderr, 'Sorry, passwords do not match.'
++        sys.exit(1)
++    salt = crypt_type + gen_salt()
++    print crypt.crypt(password, salt)
++
++if __name__ == '__main__':
++    main()
 diff --git a/util/grub-install.in b/util/grub-install.in
-index 2e598b0..5ceb77d 100644
+index 2e598b0..63d6284 100644
 --- a/util/grub-install.in
 +++ b/util/grub-install.in
 @@ -21,26 +21,28 @@
@@ -40809,7 +45276,7 @@ index 2e598b0..5ceb77d 100644
 -	tmp_disk=`echo "$1" | sed -e 's%\([sh]d[a-z]\)[0-9]*$%\1%' \
 +	tmp_disk=`echo "$1" | grep -v '/mapper/control$' |
 +		grep -v '/mapper/[[:alnum:]]\+-[[:alnum:]]\+$' | uniq |
-+		sed -e 's%\([sh]d[a-z]\)[0-9]*$%\1%' \
++		sed -e 's%\([shv]d[a-z]\)[0-9]*$%\1%' \
  				  -e 's%\(d[0-9]*\)p[0-9]*$%\1%' \
  				  -e 's%\(fd[0-9]*\)$%\1%' \
  				  -e 's%/part[0-9]*$%/disc%' \
@@ -40821,7 +45288,7 @@ index 2e598b0..5ceb77d 100644
 +	  -e 's%\(/mapper/[[:alpha:]]\+_[[:alpha:]]\+\)[[:digit:]]\+$%\1%'`
 +	tmp_part=`echo "$1" | grep -v '/mapper/control$' |
 +		grep -v '/mapper/[[:alnum:]]\+-[[:alnum:]]\+$' | uniq |
-+		sed -e 's%.*/[sh]d[a-z]\([0-9]*\)$%\1%' \
++		sed -e 's%.*/[shv]d[a-z]\([0-9]*\)$%\1%' \
  				  -e 's%.*d[0-9]*p%%' \
  				  -e 's%.*/fd[0-9]*$%%' \
  				  -e 's%.*/floppy/[0-9]*$%%' \
@@ -41168,7 +45635,7 @@ index 2e598b0..5ceb77d 100644
  
  if test "x$grubdir_device" != "x$root_device"; then
      # For now, cannot deal with this situation.
-@@ -406,61 +576,66 @@ EOF
+@@ -406,61 +576,71 @@ EOF
      exit 1
  fi
  
@@ -41216,9 +45683,14 @@ index 2e598b0..5ceb77d 100644
 -	count=`expr $count - 1`    
 +        dump_boot_block $root_drive $img_file
 +        if grep "Error [0-9]*: " $log_file >/dev/null; then
-+    	:
-+        elif cmp $file $img_file >/dev/null; then
-+    	break
++            :
++        else
++            # Use sha1sum instead of cmp to avoid a dependency on diffutils.
++            sha1=`sha1sum $file | cut -d' ' -f 1`
++            sha2=`sha1sum $img_file | cut -d' ' -f 1`
++            if test -f $file -a -f $img_file -a "$sha1" = "$sha2"; then
++                break
++            fi
 +        fi
 +        sleep 1
 +        count=`expr $count - 1`    
diff --git a/grub.spec b/grub.spec
index f91e652..f891e63 100644
--- a/grub.spec
+++ b/grub.spec
@@ -1,6 +1,6 @@
 Name: grub
 Version: 0.97
-Release: 69%{?dist}
+Release: 70%{?dist}
 Epoch: 1
 Summary: Grand Unified Boot Loader.
 Group: System Environment/Base
@@ -22,45 +22,7 @@ Source0: ftp://alpha.gnu.org/gnu/%{name}/%{name}-%{version}.tar.gz
 
 # This is from
 # http://git.kernel.org/?p=boot/grub-fedora/grub-fedora.git;a=summary
-Patch0: grub-fedora-9.patch
-Patch1: grub-keystatus.patch
-
-# Various bugfixes
-# http://fedorapeople.org/~lkundrak/grub-fedora.git/
-Patch2: 0001-Get-rid-of-usr-bin-cmp-dependency.patch
-Patch3: 0002-Add-strspn-strcspn-and-strtok_r.patch
-Patch4: 0003-Allow-passing-multiple-image-files-to-the-initrd-com.patch
-Patch5: 0004-Obey-2.06-boot-protocol-s-cmdline_size.patch
-
-Patch6: grub-0.97-printf_hex.patch
-Patch7: grub-0.97-eficd.patch
-Patch8: grub-0.97-xfs-buildfix.patch
-Patch9: grub-0.97-efigraph-use-blt.patch
-Patch10: grub-0.97-efislice.patch
-Patch11: grub-0.97-efistatus.patch
-Patch12: grub-0.97-fat-lowercase.patch
-Patch13: grub-0.97-efipxe.patch
-Patch14: grub-0.97-tolower.patch
-Patch15: grub-low-memory.patch
-Patch16: grub-install_virtio_blk_support.patch
-Patch17: grub-fix-memory-corruption.patch
-Patch18: grub-ext4-support.patch
-Patch19: grub-0.97-xfs-writable-strings.patch
-Patch20: grub-0.97-partitionable-md.patch
-Patch21: grub-0.97-relocatable-kernel-on-x86_64-uefi.patch
-Patch22: grub-0.97-use-gnuefi.patch
-Patch23: grub-0.97-gate-a20.patch
-Patch24: grub-0.97-efi-graphics-mode-selection.patch
-Patch25: grub-silent.patch
-Patch26: grub-0.97-bz553741-sha2.patch
-Patch27: grub-0.97-invert-highlighted-menu-line-rhbz613153.patch
-Patch28: grub-0.97-better-get-memory-map-rhbz607213.patch
-Patch29: grub-0.97-add-strnchr.patch
-Patch30: grub-0.97-efimap.patch
-Patch31: grub-efi-large-memory-map.patch
-Patch32: grub-0.97-version-command-rhbz621989.patch
-Patch33: grub-0.97-devpath-parsing-error-rhbz626447.patch
-Patch34: grub-0.97-handle-bad-tftp.patch
+Patch0: grub-fedora-14.patch
 
 %description
 GRUB (Grand Unified Boot Loader) is an experimental boot loader
@@ -70,41 +32,12 @@ systems.
 
 %prep
 %setup -q
-%patch0 -p1
-%patch1 -p1
-%patch2 -p1
-%patch3 -p1
-%patch4 -p1
-%patch5 -p1
-%patch6 -p1
-%patch7 -p1
-%patch8 -p1
-%patch9 -p1
-%patch10 -p1
-%patch11 -p1
-%patch12 -p1
-%patch13 -p1
-%patch14 -p1
-%patch15 -p1
-%patch16 -p1
-%patch17 -p1
-%patch18 -p1
-%patch19 -p1
-%patch20 -p1
-%patch21 -p1
-%patch22 -p1
-%patch23 -p1
-%patch24 -p1
-%patch25 -p1
-%patch26 -p1
-%patch27 -p1
-%patch28 -p1
-%patch29 -p1
-%patch30 -p1
-%patch31 -p1
-%patch32 -p1
-%patch33 -p1
-%patch34 -p1
+git init
+git config user.email "pjones at fedoraproject.org"
+git config user.name "Fedora Ninjas"
+git add .
+git commit -a -q -m "%{version} baseline."
+git am %{patches}
 
 # Modify grub to show the full version number
 sed -i 's/0\.97/%{version}-%{release}/' configure.in


More information about the scm-commits mailing list