[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,
+ ¶ms->red_field_pos, ¶ms->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 = ¶ms->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,
¤t_partition, ¤t_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