diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f072794
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+SOURCES/grub-2.02.tar.xz
+SOURCES/theme.tar.bz2
+SOURCES/unifont-5.1.20080820.pcf.gz
diff --git a/.grub2.metadata b/.grub2.metadata
new file mode 100644
index 0000000..3bb3b94
--- /dev/null
+++ b/.grub2.metadata
@@ -0,0 +1,3 @@
+3d7eb6eaab28b88cb969ba9ab24af959f4d1b178 SOURCES/grub-2.02.tar.xz
+cf0b7763c528902da7e8b05cfa248f20c8825ce5 SOURCES/theme.tar.bz2
+87f8600ba24e521b5d20bdf6c4b71af8ae861e3a SOURCES/unifont-5.1.20080820.pcf.gz
diff --git a/SOURCES/0001-Add-support-for-Linux-EFI-stub-loading.patch b/SOURCES/0001-Add-support-for-Linux-EFI-stub-loading.patch
new file mode 100644
index 0000000..88fae3c
--- /dev/null
+++ b/SOURCES/0001-Add-support-for-Linux-EFI-stub-loading.patch
@@ -0,0 +1,997 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Tue, 10 Jul 2012 11:58:52 -0400
+Subject: [PATCH] Add support for Linux EFI stub loading.
+
+Also:
+
+commit 71c843745f22f81e16d259e2e19c99bf3c1855c1
+Author: Colin Watson <cjwatson@ubuntu.com>
+Date:   Tue Oct 23 10:40:49 2012 -0400
+
+Don't allow insmod when secure boot is enabled.
+
+Hi,
+
+Fedora's patch to forbid insmod in UEFI Secure Boot environments is fine
+as far as it goes.  However, the insmod command is not the only way that
+modules can be loaded.  In particular, the 'normal' command, which
+implements the usual GRUB menu and the fully-featured command prompt,
+will implicitly load commands not currently loaded into memory.  This
+permits trivial Secure Boot violations by writing commands implementing
+whatever you want to do and pointing $prefix at the malicious code.
+
+I'm currently test-building this patch (replacing your current
+grub-2.00-no-insmod-on-sb.patch), but this should be more correct.  It
+moves the check into grub_dl_load_file.
+---
+ grub-core/Makefile.core.def       |  16 +-
+ grub-core/kern/dl.c               |  21 +++
+ grub-core/kern/efi/efi.c          |  28 ++++
+ grub-core/kern/efi/mm.c           |  32 ++++
+ grub-core/loader/arm64/linux.c    | 118 +++++++-------
+ grub-core/loader/arm64/xen_boot.c |   1 -
+ grub-core/loader/efi/linux.c      |  70 ++++++++
+ grub-core/loader/i386/efi/linux.c | 335 ++++++++++++++++++++++++++++++++++++++
+ grub-core/loader/i386/pc/linux.c  |  10 +-
+ include/grub/arm/linux.h          |   9 +
+ include/grub/arm64/linux.h        |  10 ++
+ include/grub/efi/efi.h            |   7 +-
+ include/grub/efi/linux.h          |  31 ++++
+ include/grub/i386/linux.h         |   1 +
+ 14 files changed, 620 insertions(+), 69 deletions(-)
+ create mode 100644 grub-core/loader/efi/linux.c
+ create mode 100644 grub-core/loader/i386/efi/linux.c
+ create mode 100644 include/grub/efi/linux.h
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 9590e87d9c0..0b4b0c2122d 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -1626,13 +1626,6 @@ module = {
+   enable = i386_pc;
+ };
+ 
+-
+-module = {
+-  name = linux16;
+-  common = loader/i386/pc/linux.c;
+-  enable = x86;
+-};
+-
+ module = {
+   name = ntldr;
+   i386_pc = loader/i386/pc/ntldr.c;
+@@ -1685,7 +1678,9 @@ module = {
+ 
+ module = {
+   name = linux;
+-  x86 = loader/i386/linux.c;
++  i386_pc = loader/i386/pc/linux.c;
++  x86_64_efi = loader/i386/efi/linux.c;
++  i386_efi = loader/i386/efi/linux.c;
+   xen = loader/i386/xen.c;
+   i386_pc = lib/i386/pc/vesa_modes_table.c;
+   mips = loader/mips/linux.c;
+@@ -1696,9 +1691,14 @@ module = {
+   arm_efi = loader/arm64/linux.c;
+   arm_uboot = loader/arm/linux.c;
+   arm64 = loader/arm64/linux.c;
++  emu = loader/emu/linux.c;
++  fdt = lib/fdt.c;
++
+   common = loader/linux.c;
+   common = lib/cmdline.c;
+   enable = noemu;
++
++  efi = loader/efi/linux.c;
+ };
+ 
+ module = {
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index e394cd96f8c..04e804d1668 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -38,6 +38,14 @@
+ #define GRUB_MODULES_MACHINE_READONLY
+ #endif
+ 
++#ifdef GRUB_MACHINE_EMU
++#include <sys/mman.h>
++#endif
++
++#ifdef GRUB_MACHINE_EFI
++#include <grub/efi/efi.h>
++#endif
++
+ 
+ 
+ #pragma GCC diagnostic ignored "-Wcast-align"
+@@ -686,6 +694,19 @@ grub_dl_load_file (const char *filename)
+   void *core = 0;
+   grub_dl_t mod = 0;
+ 
++#ifdef GRUB_MACHINE_EFI
++  if (grub_efi_secure_boot ())
++    {
++#if 0
++      /* This is an error, but grub2-mkconfig still generates a pile of
++       * insmod commands, so emitting it would be mostly just obnoxious. */
++      grub_error (GRUB_ERR_ACCESS_DENIED,
++		  "Secure Boot forbids loading module from %s", filename);
++#endif
++      return 0;
++    }
++#endif
++
+   grub_boot_time ("Loading module %s", filename);
+ 
+   file = grub_file_open (filename);
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index 708581fcbde..c8a9d8307c0 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -273,6 +273,34 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
+   return NULL;
+ }
+ 
++grub_efi_boolean_t
++grub_efi_secure_boot (void)
++{
++  grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID;
++  grub_size_t datasize;
++  char *secure_boot = NULL;
++  char *setup_mode = NULL;
++  grub_efi_boolean_t ret = 0;
++
++  secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize);
++
++  if (datasize != 1 || !secure_boot)
++    goto out;
++
++  setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize);
++
++  if (datasize != 1 || !setup_mode)
++    goto out;
++
++  if (*secure_boot && !*setup_mode)
++    ret = 1;
++
++ out:
++  grub_free (secure_boot);
++  grub_free (setup_mode);
++  return ret;
++}
++
+ #pragma GCC diagnostic ignored "-Wcast-align"
+ 
+ /* Search the mods section from the PE32/PE32+ image. This code uses
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index 42ad7c570a5..5cdf6c943f2 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -113,6 +113,38 @@ grub_efi_drop_alloc (grub_efi_physical_address_t address,
+     }
+ }
+ 
++/* Allocate pages below a specified address */
++void *
++grub_efi_allocate_pages_max (grub_efi_physical_address_t max,
++			     grub_efi_uintn_t pages)
++{
++  grub_efi_status_t status;
++  grub_efi_boot_services_t *b;
++  grub_efi_physical_address_t address = max;
++
++  if (max > 0xffffffff)
++    return 0;
++
++  b = grub_efi_system_table->boot_services;
++  status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++
++  if (address == 0)
++    {
++      /* Uggh, the address 0 was allocated... This is too annoying,
++	 so reallocate another one.  */
++      address = max;
++      status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
++      grub_efi_free_pages (0, pages);
++      if (status != GRUB_EFI_SUCCESS)
++	return 0;
++    }
++
++  return (void *) ((grub_addr_t) address);
++}
++
+ /* Allocate pages. Return the pointer to the first of allocated pages.  */
+ void *
+ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index 1f86229f86b..6c00af98dce 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -29,6 +29,7 @@
+ #include <grub/efi/efi.h>
+ #include <grub/efi/fdtload.h>
+ #include <grub/efi/memory.h>
++#include <grub/efi/linux.h>
+ #include <grub/efi/pe32.h>
+ #include <grub/i18n.h>
+ #include <grub/lib/cmdline.h>
+@@ -40,6 +41,7 @@ static int loaded;
+ 
+ static void *kernel_addr;
+ static grub_uint64_t kernel_size;
++static grub_uint32_t handover_offset;
+ 
+ static char *linux_args;
+ static grub_uint32_t cmdline_size;
+@@ -66,7 +68,8 @@ grub_armxx_efi_linux_check_image (struct linux_armxx_kernel_header * lh)
+ static grub_err_t
+ finalize_params_linux (void)
+ {
+-  int node, retval;
++  grub_efi_loaded_image_t *loaded_image = NULL;
++  int node, retval, len;
+ 
+   void *fdt;
+ 
+@@ -101,79 +104,70 @@ finalize_params_linux (void)
+   if (grub_fdt_install() != GRUB_ERR_NONE)
+     goto failure;
+ 
+-  return GRUB_ERR_NONE;
+-
+-failure:
+-  grub_fdt_unload();
+-  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
+-}
+-
+-grub_err_t
+-grub_armxx_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args)
+-{
+-  grub_efi_memory_mapped_device_path_t *mempath;
+-  grub_efi_handle_t image_handle;
+-  grub_efi_boot_services_t *b;
+-  grub_efi_status_t status;
+-  grub_efi_loaded_image_t *loaded_image;
+-  int len;
+-
+-  mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t));
+-  if (!mempath)
+-    return grub_errno;
+-
+-  mempath[0].header.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE;
+-  mempath[0].header.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE;
+-  mempath[0].header.length = grub_cpu_to_le16_compile_time (sizeof (*mempath));
+-  mempath[0].memory_type = GRUB_EFI_LOADER_DATA;
+-  mempath[0].start_address = addr;
+-  mempath[0].end_address = addr + size;
+-
+-  mempath[1].header.type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+-  mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+-  mempath[1].header.length = sizeof (grub_efi_device_path_t);
+-
+-  b = grub_efi_system_table->boot_services;
+-  status = b->load_image (0, grub_efi_image_handle,
+-			  (grub_efi_device_path_t *) mempath,
+-			  (void *) addr, size, &image_handle);
+-  if (status != GRUB_EFI_SUCCESS)
+-    return grub_error (GRUB_ERR_BAD_OS, "cannot load image");
+-
+-  grub_dprintf ("linux", "linux command line: '%s'\n", args);
++  grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
++		fdt);
+ 
+   /* Convert command line to UCS-2 */
+-  loaded_image = grub_efi_get_loaded_image (image_handle);
++  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
++  if (!loaded_image)
++    goto failure;
++
+   loaded_image->load_options_size = len =
+-    (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t);
++    (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t);
+   loaded_image->load_options =
+     grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
+   if (!loaded_image->load_options)
+-    return grub_errno;
++    return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
+ 
+   loaded_image->load_options_size =
+     2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
+-			    (grub_uint8_t *) args, len, NULL);
++			    (grub_uint8_t *) linux_args, len, NULL);
+ 
+-  grub_dprintf ("linux", "starting image %p\n", image_handle);
+-  status = b->start_image (image_handle, 0, NULL);
++  return GRUB_ERR_NONE;
+ 
+-  /* When successful, not reached */
+-  b->unload_image (image_handle);
+-  grub_efi_free_pages ((grub_addr_t) loaded_image->load_options,
+-		       GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
++failure:
++  grub_fdt_unload();
++  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
++}
+ 
+-  return grub_errno;
++static void
++free_params (void)
++{
++  grub_efi_loaded_image_t *loaded_image = NULL;
++
++  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
++  if (loaded_image)
++    {
++      if (loaded_image->load_options)
++	grub_efi_free_pages ((grub_efi_physical_address_t)(grub_efi_uintn_t)loaded_image->load_options,
++			     GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
++      loaded_image->load_options = NULL;
++      loaded_image->load_options_size = 0;
++    }
++}
++
++grub_err_t
++grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args)
++{
++  grub_err_t retval;
++
++  retval = finalize_params_linux ();
++  if (retval != GRUB_ERR_NONE)
++    return grub_errno;
++
++  grub_dprintf ("linux", "linux command line: '%s'\n", args);
++
++  retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr);
++
++  /* Never reached... */
++  free_params();
++  return retval;
+ }
+ 
+ static grub_err_t
+ grub_linux_boot (void)
+ {
+-  if (finalize_params_linux () != GRUB_ERR_NONE)
+-    return grub_errno;
+-
+-  return (grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr,
+-                                          kernel_size, linux_args));
++  return grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args);
+ }
+ 
+ static grub_err_t
+@@ -287,6 +281,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ {
+   grub_file_t file = 0;
+   struct linux_armxx_kernel_header lh;
++  struct grub_armxx_linux_pe_header *pe;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -331,6 +326,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
+ 
++  if (!grub_linuxefi_secure_validate (kernel_addr, kernel_size))
++    {
++      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
++      goto fail;
++    }
++
++  pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
++  handover_offset = pe->opt.entry_addr;
++
+   cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
+   linux_args = grub_malloc (cmdline_size);
+   if (!linux_args)
+diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
+index 1003a0b9997..f35b16caa92 100644
+--- a/grub-core/loader/arm64/xen_boot.c
++++ b/grub-core/loader/arm64/xen_boot.c
+@@ -266,7 +266,6 @@ xen_boot (void)
+     return err;
+ 
+   return grub_armxx_efi_linux_boot_image (xen_hypervisor->start,
+-					  xen_hypervisor->size,
+ 					  xen_hypervisor->cmdline);
+ }
+ 
+diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
+new file mode 100644
+index 00000000000..c24202a5dd1
+--- /dev/null
++++ b/grub-core/loader/efi/linux.c
+@@ -0,0 +1,70 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2014 Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/types.h>
++#include <grub/cpu/linux.h>
++#include <grub/efi/efi.h>
++#include <grub/efi/pe32.h>
++#include <grub/efi/linux.h>
++
++#define SHIM_LOCK_GUID \
++ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
++
++struct grub_efi_shim_lock
++{
++  grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size);
++};
++typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
++
++grub_efi_boolean_t
++grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
++{
++  grub_efi_guid_t guid = SHIM_LOCK_GUID;
++  grub_efi_shim_lock_t *shim_lock;
++
++  shim_lock = grub_efi_locate_protocol(&guid, NULL);
++
++  if (!shim_lock)
++    return 1;
++
++  if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
++    return 1;
++
++  return 0;
++}
++
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Wcast-align"
++
++typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
++
++grub_err_t
++grub_efi_linux_boot (void *kernel_addr, grub_off_t offset,
++		     void *kernel_params)
++{
++  handover_func hf;
++
++  hf = (handover_func)((char *)kernel_addr + offset);
++  hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
++
++  return GRUB_ERR_BUG;
++}
++
++#pragma GCC diagnostic pop
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+new file mode 100644
+index 00000000000..3db82e782df
+--- /dev/null
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -0,0 +1,335 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2012  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/loader.h>
++#include <grub/file.h>
++#include <grub/err.h>
++#include <grub/types.h>
++#include <grub/mm.h>
++#include <grub/cpu/linux.h>
++#include <grub/command.h>
++#include <grub/i18n.h>
++#include <grub/lib/cmdline.h>
++#include <grub/efi/efi.h>
++#include <grub/efi/linux.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static grub_dl_t my_mod;
++static int loaded;
++static void *kernel_mem;
++static grub_uint64_t kernel_size;
++static grub_uint8_t *initrd_mem;
++static grub_uint32_t handover_offset;
++struct linux_kernel_params *params;
++static char *linux_cmdline;
++
++#define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> 12)
++
++static grub_err_t
++grub_linuxefi_boot (void)
++{
++  int offset = 0;
++
++#ifdef __x86_64__
++  offset = 512;
++#endif
++  asm volatile ("cli");
++
++  return grub_efi_linux_boot ((char *)kernel_mem, handover_offset + offset,
++			      params);
++}
++
++static grub_err_t
++grub_linuxefi_unload (void)
++{
++  grub_dl_unref (my_mod);
++  loaded = 0;
++  if (initrd_mem)
++    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem,
++			 BYTES_TO_PAGES(params->ramdisk_size));
++  if (linux_cmdline)
++    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)
++			 linux_cmdline,
++			 BYTES_TO_PAGES(params->cmdline_size + 1));
++  if (kernel_mem)
++    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem,
++			 BYTES_TO_PAGES(kernel_size));
++  if (params)
++    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params,
++			 BYTES_TO_PAGES(16384));
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
++                 int argc, char *argv[])
++{
++  grub_file_t *files = 0;
++  int i, nfiles = 0;
++  grub_size_t size = 0;
++  grub_uint8_t *ptr;
++
++  if (argc == 0)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
++      goto fail;
++    }
++
++  if (!loaded)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
++      goto fail;
++    }
++
++  files = grub_zalloc (argc * sizeof (files[0]));
++  if (!files)
++    goto fail;
++
++  for (i = 0; i < argc; i++)
++    {
++      grub_file_filter_disable_compression ();
++      files[i] = grub_file_open (argv[i]);
++      if (! files[i])
++        goto fail;
++      nfiles++;
++      size += ALIGN_UP (grub_file_size (files[i]), 4);
++    }
++
++  initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size));
++  if (!initrd_mem)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
++      goto fail;
++    }
++
++  params->ramdisk_size = size;
++  params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem;
++
++  ptr = initrd_mem;
++
++  for (i = 0; i < nfiles; i++)
++    {
++      grub_ssize_t cursize = grub_file_size (files[i]);
++      if (grub_file_read (files[i], ptr, cursize) != cursize)
++        {
++          if (!grub_errno)
++            grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
++                        argv[i]);
++          goto fail;
++        }
++      ptr += cursize;
++      grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
++      ptr += ALIGN_UP_OVERHEAD (cursize, 4);
++    }
++
++  params->ramdisk_size = size;
++
++ fail:
++  for (i = 0; i < nfiles; i++)
++    grub_file_close (files[i]);
++  grub_free (files);
++
++  if (initrd_mem && grub_errno)
++    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem,
++			 BYTES_TO_PAGES(size));
++
++  return grub_errno;
++}
++
++static grub_err_t
++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
++		int argc, char *argv[])
++{
++  grub_file_t file = 0;
++  struct linux_kernel_header lh;
++  grub_ssize_t len, start, filelen;
++  void *kernel = NULL;
++
++  grub_dl_ref (my_mod);
++
++  if (argc == 0)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
++      goto fail;
++    }
++
++  file = grub_file_open (argv[0]);
++  if (! file)
++    goto fail;
++
++  filelen = grub_file_size (file);
++
++  kernel = grub_malloc(filelen);
++
++  if (!kernel)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
++      goto fail;
++    }
++
++  if (grub_file_read (file, kernel, filelen) != filelen)
++    {
++      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]);
++      goto fail;
++    }
++
++  if (! grub_linuxefi_secure_validate (kernel, filelen))
++    {
++      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"),
++		  argv[0]);
++      goto fail;
++    }
++
++  params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384));
++
++  if (! params)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
++      goto fail;
++    }
++
++  grub_memset (params, 0, 16384);
++
++  grub_memcpy (&lh, kernel, sizeof (lh));
++
++  if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
++    {
++      grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number"));
++      goto fail;
++    }
++
++  if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
++    {
++      grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors"));
++      goto fail;
++    }
++
++  if (lh.version < grub_cpu_to_le16 (0x020b))
++    {
++      grub_error (GRUB_ERR_BAD_OS, N_("kernel too old"));
++      goto fail;
++    }
++
++  if (!lh.handover_offset)
++    {
++      grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover"));
++      goto fail;
++    }
++
++  grub_dprintf ("linux", "setting up cmdline\n");
++  linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff,
++					 BYTES_TO_PAGES(lh.cmdline_size + 1));
++
++  if (!linux_cmdline)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
++      goto fail;
++    }
++
++  grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
++  grub_create_loader_cmdline (argc, argv,
++                              linux_cmdline + sizeof (LINUX_IMAGE) - 1,
++			      lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1));
++
++  lh.cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline;
++
++  handover_offset = lh.handover_offset;
++
++  start = (lh.setup_sects + 1) * 512;
++  len = grub_file_size(file) - start;
++
++  kernel_mem = grub_efi_allocate_pages_max(lh.pref_address,
++					   BYTES_TO_PAGES(lh.init_size));
++
++  if (!kernel_mem)
++    kernel_mem = grub_efi_allocate_pages_max(0x3fffffff,
++					     BYTES_TO_PAGES(lh.init_size));
++
++  if (!kernel_mem)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
++      goto fail;
++    }
++
++  grub_memcpy (kernel_mem, (char *)kernel + start, len);
++  grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
++  loaded=1;
++
++  lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem;
++  grub_memcpy (params, &lh, 2 * 512);
++
++  params->type_of_loader = 0x21;
++
++ fail:
++
++  if (file)
++    grub_file_close (file);
++
++  if (kernel)
++    grub_free (kernel);
++
++  if (grub_errno != GRUB_ERR_NONE)
++    {
++      grub_dl_unref (my_mod);
++      loaded = 0;
++    }
++
++  if (linux_cmdline && !loaded)
++    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)
++			 linux_cmdline,
++			 BYTES_TO_PAGES(lh.cmdline_size + 1));
++
++  if (kernel_mem && !loaded)
++    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem,
++			 BYTES_TO_PAGES(kernel_size));
++
++  if (params && !loaded)
++    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params,
++			 BYTES_TO_PAGES(16384));
++
++  return grub_errno;
++}
++
++static grub_command_t cmd_linux, cmd_initrd;
++static grub_command_t cmd_linuxefi, cmd_initrdefi;
++
++GRUB_MOD_INIT(linux)
++{
++  cmd_linux =
++    grub_register_command ("linux", grub_cmd_linux,
++                           0, N_("Load Linux."));
++  cmd_linuxefi =
++    grub_register_command ("linuxefi", grub_cmd_linux,
++                           0, N_("Load Linux."));
++  cmd_initrd =
++    grub_register_command ("initrd", grub_cmd_initrd,
++                           0, N_("Load initrd."));
++  cmd_initrdefi =
++    grub_register_command ("initrdefi", grub_cmd_initrd,
++                           0, N_("Load initrd."));
++  my_mod = mod;
++}
++
++GRUB_MOD_FINI(linux)
++{
++  grub_unregister_command (cmd_linux);
++  grub_unregister_command (cmd_linuxefi);
++  grub_unregister_command (cmd_initrd);
++  grub_unregister_command (cmd_initrdefi);
++}
+diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
+index b69cb7a3a7f..a3c87cf2fc2 100644
+--- a/grub-core/loader/i386/pc/linux.c
++++ b/grub-core/loader/i386/pc/linux.c
+@@ -468,14 +468,20 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+   return grub_errno;
+ }
+ 
+-static grub_command_t cmd_linux, cmd_initrd;
++static grub_command_t cmd_linux, cmd_linux16, cmd_initrd, cmd_initrd16;
+ 
+ GRUB_MOD_INIT(linux16)
+ {
+   cmd_linux =
++    grub_register_command ("linux", grub_cmd_linux,
++			   0, N_("Load Linux."));
++  cmd_linux16 =
+     grub_register_command ("linux16", grub_cmd_linux,
+ 			   0, N_("Load Linux."));
+   cmd_initrd =
++    grub_register_command ("initrd", grub_cmd_initrd,
++			   0, N_("Load initrd."));
++  cmd_initrd16 =
+     grub_register_command ("initrd16", grub_cmd_initrd,
+ 			   0, N_("Load initrd."));
+   my_mod = mod;
+@@ -484,5 +490,7 @@ GRUB_MOD_INIT(linux16)
+ GRUB_MOD_FINI(linux16)
+ {
+   grub_unregister_command (cmd_linux);
++  grub_unregister_command (cmd_linux16);
+   grub_unregister_command (cmd_initrd);
++  grub_unregister_command (cmd_initrd16);
+ }
+diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h
+index 712ba17b9ba..5900fc8a40c 100644
+--- a/include/grub/arm/linux.h
++++ b/include/grub/arm/linux.h
+@@ -20,6 +20,7 @@
+ #ifndef GRUB_ARM_LINUX_HEADER
+ #define GRUB_ARM_LINUX_HEADER 1
+ 
++#include <grub/efi/pe32.h>
+ #include "system.h"
+ 
+ #define GRUB_LINUX_ARM_MAGIC_SIGNATURE 0x016f2818
+@@ -34,9 +35,17 @@ struct linux_arm_kernel_header {
+   grub_uint32_t hdr_offset;
+ };
+ 
++struct grub_arm_linux_pe_header
++{
++  grub_uint32_t magic;
++  struct grub_pe32_coff_header coff;
++  struct grub_pe32_optional_header opt;
++};
++
+ #if defined(__arm__)
+ # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM_MAGIC_SIGNATURE
+ # define linux_armxx_kernel_header linux_arm_kernel_header
++# define grub_armxx_linux_pe_header grub_arm_linux_pe_header
+ #endif
+ 
+ #if defined GRUB_MACHINE_UBOOT
+diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h
+index 8655067e039..7b533b57139 100644
+--- a/include/grub/arm64/linux.h
++++ b/include/grub/arm64/linux.h
+@@ -19,6 +19,8 @@
+ #ifndef GRUB_ARM64_LINUX_HEADER
+ #define GRUB_ARM64_LINUX_HEADER 1
+ 
++#include <grub/efi/pe32.h>
++
+ #define GRUB_LINUX_ARM64_MAGIC_SIGNATURE 0x644d5241 /* 'ARM\x64' */
+ 
+ /* From linux/Documentation/arm64/booting.txt */
+@@ -36,9 +38,17 @@ struct linux_arm64_kernel_header
+   grub_uint32_t hdr_offset;	/* Offset of PE/COFF header */
+ };
+ 
++struct grub_arm64_linux_pe_header
++{
++  grub_uint32_t magic;
++  struct grub_pe32_coff_header coff;
++  struct grub_pe64_optional_header opt;
++};
++
+ #if defined(__aarch64__)
+ # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM64_MAGIC_SIGNATURE
+ # define linux_armxx_kernel_header linux_arm64_kernel_header
++# define grub_armxx_linux_pe_header grub_arm64_linux_pe_header
+ #endif
+ 
+ #endif /* ! GRUB_ARM64_LINUX_HEADER */
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index 2c6648d46fc..1061aee9726 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -47,6 +47,9 @@ EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address,
+ 				      grub_efi_uintn_t pages);
+ void *
+ EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages);
++void *
++EXPORT_FUNC(grub_efi_allocate_pages_max) (grub_efi_physical_address_t max,
++					  grub_efi_uintn_t pages);
+ void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address,
+ 				       grub_efi_uintn_t pages);
+ grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void);
+@@ -82,6 +85,7 @@ EXPORT_FUNC (grub_efi_set_variable) (const char *var,
+ 				     const grub_efi_guid_t *guid,
+ 				     void *data,
+ 				     grub_size_t datasize);
++grub_efi_boolean_t EXPORT_FUNC (grub_efi_secure_boot) (void);
+ int
+ EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1,
+ 					     const grub_efi_device_path_t *dp2);
+@@ -95,8 +99,7 @@ void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
+ grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
+ #include <grub/cpu/linux.h>
+ grub_err_t grub_armxx_efi_linux_check_image(struct linux_armxx_kernel_header *lh);
+-grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, grub_size_t size,
+-                                           char *args);
++grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, char *args);
+ #endif
+ 
+ grub_addr_t grub_efi_modules_addr (void);
+diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
+new file mode 100644
+index 00000000000..d9ede36773b
+--- /dev/null
++++ b/include/grub/efi/linux.h
+@@ -0,0 +1,31 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2014  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++#ifndef GRUB_EFI_LINUX_HEADER
++#define GRUB_EFI_LINUX_HEADER	1
++
++#include <grub/efi/api.h>
++#include <grub/err.h>
++#include <grub/symbol.h>
++
++grub_efi_boolean_t
++EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size);
++grub_err_t
++EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
++				  void *kernel_param);
++
++#endif /* ! GRUB_EFI_LINUX_HEADER */
+diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h
+index 60c7c3b5e66..bb19dbd5a77 100644
+--- a/include/grub/i386/linux.h
++++ b/include/grub/i386/linux.h
+@@ -142,6 +142,7 @@ struct linux_i386_kernel_header
+   grub_uint64_t setup_data;
+   grub_uint64_t pref_address;
+   grub_uint32_t init_size;
++  grub_uint32_t handover_offset;
+ } GRUB_PACKED;
+ 
+ /* Boot parameters for Linux based on 2.6.12. This is used by the setup
diff --git a/SOURCES/0002-Rework-linux-command.patch b/SOURCES/0002-Rework-linux-command.patch
new file mode 100644
index 0000000..485541f
--- /dev/null
+++ b/SOURCES/0002-Rework-linux-command.patch
@@ -0,0 +1,115 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Sun, 9 Aug 2015 16:12:39 -0700
+Subject: [PATCH] Rework linux command
+
+We want a single buffer that contains the entire kernel image in order to
+perform a TPM measurement. Allocate one and copy the entire kernel into it
+before pulling out the individual blocks later on.
+---
+ grub-core/loader/i386/linux.c | 37 ++++++++++++++++++++++++-------------
+ 1 file changed, 24 insertions(+), 13 deletions(-)
+
+diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
+index 9b53d3168f9..f7186be4002 100644
+--- a/grub-core/loader/i386/linux.c
++++ b/grub-core/loader/i386/linux.c
+@@ -685,13 +685,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ {
+   grub_file_t file = 0;
+   struct linux_i386_kernel_header lh;
++  grub_uint8_t *linux_params_ptr;
+   grub_uint8_t setup_sects;
+-  grub_size_t real_size, prot_size, prot_file_size;
++  grub_size_t real_size, prot_size, prot_file_size, kernel_offset;
+   grub_ssize_t len;
+   int i;
+   grub_size_t align, min_align;
+   int relocatable;
+   grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
++  grub_uint8_t *kernel = NULL;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -705,7 +707,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   if (! file)
+     goto fail;
+ 
+-  if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
++  len = grub_file_size (file);
++  kernel = grub_malloc (len);
++  if (!kernel)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
++      goto fail;
++    }
++
++  if (grub_file_read (file, kernel, len) != len)
+     {
+       if (!grub_errno)
+ 	grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+@@ -713,6 +723,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
++  grub_memcpy (&lh, kernel, sizeof (lh));
++  kernel_offset = sizeof (lh);
++
+   if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
+     {
+       grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
+@@ -804,6 +817,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 		      preferred_address))
+     goto fail;
+ 
++
+   grub_memset (&linux_params, 0, sizeof (linux_params));
+   grub_memcpy (&linux_params.setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
+ 
+@@ -812,13 +826,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   linux_params.ps_mouse = linux_params.padding10 =  0;
+ 
+   len = sizeof (linux_params) - sizeof (lh);
+-  if (grub_file_read (file, (char *) &linux_params + sizeof (lh), len) != len)
+-    {
+-      if (!grub_errno)
+-	grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+-		    argv[0]);
+-      goto fail;
+-    }
++
++  linux_params_ptr = (void *)&linux_params;
++  grub_memcpy (linux_params_ptr + sizeof (lh), kernel + kernel_offset, len);
++  kernel_offset += len;
+ 
+   linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
+ 
+@@ -877,7 +888,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   /* The other parameters are filled when booting.  */
+ 
+-  grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
++  kernel_offset = real_size + GRUB_DISK_SECTOR_SIZE;
+ 
+   grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n",
+ 		(unsigned) real_size, (unsigned) prot_size);
+@@ -1025,9 +1036,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 			      - (sizeof (LINUX_IMAGE) - 1));
+ 
+   len = prot_file_size;
+-  if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno)
+-    grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+-		argv[0]);
++  grub_memcpy (prot_mode_mem, kernel + kernel_offset, len);
+ 
+   if (grub_errno == GRUB_ERR_NONE)
+     {
+@@ -1038,6 +1047,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+  fail:
+ 
++  grub_free (kernel);
++
+   if (file)
+     grub_file_close (file);
+ 
diff --git a/SOURCES/0003-Rework-linux16-command.patch b/SOURCES/0003-Rework-linux16-command.patch
new file mode 100644
index 0000000..99d6e7c
--- /dev/null
+++ b/SOURCES/0003-Rework-linux16-command.patch
@@ -0,0 +1,98 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Sun, 9 Aug 2015 16:20:58 -0700
+Subject: [PATCH] Rework linux16 command
+
+We want a single buffer that contains the entire kernel image in order to
+perform a TPM measurement. Allocate one and copy the entire kernel int it
+before pulling out the individual blocks later on.
+---
+ grub-core/loader/i386/pc/linux.c | 34 +++++++++++++++++++++-------------
+ 1 file changed, 21 insertions(+), 13 deletions(-)
+
+diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
+index a3c87cf2fc2..caa76bee8af 100644
+--- a/grub-core/loader/i386/pc/linux.c
++++ b/grub-core/loader/i386/pc/linux.c
+@@ -123,13 +123,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_file_t file = 0;
+   struct linux_i386_kernel_header lh;
+   grub_uint8_t setup_sects;
+-  grub_size_t real_size;
++  grub_size_t real_size, kernel_offset = 0;
+   grub_ssize_t len;
+   int i;
+   char *grub_linux_prot_chunk;
+   int grub_linux_is_bzimage;
+   grub_addr_t grub_linux_prot_target;
+   grub_err_t err;
++  grub_uint8_t *kernel = NULL;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -143,7 +144,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   if (! file)
+     goto fail;
+ 
+-  if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
++  len = grub_file_size (file);
++  kernel = grub_malloc (len);
++  if (!kernel)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
++      goto fail;
++    }
++
++  if (grub_file_read (file, kernel, len) != len)
+     {
+       if (!grub_errno)
+ 	grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+@@ -151,6 +160,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
++  grub_memcpy (&lh, kernel, sizeof (lh));
++  kernel_offset = sizeof (lh);
++
+   if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
+     {
+       grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
+@@ -314,13 +326,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_memmove (grub_linux_real_chunk, &lh, sizeof (lh));
+ 
+   len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh);
+-  if (grub_file_read (file, grub_linux_real_chunk + sizeof (lh), len) != len)
+-    {
+-      if (!grub_errno)
+-	grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+-		    argv[0]);
+-      goto fail;
+-    }
++  grub_memcpy (grub_linux_real_chunk + sizeof (lh), kernel + kernel_offset,
++	       len);
++  kernel_offset += len;
+ 
+   if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
+       || grub_le_to_cpu16 (lh.version) < 0x0200)
+@@ -355,10 +363,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   }
+ 
+   len = grub_linux16_prot_size;
+-  if (grub_file_read (file, grub_linux_prot_chunk, grub_linux16_prot_size)
+-      != (grub_ssize_t) grub_linux16_prot_size && !grub_errno)
+-    grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+-		argv[0]);
++  grub_memcpy (grub_linux_prot_chunk, kernel + kernel_offset, len);
++  kernel_offset += len;
+ 
+   if (grub_errno == GRUB_ERR_NONE)
+     {
+@@ -368,6 +374,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+  fail:
+ 
++  grub_free (kernel);
++
+   if (file)
+     grub_file_close (file);
+ 
diff --git a/SOURCES/0004-Add-secureboot-support-on-efi-chainloader.patch b/SOURCES/0004-Add-secureboot-support-on-efi-chainloader.patch
new file mode 100644
index 0000000..6a347d8
--- /dev/null
+++ b/SOURCES/0004-Add-secureboot-support-on-efi-chainloader.patch
@@ -0,0 +1,1390 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Raymund Will <rw@suse.com>
+Date: Fri, 10 Apr 2015 01:45:02 -0400
+Subject: [PATCH] Add secureboot support on efi chainloader
+
+Expand the chainloader to be able to verify the image by means of shim
+lock protocol. The PE/COFF image is loaded and relocated by the
+chainloader instead of calling LoadImage and StartImage UEFI boot
+Service as they require positive verification result from keys enrolled
+in KEK or DB. The shim will use MOK in addition to firmware enrolled
+keys to verify the image.
+
+The chainloader module could be used to load other UEFI bootloaders,
+such as xen.efi, and could be signed by any of MOK, KEK or DB.
+
+Based on https://build.opensuse.org/package/view_file/openSUSE:Factory/grub2/grub2-secureboot-chainloader.patch
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+
+Also:
+
+commit cd7a8984d4fda905877b5bfe466339100156b3bc
+Author: Raymund Will <rw@suse.com>
+Date:   Fri Apr 10 01:45:02 2015 -0400
+
+Use device part of chainloader target, if present.
+
+Otherwise chainloading is restricted to '$root', which might not even
+be readable by EFI!
+
+v1. use grub_file_get_device_name() to get device name
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Peter Jones <pjones@redhat.com>
+
+Also:
+
+commit 0872a2310a0eeac4ecfe9e1b49dd2d72ab373039
+Author: Peter Jones <pjones@redhat.com>
+Date:   Fri Jun 10 14:06:15 2016 -0400
+
+Rework even more of efi chainload so non-sb cases work right.
+
+This ensures that if shim protocol is not loaded, or is loaded but shim
+is disabled, we will fall back to a correct load method for the efi
+chain loader.
+
+Here's what I tested with this version:
+
+results                             expected    actual
+------------------------------------------------------------
+sb + enabled + shim + fedora        success     success
+sb + enabled + shim + win           success     success
+sb + enabled + grub + fedora        fail        fail
+sb + enabled + grub + win           fail        fail
+
+sb + mokdisabled + shim + fedora    success     success
+sb + mokdisabled + shim + win       success     success
+sb + mokdisabled + grub + fedora    fail        fail
+sb + mokdisabled + grub + win       fail        fail
+
+sb disabled + shim + fedora         success     success*
+sb disabled + shim + win            success     success*
+sb disabled + grub + fedora         success     success
+sb disabled + grub + win            success     success
+
+nosb + shim + fedora                success     success*
+nosb + shim + win                   success     success*
+nosb + grub + fedora                success     success
+nosb + grub + win                   success     success
+
+* for some reason shim protocol is being installed in these cases, and I
+  can't see why, but I think it may be this firmware build returning an
+  erroneous value.  But this effectively falls back to the mokdisabled
+  behavior, which works correctly, and the presence of the "grub" (i.e.
+  no shim) tests effectively tests the desired behavior here.
+
+Resolves: rhbz#1344512
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+
+Also:
+
+commit ff7b1cb7f69487870211aeb69ff4f54470fbcb58
+Author: Laszlo Ersek <lersek@redhat.com>
+Date:   Mon Nov 21 15:34:00 2016 +0100
+
+efi/chainloader: fix wrong sanity check in relocate_coff()
+
+In relocate_coff(), the relocation entries are parsed from the original
+image (not the section-wise copied image). The original image is
+pointed-to by the "orig" pointer. The current check
+
+  (void *)reloc_end < data
+
+compares the addresses of independent memory allocations. "data" is a typo
+here, it should be "orig".
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1347291
+Signed-off-by: Laszlo Ersek <lersek@redhat.com>
+Tested-by: Bogdan Costescu <bcostescu@gmail.com>
+Tested-by: Juan Orti <j.orti.alcaine@gmail.com>
+
+Also:
+
+commit ab4ba9997ad4832449e54d930fa2aac6a160d0e9
+Author: Laszlo Ersek <lersek@redhat.com>
+Date:   Wed Nov 23 06:27:09 2016 +0100
+
+efi/chainloader: truncate overlong relocation section
+
+The UEFI Windows 7 boot loader ("EFI/Microsoft/Boot/bootmgfw.efi", SHA1
+31b410e029bba87d2068c65a80b88882f9f8ea25) has inconsistent headers.
+
+Compare:
+
+> The Data Directory
+> ...
+> Entry 5 00000000000d9000 00000574 Base Relocation Directory [.reloc]
+
+Versus:
+
+> Sections:
+> Idx Name      Size      VMA               LMA               File off ...
+> ...
+>  10 .reloc    00000e22  00000000100d9000  00000000100d9000  000a1800 ...
+
+That is, the size reported by the RelocDir entry (0x574) is smaller than
+the virtual size of the .reloc section (0xe22).
+
+Quoting the grub2 debug log for the same:
+
+> chainloader.c:595: reloc_dir: 0xd9000 reloc_size: 0x00000574
+> chainloader.c:603: reloc_base: 0x7d208000 reloc_base_end: 0x7d208573
+> ...
+> chainloader.c:620: Section 10 ".reloc" at 0x7d208000..0x7d208e21
+> chainloader.c:661:  section is not reloc section?
+> chainloader.c:663:  rds: 0x00001000, vs: 00000e22
+> chainloader.c:664:  base: 0x7d208000 end: 0x7d208e21
+> chainloader.c:666:  reloc_base: 0x7d208000 reloc_base_end: 0x7d208573
+> chainloader.c:671:  Section characteristics are 42000040
+> chainloader.c:673:  Section virtual size: 00000e22
+> chainloader.c:675:  Section raw_data size: 00001000
+> chainloader.c:678:  Discarding section
+
+After hexdumping "bootmgfw.efi" and manually walking its relocation blocks
+(yes, really), I determined that the (smaller) RelocDir value is correct.
+The remaining area that extends up to the .reloc section size (== 0xe22 -
+0x574 == 0x8ae bytes) exists as zero padding in the file.
+
+This zero padding shouldn't be passed to relocate_coff() for parsing. In
+order to cope with it, split the handling of .reloc sections into the
+following branches:
+
+- original case (equal size): original behavior (--> relocation
+  attempted),
+
+- overlong .reloc section (longer than reported by RelocDir): truncate the
+  section to the RelocDir size for the purposes of relocate_coff(), and
+  attempt relocation,
+
+- .reloc section is too short, or other checks fail: original behavior
+  (--> relocation not attempted).
+
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1347291
+Signed-off-by: Laszlo Ersek <lersek@redhat.com>
+---
+ grub-core/kern/efi/efi.c           |  14 +-
+ grub-core/loader/arm64/linux.c     |   4 +-
+ grub-core/loader/efi/chainloader.c | 817 +++++++++++++++++++++++++++++++++----
+ grub-core/loader/efi/linux.c       |  25 +-
+ grub-core/loader/i386/efi/linux.c  |  17 +-
+ include/grub/efi/linux.h           |   2 +-
+ include/grub/efi/pe32.h            |  52 ++-
+ 7 files changed, 840 insertions(+), 91 deletions(-)
+
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index c8a9d8307c0..91129e33566 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -283,14 +283,20 @@ grub_efi_secure_boot (void)
+   grub_efi_boolean_t ret = 0;
+ 
+   secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize);
+-
+   if (datasize != 1 || !secure_boot)
+-    goto out;
++    {
++      grub_dprintf ("secureboot", "No SecureBoot variable\n");
++      goto out;
++    }
++  grub_dprintf ("secureboot", "SecureBoot: %d\n", *secure_boot);
+ 
+   setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize);
+-
+   if (datasize != 1 || !setup_mode)
+-    goto out;
++    {
++      grub_dprintf ("secureboot", "No SetupMode variable\n");
++      goto out;
++    }
++  grub_dprintf ("secureboot", "SetupMode: %d\n", *setup_mode);
+ 
+   if (*secure_boot && !*setup_mode)
+     ret = 1;
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index 6c00af98dce..a1ac7a38867 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -282,6 +282,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_file_t file = 0;
+   struct linux_armxx_kernel_header lh;
+   struct grub_armxx_linux_pe_header *pe;
++  int rc;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -326,7 +327,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
+ 
+-  if (!grub_linuxefi_secure_validate (kernel_addr, kernel_size))
++  rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
++  if (rc < 0)
+     {
+       grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
+       goto fail;
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index adc85636633..af2189619a3 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -32,6 +32,8 @@
+ #include <grub/efi/api.h>
+ #include <grub/efi/efi.h>
+ #include <grub/efi/disk.h>
++#include <grub/efi/pe32.h>
++#include <grub/efi/linux.h>
+ #include <grub/command.h>
+ #include <grub/i18n.h>
+ #include <grub/net.h>
+@@ -46,9 +48,14 @@ static grub_dl_t my_mod;
+ 
+ static grub_efi_physical_address_t address;
+ static grub_efi_uintn_t pages;
++static grub_ssize_t fsize;
+ static grub_efi_device_path_t *file_path;
+ static grub_efi_handle_t image_handle;
+ static grub_efi_char16_t *cmdline;
++static grub_ssize_t cmdline_len;
++static grub_efi_handle_t dev_handle;
++
++static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
+ 
+ static grub_err_t
+ grub_chainloader_unload (void)
+@@ -63,6 +70,7 @@ grub_chainloader_unload (void)
+   grub_free (cmdline);
+   cmdline = 0;
+   file_path = 0;
++  dev_handle = 0;
+ 
+   grub_dl_unref (my_mod);
+   return GRUB_ERR_NONE;
+@@ -173,7 +181,6 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
+   /* Fill the file path for the directory.  */
+   d = (grub_efi_device_path_t *) ((char *) file_path
+ 				  + ((char *) d - (char *) dp));
+-  grub_efi_print_device_path (d);
+   copy_file_path ((grub_efi_file_path_device_path_t *) d,
+ 		  dir_start, dir_end - dir_start);
+ 
+@@ -191,20 +198,690 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
+   return file_path;
+ }
+ 
++#define SHIM_LOCK_GUID \
++  { 0x605dab50, 0xe046, 0x4300, { 0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23 } }
++
++typedef union
++{
++  struct grub_pe32_header_32 pe32;
++  struct grub_pe32_header_64 pe32plus;
++} grub_pe_header_t;
++
++struct pe_coff_loader_image_context
++{
++  grub_efi_uint64_t image_address;
++  grub_efi_uint64_t image_size;
++  grub_efi_uint64_t entry_point;
++  grub_efi_uintn_t size_of_headers;
++  grub_efi_uint16_t image_type;
++  grub_efi_uint16_t number_of_sections;
++  grub_efi_uint32_t section_alignment;
++  struct grub_pe32_section_table *first_section;
++  struct grub_pe32_data_directory *reloc_dir;
++  struct grub_pe32_data_directory *sec_dir;
++  grub_efi_uint64_t number_of_rva_and_sizes;
++  grub_pe_header_t *pe_hdr;
++};
++
++typedef struct pe_coff_loader_image_context pe_coff_loader_image_context_t;
++
++struct grub_efi_shim_lock
++{
++  grub_efi_status_t (*verify)(void *buffer,
++                              grub_efi_uint32_t size);
++  grub_efi_status_t (*hash)(void *data,
++                            grub_efi_int32_t datasize,
++                            pe_coff_loader_image_context_t *context,
++                            grub_efi_uint8_t *sha256hash,
++                            grub_efi_uint8_t *sha1hash);
++  grub_efi_status_t (*context)(void *data,
++                               grub_efi_uint32_t size,
++                               pe_coff_loader_image_context_t *context);
++};
++
++typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
++
++static grub_efi_boolean_t
++read_header (void *data, grub_efi_uint32_t size,
++	     pe_coff_loader_image_context_t *context)
++{
++  grub_efi_guid_t guid = SHIM_LOCK_GUID;
++  grub_efi_shim_lock_t *shim_lock;
++  grub_efi_status_t status;
++
++  shim_lock = grub_efi_locate_protocol (&guid, NULL);
++  if (!shim_lock)
++    {
++      grub_dprintf ("chain", "no shim lock protocol");
++      return 0;
++    }
++
++  status = shim_lock->context (data, size, context);
++
++  if (status == GRUB_EFI_SUCCESS)
++    {
++      grub_dprintf ("chain", "context success\n");
++      return 1;
++    }
++
++  switch (status)
++    {
++      case GRUB_EFI_UNSUPPORTED:
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "context error unsupported");
++      break;
++      case GRUB_EFI_INVALID_PARAMETER:
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "context error invalid parameter");
++      break;
++      default:
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "context error code");
++      break;
++    }
++
++  return -1;
++}
++
++static void*
++image_address (void *image, grub_efi_uint64_t sz, grub_efi_uint64_t adr)
++{
++  if (adr > sz)
++    return NULL;
++
++  return ((grub_uint8_t*)image + adr);
++}
++
++static int
++image_is_64_bit (grub_pe_header_t *pe_hdr)
++{
++  /* .Magic is the same offset in all cases */
++  if (pe_hdr->pe32plus.optional_header.magic == GRUB_PE32_PE64_MAGIC)
++    return 1;
++  return 0;
++}
++
++static const grub_uint16_t machine_type __attribute__((__unused__)) =
++#if defined(__x86_64__)
++  GRUB_PE32_MACHINE_X86_64;
++#elif defined(__aarch64__)
++  GRUB_PE32_MACHINE_ARM64;
++#elif defined(__arm__)
++  GRUB_PE32_MACHINE_ARMTHUMB_MIXED;
++#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
++  GRUB_PE32_MACHINE_I386;
++#elif defined(__ia64__)
++  GRUB_PE32_MACHINE_IA64;
++#else
++#error this architecture is not supported by grub2
++#endif
++
++static grub_efi_status_t
++relocate_coff (pe_coff_loader_image_context_t *context,
++	       struct grub_pe32_section_table *section,
++	       void *orig, void *data)
++{
++  struct grub_pe32_data_directory *reloc_base, *reloc_base_end;
++  grub_efi_uint64_t adjust;
++  struct grub_pe32_fixup_block *reloc, *reloc_end;
++  char *fixup, *fixup_base, *fixup_data = NULL;
++  grub_efi_uint16_t *fixup_16;
++  grub_efi_uint32_t *fixup_32;
++  grub_efi_uint64_t *fixup_64;
++  grub_efi_uint64_t size = context->image_size;
++  void *image_end = (char *)orig + size;
++  int n = 0;
++
++  if (image_is_64_bit (context->pe_hdr))
++    context->pe_hdr->pe32plus.optional_header.image_base =
++      (grub_uint64_t)(unsigned long)data;
++  else
++    context->pe_hdr->pe32.optional_header.image_base =
++      (grub_uint32_t)(unsigned long)data;
++
++  /* Alright, so here's how this works:
++   *
++   * context->reloc_dir gives us two things:
++   * - the VA the table of base relocation blocks are (maybe) to be
++   *   mapped at (reloc_dir->rva)
++   * - the virtual size (reloc_dir->size)
++   *
++   * The .reloc section (section here) gives us some other things:
++   * - the name! kind of. (section->name)
++   * - the virtual size (section->virtual_size), which should be the same
++   *   as RelocDir->Size
++   * - the virtual address (section->virtual_address)
++   * - the file section size (section->raw_data_size), which is
++   *   a multiple of optional_header->file_alignment.  Only useful for image
++   *   validation, not really useful for iteration bounds.
++   * - the file address (section->raw_data_offset)
++   * - a bunch of stuff we don't use that's 0 in our binaries usually
++   * - Flags (section->characteristics)
++   *
++   * and then the thing that's actually at the file address is an array
++   * of struct grub_pe32_fixup_block structs with some values packed behind
++   * them.  The block_size field of this structure includes the
++   * structure itself, and adding it to that structure's address will
++   * yield the next entry in the array.
++   */
++
++  reloc_base = image_address (orig, size, section->raw_data_offset);
++  reloc_base_end = image_address (orig, size, section->raw_data_offset
++				  + section->virtual_size);
++
++  grub_dprintf ("chain", "relocate_coff(): reloc_base %p reloc_base_end %p\n",
++		reloc_base, reloc_base_end);
++
++  if (!reloc_base && !reloc_base_end)
++    return GRUB_EFI_SUCCESS;
++
++  if (!reloc_base || !reloc_base_end)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc table overflows binary");
++      return GRUB_EFI_UNSUPPORTED;
++    }
++
++  adjust = (grub_uint64_t)(grub_efi_uintn_t)data - context->image_address;
++  if (adjust == 0)
++    return GRUB_EFI_SUCCESS;
++
++  while (reloc_base < reloc_base_end)
++    {
++      grub_uint16_t *entry;
++      reloc = (struct grub_pe32_fixup_block *)((char*)reloc_base);
++
++      if ((reloc_base->size == 0) ||
++	  (reloc_base->size > context->reloc_dir->size))
++	{
++	  grub_error (GRUB_ERR_BAD_ARGUMENT,
++		      "Reloc %d block size %d is invalid\n", n,
++		      reloc_base->size);
++	  return GRUB_EFI_UNSUPPORTED;
++	}
++
++      entry = &reloc->entries[0];
++      reloc_end = (struct grub_pe32_fixup_block *)
++	((char *)reloc_base + reloc_base->size);
++
++      if ((void *)reloc_end < orig || (void *)reloc_end > image_end)
++        {
++          grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc entry %d overflows binary",
++		      n);
++          return GRUB_EFI_UNSUPPORTED;
++        }
++
++      fixup_base = image_address(data, size, reloc_base->rva);
++
++      if (!fixup_base)
++        {
++          grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc %d Invalid fixupbase", n);
++          return GRUB_EFI_UNSUPPORTED;
++        }
++
++      while ((void *)entry < (void *)reloc_end)
++        {
++          fixup = fixup_base + (*entry & 0xFFF);
++          switch ((*entry) >> 12)
++            {
++              case GRUB_PE32_REL_BASED_ABSOLUTE:
++                break;
++              case GRUB_PE32_REL_BASED_HIGH:
++                fixup_16 = (grub_uint16_t *)fixup;
++                *fixup_16 = (grub_uint16_t)
++		  (*fixup_16 + ((grub_uint16_t)((grub_uint32_t)adjust >> 16)));
++                if (fixup_data != NULL)
++                  {
++                    *(grub_uint16_t *) fixup_data = *fixup_16;
++                    fixup_data = fixup_data + sizeof (grub_uint16_t);
++                  }
++                break;
++              case GRUB_PE32_REL_BASED_LOW:
++                fixup_16 = (grub_uint16_t *)fixup;
++                *fixup_16 = (grub_uint16_t) (*fixup_16 + (grub_uint16_t)adjust);
++                if (fixup_data != NULL)
++                  {
++                    *(grub_uint16_t *) fixup_data = *fixup_16;
++                    fixup_data = fixup_data + sizeof (grub_uint16_t);
++                  }
++                break;
++              case GRUB_PE32_REL_BASED_HIGHLOW:
++                fixup_32 = (grub_uint32_t *)fixup;
++                *fixup_32 = *fixup_32 + (grub_uint32_t)adjust;
++                if (fixup_data != NULL)
++                  {
++                    fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint32_t));
++                    *(grub_uint32_t *) fixup_data = *fixup_32;
++                    fixup_data += sizeof (grub_uint32_t);
++                  }
++                break;
++              case GRUB_PE32_REL_BASED_DIR64:
++                fixup_64 = (grub_uint64_t *)fixup;
++                *fixup_64 = *fixup_64 + (grub_uint64_t)adjust;
++                if (fixup_data != NULL)
++                  {
++                    fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint64_t));
++                    *(grub_uint64_t *) fixup_data = *fixup_64;
++                    fixup_data += sizeof (grub_uint64_t);
++                  }
++                break;
++              default:
++                grub_error (GRUB_ERR_BAD_ARGUMENT,
++			    "Reloc %d unknown relocation type %d",
++			    n, (*entry) >> 12);
++                return GRUB_EFI_UNSUPPORTED;
++            }
++          entry += 1;
++        }
++      reloc_base = (struct grub_pe32_data_directory *)reloc_end;
++      n++;
++    }
++
++  return GRUB_EFI_SUCCESS;
++}
++
++static grub_efi_device_path_t *
++grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
++{
++  while (1)
++    {
++      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
++      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
++
++      if (type == GRUB_EFI_END_DEVICE_PATH_TYPE)
++        break;
++      else if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
++            && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE)
++      return dp;
++
++      dp = GRUB_EFI_NEXT_DEVICE_PATH (dp);
++    }
++
++    return NULL;
++}
++
++static grub_efi_boolean_t
++handle_image (void *data, grub_efi_uint32_t datasize)
++{
++  grub_efi_boot_services_t *b;
++  grub_efi_loaded_image_t *li, li_bak;
++  grub_efi_status_t efi_status;
++  char *buffer = NULL;
++  char *buffer_aligned = NULL;
++  grub_efi_uint32_t i;
++  struct grub_pe32_section_table *section;
++  char *base, *end;
++  pe_coff_loader_image_context_t context;
++  grub_uint32_t section_alignment;
++  grub_uint32_t buffer_size;
++  int found_entry_point = 0;
++  int rc;
++
++  b = grub_efi_system_table->boot_services;
++
++  rc = read_header (data, datasize, &context);
++  if (rc < 0)
++    {
++      grub_dprintf ("chain", "Failed to read header\n");
++      goto error_exit;
++    }
++  else if (rc == 0)
++    {
++      grub_dprintf ("chain", "Secure Boot is not enabled\n");
++      return 0;
++    }
++  else
++    {
++      grub_dprintf ("chain", "Header read without error\n");
++    }
++
++  /*
++   * The spec says, uselessly, of SectionAlignment:
++   * =====
++   * The alignment (in bytes) of sections when they are loaded into
++   * memory. It must be greater than or equal to FileAlignment. The
++   * default is the page size for the architecture.
++   * =====
++   * Which doesn't tell you whose responsibility it is to enforce the
++   * "default", or when.  It implies that the value in the field must
++   * be > FileAlignment (also poorly defined), but it appears visual
++   * studio will happily write 512 for FileAlignment (its default) and
++   * 0 for SectionAlignment, intending to imply PAGE_SIZE.
++   *
++   * We only support one page size, so if it's zero, nerf it to 4096.
++   */
++  section_alignment = context.section_alignment;
++  if (section_alignment == 0)
++    section_alignment = 4096;
++
++  buffer_size = context.image_size + section_alignment;
++  grub_dprintf ("chain", "image size is %08"PRIxGRUB_UINT64_T", datasize is %08x\n",
++	       context.image_size, datasize);
++
++  efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA,
++			   buffer_size, &buffer);
++
++  if (efi_status != GRUB_EFI_SUCCESS)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
++      goto error_exit;
++    }
++
++  buffer_aligned = (char *)ALIGN_UP ((grub_addr_t)buffer, section_alignment);
++  if (!buffer_aligned)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
++      goto error_exit;
++    }
++
++  grub_memcpy (buffer_aligned, data, context.size_of_headers);
++
++  entry_point = image_address (buffer_aligned, context.image_size,
++			       context.entry_point);
++
++  grub_dprintf ("chain", "entry_point: %p\n", entry_point);
++  if (!entry_point)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid entry point");
++      goto error_exit;
++    }
++
++  char *reloc_base, *reloc_base_end;
++  grub_dprintf ("chain", "reloc_dir: %p reloc_size: 0x%08x\n",
++		(void *)(unsigned long)context.reloc_dir->rva,
++		context.reloc_dir->size);
++  reloc_base = image_address (buffer_aligned, context.image_size,
++			      context.reloc_dir->rva);
++  /* RelocBaseEnd here is the address of the last byte of the table */
++  reloc_base_end = image_address (buffer_aligned, context.image_size,
++				  context.reloc_dir->rva
++				  + context.reloc_dir->size - 1);
++  grub_dprintf ("chain", "reloc_base: %p reloc_base_end: %p\n",
++		reloc_base, reloc_base_end);
++
++  struct grub_pe32_section_table *reloc_section = NULL, fake_reloc_section;
++
++  section = context.first_section;
++  for (i = 0; i < context.number_of_sections; i++, section++)
++    {
++      char name[9];
++
++      base = image_address (buffer_aligned, context.image_size,
++			    section->virtual_address);
++      end = image_address (buffer_aligned, context.image_size,
++			   section->virtual_address + section->virtual_size -1);
++
++      grub_strncpy(name, section->name, 9);
++      name[8] = '\0';
++      grub_dprintf ("chain", "Section %d \"%s\" at %p..%p\n", i,
++		   name, base, end);
++
++      if (end < base)
++	{
++	  grub_dprintf ("chain", " base is %p but end is %p... bad.\n",
++		       base, end);
++	  grub_error (GRUB_ERR_BAD_ARGUMENT,
++		      "Image has invalid negative size");
++	  goto error_exit;
++	}
++
++      if (section->virtual_address <= context.entry_point &&
++	  (section->virtual_address + section->raw_data_size - 1)
++	  > context.entry_point)
++	{
++	  found_entry_point++;
++	  grub_dprintf ("chain", " section contains entry point\n");
++	}
++
++      /* We do want to process .reloc, but it's often marked
++       * discardable, so we don't want to memcpy it. */
++      if (grub_memcmp (section->name, ".reloc\0\0", 8) == 0)
++	{
++	  if (reloc_section)
++	    {
++	      grub_error (GRUB_ERR_BAD_ARGUMENT,
++			  "Image has multiple relocation sections");
++	      goto error_exit;
++	    }
++
++	  /* If it has nonzero sizes, and our bounds check
++	   * made sense, and the VA and size match RelocDir's
++	   * versions, then we believe in this section table. */
++	  if (section->raw_data_size && section->virtual_size &&
++	      base && end && reloc_base == base)
++	    {
++	      if (reloc_base_end == end)
++		{
++		  grub_dprintf ("chain", " section is relocation section\n");
++		  reloc_section = section;
++		}
++	      else if (reloc_base_end && reloc_base_end < end)
++	        {
++		  /* Bogus virtual size in the reloc section -- RelocDir
++		   * reported a smaller Base Relocation Directory. Decrease
++		   * the section's virtual size so that it equal RelocDir's
++		   * idea, but only for the purposes of relocate_coff(). */
++		  grub_dprintf ("chain",
++				" section is (overlong) relocation section\n");
++		  grub_memcpy (&fake_reloc_section, section, sizeof *section);
++		  fake_reloc_section.virtual_size -= (end - reloc_base_end);
++		  reloc_section = &fake_reloc_section;
++		}
++	    }
++
++	  if (!reloc_section)
++	    {
++	      grub_dprintf ("chain", " section is not reloc section?\n");
++	      grub_dprintf ("chain", " rds: 0x%08x, vs: %08x\n",
++			    section->raw_data_size, section->virtual_size);
++	      grub_dprintf ("chain", " base: %p end: %p\n", base, end);
++	      grub_dprintf ("chain", " reloc_base: %p reloc_base_end: %p\n",
++			    reloc_base, reloc_base_end);
++	    }
++	}
++
++      grub_dprintf ("chain", " Section characteristics are %08x\n",
++		   section->characteristics);
++      grub_dprintf ("chain", " Section virtual size: %08x\n",
++		   section->virtual_size);
++      grub_dprintf ("chain", " Section raw_data size: %08x\n",
++		   section->raw_data_size);
++      if (section->characteristics & GRUB_PE32_SCN_MEM_DISCARDABLE)
++	{
++	  grub_dprintf ("chain", " Discarding section\n");
++	  continue;
++	}
++
++      if (!base || !end)
++        {
++	  grub_dprintf ("chain", " section is invalid\n");
++          grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid section size");
++          goto error_exit;
++        }
++
++      if (section->characteristics & GRUB_PE32_SCN_CNT_UNINITIALIZED_DATA)
++	{
++	  if (section->raw_data_size != 0)
++	    grub_dprintf ("chain", " UNINITIALIZED_DATA section has data?\n");
++	}
++      else if (section->virtual_address < context.size_of_headers ||
++	       section->raw_data_offset < context.size_of_headers)
++	{
++	  grub_error (GRUB_ERR_BAD_ARGUMENT,
++		      "Section %d is inside image headers", i);
++	  goto error_exit;
++	}
++
++      if (section->raw_data_size > 0)
++	{
++	  grub_dprintf ("chain", " copying 0x%08x bytes to %p\n",
++			section->raw_data_size, base);
++	  grub_memcpy (base,
++		       (grub_efi_uint8_t*)data + section->raw_data_offset,
++		       section->raw_data_size);
++	}
++
++      if (section->raw_data_size < section->virtual_size)
++	{
++	  grub_dprintf ("chain", " padding with 0x%08x bytes at %p\n",
++			section->virtual_size - section->raw_data_size,
++			base + section->raw_data_size);
++	  grub_memset (base + section->raw_data_size, 0,
++		       section->virtual_size - section->raw_data_size);
++	}
++
++      grub_dprintf ("chain", " finished section %s\n", name);
++    }
++
++  /* 5 == EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC */
++  if (context.number_of_rva_and_sizes <= 5)
++    {
++      grub_dprintf ("chain", "image has no relocation entry\n");
++      goto error_exit;
++    }
++
++  if (context.reloc_dir->size && reloc_section)
++    {
++      /* run the relocation fixups */
++      efi_status = relocate_coff (&context, reloc_section, data,
++				  buffer_aligned);
++
++      if (efi_status != GRUB_EFI_SUCCESS)
++	{
++	  grub_error (GRUB_ERR_BAD_ARGUMENT, "relocation failed");
++	  goto error_exit;
++	}
++    }
++
++  if (!found_entry_point)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "entry point is not within sections");
++      goto error_exit;
++    }
++  if (found_entry_point > 1)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "%d sections contain entry point",
++		  found_entry_point);
++      goto error_exit;
++    }
++
++  li = grub_efi_get_loaded_image (grub_efi_image_handle);
++  if (!li)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, "no loaded image available");
++      goto error_exit;
++    }
++
++  grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t));
++  li->image_base = buffer_aligned;
++  li->image_size = context.image_size;
++  li->load_options = cmdline;
++  li->load_options_size = cmdline_len;
++  li->file_path = grub_efi_get_media_file_path (file_path);
++  li->device_handle = dev_handle;
++  if (!li->file_path)
++    {
++      grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found");
++      goto error_exit;
++    }
++
++  grub_dprintf ("chain", "booting via entry point\n");
++  efi_status = efi_call_2 (entry_point, grub_efi_image_handle,
++			   grub_efi_system_table);
++
++  grub_dprintf ("chain", "entry_point returned %ld\n", efi_status);
++  grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t));
++  efi_status = efi_call_1 (b->free_pool, buffer);
++
++  return 1;
++
++error_exit:
++  grub_dprintf ("chain", "error_exit: grub_errno: %d\n", grub_errno);
++  if (buffer)
++      efi_call_1 (b->free_pool, buffer);
++
++  return 0;
++}
++
++static grub_err_t
++grub_secureboot_chainloader_unload (void)
++{
++  grub_efi_boot_services_t *b;
++
++  b = grub_efi_system_table->boot_services;
++  efi_call_2 (b->free_pages, address, pages);
++  grub_free (file_path);
++  grub_free (cmdline);
++  cmdline = 0;
++  file_path = 0;
++  dev_handle = 0;
++
++  grub_dl_unref (my_mod);
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_load_and_start_image(void *boot_image)
++{
++  grub_efi_boot_services_t *b;
++  grub_efi_status_t status;
++  grub_efi_loaded_image_t *loaded_image;
++
++  b = grub_efi_system_table->boot_services;
++
++  status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
++		       boot_image, fsize, &image_handle);
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      if (status == GRUB_EFI_OUT_OF_RESOURCES)
++	grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
++      else
++	grub_error (GRUB_ERR_BAD_OS, "cannot load image");
++      return -1;
++    }
++
++  /* LoadImage does not set a device handler when the image is
++     loaded from memory, so it is necessary to set it explicitly here.
++     This is a mess.  */
++  loaded_image = grub_efi_get_loaded_image (image_handle);
++  if (! loaded_image)
++    {
++      grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
++      return -1;
++    }
++  loaded_image->device_handle = dev_handle;
++
++  if (cmdline)
++    {
++      loaded_image->load_options = cmdline;
++      loaded_image->load_options_size = cmdline_len;
++    }
++
++  return 0;
++}
++
++static grub_err_t
++grub_secureboot_chainloader_boot (void)
++{
++  int rc;
++  rc = handle_image ((void *)(unsigned long)address, fsize);
++  if (rc == 0)
++    {
++      grub_load_and_start_image((void *)(unsigned long)address);
++    }
++
++  grub_loader_unset ();
++  return grub_errno;
++}
++
+ static grub_err_t
+ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ 		      int argc, char *argv[])
+ {
+   grub_file_t file = 0;
+-  grub_ssize_t size;
+   grub_efi_status_t status;
+   grub_efi_boot_services_t *b;
+   grub_device_t dev = 0;
+   grub_efi_device_path_t *dp = 0;
+-  grub_efi_loaded_image_t *loaded_image;
+   char *filename;
+   void *boot_image = 0;
+-  grub_efi_handle_t dev_handle = 0;
++  int rc;
+ 
+   if (argc == 0)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+@@ -216,15 +893,45 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+   address = 0;
+   image_handle = 0;
+   file_path = 0;
++  dev_handle = 0;
+ 
+   b = grub_efi_system_table->boot_services;
+ 
++  if (argc > 1)
++    {
++      int i;
++      grub_efi_char16_t *p16;
++
++      for (i = 1, cmdline_len = 0; i < argc; i++)
++        cmdline_len += grub_strlen (argv[i]) + 1;
++
++      cmdline_len *= sizeof (grub_efi_char16_t);
++      cmdline = p16 = grub_malloc (cmdline_len);
++      if (! cmdline)
++        goto fail;
++
++      for (i = 1; i < argc; i++)
++        {
++          char *p8;
++
++          p8 = argv[i];
++          while (*p8)
++            *(p16++) = *(p8++);
++
++          *(p16++) = ' ';
++        }
++      *(--p16) = 0;
++    }
++
+   file = grub_file_open (filename);
+   if (! file)
+     goto fail;
+ 
+-  /* Get the root device's device path.  */
+-  dev = grub_device_open (0);
++  /* Get the device path from filename. */
++  char *devname = grub_file_get_device_name (filename);
++  dev = grub_device_open (devname);
++  if (devname)
++    grub_free (devname);
+   if (! dev)
+     goto fail;
+ 
+@@ -261,17 +968,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+   if (! file_path)
+     goto fail;
+ 
+-  grub_printf ("file path: ");
+-  grub_efi_print_device_path (file_path);
+-
+-  size = grub_file_size (file);
+-  if (!size)
++  fsize = grub_file_size (file);
++  if (!fsize)
+     {
+       grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ 		  filename);
+       goto fail;
+     }
+-  pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12);
++  pages = (((grub_efi_uintn_t) fsize + ((1 << 12) - 1)) >> 12);
+ 
+   status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES,
+ 			      GRUB_EFI_LOADER_CODE,
+@@ -285,7 +989,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+     }
+ 
+   boot_image = (void *) ((grub_addr_t) address);
+-  if (grub_file_read (file, boot_image, size) != size)
++  if (grub_file_read (file, boot_image, fsize) != fsize)
+     {
+       if (grub_errno == GRUB_ERR_NONE)
+ 	grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+@@ -295,7 +999,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+     }
+ 
+ #if defined (__i386__) || defined (__x86_64__)
+-  if (size >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
++  if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
+     {
+       struct grub_macho_fat_header *head = boot_image;
+       if (head->magic
+@@ -304,6 +1008,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ 	  grub_uint32_t i;
+ 	  struct grub_macho_fat_arch *archs
+ 	    = (struct grub_macho_fat_arch *) (head + 1);
++
++	  if (grub_efi_secure_boot())
++	    {
++	      grub_error (GRUB_ERR_BAD_OS,
++			  "MACHO binaries are forbidden with Secure Boot");
++	      goto fail;
++	    }
++
+ 	  for (i = 0; i < grub_cpu_to_le32 (head->nfat_arch); i++)
+ 	    {
+ 	      if (GRUB_MACHO_CPUTYPE_IS_HOST_CURRENT (archs[i].cputype))
+@@ -318,79 +1030,39 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+ 	      > ~grub_cpu_to_le32 (archs[i].size)
+ 	      || grub_cpu_to_le32 (archs[i].offset)
+ 	      + grub_cpu_to_le32 (archs[i].size)
+-	      > (grub_size_t) size)
++	      > (grub_size_t) fsize)
+ 	    {
+ 	      grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ 			  filename);
+ 	      goto fail;
+ 	    }
+ 	  boot_image = (char *) boot_image + grub_cpu_to_le32 (archs[i].offset);
+-	  size = grub_cpu_to_le32 (archs[i].size);
++	  fsize = grub_cpu_to_le32 (archs[i].size);
+ 	}
+     }
+ #endif
+ 
+-  status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
+-		       boot_image, size,
+-		       &image_handle);
+-  if (status != GRUB_EFI_SUCCESS)
++  rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize);
++  grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc);
++  if (rc > 0)
+     {
+-      if (status == GRUB_EFI_OUT_OF_RESOURCES)
+-	grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
+-      else
+-	grub_error (GRUB_ERR_BAD_OS, "cannot load image");
+-
+-      goto fail;
++      grub_file_close (file);
++      grub_device_close (dev);
++      grub_loader_set (grub_secureboot_chainloader_boot,
++		       grub_secureboot_chainloader_unload, 0);
++      return 0;
+     }
+-
+-  /* LoadImage does not set a device handler when the image is
+-     loaded from memory, so it is necessary to set it explicitly here.
+-     This is a mess.  */
+-  loaded_image = grub_efi_get_loaded_image (image_handle);
+-  if (! loaded_image)
++  else if (rc == 0)
+     {
+-      grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
+-      goto fail;
+-    }
+-  loaded_image->device_handle = dev_handle;
+-
+-  if (argc > 1)
+-    {
+-      int i, len;
+-      grub_efi_char16_t *p16;
+-
+-      for (i = 1, len = 0; i < argc; i++)
+-        len += grub_strlen (argv[i]) + 1;
+-
+-      len *= sizeof (grub_efi_char16_t);
+-      cmdline = p16 = grub_malloc (len);
+-      if (! cmdline)
+-        goto fail;
++      grub_load_and_start_image(boot_image);
++      grub_file_close (file);
++      grub_device_close (dev);
++      grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
+ 
+-      for (i = 1; i < argc; i++)
+-        {
+-          char *p8;
+-
+-          p8 = argv[i];
+-          while (*p8)
+-            *(p16++) = *(p8++);
+-
+-          *(p16++) = ' ';
+-        }
+-      *(--p16) = 0;
+-
+-      loaded_image->load_options = cmdline;
+-      loaded_image->load_options_size = len;
++      return 0;
+     }
+ 
+-  grub_file_close (file);
+-  grub_device_close (dev);
+-
+-  grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
+-  return 0;
+-
+- fail:
+-
++fail:
+   if (dev)
+     grub_device_close (dev);
+ 
+@@ -402,6 +1074,9 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
+   if (address)
+     efi_call_2 (b->free_pages, address, pages);
+ 
++  if (cmdline)
++    grub_free (cmdline);
++
+   grub_dl_unref (my_mod);
+ 
+   return grub_errno;
+diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
+index c24202a5dd1..c8ecce6dfd0 100644
+--- a/grub-core/loader/efi/linux.c
++++ b/grub-core/loader/efi/linux.c
+@@ -33,21 +33,34 @@ struct grub_efi_shim_lock
+ };
+ typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
+ 
+-grub_efi_boolean_t
++int
+ grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
+ {
+   grub_efi_guid_t guid = SHIM_LOCK_GUID;
+   grub_efi_shim_lock_t *shim_lock;
++  grub_efi_status_t status;
+ 
+   shim_lock = grub_efi_locate_protocol(&guid, NULL);
+-
++  grub_dprintf ("secureboot", "shim_lock: %p\n", shim_lock);
+   if (!shim_lock)
+-    return 1;
++    {
++      grub_dprintf ("secureboot", "shim not available\n");
++      return 0;
++    }
+ 
+-  if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
+-    return 1;
++  grub_dprintf ("secureboot", "Asking shim to verify kernel signature\n");
++  status = shim_lock->verify (data, size);
++  grub_dprintf ("secureboot", "shim_lock->verify(): %ld\n", (long int)status);
++  if (status == GRUB_EFI_SUCCESS)
++    {
++      grub_dprintf ("secureboot", "Kernel signature verification passed\n");
++      return 1;
++    }
+ 
+-  return 0;
++  grub_dprintf ("secureboot", "Kernel signature verification failed (0x%lx)\n",
++		(unsigned long) status);
++
++  return -1;
+ }
+ 
+ #pragma GCC diagnostic push
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 3db82e782df..8db228c5bf5 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -118,6 +118,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
++  grub_dprintf ("linux", "initrd_mem = %lx\n", (unsigned long) initrd_mem);
++
+   params->ramdisk_size = size;
+   params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem;
+ 
+@@ -160,6 +162,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   struct linux_kernel_header lh;
+   grub_ssize_t len, start, filelen;
+   void *kernel = NULL;
++  int rc;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -185,11 +188,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   if (grub_file_read (file, kernel, filelen) != filelen)
+     {
+-      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]);
++      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"),
++		  argv[0]);
+       goto fail;
+     }
+ 
+-  if (! grub_linuxefi_secure_validate (kernel, filelen))
++  rc = grub_linuxefi_secure_validate (kernel, filelen);
++  if (rc < 0)
+     {
+       grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"),
+ 		  argv[0]);
+@@ -204,6 +209,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
++  grub_dprintf ("linux", "params = %lx\n", (unsigned long) params);
++
+   grub_memset (params, 0, 16384);
+ 
+   grub_memcpy (&lh, kernel, sizeof (lh));
+@@ -242,6 +249,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
++  grub_dprintf ("linux", "linux_cmdline = %lx\n",
++		(unsigned long)linux_cmdline);
++
+   grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+   grub_create_loader_cmdline (argc, argv,
+                               linux_cmdline + sizeof (LINUX_IMAGE) - 1,
+@@ -275,9 +285,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_memcpy (params, &lh, 2 * 512);
+ 
+   params->type_of_loader = 0x21;
++  grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n",
++	       kernel_mem, handover_offset);
+ 
+  fail:
+-
+   if (file)
+     grub_file_close (file);
+ 
+diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
+index d9ede36773b..0033d9305a9 100644
+--- a/include/grub/efi/linux.h
++++ b/include/grub/efi/linux.h
+@@ -22,7 +22,7 @@
+ #include <grub/err.h>
+ #include <grub/symbol.h>
+ 
+-grub_efi_boolean_t
++int
+ EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size);
+ grub_err_t
+ EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
+diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
+index 7d44732d2c3..c03cc599f63 100644
+--- a/include/grub/efi/pe32.h
++++ b/include/grub/efi/pe32.h
+@@ -214,7 +214,11 @@ struct grub_pe64_optional_header
+ struct grub_pe32_section_table
+ {
+   char name[8];
+-  grub_uint32_t virtual_size;
++  union
++    {
++      grub_uint32_t physical_address;
++      grub_uint32_t virtual_size;
++    };
+   grub_uint32_t virtual_address;
+   grub_uint32_t raw_data_size;
+   grub_uint32_t raw_data_offset;
+@@ -225,12 +229,18 @@ struct grub_pe32_section_table
+   grub_uint32_t characteristics;
+ };
+ 
++#define GRUB_PE32_SCN_TYPE_NO_PAD		0x00000008
+ #define GRUB_PE32_SCN_CNT_CODE			0x00000020
+ #define GRUB_PE32_SCN_CNT_INITIALIZED_DATA	0x00000040
+-#define GRUB_PE32_SCN_MEM_DISCARDABLE		0x02000000
+-#define GRUB_PE32_SCN_MEM_EXECUTE		0x20000000
+-#define GRUB_PE32_SCN_MEM_READ			0x40000000
+-#define GRUB_PE32_SCN_MEM_WRITE			0x80000000
++#define GRUB_PE32_SCN_CNT_UNINITIALIZED_DATA	0x00000080
++#define GRUB_PE32_SCN_LNK_OTHER			0x00000100
++#define GRUB_PE32_SCN_LNK_INFO			0x00000200
++#define GRUB_PE32_SCN_LNK_REMOVE		0x00000800
++#define GRUB_PE32_SCN_LNK_COMDAT		0x00001000
++#define GRUB_PE32_SCN_GPREL			0x00008000
++#define GRUB_PE32_SCN_MEM_16BIT			0x00020000
++#define GRUB_PE32_SCN_MEM_LOCKED		0x00040000
++#define GRUB_PE32_SCN_MEM_PRELOAD		0x00080000
+ 
+ #define GRUB_PE32_SCN_ALIGN_1BYTES		0x00100000
+ #define GRUB_PE32_SCN_ALIGN_2BYTES		0x00200000
+@@ -239,10 +249,28 @@ struct grub_pe32_section_table
+ #define GRUB_PE32_SCN_ALIGN_16BYTES		0x00500000
+ #define GRUB_PE32_SCN_ALIGN_32BYTES		0x00600000
+ #define GRUB_PE32_SCN_ALIGN_64BYTES		0x00700000
++#define GRUB_PE32_SCN_ALIGN_128BYTES		0x00800000
++#define GRUB_PE32_SCN_ALIGN_256BYTES		0x00900000
++#define GRUB_PE32_SCN_ALIGN_512BYTES		0x00A00000
++#define GRUB_PE32_SCN_ALIGN_1024BYTES		0x00B00000
++#define GRUB_PE32_SCN_ALIGN_2048BYTES		0x00C00000
++#define GRUB_PE32_SCN_ALIGN_4096BYTES		0x00D00000
++#define GRUB_PE32_SCN_ALIGN_8192BYTES		0x00E00000
+ 
+ #define GRUB_PE32_SCN_ALIGN_SHIFT		20
+ #define GRUB_PE32_SCN_ALIGN_MASK		7
+ 
++#define GRUB_PE32_SCN_LNK_NRELOC_OVFL		0x01000000
++#define GRUB_PE32_SCN_MEM_DISCARDABLE		0x02000000
++#define GRUB_PE32_SCN_MEM_NOT_CACHED		0x04000000
++#define GRUB_PE32_SCN_MEM_NOT_PAGED		0x08000000
++#define GRUB_PE32_SCN_MEM_SHARED		0x10000000
++#define GRUB_PE32_SCN_MEM_EXECUTE		0x20000000
++#define GRUB_PE32_SCN_MEM_READ			0x40000000
++#define GRUB_PE32_SCN_MEM_WRITE			0x80000000
++
++
++
+ #define GRUB_PE32_SIGNATURE_SIZE 4
+ 
+ struct grub_pe32_header
+@@ -265,6 +293,20 @@ struct grub_pe32_header
+ #endif
+ };
+ 
++struct grub_pe32_header_32
++{
++  char signature[GRUB_PE32_SIGNATURE_SIZE];
++  struct grub_pe32_coff_header coff_header;
++  struct grub_pe32_optional_header optional_header;
++};
++
++struct grub_pe32_header_64
++{
++  char signature[GRUB_PE32_SIGNATURE_SIZE];
++  struct grub_pe32_coff_header coff_header;
++  struct grub_pe64_optional_header optional_header;
++};
++
+ struct grub_pe32_fixup_block
+ {
+   grub_uint32_t page_rva;
diff --git a/SOURCES/0005-Make-any-of-the-loaders-that-link-in-efi-mode-honor-.patch b/SOURCES/0005-Make-any-of-the-loaders-that-link-in-efi-mode-honor-.patch
new file mode 100644
index 0000000..3c86bee
--- /dev/null
+++ b/SOURCES/0005-Make-any-of-the-loaders-that-link-in-efi-mode-honor-.patch
@@ -0,0 +1,516 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 6 Oct 2015 16:09:25 -0400
+Subject: [PATCH] Make any of the loaders that link in efi mode honor secure
+ boot.
+
+And in this case "honor" means "even if somebody does link this in, they
+won't register commands if SB is enabled."
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/Makefile.core.def        |  1 +
+ grub-core/commands/iorw.c          |  7 +++++
+ grub-core/commands/memrw.c         |  7 +++++
+ grub-core/kern/dl.c                |  1 +
+ grub-core/kern/efi/efi.c           | 34 --------------------
+ grub-core/kern/efi/sb.c            | 64 ++++++++++++++++++++++++++++++++++++++
+ grub-core/loader/efi/appleloader.c |  7 +++++
+ grub-core/loader/efi/chainloader.c |  1 +
+ grub-core/loader/i386/bsd.c        |  7 +++++
+ grub-core/loader/i386/linux.c      |  7 +++++
+ grub-core/loader/i386/pc/linux.c   |  7 +++++
+ grub-core/loader/multiboot.c       |  7 +++++
+ grub-core/loader/xnu.c             |  7 +++++
+ include/grub/efi/efi.h             |  1 -
+ include/grub/efi/sb.h              | 29 +++++++++++++++++
+ include/grub/ia64/linux.h          |  0
+ include/grub/mips/linux.h          |  0
+ include/grub/powerpc/linux.h       |  0
+ include/grub/sparc64/linux.h       |  0
+ grub-core/Makefile.am              |  1 +
+ 20 files changed, 153 insertions(+), 35 deletions(-)
+ create mode 100644 grub-core/kern/efi/sb.c
+ create mode 100644 include/grub/efi/sb.h
+ create mode 100644 include/grub/ia64/linux.h
+ create mode 100644 include/grub/mips/linux.h
+ create mode 100644 include/grub/powerpc/linux.h
+ create mode 100644 include/grub/sparc64/linux.h
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 0b4b0c2122d..e92a7ef322f 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -195,6 +195,7 @@ kernel = {
+   i386_multiboot = kern/i386/pc/acpi.c;
+   i386_coreboot = kern/acpi.c;
+   i386_multiboot = kern/acpi.c;
++  common = kern/efi/sb.c;
+ 
+   x86 = kern/i386/tsc.c;
+   x86 = kern/i386/tsc_pit.c;
+diff --git a/grub-core/commands/iorw.c b/grub-core/commands/iorw.c
+index a0c164e54f0..41a7f3f0466 100644
+--- a/grub-core/commands/iorw.c
++++ b/grub-core/commands/iorw.c
+@@ -23,6 +23,7 @@
+ #include <grub/env.h>
+ #include <grub/cpu/io.h>
+ #include <grub/i18n.h>
++#include <grub/efi/sb.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -118,6 +119,9 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv)
+ 
+ GRUB_MOD_INIT(memrw)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   cmd_read_byte =
+     grub_register_extcmd ("inb", grub_cmd_read, 0,
+ 			  N_("PORT"), N_("Read 8-bit value from PORT."),
+@@ -146,6 +150,9 @@ GRUB_MOD_INIT(memrw)
+ 
+ GRUB_MOD_FINI(memrw)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   grub_unregister_extcmd (cmd_read_byte);
+   grub_unregister_extcmd (cmd_read_word);
+   grub_unregister_extcmd (cmd_read_dword);
+diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c
+index 98769eadb34..088cbe9e2bc 100644
+--- a/grub-core/commands/memrw.c
++++ b/grub-core/commands/memrw.c
+@@ -22,6 +22,7 @@
+ #include <grub/extcmd.h>
+ #include <grub/env.h>
+ #include <grub/i18n.h>
++#include <grub/efi/sb.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -120,6 +121,9 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv)
+ 
+ GRUB_MOD_INIT(memrw)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   cmd_read_byte =
+     grub_register_extcmd ("read_byte", grub_cmd_read, 0,
+ 			  N_("ADDR"), N_("Read 8-bit value from ADDR."),
+@@ -148,6 +152,9 @@ GRUB_MOD_INIT(memrw)
+ 
+ GRUB_MOD_FINI(memrw)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   grub_unregister_extcmd (cmd_read_byte);
+   grub_unregister_extcmd (cmd_read_word);
+   grub_unregister_extcmd (cmd_read_dword);
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index 04e804d1668..621070918d4 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -32,6 +32,7 @@
+ #include <grub/env.h>
+ #include <grub/cache.h>
+ #include <grub/i18n.h>
++#include <grub/efi/sb.h>
+ 
+ /* Platforms where modules are in a readonly area of memory.  */
+ #if defined(GRUB_MACHINE_QEMU)
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index 91129e33566..708581fcbde 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -273,40 +273,6 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
+   return NULL;
+ }
+ 
+-grub_efi_boolean_t
+-grub_efi_secure_boot (void)
+-{
+-  grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID;
+-  grub_size_t datasize;
+-  char *secure_boot = NULL;
+-  char *setup_mode = NULL;
+-  grub_efi_boolean_t ret = 0;
+-
+-  secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize);
+-  if (datasize != 1 || !secure_boot)
+-    {
+-      grub_dprintf ("secureboot", "No SecureBoot variable\n");
+-      goto out;
+-    }
+-  grub_dprintf ("secureboot", "SecureBoot: %d\n", *secure_boot);
+-
+-  setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize);
+-  if (datasize != 1 || !setup_mode)
+-    {
+-      grub_dprintf ("secureboot", "No SetupMode variable\n");
+-      goto out;
+-    }
+-  grub_dprintf ("secureboot", "SetupMode: %d\n", *setup_mode);
+-
+-  if (*secure_boot && !*setup_mode)
+-    ret = 1;
+-
+- out:
+-  grub_free (secure_boot);
+-  grub_free (setup_mode);
+-  return ret;
+-}
+-
+ #pragma GCC diagnostic ignored "-Wcast-align"
+ 
+ /* Search the mods section from the PE32/PE32+ image. This code uses
+diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
+new file mode 100644
+index 00000000000..d74778b0cac
+--- /dev/null
++++ b/grub-core/kern/efi/sb.c
+@@ -0,0 +1,64 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2014 Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/types.h>
++#include <grub/cpu/linux.h>
++#include <grub/efi/efi.h>
++#include <grub/efi/pe32.h>
++#include <grub/efi/linux.h>
++#include <grub/efi/sb.h>
++
++int
++grub_efi_secure_boot (void)
++{
++#ifdef GRUB_MACHINE_EFI
++  grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID;
++  grub_size_t datasize;
++  char *secure_boot = NULL;
++  char *setup_mode = NULL;
++  grub_efi_boolean_t ret = 0;
++
++  secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize);
++  if (datasize != 1 || !secure_boot)
++    {
++      grub_dprintf ("secureboot", "No SecureBoot variable\n");
++      goto out;
++    }
++  grub_dprintf ("secureboot", "SecureBoot: %d\n", *secure_boot);
++
++  setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize);
++  if (datasize != 1 || !setup_mode)
++    {
++      grub_dprintf ("secureboot", "No SetupMode variable\n");
++      goto out;
++    }
++  grub_dprintf ("secureboot", "SetupMode: %d\n", *setup_mode);
++
++  if (*secure_boot && !*setup_mode)
++    ret = 1;
++
++ out:
++  grub_free (secure_boot);
++  grub_free (setup_mode);
++  return ret;
++#else
++  return 0;
++#endif
++}
+diff --git a/grub-core/loader/efi/appleloader.c b/grub-core/loader/efi/appleloader.c
+index 74888c463ba..69c2a10d351 100644
+--- a/grub-core/loader/efi/appleloader.c
++++ b/grub-core/loader/efi/appleloader.c
+@@ -24,6 +24,7 @@
+ #include <grub/misc.h>
+ #include <grub/efi/api.h>
+ #include <grub/efi/efi.h>
++#include <grub/efi/sb.h>
+ #include <grub/command.h>
+ #include <grub/i18n.h>
+ 
+@@ -227,6 +228,9 @@ static grub_command_t cmd;
+ 
+ GRUB_MOD_INIT(appleloader)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   cmd = grub_register_command ("appleloader", grub_cmd_appleloader,
+ 			       N_("[OPTS]"),
+ 			       /* TRANSLATORS: This command is used on EFI to
+@@ -238,5 +242,8 @@ GRUB_MOD_INIT(appleloader)
+ 
+ GRUB_MOD_FINI(appleloader)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   grub_unregister_command (cmd);
+ }
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index af2189619a3..5cd9b6e08a8 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -34,6 +34,7 @@
+ #include <grub/efi/disk.h>
+ #include <grub/efi/pe32.h>
+ #include <grub/efi/linux.h>
++#include <grub/efi/sb.h>
+ #include <grub/command.h>
+ #include <grub/i18n.h>
+ #include <grub/net.h>
+diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c
+index 7f96515da65..87709aa23e8 100644
+--- a/grub-core/loader/i386/bsd.c
++++ b/grub-core/loader/i386/bsd.c
+@@ -38,6 +38,7 @@
+ #ifdef GRUB_MACHINE_PCBIOS
+ #include <grub/machine/int.h>
+ #endif
++#include <grub/efi/sb.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -2124,6 +2125,9 @@ static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk;
+ 
+ GRUB_MOD_INIT (bsd)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   /* Net and OpenBSD kernels are often compressed.  */
+   grub_dl_load ("gzio");
+ 
+@@ -2163,6 +2167,9 @@ GRUB_MOD_INIT (bsd)
+ 
+ GRUB_MOD_FINI (bsd)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   grub_unregister_extcmd (cmd_freebsd);
+   grub_unregister_extcmd (cmd_openbsd);
+   grub_unregister_extcmd (cmd_netbsd);
+diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
+index f7186be4002..c84747ea857 100644
+--- a/grub-core/loader/i386/linux.c
++++ b/grub-core/loader/i386/linux.c
+@@ -35,6 +35,7 @@
+ #include <grub/i18n.h>
+ #include <grub/lib/cmdline.h>
+ #include <grub/linux.h>
++#include <grub/efi/sb.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -1156,6 +1157,9 @@ static grub_command_t cmd_linux, cmd_initrd;
+ 
+ GRUB_MOD_INIT(linux)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   cmd_linux = grub_register_command ("linux", grub_cmd_linux,
+ 				     0, N_("Load Linux."));
+   cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
+@@ -1165,6 +1169,9 @@ GRUB_MOD_INIT(linux)
+ 
+ GRUB_MOD_FINI(linux)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   grub_unregister_command (cmd_linux);
+   grub_unregister_command (cmd_initrd);
+ }
+diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
+index caa76bee8af..783a3cd93bc 100644
+--- a/grub-core/loader/i386/pc/linux.c
++++ b/grub-core/loader/i386/pc/linux.c
+@@ -35,6 +35,7 @@
+ #include <grub/i386/floppy.h>
+ #include <grub/lib/cmdline.h>
+ #include <grub/linux.h>
++#include <grub/efi/sb.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -480,6 +481,9 @@ static grub_command_t cmd_linux, cmd_linux16, cmd_initrd, cmd_initrd16;
+ 
+ GRUB_MOD_INIT(linux16)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   cmd_linux =
+     grub_register_command ("linux", grub_cmd_linux,
+ 			   0, N_("Load Linux."));
+@@ -497,6 +501,9 @@ GRUB_MOD_INIT(linux16)
+ 
+ GRUB_MOD_FINI(linux16)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   grub_unregister_command (cmd_linux);
+   grub_unregister_command (cmd_linux16);
+   grub_unregister_command (cmd_initrd);
+diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c
+index 40c67e82489..26df46a4161 100644
+--- a/grub-core/loader/multiboot.c
++++ b/grub-core/loader/multiboot.c
+@@ -50,6 +50,7 @@
+ #include <grub/video.h>
+ #include <grub/memory.h>
+ #include <grub/i18n.h>
++#include <grub/efi/sb.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -446,6 +447,9 @@ static grub_command_t cmd_multiboot, cmd_module;
+ 
+ GRUB_MOD_INIT(multiboot)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   cmd_multiboot =
+ #ifdef GRUB_USE_MULTIBOOT2
+     grub_register_command ("multiboot2", grub_cmd_multiboot,
+@@ -466,6 +470,9 @@ GRUB_MOD_INIT(multiboot)
+ 
+ GRUB_MOD_FINI(multiboot)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   grub_unregister_command (cmd_multiboot);
+   grub_unregister_command (cmd_module);
+ }
+diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c
+index c9885b1bcd7..df8dfdb4ba0 100644
+--- a/grub-core/loader/xnu.c
++++ b/grub-core/loader/xnu.c
+@@ -33,6 +33,7 @@
+ #include <grub/extcmd.h>
+ #include <grub/env.h>
+ #include <grub/i18n.h>
++#include <grub/efi/sb.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -1469,6 +1470,9 @@ static grub_extcmd_t cmd_splash;
+ 
+ GRUB_MOD_INIT(xnu)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+   cmd_kernel = grub_register_command ("xnu_kernel", grub_cmd_xnu_kernel, 0,
+ 				      N_("Load XNU image."));
+   cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64,
+@@ -1509,6 +1513,9 @@ GRUB_MOD_INIT(xnu)
+ 
+ GRUB_MOD_FINI(xnu)
+ {
++  if (grub_efi_secure_boot())
++    return;
++
+ #ifndef GRUB_MACHINE_EMU
+   grub_unregister_command (cmd_resume);
+ #endif
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index 1061aee9726..39480b38674 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -85,7 +85,6 @@ EXPORT_FUNC (grub_efi_set_variable) (const char *var,
+ 				     const grub_efi_guid_t *guid,
+ 				     void *data,
+ 				     grub_size_t datasize);
+-grub_efi_boolean_t EXPORT_FUNC (grub_efi_secure_boot) (void);
+ int
+ EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1,
+ 					     const grub_efi_device_path_t *dp2);
+diff --git a/include/grub/efi/sb.h b/include/grub/efi/sb.h
+new file mode 100644
+index 00000000000..9629fbb0f9e
+--- /dev/null
++++ b/include/grub/efi/sb.h
+@@ -0,0 +1,29 @@
++/* sb.h - declare functions for EFI Secure Boot support */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2006,2007,2008,2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_EFI_SB_HEADER
++#define GRUB_EFI_SB_HEADER	1
++
++#include <grub/types.h>
++#include <grub/dl.h>
++
++/* Functions.  */
++int EXPORT_FUNC (grub_efi_secure_boot) (void);
++
++#endif /* ! GRUB_EFI_SB_HEADER */
+diff --git a/include/grub/ia64/linux.h b/include/grub/ia64/linux.h
+new file mode 100644
+index 00000000000..e69de29bb2d
+diff --git a/include/grub/mips/linux.h b/include/grub/mips/linux.h
+new file mode 100644
+index 00000000000..e69de29bb2d
+diff --git a/include/grub/powerpc/linux.h b/include/grub/powerpc/linux.h
+new file mode 100644
+index 00000000000..e69de29bb2d
+diff --git a/include/grub/sparc64/linux.h b/include/grub/sparc64/linux.h
+new file mode 100644
+index 00000000000..e69de29bb2d
+diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
+index f4ff62b769a..9c69aa88626 100644
+--- a/grub-core/Makefile.am
++++ b/grub-core/Makefile.am
+@@ -71,6 +71,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/disk.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/dl.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/sb.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h
diff --git a/SOURCES/0006-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch b/SOURCES/0006-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch
new file mode 100644
index 0000000..76b1183
--- /dev/null
+++ b/SOURCES/0006-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch
@@ -0,0 +1,263 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 14 Feb 2017 16:18:54 -0500
+Subject: [PATCH] Handle multi-arch (64-on-32) boot in linuxefi loader.
+
+Allow booting 64-bit kernels on 32-bit EFI on x86.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/efi/linux.c      |   9 +++-
+ grub-core/loader/i386/efi/linux.c | 110 ++++++++++++++++++++++++++------------
+ include/grub/i386/linux.h         |   7 ++-
+ 3 files changed, 89 insertions(+), 37 deletions(-)
+
+diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
+index c8ecce6dfd0..0622dfa48d4 100644
+--- a/grub-core/loader/efi/linux.c
++++ b/grub-core/loader/efi/linux.c
+@@ -69,12 +69,17 @@ grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
+ typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
+ 
+ grub_err_t
+-grub_efi_linux_boot (void *kernel_addr, grub_off_t offset,
++grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
+ 		     void *kernel_params)
+ {
+   handover_func hf;
++  int offset = 0;
+ 
+-  hf = (handover_func)((char *)kernel_addr + offset);
++#ifdef __x86_64__
++  offset = 512;
++#endif
++
++  hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
+   hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
+ 
+   return GRUB_ERR_BUG;
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 8db228c5bf5..800c3e54022 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -44,14 +44,10 @@ static char *linux_cmdline;
+ static grub_err_t
+ grub_linuxefi_boot (void)
+ {
+-  int offset = 0;
+-
+-#ifdef __x86_64__
+-  offset = 512;
+-#endif
+   asm volatile ("cli");
+ 
+-  return grub_efi_linux_boot ((char *)kernel_mem, handover_offset + offset,
++  return grub_efi_linux_boot ((char *)kernel_mem,
++			      handover_offset,
+ 			      params);
+ }
+ 
+@@ -154,14 +150,20 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+   return grub_errno;
+ }
+ 
++#define MIN(a, b) \
++  ({ typeof (a) _a = (a); \
++     typeof (b) _b = (b); \
++     _a < _b ? _a : _b; })
++
+ static grub_err_t
+ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 		int argc, char *argv[])
+ {
+   grub_file_t file = 0;
+-  struct linux_kernel_header lh;
+-  grub_ssize_t len, start, filelen;
++  struct linux_i386_kernel_header *lh = NULL;
++  grub_ssize_t start, filelen;
+   void *kernel = NULL;
++  int setup_header_end_offset;
+   int rc;
+ 
+   grub_dl_ref (my_mod);
+@@ -201,48 +203,79 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384));
+-
++  params = grub_efi_allocate_pages_max (0x3fffffff,
++					BYTES_TO_PAGES(sizeof(*params)));
+   if (! params)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
+       goto fail;
+     }
+ 
+-  grub_dprintf ("linux", "params = %lx\n", (unsigned long) params);
++  grub_dprintf ("linux", "params = %p\n", params);
+ 
+-  grub_memset (params, 0, 16384);
++  grub_memset (params, 0, sizeof(*params));
+ 
+-  grub_memcpy (&lh, kernel, sizeof (lh));
+-
+-  if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
++  setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201);
++  grub_dprintf ("linux", "copying %lu bytes from %p to %p\n",
++		MIN((grub_size_t)0x202+setup_header_end_offset,
++		    sizeof (*params)) - 0x1f1,
++		(grub_uint8_t *)kernel + 0x1f1,
++		(grub_uint8_t *)params + 0x1f1);
++  grub_memcpy ((grub_uint8_t *)params + 0x1f1,
++	       (grub_uint8_t *)kernel + 0x1f1,
++		MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1);
++  lh = (struct linux_i386_kernel_header *)params;
++  grub_dprintf ("linux", "lh is at %p\n", lh);
++  grub_dprintf ("linux", "checking lh->boot_flag\n");
++  if (lh->boot_flag != grub_cpu_to_le16 (0xaa55))
+     {
+       grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number"));
+       goto fail;
+     }
+ 
+-  if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
++  grub_dprintf ("linux", "checking lh->setup_sects\n");
++  if (lh->setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
+     {
+       grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors"));
+       goto fail;
+     }
+ 
+-  if (lh.version < grub_cpu_to_le16 (0x020b))
++  grub_dprintf ("linux", "checking lh->version\n");
++  if (lh->version < grub_cpu_to_le16 (0x020b))
+     {
+       grub_error (GRUB_ERR_BAD_OS, N_("kernel too old"));
+       goto fail;
+     }
+ 
+-  if (!lh.handover_offset)
++  grub_dprintf ("linux", "checking lh->handover_offset\n");
++  if (!lh->handover_offset)
+     {
+       grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover"));
+       goto fail;
+     }
+ 
++#if defined(__x86_64__) || defined(__aarch64__)
++  grub_dprintf ("linux", "checking lh->xloadflags\n");
++  if (!(lh->xloadflags & LINUX_XLF_KERNEL_64))
++    {
++      grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support 64-bit CPUs"));
++      goto fail;
++    }
++#endif
++
++#if defined(__i386__)
++  if ((lh->xloadflags & LINUX_XLF_KERNEL_64) &&
++      !(lh->xloadflags & LINUX_XLF_EFI_HANDOVER_32))
++    {
++      grub_error (GRUB_ERR_BAD_OS,
++		  N_("kernel doesn't support 32-bit handover"));
++      goto fail;
++    }
++#endif
++
+   grub_dprintf ("linux", "setting up cmdline\n");
+   linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff,
+-					 BYTES_TO_PAGES(lh.cmdline_size + 1));
+-
++					 BYTES_TO_PAGES(lh->cmdline_size + 1));
+   if (!linux_cmdline)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
+@@ -255,21 +288,23 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+   grub_create_loader_cmdline (argc, argv,
+                               linux_cmdline + sizeof (LINUX_IMAGE) - 1,
+-			      lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1));
++			      lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1));
+ 
+-  lh.cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline;
++  grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline);
++  grub_dprintf ("linux", "setting lh->cmd_line_ptr\n");
++  lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline;
+ 
+-  handover_offset = lh.handover_offset;
++  grub_dprintf ("linux", "computing handover offset\n");
++  handover_offset = lh->handover_offset;
+ 
+-  start = (lh.setup_sects + 1) * 512;
+-  len = grub_file_size(file) - start;
++  start = (lh->setup_sects + 1) * 512;
+ 
+-  kernel_mem = grub_efi_allocate_pages_max(lh.pref_address,
+-					   BYTES_TO_PAGES(lh.init_size));
++  kernel_mem = grub_efi_allocate_pages_max(lh->pref_address,
++					   BYTES_TO_PAGES(lh->init_size));
+ 
+   if (!kernel_mem)
+     kernel_mem = grub_efi_allocate_pages_max(0x3fffffff,
+-					     BYTES_TO_PAGES(lh.init_size));
++					     BYTES_TO_PAGES(lh->init_size));
+ 
+   if (!kernel_mem)
+     {
+@@ -277,14 +312,21 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  grub_memcpy (kernel_mem, (char *)kernel + start, len);
++  grub_dprintf ("linux", "kernel_mem = %lx\n", (unsigned long) kernel_mem);
++
+   grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
+   loaded=1;
++  grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem);
++  lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem;
+ 
+-  lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem;
+-  grub_memcpy (params, &lh, 2 * 512);
++  grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start);
+ 
+-  params->type_of_loader = 0x21;
++  grub_dprintf ("linux", "setting lh->type_of_loader\n");
++  lh->type_of_loader = 0x6;
++
++  grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n");
++  params->ext_loader_type = 0;
++  params->ext_loader_ver = 2;
+   grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n",
+ 	       kernel_mem, handover_offset);
+ 
+@@ -301,10 +343,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       loaded = 0;
+     }
+ 
+-  if (linux_cmdline && !loaded)
++  if (linux_cmdline && lh && !loaded)
+     grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)
+ 			 linux_cmdline,
+-			 BYTES_TO_PAGES(lh.cmdline_size + 1));
++			 BYTES_TO_PAGES(lh->cmdline_size + 1));
+ 
+   if (kernel_mem && !loaded)
+     grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem,
+diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h
+index bb19dbd5a77..8474a857ed2 100644
+--- a/include/grub/i386/linux.h
++++ b/include/grub/i386/linux.h
+@@ -133,7 +133,12 @@ struct linux_i386_kernel_header
+   grub_uint32_t kernel_alignment;
+   grub_uint8_t relocatable;
+   grub_uint8_t min_alignment;
+-  grub_uint8_t pad[2];
++#define LINUX_XLF_KERNEL_64                   (1<<0)
++#define LINUX_XLF_CAN_BE_LOADED_ABOVE_4G      (1<<1)
++#define LINUX_XLF_EFI_HANDOVER_32             (1<<2)
++#define LINUX_XLF_EFI_HANDOVER_64             (1<<3)
++#define LINUX_XLF_EFI_KEXEC                   (1<<4)
++  grub_uint16_t xloadflags;
+   grub_uint32_t cmdline_size;
+   grub_uint32_t hardware_subarch;
+   grub_uint64_t hardware_subarch_data;
diff --git a/SOURCES/0007-re-write-.gitignore.patch b/SOURCES/0007-re-write-.gitignore.patch
new file mode 100644
index 0000000..34deea7
--- /dev/null
+++ b/SOURCES/0007-re-write-.gitignore.patch
@@ -0,0 +1,502 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 8 Aug 2017 12:48:04 -0400
+Subject: [PATCH] re-write .gitignore
+
+---
+ .gitignore                        | 357 +++++++++++++-------------------------
+ build-aux/.gitignore              |   9 +
+ docs/.gitignore                   |   4 +
+ grub-core/.gitignore              |  15 ++
+ grub-core/gnulib/.gitignore       |  22 +++
+ grub-core/lib/.gitignore          |   1 +
+ include/grub/gcrypt/.gitignore    |   2 +
+ po/.gitignore                     |   4 +
+ util/bash-completion.d/.gitignore |   1 +
+ 9 files changed, 175 insertions(+), 240 deletions(-)
+ create mode 100644 build-aux/.gitignore
+ create mode 100644 docs/.gitignore
+ create mode 100644 grub-core/.gitignore
+ create mode 100644 grub-core/gnulib/.gitignore
+ create mode 100644 grub-core/lib/.gitignore
+ create mode 100644 include/grub/gcrypt/.gitignore
+ create mode 100644 po/.gitignore
+ create mode 100644 util/bash-completion.d/.gitignore
+
+diff --git a/.gitignore b/.gitignore
+index eca17bec9b8..43f04d47277 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -1,249 +1,126 @@
+-00_header
+-10_*
+-20_linux_xen
+-30_os-prober
+-40_custom
+-41_custom
+-*.1
+-*.8
+-aclocal.m4
+-ahci_test
+-ascii.bitmaps
+-ascii.h
+-autom4te.cache
+-build-grub-gen-asciih
+-build-grub-gen-widthspec
+-build-grub-mkfont
+-cdboot_test
+-cmp_test
+-config.cache
+-config.guess
+-config.h
+-config-util.h
+-config-util.h.in
+-config.log
+-config.status
+-config.sub
+-configure
+-core_compress_test
+-DISTLIST
+-docs/*.info
+-docs/stamp-vti
+-docs/version.texi
+-ehci_test
+-example_grub_script_test
+-example_scripted_test
+-example_unit_test
++# things ./autogen.sh will create
++/Makefile.utilgcry.def
++/aclocal.m4
++/autom4te.cache
++/configure
++Makefile
++# we want to enable building in a subdirectory, but we don't want to exclude
++# /build-aux so explicitly don't ignore it.
++/build*/
++!/build-aux/
++
++# things very common editors create that we never want
++*~
++.*.sw?
++*.patch
++
++# built objects across the whole tree
++Makefile.in
++*.a
++*.am
+ *.exec
+-*.exec.exe
+-fddboot_test
+-genkernsyms.sh
+-gensymlist.sh
+-gentrigtables
+-gentrigtables.exe
+-gettext_strings_test
+-grub-bin2h
+-/grub-bios-setup
+-/grub-bios-setup.exe
+-grub_cmd_date
+-grub_cmd_echo
+-grub_cmd_regexp
+-grub_cmd_set_date
+-grub_cmd_sleep
+-/grub-editenv
+-/grub-editenv.exe
+-grub-emu
+-grub-emu-lite
+-grub-emu.exe
+-grub-emu-lite.exe
+-grub_emu_init.c
+-grub_emu_init.h
+-/grub-file
+-/grub-file.exe
+-grub-fstest
+-grub-fstest.exe
+-grub_fstest_init.c
+-grub_fstest_init.h
+-grub_func_test
+-grub-install
+-grub-install.exe
+-grub-kbdcomp
+-/grub-macbless
+-/grub-macbless.exe
+-grub-macho2img
+-/grub-menulst2cfg
+-/grub-menulst2cfg.exe
+-/grub-mk*
+-grub-mount
+-/grub-ofpathname
+-/grub-ofpathname.exe
+-grub-core/build-grub-pe2elf.exe
+-/grub-probe
+-/grub-probe.exe
+-grub_probe_init.c
+-grub_probe_init.h
+-/grub-reboot
+-grub_script_blanklines
+-grub_script_blockarg
+-grub_script_break
+-grub-script-check
+-grub-script-check.exe
+-grub_script_check_init.c
+-grub_script_check_init.h
+-grub_script_comments
+-grub_script_continue
+-grub_script_dollar
+-grub_script_echo1
+-grub_script_echo_keywords
+-grub_script_escape_comma
+-grub_script_eval
+-grub_script_expansion
+-grub_script_final_semicolon
+-grub_script_for1
+-grub_script_functions
+-grub_script_gettext
+-grub_script_if
+-grub_script_leading_whitespace
+-grub_script_no_commands
+-grub_script_not
+-grub_script_return
+-grub_script_setparams
+-grub_script_shift
+-grub_script_strcmp
+-grub_script_test
+-grub_script_vars1
+-grub_script_while1
+-grub_script.tab.c
+-grub_script.tab.h
+-grub_script.yy.c
+-grub_script.yy.h
+-grub-set-default
+-grub_setup_init.c
+-grub_setup_init.h
+-grub-shell
+-grub-shell-tester
+-grub-sparc64-setup
+-grub-sparc64-setup.exe
+-/grub-syslinux2cfg
+-/grub-syslinux2cfg.exe
+-gzcompress_test
+-hddboot_test
+-help_test
+-*.img
+ *.image
+-*.image.exe
+-include/grub/cpu
+-include/grub/machine
+-install-sh
+-lib/libgcrypt-grub
+-libgrub_a_init.c
+-*.log
++*.img
++*.info
+ *.lst
+-lzocompress_test
+ *.marker
+-Makefile
+ *.mod
+-mod-*.c
+-missing
+-netboot_test
++*.module
+ *.o
+-*.a
+-ohci_test
+-partmap_test
+-pata_test
+ *.pf2
+-*.pp
+-po/*.mo
+-po/grub.pot
+-po/POTFILES
+-po/stamp-po
+-printf_test
+-priority_queue_unit_test
+-pseries_test
+-stamp-h
+-stamp-h1
+-stamp-h.in
+-symlist.c
+-symlist.h
+-trigtables.c
+-*.trs
+-uhci_test
+-update-grub_lib
+-unidata.c
+-xzcompress_test
+-Makefile.in
+-GPATH
+-GRTAGS
+-GSYMS
+-GTAGS
+-compile
+-depcomp
+-mdate-sh
+-texinfo.tex
+-grub-core/lib/libgcrypt-grub
+-.deps
+-.deps-util
+-.deps-core
++*.yy.[ch]
++.deps/
++.deps-core/
++.deps-util/
+ .dirstamp
+-Makefile.util.am
+-contrib
+-grub-core/bootinfo.txt
+-grub-core/Makefile.core.am
+-grub-core/Makefile.gcry.def
+-grub-core/contrib
+-grub-core/gdb_grub
+-grub-core/genmod.sh
+-grub-core/gensyminfo.sh
+-grub-core/gmodule.pl
+-grub-core/grub.chrp
+-grub-core/modinfo.sh
+-grub-core/*.module
+-grub-core/*.module.exe
+-grub-core/*.pp
+-grub-core/kernel.img.bin
+-util/bash-completion.d/grub
+-grub-core/gnulib/alloca.h
+-grub-core/gnulib/arg-nonnull.h
+-grub-core/gnulib/c++defs.h
+-grub-core/gnulib/charset.alias
+-grub-core/gnulib/configmake.h
+-grub-core/gnulib/float.h
+-grub-core/gnulib/getopt.h
+-grub-core/gnulib/langinfo.h
+-grub-core/gnulib/ref-add.sed
+-grub-core/gnulib/ref-del.sed
+-grub-core/gnulib/stdio.h
+-grub-core/gnulib/stdlib.h
+-grub-core/gnulib/string.h
+-grub-core/gnulib/strings.h
+-grub-core/gnulib/sys
+-grub-core/gnulib/unistd.h
+-grub-core/gnulib/warn-on-use.h
+-grub-core/gnulib/wchar.h
+-grub-core/gnulib/wctype.h
+-grub-core/rs_decoder.h
+-widthspec.bin
+-widthspec.h
+-docs/stamp-1
+-docs/version-dev.texi
+-Makefile.utilgcry.def
+-po/*.po
+-po/*.gmo
+-po/LINGUAS
+-po/remove-potcdate.sed
+-include/grub/gcrypt/gcrypt.h
+-include/grub/gcrypt/g10lib.h
+-po/POTFILES.in
+-po/POTFILES-shell.in
+-/grub-glue-efi
+-/grub-render-label
+-/grub-glue-efi.exe
+-/grub-render-label.exe
+-grub-core/gnulib/locale.h
+-grub-core/gnulib/unitypes.h
+-grub-core/gnulib/uniwidth.h
+-build-aux/test-driver
++
++# next are things you get if you do ./configure in the topdir (for e.g.
++# "make dist" invocation.
++/config-util.h
++/config.h
++/include/grub/cpu
++/include/grub/machine
++/po/POTFILES
++/stamp-h
++/stamp-h1
++config.log
++config.status
++
++# stuff "make dist" creates
++ChangeLog
++grub-*.tar
++grub-*.tar.*
++
++# stuff "make" creates
++/[[:digit:]][[:digit:]]_?*
++/ascii.h
++/build-grub-gen-asciih
++/build-grub-gen-widthspec
++/build-grub-mkfont
++/config-util.h.in
+ /garbage-gen
+-/garbage-gen.exe
+-/grub-fs-tester
+-grub-core/build-grub-module-verifier
++/grub*-bios-setup
++/grub*-bios-setup.8
++/grub*-editenv
++/grub*-editenv.1
++/grub*-file
++/grub*-file.1
++/grub*-fs-tester
++/grub*-fstest
++/grub*-fstest.1
++/grub*-glue-efi
++/grub*-glue-efi.1
++/grub*-install
++/grub*-install.8
++/grub*-kbdcomp
++/grub*-kbdcomp.1
++/grub*-macbless
++/grub*-macbless.8
++/grub*-menulst2cfg
++/grub*-menulst2cfg.1
++/grub*-mkconfig
++/grub*-mkconfig.8
++/grub*-mkconfig_lib
++/grub*-mkfont
++/grub*-mkfont.1
++/grub*-mkimage
++/grub*-mkimage.1
++/grub*-mklayout
++/grub*-mklayout.1
++/grub*-mknetdir
++/grub*-mknetdir.1
++/grub*-mkpasswd-pbkdf2
++/grub*-mkpasswd-pbkdf2.1
++/grub*-mkrelpath
++/grub*-mkrelpath.1
++/grub*-mkrescue
++/grub*-mkrescue.1
++/grub*-mkstandalone
++/grub*-mkstandalone.1
++/grub*-ofpathname
++/grub*-ofpathname.8
++/grub*-probe
++/grub*-probe.8
++/grub*-reboot
++/grub*-reboot.8
++/grub*-render-label
++/grub*-render-label.1
++/grub*-script-check
++/grub*-script-check.1
++/grub*-set-default
++/grub*-set-default.8
++/grub*-shell
++/grub*-shell-tester
++/grub*-sparc64-setup
++/grub*-sparc64-setup.8
++/grub*-syslinux2cfg
++/grub*-syslinux2cfg.1
++/grub_fstest.pp
++/grub_fstest_init.c
++/grub_fstest_init.lst
++/grub_script.tab.[ch]
++/libgrub.pp
++/libgrub_a_init.c
++/libgrub_a_init.lst
++/stamp-h.in
++/widthspec.h
+diff --git a/build-aux/.gitignore b/build-aux/.gitignore
+new file mode 100644
+index 00000000000..f2f17aab9ff
+--- /dev/null
++++ b/build-aux/.gitignore
+@@ -0,0 +1,9 @@
++/compile
++/config.guess
++/config.sub
++/depcomp
++/install-sh
++/mdate-sh
++/missing
++/test-driver
++/texinfo.tex
+diff --git a/docs/.gitignore b/docs/.gitignore
+new file mode 100644
+index 00000000000..91aee84d3e9
+--- /dev/null
++++ b/docs/.gitignore
+@@ -0,0 +1,4 @@
++/*.in
++/stamp-1
++/stamp-vti
++/version*.texi
+diff --git a/grub-core/.gitignore b/grub-core/.gitignore
+new file mode 100644
+index 00000000000..c738ac6c649
+--- /dev/null
++++ b/grub-core/.gitignore
+@@ -0,0 +1,15 @@
++/*.lst
++/Makefile.gcry.def
++/unidata.c
++/build-grub-module-verifier
++/gdb_grub
++/genmod.sh
++/gensyminfo.sh
++/gentrigtables
++/gmodule.pl
++/grub_script.tab.[ch]
++/modinfo.sh
++/rs_decoder.h
++/symlist.c
++/symlist.h
++/trigtables.c
+diff --git a/grub-core/gnulib/.gitignore b/grub-core/gnulib/.gitignore
+new file mode 100644
+index 00000000000..29e199c2db4
+--- /dev/null
++++ b/grub-core/gnulib/.gitignore
+@@ -0,0 +1,22 @@
++/alloca.h
++/arg-nonnull.h
++/c++defs.h
++/charset.alias
++/configmake.h
++/getopt.h
++/langinfo.h
++/libgnu.a
++/locale.h
++/ref-add.sed
++/ref-del.sed
++/stdio.h
++/stdlib.h
++/string.h
++/strings.h
++/sys/
++/unistd.h
++/unitypes.h
++/uniwidth.h
++/warn-on-use.h
++/wchar.h
++/wctype.h
+diff --git a/grub-core/lib/.gitignore b/grub-core/lib/.gitignore
+new file mode 100644
+index 00000000000..68154591404
+--- /dev/null
++++ b/grub-core/lib/.gitignore
+@@ -0,0 +1 @@
++/libgcrypt-grub/
+diff --git a/include/grub/gcrypt/.gitignore b/include/grub/gcrypt/.gitignore
+new file mode 100644
+index 00000000000..8fbf5646246
+--- /dev/null
++++ b/include/grub/gcrypt/.gitignore
+@@ -0,0 +1,2 @@
++g10lib.h
++gcrypt.h
+diff --git a/po/.gitignore b/po/.gitignore
+new file mode 100644
+index 00000000000..97b679c3138
+--- /dev/null
++++ b/po/.gitignore
+@@ -0,0 +1,4 @@
++/POTFILES*.in
++/grub.pot
++/remove-potcdate.sed
++/stamp-po
+diff --git a/util/bash-completion.d/.gitignore b/util/bash-completion.d/.gitignore
+new file mode 100644
+index 00000000000..b7e1eb12428
+--- /dev/null
++++ b/util/bash-completion.d/.gitignore
+@@ -0,0 +1 @@
++grub
diff --git a/SOURCES/0008-IBM-client-architecture-CAS-reboot-support.patch b/SOURCES/0008-IBM-client-architecture-CAS-reboot-support.patch
new file mode 100644
index 0000000..0dcaa0a
--- /dev/null
+++ b/SOURCES/0008-IBM-client-architecture-CAS-reboot-support.patch
@@ -0,0 +1,172 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Date: Thu, 20 Sep 2012 18:07:39 -0300
+Subject: [PATCH] IBM client architecture (CAS) reboot support
+
+This is an implementation of IBM client architecture (CAS) reboot for GRUB.
+
+There are cases where the POWER firmware must reboot in order to support
+specific features requested by a kernel. The kernel calls
+ibm,client-architecture-support and it may either return or reboot with the new
+feature set. eg:
+
+Calling ibm,client-architecture-support.../
+Elapsed time since release of system processors: 70959 mins 50 secs
+Welcome to GRUB!
+
+Instead of return to the GRUB menu, it will check if the flag for CAS reboot is
+set. If so, grub will automatically boot the last booted kernel using the same
+parameters
+---
+ grub-core/kern/ieee1275/openfw.c | 63 ++++++++++++++++++++++++++++++++++++++++
+ grub-core/normal/main.c          | 19 ++++++++++++
+ grub-core/script/execute.c       |  7 +++++
+ include/grub/ieee1275/ieee1275.h |  2 ++
+ 4 files changed, 91 insertions(+)
+
+diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c
+index 62929d983bf..2d53c0e8608 100644
+--- a/grub-core/kern/ieee1275/openfw.c
++++ b/grub-core/kern/ieee1275/openfw.c
+@@ -588,3 +588,66 @@ grub_ieee1275_get_boot_dev (void)
+ 
+   return bootpath;
+ }
++
++/* Check if it's a CAS reboot. If so, set the script to be executed.  */
++int
++grub_ieee1275_cas_reboot (char *script)
++{
++  grub_uint32_t ibm_ca_support_reboot;
++  grub_uint32_t ibm_fw_nbr_reboots;
++  char property_value[10];
++  grub_ssize_t actual;
++  grub_ieee1275_ihandle_t options;
++
++  if (grub_ieee1275_finddevice ("/options", &options) < 0)
++    return -1;
++
++  /* Check two properties, one is enough to get cas reboot value */
++  ibm_ca_support_reboot = 0;
++  if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen,
++                                          "ibm,client-architecture-support-reboot",
++                                          &ibm_ca_support_reboot,
++                                          sizeof (ibm_ca_support_reboot),
++                                          &actual) >= 0)
++    grub_dprintf("ieee1275", "ibm,client-architecture-support-reboot: %u\n",
++                 ibm_ca_support_reboot);
++
++  ibm_fw_nbr_reboots = 0;
++  if (grub_ieee1275_get_property (options, "ibm,fw-nbr-reboots",
++                                  property_value, sizeof (property_value),
++                                  &actual) >= 0)
++    {
++      property_value[sizeof (property_value) - 1] = 0;
++      ibm_fw_nbr_reboots = (grub_uint8_t) grub_strtoul (property_value, 0, 10);
++      grub_dprintf("ieee1275", "ibm,fw-nbr-reboots: %u\n", ibm_fw_nbr_reboots);
++    }
++
++  if (ibm_ca_support_reboot || ibm_fw_nbr_reboots)
++    {
++      if (! grub_ieee1275_get_property_length (options, "boot-last-label", &actual))
++        {
++          if (actual > 1024)
++            script = grub_realloc (script, actual + 1);
++          grub_ieee1275_get_property (options, "boot-last-label", script, actual,
++                                      &actual);
++          return 0;
++        }
++    }
++
++  grub_ieee1275_set_boot_last_label ("");
++
++  return -1;
++}
++
++int grub_ieee1275_set_boot_last_label (const char *text)
++{
++  grub_ieee1275_ihandle_t options;
++  grub_ssize_t actual;
++
++  grub_dprintf("ieee1275", "set boot_last_label (size: %u)\n", grub_strlen(text));
++  if (! grub_ieee1275_finddevice ("/options", &options) &&
++      options != (grub_ieee1275_ihandle_t) -1)
++    grub_ieee1275_set_property (options, "boot-last-label", text,
++                                grub_strlen (text), &actual);
++  return 0;
++}
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 78a70a8bf47..249e19bc788 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -33,6 +33,9 @@
+ #include <grub/charset.h>
+ #include <grub/script_sh.h>
+ #include <grub/bufio.h>
++#ifdef GRUB_MACHINE_IEEE1275
++#include <grub/ieee1275/ieee1275.h>
++#endif
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -275,6 +278,22 @@ grub_normal_execute (const char *config, int nested, int batch)
+     {
+       menu = read_config_file (config);
+ 
++#ifdef GRUB_MACHINE_IEEE1275
++      int boot;
++      boot = 0;
++      char *script;
++      script = grub_malloc (1024);
++      if (! grub_ieee1275_cas_reboot (script))
++        {
++          char *dummy[1] = { NULL };
++          if (! grub_script_execute_sourcecode (script))
++            boot = 1;
++        }
++      grub_free (script);
++      if (boot)
++        grub_command_execute ("boot", 0, 0);
++#endif
++
+       /* Ignore any error.  */
+       grub_errno = GRUB_ERR_NONE;
+     }
+diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
+index a8502d90711..ab78ca87f90 100644
+--- a/grub-core/script/execute.c
++++ b/grub-core/script/execute.c
+@@ -27,6 +27,9 @@
+ #include <grub/normal.h>
+ #include <grub/extcmd.h>
+ #include <grub/i18n.h>
++#ifdef GRUB_MACHINE_IEEE1275
++#include <grub/ieee1275/ieee1275.h>
++#endif
+ 
+ /* Max digits for a char is 3 (0xFF is 255), similarly for an int it
+    is sizeof (int) * 3, and one extra for a possible -ve sign.  */
+@@ -877,6 +880,10 @@ grub_script_execute_sourcecode (const char *source)
+   grub_err_t ret = 0;
+   struct grub_script *parsed_script;
+ 
++#ifdef GRUB_MACHINE_IEEE1275
++  grub_ieee1275_set_boot_last_label (source);
++#endif
++
+   while (source)
+     {
+       char *line;
+diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
+index 8868f3a756f..2310f33dbc2 100644
+--- a/include/grub/ieee1275/ieee1275.h
++++ b/include/grub/ieee1275/ieee1275.h
+@@ -252,6 +252,8 @@ int EXPORT_FUNC(grub_ieee1275_devalias_next) (struct grub_ieee1275_devalias *ali
+ void EXPORT_FUNC(grub_ieee1275_children_peer) (struct grub_ieee1275_devalias *alias);
+ void EXPORT_FUNC(grub_ieee1275_children_first) (const char *devpath,
+ 						struct grub_ieee1275_devalias *alias);
++int EXPORT_FUNC(grub_ieee1275_cas_reboot) (char *script);
++int EXPORT_FUNC(grub_ieee1275_set_boot_last_label) (const char *text);
+ 
+ char *EXPORT_FUNC(grub_ieee1275_get_boot_dev) (void);
+ 
diff --git a/SOURCES/0009-for-ppc-reset-console-display-attr-when-clear-screen.patch b/SOURCES/0009-for-ppc-reset-console-display-attr-when-clear-screen.patch
new file mode 100644
index 0000000..ac67453
--- /dev/null
+++ b/SOURCES/0009-for-ppc-reset-console-display-attr-when-clear-screen.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Date: Wed, 24 Apr 2013 10:51:48 -0300
+Subject: [PATCH] for ppc, reset console display attr when clear screen
+
+v2: Also use \x0c instead of a literal ^L to make future patches less
+awkward.
+
+This should fix this bugzilla:
+https://bugzilla.redhat.com/show_bug.cgi?id=908519
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/term/terminfo.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c
+index d317efa368d..29df35e6d20 100644
+--- a/grub-core/term/terminfo.c
++++ b/grub-core/term/terminfo.c
+@@ -151,7 +151,7 @@ grub_terminfo_set_current (struct grub_term_output *term,
+       /* Clear the screen.  Using serial console, screen(1) only recognizes the
+        * ANSI escape sequence.  Using video console, Apple Open Firmware
+        * (version 3.1.1) only recognizes the literal ^L.  So use both.  */
+-      data->cls               = grub_strdup ("\e[2J");
++      data->cls               = grub_strdup ("\x0c\e[2J\e[m");
+       data->reverse_video_on  = grub_strdup ("\e[7m");
+       data->reverse_video_off = grub_strdup ("\e[m");
+       if (grub_strcmp ("ieee1275", str) == 0)
diff --git a/SOURCES/0010-Disable-GRUB-video-support-for-IBM-power-machines.patch b/SOURCES/0010-Disable-GRUB-video-support-for-IBM-power-machines.patch
new file mode 100644
index 0000000..ab411af
--- /dev/null
+++ b/SOURCES/0010-Disable-GRUB-video-support-for-IBM-power-machines.patch
@@ -0,0 +1,62 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Date: Tue, 11 Jun 2013 15:14:05 -0300
+Subject: [PATCH] Disable GRUB video support for IBM power machines
+
+Should fix the problem in bugzilla:
+https://bugzilla.redhat.com/show_bug.cgi?id=973205
+---
+ grub-core/kern/ieee1275/cmain.c  | 5 ++++-
+ grub-core/video/ieee1275.c       | 9 ++++++---
+ include/grub/ieee1275/ieee1275.h | 2 ++
+ 3 files changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c
+index 3e12e6b24e1..3e14f539368 100644
+--- a/grub-core/kern/ieee1275/cmain.c
++++ b/grub-core/kern/ieee1275/cmain.c
+@@ -90,7 +90,10 @@ grub_ieee1275_find_options (void)
+   }
+ 
+   if (rc >= 0 && grub_strncmp (tmp, "IBM", 3) == 0)
+-    grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS);
++    {
++      grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS);
++      grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT);
++    }
+ 
+   /* Old Macs have no key repeat, newer ones have fully working one.
+      The ones inbetween when repeated key generates an escaoe sequence
+diff --git a/grub-core/video/ieee1275.c b/grub-core/video/ieee1275.c
+index 17a3dbbb575..b8e4b3feb32 100644
+--- a/grub-core/video/ieee1275.c
++++ b/grub-core/video/ieee1275.c
+@@ -352,9 +352,12 @@ static struct grub_video_adapter grub_video_ieee1275_adapter =
+ 
+ GRUB_MOD_INIT(ieee1275_fb)
+ {
+-  find_display ();
+-  if (display)
+-    grub_video_register (&grub_video_ieee1275_adapter);
++  if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT))
++    {
++      find_display ();
++      if (display)
++        grub_video_register (&grub_video_ieee1275_adapter);
++    }
+ }
+ 
+ GRUB_MOD_FINI(ieee1275_fb)
+diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
+index 2310f33dbc2..ca08bd96681 100644
+--- a/include/grub/ieee1275/ieee1275.h
++++ b/include/grub/ieee1275/ieee1275.h
+@@ -146,6 +146,8 @@ enum grub_ieee1275_flag
+   GRUB_IEEE1275_FLAG_BROKEN_REPEAT,
+ 
+   GRUB_IEEE1275_FLAG_CURSORONOFF_ANSI_BROKEN,
++
++  GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT
+ };
+ 
+ extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag);
diff --git a/SOURCES/0011-Honor-a-symlink-when-generating-configuration-by-gru.patch b/SOURCES/0011-Honor-a-symlink-when-generating-configuration-by-gru.patch
new file mode 100644
index 0000000..1ea476c
--- /dev/null
+++ b/SOURCES/0011-Honor-a-symlink-when-generating-configuration-by-gru.patch
@@ -0,0 +1,26 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Marcel Kolaja <mkolaja@redhat.com>
+Date: Tue, 21 Jan 2014 10:57:08 -0500
+Subject: [PATCH] Honor a symlink when generating configuration by
+ grub2-mkconfig
+
+Honor a symlink when generating configuration by grub2-mkconfig, so that
+the -o option follows it rather than overwriting it with a regular file.
+---
+ util/grub-mkconfig.in | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index 33332360eec..bc5a3f17541 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -287,7 +287,8 @@ and /etc/grub.d/* files or please file a bug report with
+     exit 1
+   else
+     # none of the children aborted with error, install the new grub.cfg
+-    mv -f ${grub_cfg}.new ${grub_cfg}
++    cat ${grub_cfg}.new > ${grub_cfg}
++    rm -f ${grub_cfg}.new
+   fi
+ fi
+ 
diff --git a/SOURCES/0012-Move-bash-completion-script-922997.patch b/SOURCES/0012-Move-bash-completion-script-922997.patch
new file mode 100644
index 0000000..6c3c773
--- /dev/null
+++ b/SOURCES/0012-Move-bash-completion-script-922997.patch
@@ -0,0 +1,52 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 3 Apr 2013 14:35:34 -0400
+Subject: [PATCH] Move bash completion script (#922997)
+
+Apparently these go in a new place now.
+---
+ configure.ac                       | 11 +++++++++++
+ util/bash-completion.d/Makefile.am |  1 -
+ 2 files changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index c7888e40f66..783118ccdcd 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -289,6 +289,14 @@ AC_SUBST(grubdirname)
+ AC_DEFINE_UNQUOTED(GRUB_DIR_NAME, "$grubdirname",
+     [Default grub directory name])
+ 
++PKG_PROG_PKG_CONFIG
++AS_IF([$($PKG_CONFIG --exists bash-completion)], [
++	bashcompletiondir=$($PKG_CONFIG --variable=completionsdir bash-completion)
++] , [
++	bashcompletiondir=${datadir}/bash-completion/completions
++])
++AC_SUBST(bashcompletiondir)
++
+ #
+ # Checks for build programs.
+ #
+@@ -498,6 +506,9 @@ HOST_CFLAGS="$HOST_CFLAGS $grub_cv_cc_w_extra_flags"
+ # Check for target programs.
+ #
+ 
++# This makes sure pkg.m4 is available.
++m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-config])
++
+ # Find tools for the target.
+ if test "x$target_alias" != x && test "x$host_alias" != "x$target_alias"; then
+   tmp_ac_tool_prefix="$ac_tool_prefix"
+diff --git a/util/bash-completion.d/Makefile.am b/util/bash-completion.d/Makefile.am
+index 136287cf1bf..61108f05429 100644
+--- a/util/bash-completion.d/Makefile.am
++++ b/util/bash-completion.d/Makefile.am
+@@ -6,7 +6,6 @@ EXTRA_DIST = $(bash_completion_source)
+ 
+ CLEANFILES = $(bash_completion_script) config.log
+ 
+-bashcompletiondir = $(sysconfdir)/bash_completion.d
+ bashcompletion_DATA = $(bash_completion_script)
+ 
+ $(bash_completion_script): $(bash_completion_source) $(top_builddir)/config.status
diff --git a/SOURCES/0013-Update-to-minilzo-2.08.patch b/SOURCES/0013-Update-to-minilzo-2.08.patch
new file mode 100644
index 0000000..a71c501
--- /dev/null
+++ b/SOURCES/0013-Update-to-minilzo-2.08.patch
@@ -0,0 +1,8509 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 4 Dec 2014 15:36:09 -0500
+Subject: [PATCH] Update to minilzo-2.08
+
+This fixes CVE-2014-4607 - lzo: lzo1x_decompress_safe() integer overflow
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/lib/minilzo/minilzo.c | 3801 +++++++++++++++++++++++++++------------
+ grub-core/lib/minilzo/lzoconf.h |  216 ++-
+ grub-core/lib/minilzo/lzodefs.h | 2320 ++++++++++++++++++------
+ grub-core/lib/minilzo/minilzo.h |   21 +-
+ 4 files changed, 4489 insertions(+), 1869 deletions(-)
+
+diff --git a/grub-core/lib/minilzo/minilzo.c b/grub-core/lib/minilzo/minilzo.c
+index 25a1f68b3b5..ab2be5f4fd0 100644
+--- a/grub-core/lib/minilzo/minilzo.c
++++ b/grub-core/lib/minilzo/minilzo.c
+@@ -2,22 +2,7 @@
+ 
+    This file is part of the LZO real-time data compression library.
+ 
+-   Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
++   Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
+    All Rights Reserved.
+ 
+    The LZO library is free software; you can redistribute it and/or
+@@ -67,12 +52,6 @@
+ #if defined(__CYGWIN32__) && !defined(__CYGWIN__)
+ #  define __CYGWIN__ __CYGWIN32__
+ #endif
+-#if defined(__IBMCPP__) && !defined(__IBMC__)
+-#  define __IBMC__ __IBMCPP__
+-#endif
+-#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER)
+-#  define __INTEL_COMPILER __ICL
+-#endif
+ #if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE)
+ #  define _ALL_SOURCE 1
+ #endif
+@@ -81,19 +60,30 @@
+ #    define __LONG_MAX__ 9223372036854775807L
+ #  endif
+ #endif
+-#if defined(__INTEL_COMPILER) && defined(__linux__)
++#if !defined(LZO_CFG_NO_DISABLE_WUNDEF)
++#if defined(__ARMCC_VERSION)
++#  pragma diag_suppress 193
++#elif defined(__clang__) && defined(__clang_minor__)
++#  pragma clang diagnostic ignored "-Wundef"
++#elif defined(__INTEL_COMPILER)
+ #  pragma warning(disable: 193)
+-#endif
+-#if defined(__KEIL__) && defined(__C166__)
++#elif defined(__KEIL__) && defined(__C166__)
+ #  pragma warning disable = 322
+-#elif 0 && defined(__C251__)
+-#  pragma warning disable = 322
+-#endif
+-#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__)
+-#  if (_MSC_VER >= 1300)
++#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__PATHSCALE__)
++#  if ((__GNUC__-0) >= 5 || ((__GNUC__-0) == 4 && (__GNUC_MINOR__-0) >= 2))
++#    pragma GCC diagnostic ignored "-Wundef"
++#  endif
++#elif defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__)
++#  if ((_MSC_VER-0) >= 1300)
+ #    pragma warning(disable: 4668)
+ #  endif
+ #endif
++#endif
++#if 0 && defined(__POCC__) && defined(_WIN32)
++#  if (__POCC__ >= 400)
++#    pragma warn(disable: 2216)
++#  endif
++#endif
+ #if 0 && defined(__WATCOMC__)
+ #  if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060)
+ #    pragma warning 203 9
+@@ -102,13 +92,29 @@
+ #if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__)
+ #  pragma option -h
+ #endif
++#if !(LZO_CFG_NO_DISABLE_WCRTNONSTDC)
++#ifndef _CRT_NONSTDC_NO_DEPRECATE
++#define _CRT_NONSTDC_NO_DEPRECATE 1
++#endif
++#ifndef _CRT_NONSTDC_NO_WARNINGS
++#define _CRT_NONSTDC_NO_WARNINGS 1
++#endif
++#ifndef _CRT_SECURE_NO_DEPRECATE
++#define _CRT_SECURE_NO_DEPRECATE 1
++#endif
++#ifndef _CRT_SECURE_NO_WARNINGS
++#define _CRT_SECURE_NO_WARNINGS 1
++#endif
++#endif
+ #if 0
+-#define LZO_0xffffL             0xfffful
+-#define LZO_0xffffffffL         0xfffffffful
++#define LZO_0xffffUL            0xfffful
++#define LZO_0xffffffffUL        0xfffffffful
+ #else
+-#define LZO_0xffffL             65535ul
+-#define LZO_0xffffffffL         4294967295ul
++#define LZO_0xffffUL            65535ul
++#define LZO_0xffffffffUL        4294967295ul
+ #endif
++#define LZO_0xffffL             LZO_0xffffUL
++#define LZO_0xffffffffL         LZO_0xffffffffUL
+ #if (LZO_0xffffL == LZO_0xffffffffL)
+ #  error "your preprocessor is broken 1"
+ #endif
+@@ -123,6 +129,13 @@
+ #  error "your preprocessor is broken 4"
+ #endif
+ #endif
++#if defined(__COUNTER__)
++#  ifndef LZO_CFG_USE_COUNTER
++#  define LZO_CFG_USE_COUNTER 1
++#  endif
++#else
++#  undef LZO_CFG_USE_COUNTER
++#endif
+ #if (UINT_MAX == LZO_0xffffL)
+ #if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__)
+ #  if !defined(MSDOS)
+@@ -253,14 +266,31 @@
+ #endif
+ #define LZO_PP_STRINGIZE(x)             #x
+ #define LZO_PP_MACRO_EXPAND(x)          LZO_PP_STRINGIZE(x)
++#define LZO_PP_CONCAT0()                /*empty*/
++#define LZO_PP_CONCAT1(a)               a
+ #define LZO_PP_CONCAT2(a,b)             a ## b
+ #define LZO_PP_CONCAT3(a,b,c)           a ## b ## c
+ #define LZO_PP_CONCAT4(a,b,c,d)         a ## b ## c ## d
+ #define LZO_PP_CONCAT5(a,b,c,d,e)       a ## b ## c ## d ## e
++#define LZO_PP_CONCAT6(a,b,c,d,e,f)     a ## b ## c ## d ## e ## f
++#define LZO_PP_CONCAT7(a,b,c,d,e,f,g)   a ## b ## c ## d ## e ## f ## g
++#define LZO_PP_ECONCAT0()               LZO_PP_CONCAT0()
++#define LZO_PP_ECONCAT1(a)              LZO_PP_CONCAT1(a)
+ #define LZO_PP_ECONCAT2(a,b)            LZO_PP_CONCAT2(a,b)
+ #define LZO_PP_ECONCAT3(a,b,c)          LZO_PP_CONCAT3(a,b,c)
+ #define LZO_PP_ECONCAT4(a,b,c,d)        LZO_PP_CONCAT4(a,b,c,d)
+ #define LZO_PP_ECONCAT5(a,b,c,d,e)      LZO_PP_CONCAT5(a,b,c,d,e)
++#define LZO_PP_ECONCAT6(a,b,c,d,e,f)    LZO_PP_CONCAT6(a,b,c,d,e,f)
++#define LZO_PP_ECONCAT7(a,b,c,d,e,f,g)  LZO_PP_CONCAT7(a,b,c,d,e,f,g)
++#define LZO_PP_EMPTY                    /*empty*/
++#define LZO_PP_EMPTY0()                 /*empty*/
++#define LZO_PP_EMPTY1(a)                /*empty*/
++#define LZO_PP_EMPTY2(a,b)              /*empty*/
++#define LZO_PP_EMPTY3(a,b,c)            /*empty*/
++#define LZO_PP_EMPTY4(a,b,c,d)          /*empty*/
++#define LZO_PP_EMPTY5(a,b,c,d,e)        /*empty*/
++#define LZO_PP_EMPTY6(a,b,c,d,e,f)      /*empty*/
++#define LZO_PP_EMPTY7(a,b,c,d,e,f,g)    /*empty*/
+ #if 1
+ #define LZO_CPP_STRINGIZE(x)            #x
+ #define LZO_CPP_MACRO_EXPAND(x)         LZO_CPP_STRINGIZE(x)
+@@ -268,12 +298,16 @@
+ #define LZO_CPP_CONCAT3(a,b,c)          a ## b ## c
+ #define LZO_CPP_CONCAT4(a,b,c,d)        a ## b ## c ## d
+ #define LZO_CPP_CONCAT5(a,b,c,d,e)      a ## b ## c ## d ## e
++#define LZO_CPP_CONCAT6(a,b,c,d,e,f)    a ## b ## c ## d ## e ## f
++#define LZO_CPP_CONCAT7(a,b,c,d,e,f,g)  a ## b ## c ## d ## e ## f ## g
+ #define LZO_CPP_ECONCAT2(a,b)           LZO_CPP_CONCAT2(a,b)
+ #define LZO_CPP_ECONCAT3(a,b,c)         LZO_CPP_CONCAT3(a,b,c)
+ #define LZO_CPP_ECONCAT4(a,b,c,d)       LZO_CPP_CONCAT4(a,b,c,d)
+ #define LZO_CPP_ECONCAT5(a,b,c,d,e)     LZO_CPP_CONCAT5(a,b,c,d,e)
++#define LZO_CPP_ECONCAT6(a,b,c,d,e,f)   LZO_CPP_CONCAT6(a,b,c,d,e,f)
++#define LZO_CPP_ECONCAT7(a,b,c,d,e,f,g) LZO_CPP_CONCAT7(a,b,c,d,e,f,g)
+ #endif
+-#define __LZO_MASK_GEN(o,b)     (((((o) << ((b)-1)) - (o)) << 1) + (o))
++#define __LZO_MASK_GEN(o,b)     (((((o) << ((b)-!!(b))) - (o)) << 1) + (o)*!!(b))
+ #if 1 && defined(__cplusplus)
+ #  if !defined(__STDC_CONSTANT_MACROS)
+ #    define __STDC_CONSTANT_MACROS 1
+@@ -283,9 +317,13 @@
+ #  endif
+ #endif
+ #if defined(__cplusplus)
+-#  define LZO_EXTERN_C extern "C"
++#  define LZO_EXTERN_C          extern "C"
++#  define LZO_EXTERN_C_BEGIN    extern "C" {
++#  define LZO_EXTERN_C_END      }
+ #else
+-#  define LZO_EXTERN_C extern
++#  define LZO_EXTERN_C          extern
++#  define LZO_EXTERN_C_BEGIN    /*empty*/
++#  define LZO_EXTERN_C_END      /*empty*/
+ #endif
+ #if !defined(__LZO_OS_OVERRIDE)
+ #if (LZO_OS_FREESTANDING)
+@@ -386,12 +424,12 @@
+ #elif defined(__VMS)
+ #  define LZO_OS_VMS            1
+ #  define LZO_INFO_OS           "vms"
+-#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
++#elif (defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)
+ #  define LZO_OS_CONSOLE        1
+ #  define LZO_OS_CONSOLE_PS2    1
+ #  define LZO_INFO_OS           "console"
+ #  define LZO_INFO_OS_CONSOLE   "ps2"
+-#elif (defined(__mips__) && defined(__psp__))
++#elif defined(__mips__) && defined(__psp__)
+ #  define LZO_OS_CONSOLE        1
+ #  define LZO_OS_CONSOLE_PSP    1
+ #  define LZO_INFO_OS           "console"
+@@ -419,9 +457,18 @@
+ #  elif defined(__linux__) || defined(__linux) || defined(__LINUX__)
+ #    define LZO_OS_POSIX_LINUX      1
+ #    define LZO_INFO_OS_POSIX       "linux"
+-#  elif defined(__APPLE__) || defined(__MACOS__)
+-#    define LZO_OS_POSIX_MACOSX     1
+-#    define LZO_INFO_OS_POSIX       "macosx"
++#  elif defined(__APPLE__) && defined(__MACH__)
++#    if ((__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__-0) >= 20000)
++#      define LZO_OS_POSIX_DARWIN     1040
++#      define LZO_INFO_OS_POSIX       "darwin_iphone"
++#    elif ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) >= 1040)
++#      define LZO_OS_POSIX_DARWIN     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
++#      define LZO_INFO_OS_POSIX       "darwin"
++#    else
++#      define LZO_OS_POSIX_DARWIN     1
++#      define LZO_INFO_OS_POSIX       "darwin"
++#    endif
++#    define LZO_OS_POSIX_MACOSX     LZO_OS_POSIX_DARWIN
+ #  elif defined(__minix__) || defined(__minix)
+ #    define LZO_OS_POSIX_MINIX      1
+ #    define LZO_INFO_OS_POSIX       "minix"
+@@ -456,18 +503,18 @@
+ #endif
+ #if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+ #  if (UINT_MAX != LZO_0xffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #  if (ULONG_MAX != LZO_0xffffffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #endif
+ #if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64)
+ #  if (UINT_MAX != LZO_0xffffffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #  if (ULONG_MAX != LZO_0xffffffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #endif
+ #if defined(CIL) && defined(_GNUCC) && defined(__GNUC__)
+@@ -483,59 +530,65 @@
+ #  define LZO_INFO_CC           "sdcc"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(SDCC)
+ #elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__)
+-#  define LZO_CC_PATHSCALE      (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__)
++#  define LZO_CC_PATHSCALE      (__PATHCC__ * 0x10000L + (__PATHCC_MINOR__-0) * 0x100 + (__PATHCC_PATCHLEVEL__-0))
+ #  define LZO_INFO_CC           "Pathscale C"
+ #  define LZO_INFO_CCVER        __PATHSCALE__
+-#elif defined(__INTEL_COMPILER)
+-#  define LZO_CC_INTELC         1
++#  if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
++#    define LZO_CC_PATHSCALE_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
++#  endif
++#elif defined(__INTEL_COMPILER) && ((__INTEL_COMPILER-0) > 0)
++#  define LZO_CC_INTELC         __INTEL_COMPILER
+ #  define LZO_INFO_CC           "Intel C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__INTEL_COMPILER)
+-#  if defined(_WIN32) || defined(_WIN64)
+-#    define LZO_CC_SYNTAX_MSC 1
+-#  else
+-#    define LZO_CC_SYNTAX_GNUC 1
++#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)
++#    define LZO_CC_INTELC_MSC   _MSC_VER
++#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
++#    define LZO_CC_INTELC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+ #  endif
+ #elif defined(__POCC__) && defined(_WIN32)
+ #  define LZO_CC_PELLESC        1
+ #  define LZO_INFO_CC           "Pelles C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__POCC__)
+-#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
++#elif defined(__ARMCC_VERSION) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+ #  if defined(__GNUC_PATCHLEVEL__)
+-#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
++#    define LZO_CC_ARMCC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+ #  else
+-#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
++#    define LZO_CC_ARMCC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)
+ #  endif
++#  define LZO_CC_ARMCC          __ARMCC_VERSION
++#  define LZO_INFO_CC           "ARM C Compiler"
++#  define LZO_INFO_CCVER        __VERSION__
++#elif defined(__clang__) && defined(__llvm__) && defined(__VERSION__)
+ #  if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)
+-#    define LZO_CC_CLANG_CLANG  (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__)
++#    define LZO_CC_CLANG        (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0))
+ #  else
+-#    define LZO_CC_CLANG_CLANG  0x010000L
++#    define LZO_CC_CLANG        0x010000L
++#  endif
++#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)
++#    define LZO_CC_CLANG_MSC    _MSC_VER
++#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
++#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+ #  endif
+-#  define LZO_CC_CLANG          LZO_CC_CLANG_GNUC
+ #  define LZO_INFO_CC           "clang"
+ #  define LZO_INFO_CCVER        __VERSION__
+ #elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+ #  if defined(__GNUC_PATCHLEVEL__)
+-#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
++#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+ #  else
+-#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
++#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)
+ #  endif
+ #  define LZO_CC_LLVM           LZO_CC_LLVM_GNUC
+ #  define LZO_INFO_CC           "llvm-gcc"
+ #  define LZO_INFO_CCVER        __VERSION__
+-#elif defined(__GNUC__) && defined(__VERSION__)
+-#  if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+-#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+-#  elif defined(__GNUC_MINOR__)
+-#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+-#  else
+-#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L)
+-#  endif
+-#  define LZO_INFO_CC           "gcc"
+-#  define LZO_INFO_CCVER        __VERSION__
+ #elif defined(__ACK__) && defined(_ACK)
+ #  define LZO_CC_ACK            1
+ #  define LZO_INFO_CC           "Amsterdam Compiler Kit C"
+ #  define LZO_INFO_CCVER        "unknown"
++#elif defined(__ARMCC_VERSION) && !defined(__GNUC__)
++#  define LZO_CC_ARMCC          __ARMCC_VERSION
++#  define LZO_CC_ARMCC_ARMCC    __ARMCC_VERSION
++#  define LZO_INFO_CC           "ARM C Compiler"
++#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__ARMCC_VERSION)
+ #elif defined(__AZTEC_C__)
+ #  define LZO_CC_AZTECC         1
+ #  define LZO_INFO_CC           "Aztec C"
+@@ -560,10 +613,23 @@
+ #  define LZO_CC_DECC           1
+ #  define LZO_INFO_CC           "DEC C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__DECC)
++#elif (defined(__ghs) || defined(__ghs__)) && defined(__GHS_VERSION_NUMBER) && ((__GHS_VERSION_NUMBER-0) > 0)
++#  define LZO_CC_GHS            1
++#  define LZO_INFO_CC           "Green Hills C"
++#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__GHS_VERSION_NUMBER)
++#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)
++#    define LZO_CC_GHS_MSC      _MSC_VER
++#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
++#    define LZO_CC_GHS_GNUC     (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
++#  endif
+ #elif defined(__HIGHC__)
+ #  define LZO_CC_HIGHC          1
+ #  define LZO_INFO_CC           "MetaWare High C"
+ #  define LZO_INFO_CCVER        "unknown"
++#elif defined(__HP_aCC) && ((__HP_aCC-0) > 0)
++#  define LZO_CC_HPACC          __HP_aCC
++#  define LZO_INFO_CC           "HP aCC"
++#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__HP_aCC)
+ #elif defined(__IAR_SYSTEMS_ICC__)
+ #  define LZO_CC_IARC           1
+ #  define LZO_INFO_CC           "IAR C"
+@@ -572,10 +638,14 @@
+ #  else
+ #    define LZO_INFO_CCVER      "unknown"
+ #  endif
+-#elif defined(__IBMC__)
+-#  define LZO_CC_IBMC           1
++#elif defined(__IBMC__) && ((__IBMC__-0) > 0)
++#  define LZO_CC_IBMC           __IBMC__
+ #  define LZO_INFO_CC           "IBM C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__IBMC__)
++#elif defined(__IBMCPP__) && ((__IBMCPP__-0) > 0)
++#  define LZO_CC_IBMC           __IBMCPP__
++#  define LZO_INFO_CC           "IBM C"
++#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__IBMCPP__)
+ #elif defined(__KEIL__) && defined(__C166__)
+ #  define LZO_CC_KEILC          1
+ #  define LZO_INFO_CC           "Keil C"
+@@ -592,16 +662,8 @@
+ #  else
+ #    define LZO_INFO_CCVER      "unknown"
+ #  endif
+-#elif defined(_MSC_VER)
+-#  define LZO_CC_MSC            1
+-#  define LZO_INFO_CC           "Microsoft C"
+-#  if defined(_MSC_FULL_VER)
+-#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER)
+-#  else
+-#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER)
+-#  endif
+-#elif defined(__MWERKS__)
+-#  define LZO_CC_MWERKS         1
++#elif defined(__MWERKS__) && ((__MWERKS__-0) > 0)
++#  define LZO_CC_MWERKS         __MWERKS__
+ #  define LZO_INFO_CC           "Metrowerks C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__MWERKS__)
+ #elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386)
+@@ -612,6 +674,15 @@
+ #  define LZO_CC_PACIFICC       1
+ #  define LZO_INFO_CC           "Pacific C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__PACIFIC__)
++#elif defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__)
++#  if defined(__PGIC_PATCHLEVEL__)
++#    define LZO_CC_PGI          (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100 + (__PGIC_PATCHLEVEL__-0))
++#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__PGIC__) "." LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) "." LZO_PP_MACRO_EXPAND(__PGIC_PATCHLEVEL__)
++#  else
++#    define LZO_CC_PGI          (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100)
++#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__PGIC__) "." LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) ".0"
++#  endif
++#  define LZO_INFO_CC           "Portland Group PGI C"
+ #elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__))
+ #  define LZO_CC_PGI            1
+ #  define LZO_INFO_CC           "Portland Group PGI C"
+@@ -626,7 +697,7 @@
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__SC__)
+ #elif defined(__SUNPRO_C)
+ #  define LZO_INFO_CC           "SunPro C"
+-#  if ((__SUNPRO_C)+0 > 0)
++#  if ((__SUNPRO_C-0) > 0)
+ #    define LZO_CC_SUNPROC      __SUNPRO_C
+ #    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_C)
+ #  else
+@@ -635,7 +706,7 @@
+ #  endif
+ #elif defined(__SUNPRO_CC)
+ #  define LZO_INFO_CC           "SunPro C"
+-#  if ((__SUNPRO_CC)+0 > 0)
++#  if ((__SUNPRO_CC-0) > 0)
+ #    define LZO_CC_SUNPROC      __SUNPRO_CC
+ #    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_CC)
+ #  else
+@@ -661,16 +732,46 @@
+ #elif defined(__ZTC__)
+ #  define LZO_CC_ZORTECHC       1
+ #  define LZO_INFO_CC           "Zortech C"
+-#  if (__ZTC__ == 0x310)
++#  if ((__ZTC__-0) == 0x310)
+ #    define LZO_INFO_CCVER      "0x310"
+ #  else
+ #    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__ZTC__)
+ #  endif
++#elif defined(__GNUC__) && defined(__VERSION__)
++#  if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
++#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
++#  elif defined(__GNUC_MINOR__)
++#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)
++#  else
++#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L)
++#  endif
++#  define LZO_INFO_CC           "gcc"
++#  define LZO_INFO_CCVER        __VERSION__
++#elif defined(_MSC_VER) && ((_MSC_VER-0) > 0)
++#  define LZO_CC_MSC            _MSC_VER
++#  define LZO_INFO_CC           "Microsoft C"
++#  if defined(_MSC_FULL_VER)
++#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER)
++#  else
++#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER)
++#  endif
+ #else
+ #  define LZO_CC_UNKNOWN        1
+ #  define LZO_INFO_CC           "unknown"
+ #  define LZO_INFO_CCVER        "unknown"
+ #endif
++#if (LZO_CC_GNUC) && defined(__OPEN64__)
++#  if defined(__OPENCC__) && defined(__OPENCC_MINOR__) && defined(__OPENCC_PATCHLEVEL__)
++#    define LZO_CC_OPEN64       (__OPENCC__ * 0x10000L + (__OPENCC_MINOR__-0) * 0x100 + (__OPENCC_PATCHLEVEL__-0))
++#    define LZO_CC_OPEN64_GNUC  LZO_CC_GNUC
++#  endif
++#endif
++#if (LZO_CC_GNUC) && defined(__PCC__)
++#  if defined(__PCC__) && defined(__PCC_MINOR__) && defined(__PCC_MINORMINOR__)
++#    define LZO_CC_PCC          (__PCC__ * 0x10000L + (__PCC_MINOR__-0) * 0x100 + (__PCC_MINORMINOR__-0))
++#    define LZO_CC_PCC_GNUC     LZO_CC_GNUC
++#  endif
++#endif
+ #if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)
+ #  error "LZO_CC_MSC: _MSC_FULL_VER is not defined"
+ #endif
+@@ -688,8 +789,10 @@
+ #  define LZO_INFO_ARCH             "generic"
+ #elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+ #  define LZO_ARCH_I086             1
+-#  define LZO_ARCH_IA16             1
+ #  define LZO_INFO_ARCH             "i086"
++#elif defined(__aarch64__)
++#  define LZO_ARCH_ARM64            1
++#  define LZO_INFO_ARCH             "arm64"
+ #elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)
+ #  define LZO_ARCH_ALPHA            1
+ #  define LZO_INFO_ARCH             "alpha"
+@@ -705,10 +808,10 @@
+ #  define LZO_INFO_ARCH             "arm_thumb"
+ #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__)
+ #  define LZO_ARCH_ARM              1
+-#  if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1)
++#  if defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 1)
+ #    define LZO_ARCH_ARM_THUMB      1
+ #    define LZO_INFO_ARCH           "arm_thumb"
+-#  elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2)
++#  elif defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 2)
+ #    define LZO_INFO_ARCH           "arm"
+ #  else
+ #    define LZO_INFO_ARCH           "arm"
+@@ -826,53 +929,147 @@
+ #  error "FIXME - missing define for CPU architecture"
+ #endif
+ #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32)
+-#  error "FIXME - missing WIN32 define for CPU architecture"
++#  error "FIXME - missing LZO_OS_WIN32 define for CPU architecture"
+ #endif
+ #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64)
+-#  error "FIXME - missing WIN64 define for CPU architecture"
++#  error "FIXME - missing LZO_OS_WIN64 define for CPU architecture"
+ #endif
+ #if (LZO_OS_OS216 || LZO_OS_WIN16)
+ #  define LZO_ARCH_I086PM           1
+-#  define LZO_ARCH_IA16PM           1
+ #elif 1 && (LZO_OS_DOS16 && defined(BLX286))
+ #  define LZO_ARCH_I086PM           1
+-#  define LZO_ARCH_IA16PM           1
+ #elif 1 && (LZO_OS_DOS16 && defined(DOSX286))
+ #  define LZO_ARCH_I086PM           1
+-#  define LZO_ARCH_IA16PM           1
+ #elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__))
+ #  define LZO_ARCH_I086PM           1
+-#  define LZO_ARCH_IA16PM           1
+ #endif
+-#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM)
+-#  error "this should not happen"
++#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64)
++#  define LZO_ARCH_X64              1
++#elif (!LZO_ARCH_AMD64 && LZO_ARCH_X64) && defined(__LZO_ARCH_OVERRIDE)
++#  define LZO_ARCH_AMD64            1
+ #endif
+-#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086)
+-#  error "this should not happen"
++#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64)
++#  define LZO_ARCH_AARCH64          1
++#elif (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64) && defined(__LZO_ARCH_OVERRIDE)
++#  define LZO_ARCH_ARM64            1
++#endif
++#if (LZO_ARCH_I386 && !LZO_ARCH_X86)
++#  define LZO_ARCH_X86              1
++#elif (!LZO_ARCH_I386 && LZO_ARCH_X86) && defined(__LZO_ARCH_OVERRIDE)
++#  define LZO_ARCH_I386            1
++#endif
++#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64) || (!LZO_ARCH_AMD64 && LZO_ARCH_X64)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64) || (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_I386 && !LZO_ARCH_X86) || (!LZO_ARCH_I386 && LZO_ARCH_X86)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM_THUMB && !LZO_ARCH_ARM)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM_THUMB)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM_THUMB)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM_THUMB1 && LZO_ARCH_ARM_THUMB2)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_I086PM && !LZO_ARCH_I086)
++#  error "unexpected configuration - check your compiler defines"
+ #endif
+ #if (LZO_ARCH_I086)
+ #  if (UINT_MAX != LZO_0xffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #  if (ULONG_MAX != LZO_0xffffffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #endif
+ #if (LZO_ARCH_I386)
+ #  if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #  if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #  if (ULONG_MAX != LZO_0xffffffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #endif
+-#if !defined(__LZO_MM_OVERRIDE)
++#if (LZO_ARCH_AMD64 || LZO_ARCH_I386)
++#  if !defined(LZO_TARGET_FEATURE_SSE2)
++#    if defined(__SSE2__)
++#      define LZO_TARGET_FEATURE_SSE2       1
++#    elif defined(_MSC_VER) && ((defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2)) || defined(_M_AMD64))
++#      define LZO_TARGET_FEATURE_SSE2       1
++#    endif
++#  endif
++#  if !defined(LZO_TARGET_FEATURE_SSSE3)
++#  if (LZO_TARGET_FEATURE_SSE2)
++#    if defined(__SSSE3__)
++#      define LZO_TARGET_FEATURE_SSSE3      1
++#    elif defined(_MSC_VER) && defined(__AVX__)
++#      define LZO_TARGET_FEATURE_SSSE3      1
++#    endif
++#  endif
++#  endif
++#  if !defined(LZO_TARGET_FEATURE_SSE4_2)
++#  if (LZO_TARGET_FEATURE_SSSE3)
++#    if defined(__SSE4_2__)
++#      define LZO_TARGET_FEATURE_SSE4_2     1
++#    endif
++#  endif
++#  endif
++#  if !defined(LZO_TARGET_FEATURE_AVX)
++#  if (LZO_TARGET_FEATURE_SSSE3)
++#    if defined(__AVX__)
++#      define LZO_TARGET_FEATURE_AVX        1
++#    endif
++#  endif
++#  endif
++#  if !defined(LZO_TARGET_FEATURE_AVX2)
++#  if (LZO_TARGET_FEATURE_AVX)
++#    if defined(__AVX2__)
++#      define LZO_TARGET_FEATURE_AVX2       1
++#    endif
++#  endif
++#  endif
++#endif
++#if (LZO_TARGET_FEATURE_SSSE3 && !(LZO_TARGET_FEATURE_SSE2))
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_TARGET_FEATURE_SSE4_2 && !(LZO_TARGET_FEATURE_SSSE3))
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_TARGET_FEATURE_AVX && !(LZO_TARGET_FEATURE_SSSE3))
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_TARGET_FEATURE_AVX2 && !(LZO_TARGET_FEATURE_AVX))
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM)
++#  if !defined(LZO_TARGET_FEATURE_NEON)
++#    if defined(__ARM_NEON__)
++#      define LZO_TARGET_FEATURE_NEON       1
++#    endif
++#  endif
++#elif (LZO_ARCH_ARM64)
++#  if !defined(LZO_TARGET_FEATURE_NEON)
++#    if 1
++#      define LZO_TARGET_FEATURE_NEON       1
++#    endif
++#  endif
++#endif
++#if 0
++#elif !defined(__LZO_MM_OVERRIDE)
+ #if (LZO_ARCH_I086)
+ #if (UINT_MAX != LZO_0xffffL)
+-#  error "this should not happen"
++#  error "unexpected configuration - check your compiler defines"
+ #endif
+ #if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM)
+ #  define LZO_MM_TINY           1
+@@ -899,7 +1096,7 @@
+ #elif (LZO_CC_ZORTECHC && defined(__VCM__))
+ #  define LZO_MM_LARGE          1
+ #else
+-#  error "unknown memory model"
++#  error "unknown LZO_ARCH_I086 memory model"
+ #endif
+ #if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+ #define LZO_HAVE_MM_HUGE_PTR        1
+@@ -922,10 +1119,10 @@
+ #endif
+ #if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR)
+ #  if (LZO_OS_DOS16)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  elif (LZO_CC_ZORTECHC)
+ #  else
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #endif
+ #ifdef __cplusplus
+@@ -957,7 +1154,7 @@ extern "C" {
+ #endif
+ #elif (LZO_ARCH_C166)
+ #if !defined(__MODEL__)
+-#  error "FIXME - C166 __MODEL__"
++#  error "FIXME - LZO_ARCH_C166 __MODEL__"
+ #elif ((__MODEL__) == 0)
+ #  define LZO_MM_SMALL          1
+ #elif ((__MODEL__) == 1)
+@@ -971,11 +1168,11 @@ extern "C" {
+ #elif ((__MODEL__) == 5)
+ #  define LZO_MM_XSMALL         1
+ #else
+-#  error "FIXME - C166 __MODEL__"
++#  error "FIXME - LZO_ARCH_C166 __MODEL__"
+ #endif
+ #elif (LZO_ARCH_MCS251)
+ #if !defined(__MODEL__)
+-#  error "FIXME - MCS251 __MODEL__"
++#  error "FIXME - LZO_ARCH_MCS251 __MODEL__"
+ #elif ((__MODEL__) == 0)
+ #  define LZO_MM_SMALL          1
+ #elif ((__MODEL__) == 2)
+@@ -987,11 +1184,11 @@ extern "C" {
+ #elif ((__MODEL__) == 5)
+ #  define LZO_MM_XSMALL         1
+ #else
+-#  error "FIXME - MCS251 __MODEL__"
++#  error "FIXME - LZO_ARCH_MCS251 __MODEL__"
+ #endif
+ #elif (LZO_ARCH_MCS51)
+ #if !defined(__MODEL__)
+-#  error "FIXME - MCS51 __MODEL__"
++#  error "FIXME - LZO_ARCH_MCS51 __MODEL__"
+ #elif ((__MODEL__) == 1)
+ #  define LZO_MM_SMALL          1
+ #elif ((__MODEL__) == 2)
+@@ -1003,7 +1200,7 @@ extern "C" {
+ #elif ((__MODEL__) == 5)
+ #  define LZO_MM_XSMALL         1
+ #else
+-#  error "FIXME - MCS51 __MODEL__"
++#  error "FIXME - LZO_ARCH_MCS51 __MODEL__"
+ #endif
+ #elif (LZO_ARCH_CRAY_PVP)
+ #  define LZO_MM_PVP            1
+@@ -1030,35 +1227,818 @@ extern "C" {
+ #  error "unknown memory model"
+ #endif
+ #endif
++#if !defined(__lzo_gnuc_extension__)
++#if (LZO_CC_GNUC >= 0x020800ul)
++#  define __lzo_gnuc_extension__    __extension__
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_gnuc_extension__    __extension__
++#elif (LZO_CC_IBMC >= 600)
++#  define __lzo_gnuc_extension__    __extension__
++#else
++#endif
++#endif
++#if !defined(__lzo_gnuc_extension__)
++#  define __lzo_gnuc_extension__    /*empty*/
++#endif
++#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) && defined(__cplusplus) && 0
++#  if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul))
++#    define LZO_CFG_USE_NEW_STYLE_CASTS 0
++#  elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1200))
++#    define LZO_CFG_USE_NEW_STYLE_CASTS 0
++#  else
++#    define LZO_CFG_USE_NEW_STYLE_CASTS 1
++#  endif
++#endif
++#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS)
++#  define LZO_CFG_USE_NEW_STYLE_CASTS 0
++#endif
++#if !defined(__cplusplus)
++#  if defined(LZO_CFG_USE_NEW_STYLE_CASTS)
++#    undef LZO_CFG_USE_NEW_STYLE_CASTS
++#  endif
++#  define LZO_CFG_USE_NEW_STYLE_CASTS 0
++#endif
++#if !defined(LZO_REINTERPRET_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_REINTERPRET_CAST(t,e)       (reinterpret_cast<t> (e))
++#  endif
++#endif
++#if !defined(LZO_REINTERPRET_CAST)
++#  define LZO_REINTERPRET_CAST(t,e)         ((t) (e))
++#endif
++#if !defined(LZO_STATIC_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_STATIC_CAST(t,e)            (static_cast<t> (e))
++#  endif
++#endif
++#if !defined(LZO_STATIC_CAST)
++#  define LZO_STATIC_CAST(t,e)              ((t) (e))
++#endif
++#if !defined(LZO_STATIC_CAST2)
++#  define LZO_STATIC_CAST2(t1,t2,e)         LZO_STATIC_CAST(t1, LZO_STATIC_CAST(t2, e))
++#endif
++#if !defined(LZO_UNCONST_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_UNCONST_CAST(t,e)           (const_cast<t> (e))
++#  elif (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_UNCONST_CAST(t,e)           ((t) (e))
++#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#    define LZO_UNCONST_CAST(t,e)           ((t) ((void *) ((lzo_uintptr_t) ((const void *) (e)))))
++#  endif
++#endif
++#if !defined(LZO_UNCONST_CAST)
++#  define LZO_UNCONST_CAST(t,e)             ((t) ((void *) ((const void *) (e))))
++#endif
++#if !defined(LZO_UNCONST_VOLATILE_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_UNCONST_VOLATILE_CAST(t,e)  (const_cast<t> (e))
++#  elif (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_UNCONST_VOLATILE_CAST(t,e)  ((t) (e))
++#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#    define LZO_UNCONST_VOLATILE_CAST(t,e)  ((t) ((volatile void *) ((lzo_uintptr_t) ((volatile const void *) (e)))))
++#  endif
++#endif
++#if !defined(LZO_UNCONST_VOLATILE_CAST)
++#  define LZO_UNCONST_VOLATILE_CAST(t,e)    ((t) ((volatile void *) ((volatile const void *) (e))))
++#endif
++#if !defined(LZO_UNVOLATILE_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_UNVOLATILE_CAST(t,e)        (const_cast<t> (e))
++#  elif (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_UNVOLATILE_CAST(t,e)        ((t) (e))
++#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#    define LZO_UNVOLATILE_CAST(t,e)        ((t) ((void *) ((lzo_uintptr_t) ((volatile void *) (e)))))
++#  endif
++#endif
++#if !defined(LZO_UNVOLATILE_CAST)
++#  define LZO_UNVOLATILE_CAST(t,e)          ((t) ((void *) ((volatile void *) (e))))
++#endif
++#if !defined(LZO_UNVOLATILE_CONST_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_UNVOLATILE_CONST_CAST(t,e)  (const_cast<t> (e))
++#  elif (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_UNVOLATILE_CONST_CAST(t,e)  ((t) (e))
++#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#    define LZO_UNVOLATILE_CONST_CAST(t,e)  ((t) ((const void *) ((lzo_uintptr_t) ((volatile const void *) (e)))))
++#  endif
++#endif
++#if !defined(LZO_UNVOLATILE_CONST_CAST)
++#  define LZO_UNVOLATILE_CONST_CAST(t,e)    ((t) ((const void *) ((volatile const void *) (e))))
++#endif
++#if !defined(LZO_PCAST)
++#  if (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_PCAST(t,e)                  ((t) (e))
++#  endif
++#endif
++#if !defined(LZO_PCAST)
++#  define LZO_PCAST(t,e)                    LZO_STATIC_CAST(t, LZO_STATIC_CAST(void *, e))
++#endif
++#if !defined(LZO_CCAST)
++#  if (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_CCAST(t,e)                  ((t) (e))
++#  endif
++#endif
++#if !defined(LZO_CCAST)
++#  define LZO_CCAST(t,e)                    LZO_STATIC_CAST(t, LZO_STATIC_CAST(const void *, e))
++#endif
++#if !defined(LZO_ICONV)
++#  define LZO_ICONV(t,e)                    LZO_STATIC_CAST(t, e)
++#endif
++#if !defined(LZO_ICAST)
++#  define LZO_ICAST(t,e)                    LZO_STATIC_CAST(t, e)
++#endif
++#if !defined(LZO_ITRUNC)
++#  define LZO_ITRUNC(t,e)                   LZO_STATIC_CAST(t, e)
++#endif
++#if !defined(__lzo_cte)
++#  if (LZO_CC_MSC || LZO_CC_WATCOMC)
++#    define __lzo_cte(e)            ((void)0,(e))
++#  elif 1
++#    define __lzo_cte(e)            ((void)0,(e))
++#  endif
++#endif
++#if !defined(__lzo_cte)
++#  define __lzo_cte(e)              (e)
++#endif
++#if !defined(LZO_BLOCK_BEGIN)
++#  define LZO_BLOCK_BEGIN           do {
++#  define LZO_BLOCK_END             } while __lzo_cte(0)
++#endif
++#if !defined(LZO_UNUSED)
++#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
++#    define LZO_UNUSED(var)         ((void) &var)
++#  elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
++#    define LZO_UNUSED(var)         if (&var) ; else
++#  elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030200ul))
++#    define LZO_UNUSED(var)         ((void) &var)
++#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#    define LZO_UNUSED(var)         ((void) var)
++#  elif (LZO_CC_MSC && (_MSC_VER < 900))
++#    define LZO_UNUSED(var)         if (&var) ; else
++#  elif (LZO_CC_KEILC)
++#    define LZO_UNUSED(var)         {LZO_EXTERN_C int lzo_unused__[1-2*!(sizeof(var)>0)];}
++#  elif (LZO_CC_PACIFICC)
++#    define LZO_UNUSED(var)         ((void) sizeof(var))
++#  elif (LZO_CC_WATCOMC) && defined(__cplusplus)
++#    define LZO_UNUSED(var)         ((void) var)
++#  else
++#    define LZO_UNUSED(var)         ((void) &var)
++#  endif
++#endif
++#if !defined(LZO_UNUSED_FUNC)
++#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
++#    define LZO_UNUSED_FUNC(func)   ((void) func)
++#  elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
++#    define LZO_UNUSED_FUNC(func)   if (func) ; else
++#  elif (LZO_CC_CLANG || LZO_CC_LLVM)
++#    define LZO_UNUSED_FUNC(func)   ((void) &func)
++#  elif (LZO_CC_MSC && (_MSC_VER < 900))
++#    define LZO_UNUSED_FUNC(func)   if (func) ; else
++#  elif (LZO_CC_MSC)
++#    define LZO_UNUSED_FUNC(func)   ((void) &func)
++#  elif (LZO_CC_KEILC || LZO_CC_PELLESC)
++#    define LZO_UNUSED_FUNC(func)   {LZO_EXTERN_C int lzo_unused_func__[1-2*!(sizeof((int)func)>0)];}
++#  else
++#    define LZO_UNUSED_FUNC(func)   ((void) func)
++#  endif
++#endif
++#if !defined(LZO_UNUSED_LABEL)
++#  if (LZO_CC_CLANG >= 0x020800ul)
++#    define LZO_UNUSED_LABEL(l)     (__lzo_gnuc_extension__ ((void) ((const void *) &&l)))
++#  elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)
++#    define LZO_UNUSED_LABEL(l)     if __lzo_cte(0) goto l
++#  else
++#    define LZO_UNUSED_LABEL(l)     switch (0) case 1:goto l
++#  endif
++#endif
++#if !defined(LZO_DEFINE_UNINITIALIZED_VAR)
++#  if 0
++#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var
++#  elif 0 && (LZO_CC_GNUC)
++#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = var
++#  else
++#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = init
++#  endif
++#endif
++#if !defined(__lzo_inline)
++#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295))
++#elif defined(__cplusplus)
++#  define __lzo_inline          inline
++#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L)
++#  define __lzo_inline          inline
++#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
++#  define __lzo_inline          __inline
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
++#  define __lzo_inline          __inline__
++#elif (LZO_CC_DMC)
++#  define __lzo_inline          __inline
++#elif (LZO_CC_GHS)
++#  define __lzo_inline          __inline__
++#elif (LZO_CC_IBMC >= 600)
++#  define __lzo_inline          __inline__
++#elif (LZO_CC_INTELC)
++#  define __lzo_inline          __inline
++#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405))
++#  define __lzo_inline          __inline
++#elif (LZO_CC_MSC && (_MSC_VER >= 900))
++#  define __lzo_inline          __inline
++#elif (LZO_CC_SUNPROC >= 0x5100)
++#  define __lzo_inline          __inline__
++#endif
++#endif
++#if defined(__lzo_inline)
++#  ifndef __lzo_HAVE_inline
++#  define __lzo_HAVE_inline 1
++#  endif
++#else
++#  define __lzo_inline          /*empty*/
++#endif
++#if !defined(__lzo_forceinline)
++#if (LZO_CC_GNUC >= 0x030200ul)
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#elif (LZO_CC_IBMC >= 700)
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450))
++#  define __lzo_forceinline     __forceinline
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
++#  define __lzo_forceinline     __forceinline
++#elif (LZO_CC_PGI >= 0x0d0a00ul)
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#elif (LZO_CC_SUNPROC >= 0x5100)
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#endif
++#endif
++#if defined(__lzo_forceinline)
++#  ifndef __lzo_HAVE_forceinline
++#  define __lzo_HAVE_forceinline 1
++#  endif
++#else
++#  define __lzo_forceinline     __lzo_inline
++#endif
++#if !defined(__lzo_noinline)
++#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
++#  define __lzo_noinline        __attribute__((__noinline__,__used__))
++#elif (LZO_CC_GNUC >= 0x030200ul)
++#  define __lzo_noinline        __attribute__((__noinline__))
++#elif (LZO_CC_IBMC >= 700)
++#  define __lzo_noinline        __attribute__((__noinline__))
++#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600))
++#  define __lzo_noinline        __declspec(noinline)
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))
++#  define __lzo_noinline        __attribute__((__noinline__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_noinline        __attribute__((__noinline__))
++#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
++#  define __lzo_noinline        __declspec(noinline)
++#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64))
++#  if defined(__cplusplus)
++#  else
++#    define __lzo_noinline      __declspec(noinline)
++#  endif
++#elif (LZO_CC_PGI >= 0x0d0a00ul)
++#  define __lzo_noinline        __attribute__((__noinline__))
++#elif (LZO_CC_SUNPROC >= 0x5100)
++#  define __lzo_noinline        __attribute__((__noinline__))
++#endif
++#endif
++#if defined(__lzo_noinline)
++#  ifndef __lzo_HAVE_noinline
++#  define __lzo_HAVE_noinline 1
++#  endif
++#else
++#  define __lzo_noinline        /*empty*/
++#endif
++#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if !defined(__lzo_static_inline)
++#if (LZO_CC_IBMC)
++#  define __lzo_static_inline       __lzo_gnuc_extension__ static __lzo_inline
++#endif
++#endif
++#if !defined(__lzo_static_inline)
++#  define __lzo_static_inline       static __lzo_inline
++#endif
++#if !defined(__lzo_static_forceinline)
++#if (LZO_CC_IBMC)
++#  define __lzo_static_forceinline  __lzo_gnuc_extension__ static __lzo_forceinline
++#endif
++#endif
++#if !defined(__lzo_static_forceinline)
++#  define __lzo_static_forceinline  static __lzo_forceinline
++#endif
++#if !defined(__lzo_static_noinline)
++#if (LZO_CC_IBMC)
++#  define __lzo_static_noinline     __lzo_gnuc_extension__ static __lzo_noinline
++#endif
++#endif
++#if !defined(__lzo_static_noinline)
++#  define __lzo_static_noinline     static __lzo_noinline
++#endif
++#if !defined(__lzo_c99_extern_inline)
++#if defined(__GNUC_GNU_INLINE__)
++#  define __lzo_c99_extern_inline   __lzo_inline
++#elif defined(__GNUC_STDC_INLINE__)
++#  define __lzo_c99_extern_inline   extern __lzo_inline
++#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L)
++#  define __lzo_c99_extern_inline   extern __lzo_inline
++#endif
++#if !defined(__lzo_c99_extern_inline) && (__lzo_HAVE_inline)
++#  define __lzo_c99_extern_inline   __lzo_inline
++#endif
++#endif
++#if defined(__lzo_c99_extern_inline)
++#  ifndef __lzo_HAVE_c99_extern_inline
++#  define __lzo_HAVE_c99_extern_inline 1
++#  endif
++#else
++#  define __lzo_c99_extern_inline   /*empty*/
++#endif
++#if !defined(__lzo_may_alias)
++#if (LZO_CC_GNUC >= 0x030400ul)
++#  define __lzo_may_alias       __attribute__((__may_alias__))
++#elif (LZO_CC_CLANG >= 0x020900ul)
++#  define __lzo_may_alias       __attribute__((__may_alias__))
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1210)) && 0
++#  define __lzo_may_alias       __attribute__((__may_alias__))
++#elif (LZO_CC_PGI >= 0x0d0a00ul) && 0
++#  define __lzo_may_alias       __attribute__((__may_alias__))
++#endif
++#endif
++#if defined(__lzo_may_alias)
++#  ifndef __lzo_HAVE_may_alias
++#  define __lzo_HAVE_may_alias 1
++#  endif
++#else
++#  define __lzo_may_alias       /*empty*/
++#endif
++#if !defined(__lzo_noreturn)
++#if (LZO_CC_GNUC >= 0x020700ul)
++#  define __lzo_noreturn        __attribute__((__noreturn__))
++#elif (LZO_CC_IBMC >= 700)
++#  define __lzo_noreturn        __attribute__((__noreturn__))
++#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450))
++#  define __lzo_noreturn        __declspec(noreturn)
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600))
++#  define __lzo_noreturn        __attribute__((__noreturn__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_noreturn        __attribute__((__noreturn__))
++#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
++#  define __lzo_noreturn        __declspec(noreturn)
++#elif (LZO_CC_PGI >= 0x0d0a00ul)
++#  define __lzo_noreturn        __attribute__((__noreturn__))
++#endif
++#endif
++#if defined(__lzo_noreturn)
++#  ifndef __lzo_HAVE_noreturn
++#  define __lzo_HAVE_noreturn 1
++#  endif
++#else
++#  define __lzo_noreturn        /*empty*/
++#endif
++#if !defined(__lzo_nothrow)
++#if (LZO_CC_GNUC >= 0x030300ul)
++#  define __lzo_nothrow         __attribute__((__nothrow__))
++#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450)) && defined(__cplusplus)
++#  define __lzo_nothrow         __declspec(nothrow)
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 900))
++#  define __lzo_nothrow         __attribute__((__nothrow__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_nothrow         __attribute__((__nothrow__))
++#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
++#  define __lzo_nothrow         __declspec(nothrow)
++#endif
++#endif
++#if defined(__lzo_nothrow)
++#  ifndef __lzo_HAVE_nothrow
++#  define __lzo_HAVE_nothrow 1
++#  endif
++#else
++#  define __lzo_nothrow         /*empty*/
++#endif
++#if !defined(__lzo_restrict)
++#if (LZO_CC_GNUC >= 0x030400ul)
++#  define __lzo_restrict        __restrict__
++#elif (LZO_CC_IBMC >= 800) && !defined(__cplusplus)
++#  define __lzo_restrict        __restrict__
++#elif (LZO_CC_IBMC >= 1210)
++#  define __lzo_restrict        __restrict__
++#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600))
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600))
++#  define __lzo_restrict        __restrict__
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM)
++#  define __lzo_restrict        __restrict__
++#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
++#  define __lzo_restrict        __restrict
++#elif (LZO_CC_PGI >= 0x0d0a00ul)
++#  define __lzo_restrict        __restrict__
++#endif
++#endif
++#if defined(__lzo_restrict)
++#  ifndef __lzo_HAVE_restrict
++#  define __lzo_HAVE_restrict 1
++#  endif
++#else
++#  define __lzo_restrict        /*empty*/
++#endif
++#if !defined(__lzo_alignof)
++#if (LZO_CC_ARMCC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
++#  define __lzo_alignof(e)      __alignof__(e)
++#elif (LZO_CC_GHS) && !defined(__cplusplus)
++#  define __lzo_alignof(e)      __alignof__(e)
++#elif (LZO_CC_IBMC >= 600)
++#  define __lzo_alignof(e)      (__lzo_gnuc_extension__ __alignof__(e))
++#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
++#  define __lzo_alignof(e)      __alignof__(e)
++#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
++#  define __lzo_alignof(e)      __alignof(e)
++#elif (LZO_CC_SUNPROC >= 0x5100)
++#  define __lzo_alignof(e)      __alignof__(e)
++#endif
++#endif
++#if defined(__lzo_alignof)
++#  ifndef __lzo_HAVE_alignof
++#  define __lzo_HAVE_alignof 1
++#  endif
++#endif
++#if !defined(__lzo_struct_packed)
++#if   (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)
++#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul))
++#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus)
++#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul))
++#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus)
++#elif (LZO_CC_GNUC >= 0x030400ul) && !(LZO_CC_PCC_GNUC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)
++#  define __lzo_struct_packed(s)        struct s {
++#  define __lzo_struct_packed_end()     } __attribute__((__gcc_struct__,__packed__));
++#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__gcc_struct__,__packed__));
++#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100))
++#  define __lzo_struct_packed(s)        struct s {
++#  define __lzo_struct_packed_end()     } __attribute__((__packed__));
++#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__packed__));
++#elif (LZO_CC_IBMC >= 700)
++#  define __lzo_struct_packed(s)        __lzo_gnuc_extension__ struct s {
++#  define __lzo_struct_packed_end()     } __attribute__((__packed__));
++#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__packed__));
++#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))
++#  define __lzo_struct_packed(s)        __pragma(pack(push,1)) struct s {
++#  define __lzo_struct_packed_end()     } __pragma(pack(pop));
++#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900))
++#  define __lzo_struct_packed(s)        _Packed struct s {
++#  define __lzo_struct_packed_end()     };
++#endif
++#endif
++#if defined(__lzo_struct_packed) && !defined(__lzo_struct_packed_ma)
++#  define __lzo_struct_packed_ma(s)     __lzo_struct_packed(s)
++#endif
++#if defined(__lzo_struct_packed_end) && !defined(__lzo_struct_packed_ma_end)
++#  define __lzo_struct_packed_ma_end()  __lzo_struct_packed_end()
++#endif
++#if !defined(__lzo_byte_struct)
++#if defined(__lzo_struct_packed)
++#  define __lzo_byte_struct(s,n)        __lzo_struct_packed(s) unsigned char a[n]; __lzo_struct_packed_end()
++#  define __lzo_byte_struct_ma(s,n)     __lzo_struct_packed_ma(s) unsigned char a[n]; __lzo_struct_packed_ma_end()
++#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_PGI || (LZO_CC_SUNPROC >= 0x5100))
++#  define __lzo_byte_struct(s,n)        struct s { unsigned char a[n]; } __attribute__((__packed__));
++#  define __lzo_byte_struct_ma(s,n)     struct s { unsigned char a[n]; } __lzo_may_alias __attribute__((__packed__));
++#endif
++#endif
++#if defined(__lzo_byte_struct) &&  !defined(__lzo_byte_struct_ma)
++#  define __lzo_byte_struct_ma(s,n)     __lzo_byte_struct(s,n)
++#endif
++#if !defined(__lzo_struct_align16) && (__lzo_HAVE_alignof)
++#if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul))
++#elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)
++#elif (LZO_CC_CILLY || LZO_CC_PCC)
++#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))
++#  define __lzo_struct_align16(s)       struct __declspec(align(16)) s {
++#  define __lzo_struct_align16_end()    };
++#  define __lzo_struct_align32(s)       struct __declspec(align(32)) s {
++#  define __lzo_struct_align32_end()    };
++#  define __lzo_struct_align64(s)       struct __declspec(align(64)) s {
++#  define __lzo_struct_align64_end()    };
++#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || (LZO_CC_IBMC >= 700) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_struct_align16(s)       struct s {
++#  define __lzo_struct_align16_end()    } __attribute__((__aligned__(16)));
++#  define __lzo_struct_align32(s)       struct s {
++#  define __lzo_struct_align32_end()    } __attribute__((__aligned__(32)));
++#  define __lzo_struct_align64(s)       struct s {
++#  define __lzo_struct_align64_end()    } __attribute__((__aligned__(64)));
++#endif
++#endif
++#if !defined(__lzo_union_um)
++#if   (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)
++#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul))
++#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus)
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER < 810))
++#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul))
++#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus)
++#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100))
++#  define __lzo_union_am(s)             union s {
++#  define __lzo_union_am_end()          } __lzo_may_alias;
++#  define __lzo_union_um(s)             union s {
++#  define __lzo_union_um_end()          } __lzo_may_alias __attribute__((__packed__));
++#elif (LZO_CC_IBMC >= 700)
++#  define __lzo_union_am(s)             __lzo_gnuc_extension__ union s {
++#  define __lzo_union_am_end()          } __lzo_may_alias;
++#  define __lzo_union_um(s)             __lzo_gnuc_extension__ union s {
++#  define __lzo_union_um_end()          } __lzo_may_alias __attribute__((__packed__));
++#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))
++#  define __lzo_union_um(s)             __pragma(pack(push,1)) union s {
++#  define __lzo_union_um_end()          } __pragma(pack(pop));
++#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900))
++#  define __lzo_union_um(s)             _Packed union s {
++#  define __lzo_union_um_end()          };
++#endif
++#endif
++#if !defined(__lzo_union_am)
++#  define __lzo_union_am(s)             union s {
++#  define __lzo_union_am_end()          };
++#endif
++#if !defined(__lzo_constructor)
++#if (LZO_CC_GNUC >= 0x030400ul)
++#  define __lzo_constructor     __attribute__((__constructor__,__used__))
++#elif (LZO_CC_GNUC >= 0x020700ul)
++#  define __lzo_constructor     __attribute__((__constructor__))
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))
++#  define __lzo_constructor     __attribute__((__constructor__,__used__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_constructor     __attribute__((__constructor__))
++#endif
++#endif
++#if defined(__lzo_constructor)
++#  ifndef __lzo_HAVE_constructor
++#  define __lzo_HAVE_constructor 1
++#  endif
++#endif
++#if !defined(__lzo_destructor)
++#if (LZO_CC_GNUC >= 0x030400ul)
++#  define __lzo_destructor      __attribute__((__destructor__,__used__))
++#elif (LZO_CC_GNUC >= 0x020700ul)
++#  define __lzo_destructor      __attribute__((__destructor__))
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))
++#  define __lzo_destructor      __attribute__((__destructor__,__used__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_destructor      __attribute__((__destructor__))
++#endif
++#endif
++#if defined(__lzo_destructor)
++#  ifndef __lzo_HAVE_destructor
++#  define __lzo_HAVE_destructor 1
++#  endif
++#endif
++#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
++#if (LZO_CC_GNUC >= 0x030200ul)
++#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
++#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
++#elif (LZO_CC_IBMC >= 1010)
++#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
++#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
++#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
++#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
++#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
++#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
++#endif
++#endif
++#if defined(__lzo_likely)
++#  ifndef __lzo_HAVE_likely
++#  define __lzo_HAVE_likely 1
++#  endif
++#else
++#  define __lzo_likely(e)       (e)
++#endif
++#if defined(__lzo_unlikely)
++#  ifndef __lzo_HAVE_unlikely
++#  define __lzo_HAVE_unlikely 1
++#  endif
++#else
++#  define __lzo_unlikely(e)     (e)
++#endif
++#if !defined(__lzo_static_unused_void_func)
++#  if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
++#    define __lzo_static_unused_void_func(f)    static void __attribute__((__unused__)) f(void)
++#  else
++#    define __lzo_static_unused_void_func(f)    static __lzo_inline void f(void)
++#  endif
++#endif
++#if !defined(__lzo_loop_forever)
++#  if (LZO_CC_IBMC)
++#    define __lzo_loop_forever()    LZO_BLOCK_BEGIN for (;;) { ; } LZO_BLOCK_END
++#  else
++#    define __lzo_loop_forever()    do { ; } while __lzo_cte(1)
++#  endif
++#endif
++#if !defined(__lzo_unreachable)
++#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul))
++#  define __lzo_unreachable()       __builtin_unreachable();
++#elif (LZO_CC_GNUC >= 0x040500ul)
++#  define __lzo_unreachable()       __builtin_unreachable();
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1300)) && 1
++#  define __lzo_unreachable()       __builtin_unreachable();
++#endif
++#endif
++#if defined(__lzo_unreachable)
++#  ifndef __lzo_HAVE_unreachable
++#  define __lzo_HAVE_unreachable 1
++#  endif
++#else
++#  if 0
++#  define __lzo_unreachable()       ((void)0);
++#  else
++#  define __lzo_unreachable()       __lzo_loop_forever();
++#  endif
++#endif
++#ifndef __LZO_CTA_NAME
++#if (LZO_CFG_USE_COUNTER)
++#  define __LZO_CTA_NAME(a)         LZO_PP_ECONCAT2(a,__COUNTER__)
++#else
++#  define __LZO_CTA_NAME(a)         LZO_PP_ECONCAT2(a,__LINE__)
++#endif
++#endif
++#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
++#  if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END
++#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1u-2*!(e)]; LZO_EXTERN_C_END
++#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END
++#  elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020900ul)) && defined(__cplusplus)
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN int __LZO_CTA_NAME(lzo_cta_f__)(int [1-2*!(e)]); LZO_EXTERN_C_END
++#  elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__)
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__)); LZO_EXTERN_C_END
++#  else
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-2*!(e)]; LZO_EXTERN_C_END
++#  endif
++#endif
++#if !defined(LZO_COMPILE_TIME_ASSERT)
++#  if (LZO_CC_AZTECC)
++#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-!(e)];}
++#  elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
++#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
++#  elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__)
++#    define LZO_COMPILE_TIME_ASSERT(e)  {(void) (0/!!(e));}
++#  elif (LZO_CC_GNUC >= 0x040700ul) && (LZO_CFG_USE_COUNTER) && defined(__cplusplus)
++#    define LZO_COMPILE_TIME_ASSERT(e)  {enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__));}
++#  elif (LZO_CC_GNUC >= 0x040700ul)
++#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));}
++#  elif (LZO_CC_MSC && (_MSC_VER < 900))
++#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
++#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
++#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
++#  else
++#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)];}
++#  endif
++#endif
++LZO_COMPILE_TIME_ASSERT_HEADER(1 == 1)
++#if defined(__cplusplus)
++extern "C" { LZO_COMPILE_TIME_ASSERT_HEADER(2 == 2) }
++#endif
++LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3)
++#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)
++#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
++#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
++#    define __lzo_cdecl                 __cdecl
++#    define __lzo_cdecl_atexit          /*empty*/
++#    define __lzo_cdecl_main            __cdecl
++#    if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
++#      define __lzo_cdecl_qsort         __pascal
++#    elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
++#      define __lzo_cdecl_qsort         _stdcall
++#    else
++#      define __lzo_cdecl_qsort         __cdecl
++#    endif
++#  elif (LZO_CC_WATCOMC)
++#    define __lzo_cdecl                 __cdecl
++#  else
++#    define __lzo_cdecl                 __cdecl
++#    define __lzo_cdecl_atexit          __cdecl
++#    define __lzo_cdecl_main            __cdecl
++#    define __lzo_cdecl_qsort           __cdecl
++#  endif
++#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC)
++#  elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
++#    define __lzo_cdecl_sighandler      __pascal
++#  elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
++#    define __lzo_cdecl_sighandler      _stdcall
++#  elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE)
++#    define __lzo_cdecl_sighandler      __clrcall
++#  elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700))
++#    if defined(_DLL)
++#      define __lzo_cdecl_sighandler    _far _cdecl _loadds
++#    elif defined(_MT)
++#      define __lzo_cdecl_sighandler    _far _cdecl
++#    else
++#      define __lzo_cdecl_sighandler    _cdecl
++#    endif
++#  else
++#    define __lzo_cdecl_sighandler      __cdecl
++#  endif
++#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC)
++#  define __lzo_cdecl                   __cdecl
++#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC))
++#  define __lzo_cdecl                   cdecl
++#endif
++#if !defined(__lzo_cdecl)
++#  define __lzo_cdecl                   /*empty*/
++#endif
++#if !defined(__lzo_cdecl_atexit)
++#  define __lzo_cdecl_atexit            /*empty*/
++#endif
++#if !defined(__lzo_cdecl_main)
++#  define __lzo_cdecl_main              /*empty*/
++#endif
++#if !defined(__lzo_cdecl_qsort)
++#  define __lzo_cdecl_qsort             /*empty*/
++#endif
++#if !defined(__lzo_cdecl_sighandler)
++#  define __lzo_cdecl_sighandler        /*empty*/
++#endif
++#if !defined(__lzo_cdecl_va)
++#  define __lzo_cdecl_va                __lzo_cdecl
++#endif
++#if !(LZO_CFG_NO_WINDOWS_H)
++#if !defined(LZO_HAVE_WINDOWS_H)
++#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
++#  if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
++#  elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
++#  elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))
++#  else
++#    define LZO_HAVE_WINDOWS_H 1
++#  endif
++#endif
++#endif
++#endif
++#ifndef LZO_SIZEOF_SHORT
+ #if defined(SIZEOF_SHORT)
+ #  define LZO_SIZEOF_SHORT          (SIZEOF_SHORT)
++#elif defined(__SIZEOF_SHORT__)
++#  define LZO_SIZEOF_SHORT          (__SIZEOF_SHORT__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_INT
+ #if defined(SIZEOF_INT)
+ #  define LZO_SIZEOF_INT            (SIZEOF_INT)
++#elif defined(__SIZEOF_INT__)
++#  define LZO_SIZEOF_INT            (__SIZEOF_INT__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_LONG
+ #if defined(SIZEOF_LONG)
+ #  define LZO_SIZEOF_LONG           (SIZEOF_LONG)
++#elif defined(__SIZEOF_LONG__)
++#  define LZO_SIZEOF_LONG           (__SIZEOF_LONG__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_LONG_LONG
+ #if defined(SIZEOF_LONG_LONG)
+ #  define LZO_SIZEOF_LONG_LONG      (SIZEOF_LONG_LONG)
++#elif defined(__SIZEOF_LONG_LONG__)
++#  define LZO_SIZEOF_LONG_LONG      (__SIZEOF_LONG_LONG__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF___INT16
+ #if defined(SIZEOF___INT16)
+ #  define LZO_SIZEOF___INT16        (SIZEOF___INT16)
+ #endif
++#endif
++#ifndef LZO_SIZEOF___INT32
+ #if defined(SIZEOF___INT32)
+ #  define LZO_SIZEOF___INT32        (SIZEOF___INT32)
+ #endif
++#endif
++#ifndef LZO_SIZEOF___INT64
+ #if defined(SIZEOF___INT64)
+ #  define LZO_SIZEOF___INT64        (SIZEOF___INT64)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_VOID_P
+ #if defined(SIZEOF_VOID_P)
+ #  define LZO_SIZEOF_VOID_P         (SIZEOF_VOID_P)
++#elif defined(__SIZEOF_POINTER__)
++#  define LZO_SIZEOF_VOID_P         (__SIZEOF_POINTER__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_SIZE_T
+ #if defined(SIZEOF_SIZE_T)
+ #  define LZO_SIZEOF_SIZE_T         (SIZEOF_SIZE_T)
++#elif defined(__SIZEOF_SIZE_T__)
++#  define LZO_SIZEOF_SIZE_T         (__SIZEOF_SIZE_T__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_PTRDIFF_T
+ #if defined(SIZEOF_PTRDIFF_T)
+ #  define LZO_SIZEOF_PTRDIFF_T      (SIZEOF_PTRDIFF_T)
++#elif defined(__SIZEOF_PTRDIFF_T__)
++#  define LZO_SIZEOF_PTRDIFF_T      (__SIZEOF_PTRDIFF_T__)
++#endif
+ #endif
+ #define __LZO_LSR(x,b)    (((x)+0ul) >> (b))
+ #if !defined(LZO_SIZEOF_SHORT)
+@@ -1080,6 +2060,7 @@ extern "C" {
+ #    error "LZO_SIZEOF_SHORT"
+ #  endif
+ #endif
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SHORT == sizeof(short))
+ #if !defined(LZO_SIZEOF_INT)
+ #  if (LZO_ARCH_CRAY_PVP)
+ #    define LZO_SIZEOF_INT          8
+@@ -1101,6 +2082,7 @@ extern "C" {
+ #    error "LZO_SIZEOF_INT"
+ #  endif
+ #endif
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_INT == sizeof(int))
+ #if !defined(LZO_SIZEOF_LONG)
+ #  if (ULONG_MAX == LZO_0xffffffffL)
+ #    define LZO_SIZEOF_LONG         4
+@@ -1110,6 +2092,8 @@ extern "C" {
+ #    define LZO_SIZEOF_LONG         2
+ #  elif (__LZO_LSR(ULONG_MAX,31) == 1)
+ #    define LZO_SIZEOF_LONG         4
++#  elif (__LZO_LSR(ULONG_MAX,39) == 1)
++#    define LZO_SIZEOF_LONG         5
+ #  elif (__LZO_LSR(ULONG_MAX,63) == 1)
+ #    define LZO_SIZEOF_LONG         8
+ #  elif (__LZO_LSR(ULONG_MAX,127) == 1)
+@@ -1118,11 +2102,12 @@ extern "C" {
+ #    error "LZO_SIZEOF_LONG"
+ #  endif
+ #endif
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_LONG == sizeof(long))
+ #if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)
+ #if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)
+ #  if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__)
+ #    if (LZO_CC_GNUC >= 0x030300ul)
+-#      if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0)
++#      if ((__LONG_MAX__-0) == (__LONG_LONG_MAX__-0))
+ #        define LZO_SIZEOF_LONG_LONG      LZO_SIZEOF_LONG
+ #      elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1)
+ #        define LZO_SIZEOF_LONG_LONG      4
+@@ -1136,7 +2121,7 @@ extern "C" {
+ #if (LZO_ARCH_I086 && LZO_CC_DMC)
+ #elif (LZO_CC_CILLY) && defined(__GNUC__)
+ #  define LZO_SIZEOF_LONG_LONG      8
+-#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+ #  define LZO_SIZEOF_LONG_LONG      8
+ #elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))
+ #  define LZO_SIZEOF_LONG_LONG      8
+@@ -1158,11 +2143,13 @@ extern "C" {
+ #  define LZO_SIZEOF___INT64        8
+ #elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100)))
+ #  define LZO_SIZEOF___INT64        8
+-#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64))
++#elif (LZO_CC_GHS && defined(__LLONG_BIT) && ((__LLONG_BIT-0) == 64))
++#  define LZO_SIZEOF_LONG_LONG      8
++#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && ((_INTEGRAL_MAX_BITS-0) == 64))
+ #  define LZO_SIZEOF___INT64        8
+ #elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+ #  define LZO_SIZEOF_LONG_LONG      8
+-#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
++#elif (defined(__vms) || defined(__VMS)) && ((__INITIAL_POINTER_SIZE-0) == 64)
+ #  define LZO_SIZEOF_LONG_LONG      8
+ #elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2)
+ #elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+@@ -1175,87 +2162,127 @@ extern "C" {
+ #    undef LZO_SIZEOF_LONG_LONG
+ #  endif
+ #endif
+-#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
++#if (LZO_CFG_NO_LONG_LONG)
++#  undef LZO_SIZEOF_LONG_LONG
++#elif defined(__NO_LONG_LONG)
++#  undef LZO_SIZEOF_LONG_LONG
++#elif defined(_NO_LONGLONG)
+ #  undef LZO_SIZEOF_LONG_LONG
+ #endif
+-#if !defined(LZO_SIZEOF_VOID_P)
+-#if (LZO_ARCH_I086)
+-#  define __LZO_WORDSIZE            2
+-#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM)
+-#    define LZO_SIZEOF_VOID_P       2
+-#  elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE)
+-#    define LZO_SIZEOF_VOID_P       4
++#if !defined(LZO_WORDSIZE)
++#if (LZO_ARCH_ALPHA)
++#  define LZO_WORDSIZE              8
++#elif (LZO_ARCH_AMD64)
++#  define LZO_WORDSIZE              8
++#elif (LZO_ARCH_AVR)
++#  define LZO_WORDSIZE              1
++#elif (LZO_ARCH_H8300)
++#  if defined(__NORMAL_MODE__)
++#    define LZO_WORDSIZE            4
++#  elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
++#    define LZO_WORDSIZE            4
+ #  else
+-#    error "LZO_MM"
++#    define LZO_WORDSIZE            2
+ #  endif
+-#elif (LZO_ARCH_AVR || LZO_ARCH_Z80)
+-#  define __LZO_WORDSIZE            1
++#elif (LZO_ARCH_I086)
++#  define LZO_WORDSIZE              2
++#elif (LZO_ARCH_IA64)
++#  define LZO_WORDSIZE              8
++#elif (LZO_ARCH_M16C)
++#  define LZO_WORDSIZE              2
++#elif (LZO_ARCH_SPU)
++#  define LZO_WORDSIZE              4
++#elif (LZO_ARCH_Z80)
++#  define LZO_WORDSIZE              1
++#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
++#  define LZO_WORDSIZE              8
++#elif (LZO_OS_OS400 || defined(__OS400__))
++#  define LZO_WORDSIZE              8
++#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
++#  define LZO_WORDSIZE              8
++#endif
++#endif
++#if !defined(LZO_SIZEOF_VOID_P)
++#if defined(__ILP32__) || defined(__ILP32) || defined(_ILP32)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int)  == 4)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)
++#  define LZO_SIZEOF_VOID_P         4
++#elif defined(__ILP64__) || defined(__ILP64) || defined(_ILP64)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int)  == 8)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8)
++#  define LZO_SIZEOF_VOID_P         8
++#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)
++#  define LZO_SIZEOF_VOID_P         8
++#elif defined(__LP64__) || defined(__LP64) || defined(_LP64)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8)
++#  define LZO_SIZEOF_VOID_P         8
++#elif (LZO_ARCH_AVR)
+ #  define LZO_SIZEOF_VOID_P         2
+ #elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430)
+ #  define LZO_SIZEOF_VOID_P         2
+ #elif (LZO_ARCH_H8300)
+ #  if defined(__NORMAL_MODE__)
+-#    define __LZO_WORDSIZE          4
+ #    define LZO_SIZEOF_VOID_P       2
+ #  elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+-#    define __LZO_WORDSIZE          4
+ #    define LZO_SIZEOF_VOID_P       4
+ #  else
+-#    define __LZO_WORDSIZE          2
+ #    define LZO_SIZEOF_VOID_P       2
+ #  endif
+ #  if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4)
+ #    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_INT
+ #    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_INT
+ #  endif
++#elif (LZO_ARCH_I086)
++#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM)
++#    define LZO_SIZEOF_VOID_P       2
++#  elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE)
++#    define LZO_SIZEOF_VOID_P       4
++#  else
++#    error "invalid LZO_ARCH_I086 memory model"
++#  endif
+ #elif (LZO_ARCH_M16C)
+-#  define __LZO_WORDSIZE            2
+ #  if defined(__m32c_cpu__) || defined(__m32cm_cpu__)
+ #    define LZO_SIZEOF_VOID_P       4
+ #  else
+ #    define LZO_SIZEOF_VOID_P       2
+ #  endif
++#elif (LZO_ARCH_SPU)
++#  define LZO_SIZEOF_VOID_P         4
++#elif (LZO_ARCH_Z80)
++#  define LZO_SIZEOF_VOID_P         2
+ #elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
+-#  define __LZO_WORDSIZE            8
+ #  define LZO_SIZEOF_VOID_P         4
+-#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64)
+-#  define __LZO_WORDSIZE            8
+-#  define LZO_SIZEOF_VOID_P         8
+-#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+-#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG
+-#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+-#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+ #elif (LZO_OS_OS400 || defined(__OS400__))
+-#  define __LZO_WORDSIZE            LZO_SIZEOF_LONG
+-#  define LZO_SIZEOF_VOID_P         16
+-#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+-#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+-#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
+-#  define LZO_SIZEOF_VOID_P         8
+-#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+-#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+-#elif (LZO_ARCH_SPU)
+-# if 0
+-#  define __LZO_WORDSIZE            16
+-# endif
+-#  define LZO_SIZEOF_VOID_P         4
+-#else
+-#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG
+-#endif
+-#endif
+-#if !defined(LZO_WORDSIZE)
+-#  if defined(__LZO_WORDSIZE)
+-#    define LZO_WORDSIZE            __LZO_WORDSIZE
++#  if defined(__LLP64_IFC__)
++#    define LZO_SIZEOF_VOID_P       8
++#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_LONG
++#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_LONG
+ #  else
+-#    define LZO_WORDSIZE            LZO_SIZEOF_VOID_P
++#    define LZO_SIZEOF_VOID_P       16
++#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_LONG
++#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_LONG
+ #  endif
++#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
++#  define LZO_SIZEOF_VOID_P         8
++#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
++#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+ #endif
++#endif
++#if !defined(LZO_SIZEOF_VOID_P)
++#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG
++#endif
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_VOID_P == sizeof(void *))
+ #if !defined(LZO_SIZEOF_SIZE_T)
+ #if (LZO_ARCH_I086 || LZO_ARCH_M16C)
+ #  define LZO_SIZEOF_SIZE_T         2
+-#else
++#endif
++#endif
++#if !defined(LZO_SIZEOF_SIZE_T)
+ #  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_VOID_P
+ #endif
++#if defined(offsetof)
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SIZE_T == sizeof(size_t))
+ #endif
+ #if !defined(LZO_SIZEOF_PTRDIFF_T)
+ #if (LZO_ARCH_I086)
+@@ -1268,11 +2295,18 @@ extern "C" {
+ #      define LZO_SIZEOF_PTRDIFF_T  2
+ #    endif
+ #  else
+-#    error "LZO_MM"
++#    error "invalid LZO_ARCH_I086 memory model"
+ #  endif
+-#else
++#endif
++#endif
++#if !defined(LZO_SIZEOF_PTRDIFF_T)
+ #  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_SIZE_T
+ #endif
++#if defined(offsetof)
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
++#endif
++#if !defined(LZO_WORDSIZE)
++#  define LZO_WORDSIZE              LZO_SIZEOF_VOID_P
+ #endif
+ #if (LZO_ABI_NEUTRAL_ENDIAN)
+ #  undef LZO_ABI_BIG_ENDIAN
+@@ -1284,7 +2318,7 @@ extern "C" {
+ #  define LZO_ABI_LITTLE_ENDIAN     1
+ #elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
+ #  define LZO_ABI_LITTLE_ENDIAN     1
+-#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390)
++#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390 || LZO_ARCH_SPU)
+ #  define LZO_ABI_BIG_ENDIAN        1
+ #elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)
+ #  if (__LITTLE_ENDIAN__ == 1)
+@@ -1300,6 +2334,19 @@ extern "C" {
+ #  define LZO_ABI_BIG_ENDIAN        1
+ #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__)
+ #  define LZO_ABI_LITTLE_ENDIAN     1
++#elif 1 && (LZO_ARCH_ARM && LZO_CC_ARMCC_ARMCC)
++#  if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN)
++#    error "unexpected configuration - check your compiler defines"
++#  elif defined(__BIG_ENDIAN)
++#    define LZO_ABI_BIG_ENDIAN      1
++#  else
++#    define LZO_ABI_LITTLE_ENDIAN   1
++#  endif
++#  define LZO_ABI_LITTLE_ENDIAN     1
++#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EB__) && !defined(__AARCH64EL__)
++#  define LZO_ABI_BIG_ENDIAN        1
++#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EL__) && !defined(__AARCH64EB__)
++#  define LZO_ABI_LITTLE_ENDIAN     1
+ #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__)
+ #  define LZO_ABI_BIG_ENDIAN        1
+ #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__)
+@@ -1307,7 +2354,7 @@ extern "C" {
+ #endif
+ #endif
+ #if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN)
+-#  error "this should not happen"
++#  error "unexpected configuration - check your compiler defines"
+ #endif
+ #if (LZO_ABI_BIG_ENDIAN)
+ #  define LZO_INFO_ABI_ENDIAN       "be"
+@@ -1322,6 +2369,9 @@ extern "C" {
+ #elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
+ #  define LZO_ABI_ILP16         1
+ #  define LZO_INFO_ABI_PM       "ilp16"
++#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)
++#  define LZO_ABI_LP32          1
++#  define LZO_INFO_ABI_PM       "lp32"
+ #elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)
+ #  define LZO_ABI_ILP32         1
+ #  define LZO_INFO_ABI_PM       "ilp32"
+@@ -1338,7 +2388,8 @@ extern "C" {
+ #  define LZO_ABI_IP32L64       1
+ #  define LZO_INFO_ABI_PM       "ip32l64"
+ #endif
+-#if !defined(__LZO_LIBC_OVERRIDE)
++#if 0
++#elif !defined(__LZO_LIBC_OVERRIDE)
+ #if (LZO_LIBC_NAKED)
+ #  define LZO_INFO_LIBC         "naked"
+ #elif (LZO_LIBC_FREESTANDING)
+@@ -1349,6 +2400,9 @@ extern "C" {
+ #  define LZO_INFO_LIBC         "isoc90"
+ #elif (LZO_LIBC_ISOC99)
+ #  define LZO_INFO_LIBC         "isoc99"
++#elif (LZO_CC_ARMCC_ARMCC) && defined(__ARMCLIB_VERSION)
++#  define LZO_LIBC_ISOC90       1
++#  define LZO_INFO_LIBC         "isoc90"
+ #elif defined(__dietlibc__)
+ #  define LZO_LIBC_DIETLIBC     1
+ #  define LZO_INFO_LIBC         "dietlibc"
+@@ -1357,13 +2411,13 @@ extern "C" {
+ #  define LZO_INFO_LIBC         "newlib"
+ #elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__)
+ #  if defined(__UCLIBC_SUBLEVEL__)
+-#    define LZO_LIBC_UCLIBC     (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__)
++#    define LZO_LIBC_UCLIBC     (__UCLIBC_MAJOR__ * 0x10000L + (__UCLIBC_MINOR__-0) * 0x100 + (__UCLIBC_SUBLEVEL__-0))
+ #  else
+ #    define LZO_LIBC_UCLIBC     0x00090bL
+ #  endif
+-#  define LZO_INFO_LIBC         "uclibc"
++#  define LZO_INFO_LIBC         "uc" "libc"
+ #elif defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+-#  define LZO_LIBC_GLIBC        (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100)
++#  define LZO_LIBC_GLIBC        (__GLIBC__ * 0x10000L + (__GLIBC_MINOR__-0) * 0x100)
+ #  define LZO_INFO_LIBC         "glibc"
+ #elif (LZO_CC_MWERKS) && defined(__MSL__)
+ #  define LZO_LIBC_MSL          __MSL__
+@@ -1376,423 +2430,159 @@ extern "C" {
+ #  define LZO_INFO_LIBC         "default"
+ #endif
+ #endif
+-#if !defined(__lzo_gnuc_extension__)
+-#if (LZO_CC_GNUC >= 0x020800ul)
+-#  define __lzo_gnuc_extension__    __extension__
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_gnuc_extension__    __extension__
+-#else
+-#  define __lzo_gnuc_extension__    /*empty*/
+-#endif
+-#endif
+-#if !defined(__lzo_ua_volatile)
+-#  define __lzo_ua_volatile     volatile
+-#endif
+-#if !defined(__lzo_alignof)
+-#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+-#  define __lzo_alignof(e)      __alignof__(e)
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
+-#  define __lzo_alignof(e)      __alignof__(e)
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+-#  define __lzo_alignof(e)      __alignof(e)
+-#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+-#  define __lzo_alignof(e)      __alignof__(e)
+-#endif
+-#endif
+-#if defined(__lzo_alignof)
+-#  define __lzo_HAVE_alignof 1
+-#endif
+-#if !defined(__lzo_constructor)
+-#if (LZO_CC_GNUC >= 0x030400ul)
+-#  define __lzo_constructor     __attribute__((__constructor__,__used__))
+-#elif (LZO_CC_GNUC >= 0x020700ul)
+-#  define __lzo_constructor     __attribute__((__constructor__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_constructor     __attribute__((__constructor__))
+-#endif
+-#endif
+-#if defined(__lzo_constructor)
+-#  define __lzo_HAVE_constructor 1
+-#endif
+-#if !defined(__lzo_destructor)
+-#if (LZO_CC_GNUC >= 0x030400ul)
+-#  define __lzo_destructor      __attribute__((__destructor__,__used__))
+-#elif (LZO_CC_GNUC >= 0x020700ul)
+-#  define __lzo_destructor      __attribute__((__destructor__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_destructor      __attribute__((__destructor__))
+-#endif
+-#endif
+-#if defined(__lzo_destructor)
+-#  define __lzo_HAVE_destructor 1
+-#endif
+-#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)
+-#  error "this should not happen"
+-#endif
+-#if !defined(__lzo_inline)
+-#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295))
+-#elif defined(__cplusplus)
+-#  define __lzo_inline          inline
+-#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
+-#  define __lzo_inline          __inline
+-#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+-#  define __lzo_inline          __inline__
+-#elif (LZO_CC_DMC)
+-#  define __lzo_inline          __inline
+-#elif (LZO_CC_INTELC)
+-#  define __lzo_inline          __inline
+-#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405))
+-#  define __lzo_inline          __inline
+-#elif (LZO_CC_MSC && (_MSC_VER >= 900))
+-#  define __lzo_inline          __inline
+-#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+-#  define __lzo_inline          __inline__
+-#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+-#  define __lzo_inline          inline
+-#endif
+-#endif
+-#if defined(__lzo_inline)
+-#  define __lzo_HAVE_inline 1
+-#else
+-#  define __lzo_inline          /*empty*/
+-#endif
+-#if !defined(__lzo_forceinline)
+-#if (LZO_CC_GNUC >= 0x030200ul)
+-#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+-#  define __lzo_forceinline     __forceinline
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+-#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+-#  define __lzo_forceinline     __forceinline
+-#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+-#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+-#endif
+-#endif
+-#if defined(__lzo_forceinline)
+-#  define __lzo_HAVE_forceinline 1
+-#else
+-#  define __lzo_forceinline     /*empty*/
+-#endif
+-#if !defined(__lzo_noinline)
+-#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
+-#  define __lzo_noinline        __attribute__((__noinline__,__used__))
+-#elif (LZO_CC_GNUC >= 0x030200ul)
+-#  define __lzo_noinline        __attribute__((__noinline__))
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC)
+-#  define __lzo_noinline        __declspec(noinline)
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+-#  define __lzo_noinline        __attribute__((__noinline__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_noinline        __attribute__((__noinline__))
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+-#  define __lzo_noinline        __declspec(noinline)
+-#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64))
+-#  if defined(__cplusplus)
+-#  else
+-#    define __lzo_noinline      __declspec(noinline)
+-#  endif
+-#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+-#  define __lzo_noinline        __attribute__((__noinline__))
+-#endif
+-#endif
+-#if defined(__lzo_noinline)
+-#  define __lzo_HAVE_noinline 1
+-#else
+-#  define __lzo_noinline        /*empty*/
+-#endif
+-#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)
+-#  error "this should not happen"
+-#endif
+-#if !defined(__lzo_noreturn)
+-#if (LZO_CC_GNUC >= 0x020700ul)
+-#  define __lzo_noreturn        __attribute__((__noreturn__))
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+-#  define __lzo_noreturn        __declspec(noreturn)
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+-#  define __lzo_noreturn        __attribute__((__noreturn__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_noreturn        __attribute__((__noreturn__))
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+-#  define __lzo_noreturn        __declspec(noreturn)
+-#endif
+-#endif
+-#if defined(__lzo_noreturn)
+-#  define __lzo_HAVE_noreturn 1
+-#else
+-#  define __lzo_noreturn        /*empty*/
+-#endif
+-#if !defined(__lzo_nothrow)
+-#if (LZO_CC_GNUC >= 0x030300ul)
+-#  define __lzo_nothrow         __attribute__((__nothrow__))
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus)
+-#  define __lzo_nothrow         __declspec(nothrow)
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC)
+-#  define __lzo_nothrow         __attribute__((__nothrow__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_nothrow         __attribute__((__nothrow__))
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
+-#  define __lzo_nothrow         __declspec(nothrow)
+-#endif
+-#endif
+-#if defined(__lzo_nothrow)
+-#  define __lzo_HAVE_nothrow 1
+-#else
+-#  define __lzo_nothrow         /*empty*/
+-#endif
+-#if !defined(__lzo_restrict)
+-#if (LZO_CC_GNUC >= 0x030400ul)
+-#  define __lzo_restrict        __restrict__
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+-#  define __lzo_restrict        __restrict__
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM)
+-#  define __lzo_restrict        __restrict__
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
+-#  define __lzo_restrict        __restrict
+-#endif
+-#endif
+-#if defined(__lzo_restrict)
+-#  define __lzo_HAVE_restrict 1
+-#else
+-#  define __lzo_restrict        /*empty*/
+-#endif
+-#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
+-#if (LZO_CC_GNUC >= 0x030200ul)
+-#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+-#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
+-#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+-#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+-#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+-#endif
+-#endif
+-#if defined(__lzo_likely)
+-#  define __lzo_HAVE_likely 1
+-#else
+-#  define __lzo_likely(e)       (e)
+-#endif
+-#if defined(__lzo_unlikely)
+-#  define __lzo_HAVE_unlikely 1
+-#else
+-#  define __lzo_unlikely(e)     (e)
+-#endif
+-#if !defined(LZO_UNUSED)
+-#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+-#    define LZO_UNUSED(var)         ((void) &var)
+-#  elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
+-#    define LZO_UNUSED(var)         if (&var) ; else
+-#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#    define LZO_UNUSED(var)         ((void) var)
+-#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+-#    define LZO_UNUSED(var)         if (&var) ; else
+-#  elif (LZO_CC_KEILC)
+-#    define LZO_UNUSED(var)         {extern int __lzo_unused[1-2*!(sizeof(var)>0)];}
+-#  elif (LZO_CC_PACIFICC)
+-#    define LZO_UNUSED(var)         ((void) sizeof(var))
+-#  elif (LZO_CC_WATCOMC) && defined(__cplusplus)
+-#    define LZO_UNUSED(var)         ((void) var)
+-#  else
+-#    define LZO_UNUSED(var)         ((void) &var)
+-#  endif
+-#endif
+-#if !defined(LZO_UNUSED_FUNC)
+-#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+-#    define LZO_UNUSED_FUNC(func)   ((void) func)
+-#  elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
+-#    define LZO_UNUSED_FUNC(func)   if (func) ; else
+-#  elif (LZO_CC_CLANG || LZO_CC_LLVM)
+-#    define LZO_UNUSED_FUNC(func)   ((void) &func)
+-#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+-#    define LZO_UNUSED_FUNC(func)   if (func) ; else
+-#  elif (LZO_CC_MSC)
+-#    define LZO_UNUSED_FUNC(func)   ((void) &func)
+-#  elif (LZO_CC_KEILC || LZO_CC_PELLESC)
+-#    define LZO_UNUSED_FUNC(func)   {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];}
+-#  else
+-#    define LZO_UNUSED_FUNC(func)   ((void) func)
+-#  endif
+-#endif
+-#if !defined(LZO_UNUSED_LABEL)
+-#  if (LZO_CC_WATCOMC) && defined(__cplusplus)
+-#    define LZO_UNUSED_LABEL(l)     switch(0) case 1:goto l
+-#  elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)
+-#    define LZO_UNUSED_LABEL(l)     if (0) goto l
+-#  else
+-#    define LZO_UNUSED_LABEL(l)     switch(0) case 1:goto l
+-#  endif
+-#endif
+-#if !defined(LZO_DEFINE_UNINITIALIZED_VAR)
+-#  if 0
+-#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var
+-#  elif 0 && (LZO_CC_GNUC)
+-#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = var
+-#  else
+-#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = init
+-#  endif
+-#endif
+-#if !defined(LZO_UNCONST_CAST)
+-#  if 0 && defined(__cplusplus)
+-#    define LZO_UNCONST_CAST(t,e)   (const_cast<t> (e))
+-#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#    define LZO_UNCONST_CAST(t,e)   ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e))))))
+-#  else
+-#    define LZO_UNCONST_CAST(t,e)   ((t) ((void *) ((char *) ((const void *) (e)))))
+-#  endif
+-#endif
+-#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
+-#  if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
+-#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-!(e)];
+-#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
+-#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1u-2*!(e)];
+-#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+-#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-!(e)];
+-#  else
+-#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-2*!(e)];
+-#  endif
+-#endif
+-#if !defined(LZO_COMPILE_TIME_ASSERT)
+-#  if (LZO_CC_AZTECC)
+-#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __lzo_cta_t[1-!(e)];}
+-#  elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+-#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+-#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+-#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+-#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+-#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+-#  else
+-#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __lzo_cta_t[1-2*!(e)];}
+-#  endif
+-#endif
+-#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)
+-#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
+-#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+-#    define __lzo_cdecl                 __cdecl
+-#    define __lzo_cdecl_atexit          /*empty*/
+-#    define __lzo_cdecl_main            __cdecl
+-#    if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+-#      define __lzo_cdecl_qsort         __pascal
+-#    elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+-#      define __lzo_cdecl_qsort         _stdcall
+-#    else
+-#      define __lzo_cdecl_qsort         __cdecl
+-#    endif
+-#  elif (LZO_CC_WATCOMC)
+-#    define __lzo_cdecl                 __cdecl
+-#  else
+-#    define __lzo_cdecl                 __cdecl
+-#    define __lzo_cdecl_atexit          __cdecl
+-#    define __lzo_cdecl_main            __cdecl
+-#    define __lzo_cdecl_qsort           __cdecl
+-#  endif
+-#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC)
+-#  elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+-#    define __lzo_cdecl_sighandler      __pascal
+-#  elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+-#    define __lzo_cdecl_sighandler      _stdcall
+-#  elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE)
+-#    define __lzo_cdecl_sighandler      __clrcall
+-#  elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700))
+-#    if defined(_DLL)
+-#      define __lzo_cdecl_sighandler    _far _cdecl _loadds
+-#    elif defined(_MT)
+-#      define __lzo_cdecl_sighandler    _far _cdecl
+-#    else
+-#      define __lzo_cdecl_sighandler    _cdecl
+-#    endif
+-#  else
+-#    define __lzo_cdecl_sighandler      __cdecl
+-#  endif
+-#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC)
+-#  define __lzo_cdecl                   __cdecl
+-#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC))
+-#  define __lzo_cdecl                   cdecl
+-#endif
+-#if !defined(__lzo_cdecl)
+-#  define __lzo_cdecl                   /*empty*/
+-#endif
+-#if !defined(__lzo_cdecl_atexit)
+-#  define __lzo_cdecl_atexit            /*empty*/
+-#endif
+-#if !defined(__lzo_cdecl_main)
+-#  define __lzo_cdecl_main              /*empty*/
+-#endif
+-#if !defined(__lzo_cdecl_qsort)
+-#  define __lzo_cdecl_qsort             /*empty*/
+-#endif
+-#if !defined(__lzo_cdecl_sighandler)
+-#  define __lzo_cdecl_sighandler        /*empty*/
+-#endif
+-#if !defined(__lzo_cdecl_va)
+-#  define __lzo_cdecl_va                __lzo_cdecl
+-#endif
+-#if !(LZO_CFG_NO_WINDOWS_H)
+-#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
+-#  if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
+-#  elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
+-#  elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))
+-#  else
+-#    define LZO_HAVE_WINDOWS_H 1
+-#  endif
++#if (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
++#  define LZO_ASM_SYNTAX_MSC 1
++#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
++#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))
++#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
++#  define LZO_ASM_SYNTAX_GNUC 1
++#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
++#  define LZO_ASM_SYNTAX_GNUC 1
++#elif (LZO_CC_GNUC)
++#  define LZO_ASM_SYNTAX_GNUC 1
++#endif
++#if (LZO_ASM_SYNTAX_GNUC)
++#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul))
++#  define __LZO_ASM_CLOBBER                     "ax"
++#  define __LZO_ASM_CLOBBER_LIST_CC             /*empty*/
++#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      /*empty*/
++#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/
++#elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1000))
++#  define __LZO_ASM_CLOBBER                     "memory"
++#  define __LZO_ASM_CLOBBER_LIST_CC             /*empty*/
++#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      : "memory"
++#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/
++#else
++#  define __LZO_ASM_CLOBBER                     "cc", "memory"
++#  define __LZO_ASM_CLOBBER_LIST_CC             : "cc"
++#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      : "cc", "memory"
++#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/
+ #endif
+ #endif
+ #if (LZO_ARCH_ALPHA)
+-#  define LZO_OPT_AVOID_UINT_INDEX  1
+-#  define LZO_OPT_AVOID_SHORT       1
+-#  define LZO_OPT_AVOID_USHORT      1
++#  define LZO_OPT_AVOID_UINT_INDEX          1
+ #elif (LZO_ARCH_AMD64)
+-#  define LZO_OPT_AVOID_INT_INDEX   1
+-#  define LZO_OPT_AVOID_UINT_INDEX  1
+-#  define LZO_OPT_UNALIGNED16       1
+-#  define LZO_OPT_UNALIGNED32       1
+-#  define LZO_OPT_UNALIGNED64       1
+-#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB)
++#  define LZO_OPT_AVOID_INT_INDEX           1
++#  define LZO_OPT_AVOID_UINT_INDEX          1
++#  ifndef LZO_OPT_UNALIGNED16
++#  define LZO_OPT_UNALIGNED16               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED32
++#  define LZO_OPT_UNALIGNED32               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED64
++#  define LZO_OPT_UNALIGNED64               1
++#  endif
+ #elif (LZO_ARCH_ARM)
+-#  define LZO_OPT_AVOID_SHORT       1
+-#  define LZO_OPT_AVOID_USHORT      1
++#  if defined(__ARM_FEATURE_UNALIGNED)
++#    ifndef LZO_OPT_UNALIGNED16
++#    define LZO_OPT_UNALIGNED16             1
++#    endif
++#    ifndef LZO_OPT_UNALIGNED32
++#    define LZO_OPT_UNALIGNED32             1
++#    endif
++#  elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 7)
++#    ifndef LZO_OPT_UNALIGNED16
++#    define LZO_OPT_UNALIGNED16             1
++#    endif
++#    ifndef LZO_OPT_UNALIGNED32
++#    define LZO_OPT_UNALIGNED32             1
++#    endif
++#  elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 6) && !defined(__TARGET_PROFILE_M)
++#    ifndef LZO_OPT_UNALIGNED16
++#    define LZO_OPT_UNALIGNED16             1
++#    endif
++#    ifndef LZO_OPT_UNALIGNED32
++#    define LZO_OPT_UNALIGNED32             1
++#    endif
++#  endif
++#elif (LZO_ARCH_ARM64)
++#  ifndef LZO_OPT_UNALIGNED16
++#  define LZO_OPT_UNALIGNED16               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED32
++#  define LZO_OPT_UNALIGNED32               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED64
++#  define LZO_OPT_UNALIGNED64               1
++#  endif
+ #elif (LZO_ARCH_CRIS)
+-#  define LZO_OPT_UNALIGNED16       1
+-#  define LZO_OPT_UNALIGNED32       1
++#  ifndef LZO_OPT_UNALIGNED16
++#  define LZO_OPT_UNALIGNED16               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED32
++#  define LZO_OPT_UNALIGNED32               1
++#  endif
+ #elif (LZO_ARCH_I386)
+-#  define LZO_OPT_UNALIGNED16       1
+-#  define LZO_OPT_UNALIGNED32       1
++#  ifndef LZO_OPT_UNALIGNED16
++#  define LZO_OPT_UNALIGNED16               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED32
++#  define LZO_OPT_UNALIGNED32               1
++#  endif
+ #elif (LZO_ARCH_IA64)
+-#  define LZO_OPT_AVOID_INT_INDEX   1
+-#  define LZO_OPT_AVOID_UINT_INDEX  1
+-#  define LZO_OPT_PREFER_POSTINC    1
++#  define LZO_OPT_AVOID_INT_INDEX           1
++#  define LZO_OPT_AVOID_UINT_INDEX          1
++#  define LZO_OPT_PREFER_POSTINC            1
+ #elif (LZO_ARCH_M68K)
+-#  define LZO_OPT_PREFER_POSTINC    1
+-#  define LZO_OPT_PREFER_PREDEC     1
++#  define LZO_OPT_PREFER_POSTINC            1
++#  define LZO_OPT_PREFER_PREDEC             1
+ #  if defined(__mc68020__) && !defined(__mcoldfire__)
+-#    define LZO_OPT_UNALIGNED16     1
+-#    define LZO_OPT_UNALIGNED32     1
++#    ifndef LZO_OPT_UNALIGNED16
++#    define LZO_OPT_UNALIGNED16             1
++#    endif
++#    ifndef LZO_OPT_UNALIGNED32
++#    define LZO_OPT_UNALIGNED32             1
++#    endif
+ #  endif
+ #elif (LZO_ARCH_MIPS)
+-#  define LZO_OPT_AVOID_UINT_INDEX  1
++#  define LZO_OPT_AVOID_UINT_INDEX          1
+ #elif (LZO_ARCH_POWERPC)
+-#  define LZO_OPT_PREFER_PREINC     1
+-#  define LZO_OPT_PREFER_PREDEC     1
++#  define LZO_OPT_PREFER_PREINC             1
++#  define LZO_OPT_PREFER_PREDEC             1
+ #  if (LZO_ABI_BIG_ENDIAN)
+-#    define LZO_OPT_UNALIGNED16     1
+-#    define LZO_OPT_UNALIGNED32     1
++#    ifndef LZO_OPT_UNALIGNED16
++#    define LZO_OPT_UNALIGNED16             1
++#    endif
++#    ifndef LZO_OPT_UNALIGNED32
++#    define LZO_OPT_UNALIGNED32             1
++#    endif
++#    if (LZO_WORDSIZE == 8)
++#      ifndef LZO_OPT_UNALIGNED64
++#      define LZO_OPT_UNALIGNED64           1
++#      endif
++#    endif
+ #  endif
+ #elif (LZO_ARCH_S390)
+-#  define LZO_OPT_UNALIGNED16       1
+-#  define LZO_OPT_UNALIGNED32       1
+-#  if (LZO_SIZEOF_SIZE_T == 8)
+-#    define LZO_OPT_UNALIGNED64     1
++#  ifndef LZO_OPT_UNALIGNED16
++#  define LZO_OPT_UNALIGNED16               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED32
++#  define LZO_OPT_UNALIGNED32               1
++#  endif
++#  if (LZO_WORDSIZE == 8)
++#    ifndef LZO_OPT_UNALIGNED64
++#    define LZO_OPT_UNALIGNED64             1
++#    endif
+ #  endif
+ #elif (LZO_ARCH_SH)
+-#  define LZO_OPT_PREFER_POSTINC    1
+-#  define LZO_OPT_PREFER_PREDEC     1
++#  define LZO_OPT_PREFER_POSTINC            1
++#  define LZO_OPT_PREFER_PREDEC             1
+ #endif
+ #ifndef LZO_CFG_NO_INLINE_ASM
+-#if (LZO_CC_LLVM)
++#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)
+ #  define LZO_CFG_NO_INLINE_ASM 1
++#elif (LZO_CC_LLVM)
++#  define LZO_CFG_NO_INLINE_ASM 1
++#endif
+ #endif
++#if (LZO_CFG_NO_INLINE_ASM)
++#  undef LZO_ASM_SYNTAX_MSC
++#  undef LZO_ASM_SYNTAX_GNUC
++#  undef __LZO_ASM_CLOBBER
++#  undef __LZO_ASM_CLOBBER_LIST_CC
++#  undef __LZO_ASM_CLOBBER_LIST_CC_MEMORY
++#  undef __LZO_ASM_CLOBBER_LIST_EMPTY
+ #endif
+ #ifndef LZO_CFG_NO_UNALIGNED
+ #if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)
+@@ -1804,25 +2594,6 @@ extern "C" {
+ #  undef LZO_OPT_UNALIGNED32
+ #  undef LZO_OPT_UNALIGNED64
+ #endif
+-#if (LZO_CFG_NO_INLINE_ASM)
+-#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+-#  define LZO_ASM_SYNTAX_MSC 1
+-#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+-#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))
+-#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+-#  define LZO_ASM_SYNTAX_GNUC 1
+-#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+-#  define LZO_ASM_SYNTAX_GNUC 1
+-#endif
+-#if (LZO_ASM_SYNTAX_GNUC)
+-#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul))
+-#  define __LZO_ASM_CLOBBER         "ax"
+-#elif (LZO_CC_INTELC)
+-#  define __LZO_ASM_CLOBBER         "memory"
+-#else
+-#  define __LZO_ASM_CLOBBER         "cc", "memory"
+-#endif
+-#endif
+ #if defined(__LZO_INFOSTR_MM)
+ #elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM))
+ #  define __LZO_INFOSTR_MM          ""
+@@ -1866,6 +2637,381 @@ extern "C" {
+ #define LZO_INFO_STRING \
+     LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \
+     " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER
++#if !(LZO_CFG_SKIP_LZO_TYPES)
++#if (!(LZO_SIZEOF_SHORT+0 > 0 && LZO_SIZEOF_INT+0 > 0 && LZO_SIZEOF_LONG+0 > 0))
++#  error "missing defines for sizes"
++#endif
++#if (!(LZO_SIZEOF_PTRDIFF_T+0 > 0 && LZO_SIZEOF_SIZE_T+0 > 0 && LZO_SIZEOF_VOID_P+0 > 0))
++#  error "missing defines for sizes"
++#endif
++#if !defined(lzo_llong_t)
++#if (LZO_SIZEOF_LONG_LONG+0 > 0)
++__lzo_gnuc_extension__ typedef long long lzo_llong_t__;
++__lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
++#  define lzo_llong_t               lzo_llong_t__
++#  define lzo_ullong_t              lzo_ullong_t__
++#endif
++#endif
++#if !defined(lzo_int16e_t)
++#if (LZO_SIZEOF_LONG == 2)
++#  define lzo_int16e_t              long
++#  define lzo_uint16e_t             unsigned long
++#elif (LZO_SIZEOF_INT == 2)
++#  define lzo_int16e_t              int
++#  define lzo_uint16e_t             unsigned int
++#elif (LZO_SIZEOF_SHORT == 2)
++#  define lzo_int16e_t              short int
++#  define lzo_uint16e_t             unsigned short int
++#elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM)
++   typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__)));
++   typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__)));
++#  define lzo_int16e_t              lzo_int16e_hi_t__
++#  define lzo_uint16e_t             lzo_uint16e_hi_t__
++#elif (LZO_SIZEOF___INT16 == 2)
++#  define lzo_int16e_t              __int16
++#  define lzo_uint16e_t             unsigned __int16
++#else
++#endif
++#endif
++#if defined(lzo_int16e_t)
++#  define LZO_SIZEOF_LZO_INT16E_T   2
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == 2)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == LZO_SIZEOF_LZO_INT16E_T)
++#endif
++#if !defined(lzo_int32e_t)
++#if (LZO_SIZEOF_LONG == 4)
++#  define lzo_int32e_t              long int
++#  define lzo_uint32e_t             unsigned long int
++#elif (LZO_SIZEOF_INT == 4)
++#  define lzo_int32e_t              int
++#  define lzo_uint32e_t             unsigned int
++#elif (LZO_SIZEOF_SHORT == 4)
++#  define lzo_int32e_t              short int
++#  define lzo_uint32e_t             unsigned short int
++#elif (LZO_SIZEOF_LONG_LONG == 4)
++#  define lzo_int32e_t              lzo_llong_t
++#  define lzo_uint32e_t             lzo_ullong_t
++#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L)
++   typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
++   typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
++#  define lzo_int32e_t              lzo_int32e_si_t__
++#  define lzo_uint32e_t             lzo_uint32e_si_t__
++#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L)
++   typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
++   typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
++#  define lzo_int32e_t              lzo_int32e_si_t__
++#  define lzo_uint32e_t             lzo_uint32e_si_t__
++#  define LZO_INT32_C(c)            (c##LL)
++#  define LZO_UINT32_C(c)           (c##ULL)
++#elif (LZO_SIZEOF___INT32 == 4)
++#  define lzo_int32e_t              __int32
++#  define lzo_uint32e_t             unsigned __int32
++#else
++#endif
++#endif
++#if defined(lzo_int32e_t)
++#  define LZO_SIZEOF_LZO_INT32E_T   4
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == 4)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == LZO_SIZEOF_LZO_INT32E_T)
++#endif
++#if !defined(lzo_int64e_t)
++#if (LZO_SIZEOF___INT64 == 8)
++#  if (LZO_CC_BORLANDC) && !(LZO_CFG_TYPE_PREFER___INT64)
++#    define LZO_CFG_TYPE_PREFER___INT64 1
++#  endif
++#endif
++#if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
++#  define lzo_int64e_t              int
++#  define lzo_uint64e_t             unsigned int
++#  define LZO_SIZEOF_LZO_INT64E_T   LZO_SIZEOF_INT
++#elif (LZO_SIZEOF_LONG == 8)
++#  define lzo_int64e_t              long int
++#  define lzo_uint64e_t             unsigned long int
++#  define LZO_SIZEOF_LZO_INT64E_T   LZO_SIZEOF_LONG
++#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_TYPE_PREFER___INT64)
++#  define lzo_int64e_t              lzo_llong_t
++#  define lzo_uint64e_t             lzo_ullong_t
++#  if (LZO_CC_BORLANDC)
++#    define LZO_INT64_C(c)          ((c) + 0ll)
++#    define LZO_UINT64_C(c)         ((c) + 0ull)
++#  elif 0
++#    define LZO_INT64_C(c)          (__lzo_gnuc_extension__ (c##LL))
++#    define LZO_UINT64_C(c)         (__lzo_gnuc_extension__ (c##ULL))
++#  else
++#    define LZO_INT64_C(c)          (c##LL)
++#    define LZO_UINT64_C(c)         (c##ULL)
++#  endif
++#  define LZO_SIZEOF_LZO_INT64E_T   LZO_SIZEOF_LONG_LONG
++#elif (LZO_SIZEOF___INT64 == 8)
++#  define lzo_int64e_t              __int64
++#  define lzo_uint64e_t             unsigned __int64
++#  if (LZO_CC_BORLANDC)
++#    define LZO_INT64_C(c)          ((c) + 0i64)
++#    define LZO_UINT64_C(c)         ((c) + 0ui64)
++#  else
++#    define LZO_INT64_C(c)          (c##i64)
++#    define LZO_UINT64_C(c)         (c##ui64)
++#  endif
++#  define LZO_SIZEOF_LZO_INT64E_T   LZO_SIZEOF___INT64
++#else
++#endif
++#endif
++#if defined(lzo_int64e_t)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == 8)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == LZO_SIZEOF_LZO_INT64E_T)
++#endif
++#if !defined(lzo_int32l_t)
++#if defined(lzo_int32e_t)
++#  define lzo_int32l_t              lzo_int32e_t
++#  define lzo_uint32l_t             lzo_uint32e_t
++#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_LZO_INT32E_T
++#elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
++#  define lzo_int32l_t              int
++#  define lzo_uint32l_t             unsigned int
++#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_INT
++#elif (LZO_SIZEOF_LONG >= 4)
++#  define lzo_int32l_t              long int
++#  define lzo_uint32l_t             unsigned long int
++#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_LONG
++#else
++#  error "lzo_int32l_t"
++#endif
++#endif
++#if 1
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) >= 4)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) == LZO_SIZEOF_LZO_INT32L_T)
++#endif
++#if !defined(lzo_int64l_t)
++#if defined(lzo_int64e_t)
++#  define lzo_int64l_t              lzo_int64e_t
++#  define lzo_uint64l_t             lzo_uint64e_t
++#  define LZO_SIZEOF_LZO_INT64L_T   LZO_SIZEOF_LZO_INT64E_T
++#else
++#endif
++#endif
++#if defined(lzo_int64l_t)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) >= 8)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) == LZO_SIZEOF_LZO_INT64L_T)
++#endif
++#if !defined(lzo_int32f_t)
++#if (LZO_SIZEOF_SIZE_T >= 8)
++#  define lzo_int32f_t              lzo_int64l_t
++#  define lzo_uint32f_t             lzo_uint64l_t
++#  define LZO_SIZEOF_LZO_INT32F_T   LZO_SIZEOF_LZO_INT64L_T
++#else
++#  define lzo_int32f_t              lzo_int32l_t
++#  define lzo_uint32f_t             lzo_uint32l_t
++#  define LZO_SIZEOF_LZO_INT32F_T   LZO_SIZEOF_LZO_INT32L_T
++#endif
++#endif
++#if 1
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) >= 4)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) == LZO_SIZEOF_LZO_INT32F_T)
++#endif
++#if !defined(lzo_int64f_t)
++#if defined(lzo_int64l_t)
++#  define lzo_int64f_t              lzo_int64l_t
++#  define lzo_uint64f_t             lzo_uint64l_t
++#  define LZO_SIZEOF_LZO_INT64F_T   LZO_SIZEOF_LZO_INT64L_T
++#else
++#endif
++#endif
++#if defined(lzo_int64f_t)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) >= 8)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) == LZO_SIZEOF_LZO_INT64F_T)
++#endif
++#if !defined(lzo_intptr_t)
++#if 1 && (LZO_OS_OS400 && (LZO_SIZEOF_VOID_P == 16))
++#  define __LZO_INTPTR_T_IS_POINTER 1
++   typedef char*                    lzo_intptr_t;
++   typedef char*                    lzo_uintptr_t;
++#  define lzo_intptr_t              lzo_intptr_t
++#  define lzo_uintptr_t             lzo_uintptr_t
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_VOID_P
++#elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4))
++   typedef __w64 int                lzo_intptr_t;
++   typedef __w64 unsigned int       lzo_uintptr_t;
++#  define lzo_intptr_t              lzo_intptr_t
++#  define lzo_uintptr_t             lzo_uintptr_t
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_INT
++#elif (LZO_SIZEOF_SHORT == LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT > LZO_SIZEOF_VOID_P)
++#  define lzo_intptr_t              short
++#  define lzo_uintptr_t             unsigned short
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_SHORT
++#elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
++#  define lzo_intptr_t              int
++#  define lzo_uintptr_t             unsigned int
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_INT
++#elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P)
++#  define lzo_intptr_t              long
++#  define lzo_uintptr_t             unsigned long
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_LONG
++#elif (LZO_SIZEOF_LZO_INT64L_T >= LZO_SIZEOF_VOID_P)
++#  define lzo_intptr_t              lzo_int64l_t
++#  define lzo_uintptr_t             lzo_uint64l_t
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_LZO_INT64L_T
++#else
++#  error "lzo_intptr_t"
++#endif
++#endif
++#if 1
++    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) >= sizeof(void *))
++    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) == sizeof(lzo_uintptr_t))
++#endif
++#if !defined(lzo_word_t)
++#if defined(LZO_WORDSIZE) && (LZO_WORDSIZE+0 > 0)
++#if (LZO_WORDSIZE == LZO_SIZEOF_LZO_INTPTR_T) && !(__LZO_INTPTR_T_IS_POINTER)
++#  define lzo_word_t                lzo_uintptr_t
++#  define lzo_sword_t               lzo_intptr_t
++#  define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T
++#elif (LZO_WORDSIZE == LZO_SIZEOF_LONG)
++#  define lzo_word_t                unsigned long
++#  define lzo_sword_t               long
++#  define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG
++#elif (LZO_WORDSIZE == LZO_SIZEOF_INT)
++#  define lzo_word_t                unsigned int
++#  define lzo_sword_t               int
++#  define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT
++#elif (LZO_WORDSIZE == LZO_SIZEOF_SHORT)
++#  define lzo_word_t                unsigned short
++#  define lzo_sword_t               short
++#  define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT
++#elif (LZO_WORDSIZE == 1)
++#  define lzo_word_t                unsigned char
++#  define lzo_sword_t               signed char
++#  define LZO_SIZEOF_LZO_WORD_T 1
++#elif (LZO_WORDSIZE == LZO_SIZEOF_LZO_INT64L_T)
++#  define lzo_word_t                lzo_uint64l_t
++#  define lzo_sword_t               lzo_int64l_t
++#  define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T
++#elif (LZO_ARCH_SPU) && (LZO_CC_GNUC)
++#if 0
++   typedef unsigned lzo_word_t  __attribute__((__mode__(__V16QI__)));
++   typedef int      lzo_sword_t __attribute__((__mode__(__V16QI__)));
++#  define lzo_word_t                lzo_word_t
++#  define lzo_sword_t               lzo_sword_t
++#  define LZO_SIZEOF_LZO_WORD_T     16
++#endif
++#else
++#  error "lzo_word_t"
++#endif
++#endif
++#endif
++#if 1 && defined(lzo_word_t)
++    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_word_t)  == LZO_WORDSIZE)
++    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_sword_t) == LZO_WORDSIZE)
++#endif
++#if 1
++#define lzo_int8_t                  signed char
++#define lzo_uint8_t                 unsigned char
++#define LZO_SIZEOF_LZO_INT8_T       1
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == 1)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t))
++#endif
++#if defined(lzo_int16e_t)
++#define lzo_int16_t                 lzo_int16e_t
++#define lzo_uint16_t                lzo_uint16e_t
++#define LZO_SIZEOF_LZO_INT16_T      LZO_SIZEOF_LZO_INT16E_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == 2)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t))
++#endif
++#if defined(lzo_int32e_t)
++#define lzo_int32_t                 lzo_int32e_t
++#define lzo_uint32_t                lzo_uint32e_t
++#define LZO_SIZEOF_LZO_INT32_T      LZO_SIZEOF_LZO_INT32E_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == 4)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t))
++#endif
++#if defined(lzo_int64e_t)
++#define lzo_int64_t                 lzo_int64e_t
++#define lzo_uint64_t                lzo_uint64e_t
++#define LZO_SIZEOF_LZO_INT64_T      LZO_SIZEOF_LZO_INT64E_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == 8)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t))
++#endif
++#if 1
++#define lzo_int_least32_t           lzo_int32l_t
++#define lzo_uint_least32_t          lzo_uint32l_t
++#define LZO_SIZEOF_LZO_INT_LEAST32_T LZO_SIZEOF_LZO_INT32L_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) >= 4)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_least32_t))
++#endif
++#if defined(lzo_int64l_t)
++#define lzo_int_least64_t           lzo_int64l_t
++#define lzo_uint_least64_t          lzo_uint64l_t
++#define LZO_SIZEOF_LZO_INT_LEAST64_T LZO_SIZEOF_LZO_INT64L_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) >= 8)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_least64_t))
++#endif
++#if 1
++#define lzo_int_fast32_t           lzo_int32f_t
++#define lzo_uint_fast32_t          lzo_uint32f_t
++#define LZO_SIZEOF_LZO_INT_FAST32_T LZO_SIZEOF_LZO_INT32F_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) >= 4)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast32_t))
++#endif
++#if defined(lzo_int64f_t)
++#define lzo_int_fast64_t           lzo_int64f_t
++#define lzo_uint_fast64_t          lzo_uint64f_t
++#define LZO_SIZEOF_LZO_INT_FAST64_T LZO_SIZEOF_LZO_INT64F_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) >= 8)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast64_t))
++#endif
++#if !defined(LZO_INT16_C)
++#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 2)
++#    define LZO_INT16_C(c)          ((c) + 0)
++#    define LZO_UINT16_C(c)         ((c) + 0U)
++#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 2)
++#    define LZO_INT16_C(c)          ((c) + 0L)
++#    define LZO_UINT16_C(c)         ((c) + 0UL)
++#  elif (LZO_SIZEOF_INT >= 2)
++#    define LZO_INT16_C(c)          (c)
++#    define LZO_UINT16_C(c)         (c##U)
++#  elif (LZO_SIZEOF_LONG >= 2)
++#    define LZO_INT16_C(c)          (c##L)
++#    define LZO_UINT16_C(c)         (c##UL)
++#  else
++#    error "LZO_INT16_C"
++#  endif
++#endif
++#if !defined(LZO_INT32_C)
++#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 4)
++#    define LZO_INT32_C(c)          ((c) + 0)
++#    define LZO_UINT32_C(c)         ((c) + 0U)
++#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 4)
++#    define LZO_INT32_C(c)          ((c) + 0L)
++#    define LZO_UINT32_C(c)         ((c) + 0UL)
++#  elif (LZO_SIZEOF_INT >= 4)
++#    define LZO_INT32_C(c)          (c)
++#    define LZO_UINT32_C(c)         (c##U)
++#  elif (LZO_SIZEOF_LONG >= 4)
++#    define LZO_INT32_C(c)          (c##L)
++#    define LZO_UINT32_C(c)         (c##UL)
++#  elif (LZO_SIZEOF_LONG_LONG >= 4)
++#    define LZO_INT32_C(c)          (c##LL)
++#    define LZO_UINT32_C(c)         (c##ULL)
++#  else
++#    error "LZO_INT32_C"
++#  endif
++#endif
++#if !defined(LZO_INT64_C) && defined(lzo_int64l_t)
++#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 8)
++#    define LZO_INT64_C(c)          ((c) + 0)
++#    define LZO_UINT64_C(c)         ((c) + 0U)
++#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 8)
++#    define LZO_INT64_C(c)          ((c) + 0L)
++#    define LZO_UINT64_C(c)         ((c) + 0UL)
++#  elif (LZO_SIZEOF_INT >= 8)
++#    define LZO_INT64_C(c)          (c)
++#    define LZO_UINT64_C(c)         (c##U)
++#  elif (LZO_SIZEOF_LONG >= 8)
++#    define LZO_INT64_C(c)          (c##L)
++#    define LZO_UINT64_C(c)         (c##UL)
++#  else
++#    error "LZO_INT64_C"
++#  endif
++#endif
++#endif
+ 
+ #endif
+ 
+@@ -1874,7 +3020,7 @@ extern "C" {
+ #undef LZO_HAVE_CONFIG_H
+ #include "minilzo.h"
+ 
+-#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2050)
++#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2080)
+ #  error "version mismatch in miniLZO source files"
+ #endif
+ 
+@@ -1886,23 +3032,9 @@ extern "C" {
+ #define __LZO_CONF_H 1
+ 
+ #if !defined(__LZO_IN_MINILZO)
+-#if (LZO_CFG_FREESTANDING)
++#if defined(LZO_CFG_FREESTANDING) && (LZO_CFG_FREESTANDING)
+ #  define LZO_LIBC_FREESTANDING 1
+ #  define LZO_OS_FREESTANDING 1
+-#  define ACC_LIBC_FREESTANDING 1
+-#  define ACC_OS_FREESTANDING 1
+-#endif
+-#if (LZO_CFG_NO_UNALIGNED)
+-#  define ACC_CFG_NO_UNALIGNED 1
+-#endif
+-#if (LZO_ARCH_GENERIC)
+-#  define ACC_ARCH_GENERIC 1
+-#endif
+-#if (LZO_ABI_NEUTRAL_ENDIAN)
+-#  define ACC_ABI_NEUTRAL_ENDIAN 1
+-#endif
+-#if (LZO_HAVE_CONFIG_H)
+-#  define ACC_CONFIG_NO_HEADER 1
+ #endif
+ #if defined(LZO_CFG_EXTRA_CONFIG_HEADER)
+ #  include LZO_CFG_EXTRA_CONFIG_HEADER
+@@ -1911,22 +3043,27 @@ extern "C" {
+ #  error "include this file first"
+ #endif
+ #include "lzo/lzoconf.h"
++#if defined(LZO_CFG_EXTRA_CONFIG_HEADER2)
++#  include LZO_CFG_EXTRA_CONFIG_HEADER2
++#endif
+ #endif
+ 
+-#if (LZO_VERSION < 0x02000) || !defined(__LZOCONF_H_INCLUDED)
++#if (LZO_VERSION < 0x2080) || !defined(__LZOCONF_H_INCLUDED)
+ #  error "version mismatch"
+ #endif
+ 
+-#if (LZO_CC_BORLANDC && LZO_ARCH_I086)
+-#  pragma option -h
++#if (LZO_CC_MSC && (_MSC_VER >= 1000 && _MSC_VER < 1100))
++#  pragma warning(disable: 4702)
+ #endif
+-
+ #if (LZO_CC_MSC && (_MSC_VER >= 1000))
+ #  pragma warning(disable: 4127 4701)
++#  pragma warning(disable: 4514 4710 4711)
+ #endif
+ #if (LZO_CC_MSC && (_MSC_VER >= 1300))
+ #  pragma warning(disable: 4820)
+-#  pragma warning(disable: 4514 4710 4711)
++#endif
++#if (LZO_CC_MSC && (_MSC_VER >= 1800))
++#  pragma warning(disable: 4746)
+ #endif
+ 
+ #if (LZO_CC_SUNPROC)
+@@ -1937,49 +3074,16 @@ extern "C" {
+ #endif
+ #endif
+ 
+-#if (__LZO_MMODEL_HUGE) && !(LZO_HAVE_MM_HUGE_PTR)
+-#  error "this should not happen - check defines for __huge"
+-#endif
+-
+-#if defined(__LZO_IN_MINILZO) || defined(LZO_CFG_FREESTANDING)
+-#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+-#  define ACC_WANT_ACC_INCD_H 1
+-#  define ACC_WANT_ACC_INCE_H 1
+-#  define ACC_WANT_ACC_INCI_H 1
++#if defined(__LZO_IN_MINILZO) || (LZO_CFG_FREESTANDING)
+ #elif 1
+ #  include <string.h>
+ #else
+-#  define ACC_WANT_ACC_INCD_H 1
++#  define LZO_WANT_ACC_INCD_H 1
+ #endif
+-
+-#if (LZO_ARCH_I086)
+-#  define ACC_MM_AHSHIFT        LZO_MM_AHSHIFT
+-#  define ACC_PTR_FP_OFF(x)     (((const unsigned __far*)&(x))[0])
+-#  define ACC_PTR_FP_SEG(x)     (((const unsigned __far*)&(x))[1])
+-#  define ACC_PTR_MK_FP(s,o)    ((void __far*)(((unsigned long)(s)<<16)+(unsigned)(o)))
++#if defined(LZO_HAVE_CONFIG_H)
++#  define LZO_CFG_NO_CONFIG_HEADER 1
+ #endif
+ 
+-#if !defined(lzo_uintptr_t)
+-#  if defined(__LZO_MMODEL_HUGE)
+-#    define lzo_uintptr_t       unsigned long
+-#  elif 1 && defined(LZO_OS_OS400) && (LZO_SIZEOF_VOID_P == 16)
+-#    define __LZO_UINTPTR_T_IS_POINTER 1
+-     typedef char*              lzo_uintptr_t;
+-#    define lzo_uintptr_t       lzo_uintptr_t
+-#  elif (LZO_SIZEOF_SIZE_T == LZO_SIZEOF_VOID_P)
+-#    define lzo_uintptr_t       size_t
+-#  elif (LZO_SIZEOF_LONG == LZO_SIZEOF_VOID_P)
+-#    define lzo_uintptr_t       unsigned long
+-#  elif (LZO_SIZEOF_INT == LZO_SIZEOF_VOID_P)
+-#    define lzo_uintptr_t       unsigned int
+-#  elif (LZO_SIZEOF_LONG_LONG == LZO_SIZEOF_VOID_P)
+-#    define lzo_uintptr_t       unsigned long long
+-#  else
+-#    define lzo_uintptr_t       size_t
+-#  endif
+-#endif
+-LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
+-
+ #if 1 && !defined(LZO_CFG_FREESTANDING)
+ #if 1 && !defined(HAVE_STRING_H)
+ #define HAVE_STRING_H 1
+@@ -2002,6 +3106,23 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
+ #include <string.h>
+ #endif
+ 
++#if 1 || defined(lzo_int8_t) || defined(lzo_uint8_t)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t)  == 1)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint8_t) == 1)
++#endif
++#if 1 || defined(lzo_int16_t) || defined(lzo_uint16_t)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t)  == 2)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint16_t) == 2)
++#endif
++#if 1 || defined(lzo_int32_t) || defined(lzo_uint32_t)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t)  == 4)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32_t) == 4)
++#endif
++#if defined(lzo_int64_t) || defined(lzo_uint64_t)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t)  == 8)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint64_t) == 8)
++#endif
++
+ #if (LZO_CFG_FREESTANDING)
+ #  undef HAVE_MEMCMP
+ #  undef HAVE_MEMCPY
+@@ -2012,28 +3133,28 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
+ #if !(HAVE_MEMCMP)
+ #  undef memcmp
+ #  define memcmp(a,b,c)         lzo_memcmp(a,b,c)
+-#elif !(__LZO_MMODEL_HUGE)
++#else
+ #  undef lzo_memcmp
+ #  define lzo_memcmp(a,b,c)     memcmp(a,b,c)
+ #endif
+ #if !(HAVE_MEMCPY)
+ #  undef memcpy
+ #  define memcpy(a,b,c)         lzo_memcpy(a,b,c)
+-#elif !(__LZO_MMODEL_HUGE)
++#else
+ #  undef lzo_memcpy
+ #  define lzo_memcpy(a,b,c)     memcpy(a,b,c)
+ #endif
+ #if !(HAVE_MEMMOVE)
+ #  undef memmove
+ #  define memmove(a,b,c)        lzo_memmove(a,b,c)
+-#elif !(__LZO_MMODEL_HUGE)
++#else
+ #  undef lzo_memmove
+ #  define lzo_memmove(a,b,c)    memmove(a,b,c)
+ #endif
+ #if !(HAVE_MEMSET)
+ #  undef memset
+ #  define memset(a,b,c)         lzo_memset(a,b,c)
+-#elif !(__LZO_MMODEL_HUGE)
++#else
+ #  undef lzo_memset
+ #  define lzo_memset(a,b,c)     memset(a,b,c)
+ #endif
+@@ -2058,27 +3179,29 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
+ #  define BOUNDS_CHECKING_OFF_IN_EXPR(expr)     (expr)
+ #endif
+ 
+-#if !defined(__lzo_inline)
+-#  define __lzo_inline              /*empty*/
+-#endif
+-#if !defined(__lzo_forceinline)
+-#  define __lzo_forceinline         /*empty*/
+-#endif
+-#if !defined(__lzo_noinline)
+-#  define __lzo_noinline            /*empty*/
+-#endif
+-
+ #if (LZO_CFG_PGO)
+-#  undef __acc_likely
+-#  undef __acc_unlikely
+ #  undef __lzo_likely
+ #  undef __lzo_unlikely
+-#  define __acc_likely(e)       (e)
+-#  define __acc_unlikely(e)     (e)
+ #  define __lzo_likely(e)       (e)
+ #  define __lzo_unlikely(e)     (e)
+ #endif
+ 
++#undef _
++#undef __
++#undef ___
++#undef ____
++#undef _p0
++#undef _p1
++#undef _p2
++#undef _p3
++#undef _p4
++#undef _s0
++#undef _s1
++#undef _s2
++#undef _s3
++#undef _s4
++#undef _ww
++
+ #if 1
+ #  define LZO_BYTE(x)       ((unsigned char) (x))
+ #else
+@@ -2097,84 +3220,548 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
+ #define LZO_SIZE(bits)      (1u << (bits))
+ #define LZO_MASK(bits)      (LZO_SIZE(bits) - 1)
+ 
+-#define LZO_LSIZE(bits)     (1ul << (bits))
+-#define LZO_LMASK(bits)     (LZO_LSIZE(bits) - 1)
+-
+ #define LZO_USIZE(bits)     ((lzo_uint) 1 << (bits))
+ #define LZO_UMASK(bits)     (LZO_USIZE(bits) - 1)
+ 
+ #if !defined(DMUL)
+ #if 0
+ 
+-#  define DMUL(a,b) ((lzo_xint) ((lzo_uint32)(a) * (lzo_uint32)(b)))
++#  define DMUL(a,b) ((lzo_xint) ((lzo_uint32_t)(a) * (lzo_uint32_t)(b)))
+ #else
+ #  define DMUL(a,b) ((lzo_xint) ((a) * (b)))
+ #endif
+ #endif
+ 
+-#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386 || LZO_ARCH_POWERPC)
+-#  if (LZO_SIZEOF_SHORT == 2)
+-#    define LZO_UNALIGNED_OK_2 1
+-#  endif
+-#  if (LZO_SIZEOF_INT == 4)
+-#    define LZO_UNALIGNED_OK_4 1
+-#  endif
+-#endif
+-#if 1 && (LZO_ARCH_AMD64)
+-#  if defined(LZO_UINT64_MAX)
+-#    define LZO_UNALIGNED_OK_8 1
+-#  endif
+-#endif
+-#if (LZO_CFG_NO_UNALIGNED)
+-#  undef LZO_UNALIGNED_OK_2
+-#  undef LZO_UNALIGNED_OK_4
+-#  undef LZO_UNALIGNED_OK_8
+-#endif
+-
+-#undef UA_GET16
+-#undef UA_SET16
+-#undef UA_COPY16
+-#undef UA_GET32
+-#undef UA_SET32
+-#undef UA_COPY32
+-#undef UA_GET64
+-#undef UA_SET64
+-#undef UA_COPY64
+-#if defined(LZO_UNALIGNED_OK_2)
+-   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(unsigned short) == 2)
+-#  if 1 && defined(ACC_UA_COPY16)
+-#    define UA_GET16        ACC_UA_GET16
+-#    define UA_SET16        ACC_UA_SET16
+-#    define UA_COPY16       ACC_UA_COPY16
+-#  else
+-#    define UA_GET16(p)     (* (__lzo_ua_volatile const lzo_ushortp) (__lzo_ua_volatile const lzo_voidp) (p))
+-#    define UA_SET16(p,v)   ((* (__lzo_ua_volatile lzo_ushortp) (__lzo_ua_volatile lzo_voidp) (p)) = (unsigned short) (v))
+-#    define UA_COPY16(d,s)  UA_SET16(d, UA_GET16(s))
+-#  endif
+-#endif
+-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+-   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4)
+-#  if 1 && defined(ACC_UA_COPY32)
+-#    define UA_GET32        ACC_UA_GET32
+-#    define UA_SET32        ACC_UA_SET32
+-#    define UA_COPY32       ACC_UA_COPY32
+-#  else
+-#    define UA_GET32(p)     (* (__lzo_ua_volatile const lzo_uint32p) (__lzo_ua_volatile const lzo_voidp) (p))
+-#    define UA_SET32(p,v)   ((* (__lzo_ua_volatile lzo_uint32p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint32) (v))
+-#    define UA_COPY32(d,s)  UA_SET32(d, UA_GET32(s))
+-#  endif
+-#endif
+-#if defined(LZO_UNALIGNED_OK_8)
+-   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint64) == 8)
+-#  if 1 && defined(ACC_UA_COPY64)
+-#    define UA_GET64        ACC_UA_GET64
+-#    define UA_SET64        ACC_UA_SET64
+-#    define UA_COPY64       ACC_UA_COPY64
+-#  else
+-#    define UA_GET64(p)     (* (__lzo_ua_volatile const lzo_uint64p) (__lzo_ua_volatile const lzo_voidp) (p))
+-#    define UA_SET64(p,v)   ((* (__lzo_ua_volatile lzo_uint64p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint64) (v))
+-#    define UA_COPY64(d,s)  UA_SET64(d, UA_GET64(s))
+-#  endif
++#ifndef __LZO_FUNC_H
++#define __LZO_FUNC_H 1
++
++#if !defined(LZO_BITOPS_USE_ASM_BITSCAN) && !defined(LZO_BITOPS_USE_GNUC_BITSCAN) && !defined(LZO_BITOPS_USE_MSC_BITSCAN)
++#if 1 && (LZO_ARCH_AMD64) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_ASM_SYNTAX_GNUC)
++#define LZO_BITOPS_USE_ASM_BITSCAN 1
++#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_LLVM && (!defined(__llvm_tools_version__) || (__llvm_tools_version__+0 >= 0x010500ul))))
++#define LZO_BITOPS_USE_GNUC_BITSCAN 1
++#elif (LZO_OS_WIN32 || LZO_OS_WIN64) && ((LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 1010)) || (LZO_CC_MSC && (_MSC_VER >= 1400)))
++#define LZO_BITOPS_USE_MSC_BITSCAN 1
++#if (LZO_CC_MSC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)
++#include <intrin.h>
++#endif
++#if (LZO_CC_MSC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)
++#pragma intrinsic(_BitScanReverse)
++#pragma intrinsic(_BitScanForward)
++#endif
++#if (LZO_CC_MSC) && (LZO_ARCH_AMD64)
++#pragma intrinsic(_BitScanReverse64)
++#pragma intrinsic(_BitScanForward64)
++#endif
++#endif
++#endif
++
++__lzo_static_forceinline unsigned lzo_bitops_ctlz32_func(lzo_uint32_t v)
++{
++#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)
++    unsigned long r; (void) _BitScanReverse(&r, v); return (unsigned) r ^ 31;
++#define lzo_bitops_ctlz32(v)    lzo_bitops_ctlz32_func(v)
++#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) && (LZO_ASM_SYNTAX_GNUC)
++    lzo_uint32_t r;
++    __asm__("bsr %1,%0" : "=r" (r) : "rm" (v) __LZO_ASM_CLOBBER_LIST_CC);
++    return (unsigned) r ^ 31;
++#define lzo_bitops_ctlz32(v)    lzo_bitops_ctlz32_func(v)
++#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_INT == 4)
++    unsigned r; r = (unsigned) __builtin_clz(v); return r;
++#define lzo_bitops_ctlz32(v)    ((unsigned) __builtin_clz(v))
++#else
++    LZO_UNUSED(v); return 0;
++#endif
++}
++
++#if defined(lzo_uint64_t)
++__lzo_static_forceinline unsigned lzo_bitops_ctlz64_func(lzo_uint64_t v)
++{
++#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64)
++    unsigned long r; (void) _BitScanReverse64(&r, v); return (unsigned) r ^ 63;
++#define lzo_bitops_ctlz64(v)    lzo_bitops_ctlz64_func(v)
++#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64) && (LZO_ASM_SYNTAX_GNUC)
++    lzo_uint64_t r;
++    __asm__("bsr %1,%0" : "=r" (r) : "rm" (v) __LZO_ASM_CLOBBER_LIST_CC);
++    return (unsigned) r ^ 63;
++#define lzo_bitops_ctlz64(v)    lzo_bitops_ctlz64_func(v)
++#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG == 8) && (LZO_WORDSIZE >= 8)
++    unsigned r; r = (unsigned) __builtin_clzl(v); return r;
++#define lzo_bitops_ctlz64(v)    ((unsigned) __builtin_clzl(v))
++#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG_LONG == 8) && (LZO_WORDSIZE >= 8)
++    unsigned r; r = (unsigned) __builtin_clzll(v); return r;
++#define lzo_bitops_ctlz64(v)    ((unsigned) __builtin_clzll(v))
++#else
++    LZO_UNUSED(v); return 0;
++#endif
++}
++#endif
++
++__lzo_static_forceinline unsigned lzo_bitops_cttz32_func(lzo_uint32_t v)
++{
++#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)
++    unsigned long r; (void) _BitScanForward(&r, v); return (unsigned) r;
++#define lzo_bitops_cttz32(v)    lzo_bitops_cttz32_func(v)
++#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64 || LZO_ARCH_I386) && (LZO_ASM_SYNTAX_GNUC)
++    lzo_uint32_t r;
++    __asm__("bsf %1,%0" : "=r" (r) : "rm" (v) __LZO_ASM_CLOBBER_LIST_CC);
++    return (unsigned) r;
++#define lzo_bitops_cttz32(v)    lzo_bitops_cttz32_func(v)
++#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_INT >= 4)
++    unsigned r; r = (unsigned) __builtin_ctz(v); return r;
++#define lzo_bitops_cttz32(v)    ((unsigned) __builtin_ctz(v))
++#else
++    LZO_UNUSED(v); return 0;
++#endif
++}
++
++#if defined(lzo_uint64_t)
++__lzo_static_forceinline unsigned lzo_bitops_cttz64_func(lzo_uint64_t v)
++{
++#if (LZO_BITOPS_USE_MSC_BITSCAN) && (LZO_ARCH_AMD64)
++    unsigned long r; (void) _BitScanForward64(&r, v); return (unsigned) r;
++#define lzo_bitops_cttz64(v)    lzo_bitops_cttz64_func(v)
++#elif (LZO_BITOPS_USE_ASM_BITSCAN) && (LZO_ARCH_AMD64) && (LZO_ASM_SYNTAX_GNUC)
++    lzo_uint64_t r;
++    __asm__("bsf %1,%0" : "=r" (r) : "rm" (v) __LZO_ASM_CLOBBER_LIST_CC);
++    return (unsigned) r;
++#define lzo_bitops_cttz64(v)    lzo_bitops_cttz64_func(v)
++#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG >= 8) && (LZO_WORDSIZE >= 8)
++    unsigned r; r = (unsigned) __builtin_ctzl(v); return r;
++#define lzo_bitops_cttz64(v)    ((unsigned) __builtin_ctzl(v))
++#elif (LZO_BITOPS_USE_GNUC_BITSCAN) && (LZO_SIZEOF_LONG_LONG >= 8) && (LZO_WORDSIZE >= 8)
++    unsigned r; r = (unsigned) __builtin_ctzll(v); return r;
++#define lzo_bitops_cttz64(v)    ((unsigned) __builtin_ctzll(v))
++#else
++    LZO_UNUSED(v); return 0;
++#endif
++}
++#endif
++
++#if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
++static void __attribute__((__unused__))
++#else
++__lzo_static_forceinline void
++#endif
++lzo_bitops_unused_funcs(void)
++{
++    LZO_UNUSED_FUNC(lzo_bitops_ctlz32_func);
++    LZO_UNUSED_FUNC(lzo_bitops_cttz32_func);
++#if defined(lzo_uint64_t)
++    LZO_UNUSED_FUNC(lzo_bitops_ctlz64_func);
++    LZO_UNUSED_FUNC(lzo_bitops_cttz64_func);
++#endif
++    LZO_UNUSED_FUNC(lzo_bitops_unused_funcs);
++}
++
++#if defined(__lzo_alignof) && !(LZO_CFG_NO_UNALIGNED)
++#ifndef __lzo_memops_tcheck
++#define __lzo_memops_tcheck(t,a,b) ((void)0, sizeof(t) == (a) && __lzo_alignof(t) == (b))
++#endif
++#endif
++#ifndef lzo_memops_TU0p
++#define lzo_memops_TU0p void __LZO_MMODEL *
++#endif
++#ifndef lzo_memops_TU1p
++#define lzo_memops_TU1p unsigned char __LZO_MMODEL *
++#endif
++#ifndef lzo_memops_TU2p
++#if (LZO_OPT_UNALIGNED16)
++typedef lzo_uint16_t __lzo_may_alias lzo_memops_TU2;
++#define lzo_memops_TU2p volatile lzo_memops_TU2 *
++#elif defined(__lzo_byte_struct)
++__lzo_byte_struct(lzo_memops_TU2_struct,2)
++typedef struct lzo_memops_TU2_struct lzo_memops_TU2;
++#else
++struct lzo_memops_TU2_struct { unsigned char a[2]; } __lzo_may_alias;
++typedef struct lzo_memops_TU2_struct lzo_memops_TU2;
++#endif
++#ifndef lzo_memops_TU2p
++#define lzo_memops_TU2p lzo_memops_TU2 *
++#endif
++#endif
++#ifndef lzo_memops_TU4p
++#if (LZO_OPT_UNALIGNED32)
++typedef lzo_uint32_t __lzo_may_alias lzo_memops_TU4;
++#define lzo_memops_TU4p volatile lzo_memops_TU4 __LZO_MMODEL *
++#elif defined(__lzo_byte_struct)
++__lzo_byte_struct(lzo_memops_TU4_struct,4)
++typedef struct lzo_memops_TU4_struct lzo_memops_TU4;
++#else
++struct lzo_memops_TU4_struct { unsigned char a[4]; } __lzo_may_alias;
++typedef struct lzo_memops_TU4_struct lzo_memops_TU4;
++#endif
++#ifndef lzo_memops_TU4p
++#define lzo_memops_TU4p lzo_memops_TU4 __LZO_MMODEL *
++#endif
++#endif
++#ifndef lzo_memops_TU8p
++#if (LZO_OPT_UNALIGNED64)
++typedef lzo_uint64_t __lzo_may_alias lzo_memops_TU8;
++#define lzo_memops_TU8p volatile lzo_memops_TU8 __LZO_MMODEL *
++#elif defined(__lzo_byte_struct)
++__lzo_byte_struct(lzo_memops_TU8_struct,8)
++typedef struct lzo_memops_TU8_struct lzo_memops_TU8;
++#else
++struct lzo_memops_TU8_struct { unsigned char a[8]; } __lzo_may_alias;
++typedef struct lzo_memops_TU8_struct lzo_memops_TU8;
++#endif
++#ifndef lzo_memops_TU8p
++#define lzo_memops_TU8p lzo_memops_TU8 __LZO_MMODEL *
++#endif
++#endif
++#ifndef lzo_memops_set_TU1p
++#define lzo_memops_set_TU1p     volatile lzo_memops_TU1p
++#endif
++#ifndef lzo_memops_move_TU1p
++#define lzo_memops_move_TU1p    lzo_memops_TU1p
++#endif
++#define LZO_MEMOPS_SET1(dd,cc) \
++    LZO_BLOCK_BEGIN \
++    lzo_memops_set_TU1p d__1 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \
++    d__1[0] = LZO_BYTE(cc); \
++    LZO_BLOCK_END
++#define LZO_MEMOPS_SET2(dd,cc) \
++    LZO_BLOCK_BEGIN \
++    lzo_memops_set_TU1p d__2 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \
++    d__2[0] = LZO_BYTE(cc); d__2[1] = LZO_BYTE(cc); \
++    LZO_BLOCK_END
++#define LZO_MEMOPS_SET3(dd,cc) \
++    LZO_BLOCK_BEGIN \
++    lzo_memops_set_TU1p d__3 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \
++    d__3[0] = LZO_BYTE(cc); d__3[1] = LZO_BYTE(cc); d__3[2] = LZO_BYTE(cc); \
++    LZO_BLOCK_END
++#define LZO_MEMOPS_SET4(dd,cc) \
++    LZO_BLOCK_BEGIN \
++    lzo_memops_set_TU1p d__4 = (lzo_memops_set_TU1p) (lzo_memops_TU0p) (dd); \
++    d__4[0] = LZO_BYTE(cc); d__4[1] = LZO_BYTE(cc); d__4[2] = LZO_BYTE(cc); d__4[3] = LZO_BYTE(cc); \
++    LZO_BLOCK_END
++#define LZO_MEMOPS_MOVE1(dd,ss) \
++    LZO_BLOCK_BEGIN \
++    lzo_memops_move_TU1p d__1 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \
++    const lzo_memops_move_TU1p s__1 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \
++    d__1[0] = s__1[0]; \
++    LZO_BLOCK_END
++#define LZO_MEMOPS_MOVE2(dd,ss) \
++    LZO_BLOCK_BEGIN \
++    lzo_memops_move_TU1p d__2 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \
++    const lzo_memops_move_TU1p s__2 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \
++    d__2[0] = s__2[0]; d__2[1] = s__2[1]; \
++    LZO_BLOCK_END
++#define LZO_MEMOPS_MOVE3(dd,ss) \
++    LZO_BLOCK_BEGIN \
++    lzo_memops_move_TU1p d__3 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \
++    const lzo_memops_move_TU1p s__3 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \
++    d__3[0] = s__3[0]; d__3[1] = s__3[1]; d__3[2] = s__3[2]; \
++    LZO_BLOCK_END
++#define LZO_MEMOPS_MOVE4(dd,ss) \
++    LZO_BLOCK_BEGIN \
++    lzo_memops_move_TU1p d__4 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \
++    const lzo_memops_move_TU1p s__4 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \
++    d__4[0] = s__4[0]; d__4[1] = s__4[1]; d__4[2] = s__4[2]; d__4[3] = s__4[3]; \
++    LZO_BLOCK_END
++#define LZO_MEMOPS_MOVE8(dd,ss) \
++    LZO_BLOCK_BEGIN \
++    lzo_memops_move_TU1p d__8 = (lzo_memops_move_TU1p) (lzo_memops_TU0p) (dd); \
++    const lzo_memops_move_TU1p s__8 = (const lzo_memops_move_TU1p) (const lzo_memops_TU0p) (ss); \
++    d__8[0] = s__8[0]; d__8[1] = s__8[1]; d__8[2] = s__8[2]; d__8[3] = s__8[3]; \
++    d__8[4] = s__8[4]; d__8[5] = s__8[5]; d__8[6] = s__8[6]; d__8[7] = s__8[7]; \
++    LZO_BLOCK_END
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU1p)0)==1)
++#define LZO_MEMOPS_COPY1(dd,ss) LZO_MEMOPS_MOVE1(dd,ss)
++#if (LZO_OPT_UNALIGNED16)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU2p)0)==2)
++#define LZO_MEMOPS_COPY2(dd,ss) \
++    * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss)
++#elif defined(__lzo_memops_tcheck)
++#define LZO_MEMOPS_COPY2(dd,ss) \
++    LZO_BLOCK_BEGIN if (__lzo_memops_tcheck(lzo_memops_TU2,2,1)) { \
++        * (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss); \
++    } else { LZO_MEMOPS_MOVE2(dd,ss); } LZO_BLOCK_END
++#else
++#define LZO_MEMOPS_COPY2(dd,ss) LZO_MEMOPS_MOVE2(dd,ss)
++#endif
++#if (LZO_OPT_UNALIGNED32)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU4p)0)==4)
++#define LZO_MEMOPS_COPY4(dd,ss) \
++    * (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss)
++#elif defined(__lzo_memops_tcheck)
++#define LZO_MEMOPS_COPY4(dd,ss) \
++    LZO_BLOCK_BEGIN if (__lzo_memops_tcheck(lzo_memops_TU4,4,1)) { \
++        * (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss); \
++    } else { LZO_MEMOPS_MOVE4(dd,ss); } LZO_BLOCK_END
++#else
++#define LZO_MEMOPS_COPY4(dd,ss) LZO_MEMOPS_MOVE4(dd,ss)
++#endif
++#if (LZO_WORDSIZE != 8)
++#define LZO_MEMOPS_COPY8(dd,ss) \
++    LZO_BLOCK_BEGIN LZO_MEMOPS_COPY4(dd,ss); LZO_MEMOPS_COPY4((lzo_memops_TU1p)(lzo_memops_TU0p)(dd)+4,(const lzo_memops_TU1p)(const lzo_memops_TU0p)(ss)+4); LZO_BLOCK_END
++#else
++#if (LZO_OPT_UNALIGNED64)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(*(lzo_memops_TU8p)0)==8)
++#define LZO_MEMOPS_COPY8(dd,ss) \
++    * (lzo_memops_TU8p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss)
++#elif (LZO_OPT_UNALIGNED32)
++#define LZO_MEMOPS_COPY8(dd,ss) \
++    LZO_BLOCK_BEGIN LZO_MEMOPS_COPY4(dd,ss); LZO_MEMOPS_COPY4((lzo_memops_TU1p)(lzo_memops_TU0p)(dd)+4,(const lzo_memops_TU1p)(const lzo_memops_TU0p)(ss)+4); LZO_BLOCK_END
++#elif defined(__lzo_memops_tcheck)
++#define LZO_MEMOPS_COPY8(dd,ss) \
++    LZO_BLOCK_BEGIN if (__lzo_memops_tcheck(lzo_memops_TU8,8,1)) { \
++        * (lzo_memops_TU8p) (lzo_memops_TU0p) (dd) = * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss); \
++    } else { LZO_MEMOPS_MOVE8(dd,ss); } LZO_BLOCK_END
++#else
++#define LZO_MEMOPS_COPY8(dd,ss) LZO_MEMOPS_MOVE8(dd,ss)
++#endif
++#endif
++#define LZO_MEMOPS_COPYN(dd,ss,nn) \
++    LZO_BLOCK_BEGIN \
++    lzo_memops_TU1p d__n = (lzo_memops_TU1p) (lzo_memops_TU0p) (dd); \
++    const lzo_memops_TU1p s__n = (const lzo_memops_TU1p) (const lzo_memops_TU0p) (ss); \
++    lzo_uint n__n = (nn); \
++    while ((void)0, n__n >= 8) { LZO_MEMOPS_COPY8(d__n, s__n); d__n += 8; s__n += 8; n__n -= 8; } \
++    if ((void)0, n__n >= 4) { LZO_MEMOPS_COPY4(d__n, s__n); d__n += 4; s__n += 4; n__n -= 4; } \
++    if ((void)0, n__n > 0) do { *d__n++ = *s__n++; } while (--n__n > 0); \
++    LZO_BLOCK_END
++
++__lzo_static_forceinline lzo_uint16_t lzo_memops_get_le16(const lzo_voidp ss)
++{
++    lzo_uint16_t v;
++#if (LZO_ABI_LITTLE_ENDIAN)
++    LZO_MEMOPS_COPY2(&v, ss);
++#elif (LZO_OPT_UNALIGNED16 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC)
++    const lzo_memops_TU2p s = (const lzo_memops_TU2p) ss;
++    unsigned long vv;
++    __asm__("lhbrx %0,0,%1" : "=r" (vv) : "r" (s), "m" (*s));
++    v = (lzo_uint16_t) vv;
++#else
++    const lzo_memops_TU1p s = (const lzo_memops_TU1p) ss;
++    v = (lzo_uint16_t) (((lzo_uint16_t)s[0]) | ((lzo_uint16_t)s[1] << 8));
++#endif
++    return v;
++}
++#if (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)
++#define LZO_MEMOPS_GET_LE16(ss)    * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss)
++#else
++#define LZO_MEMOPS_GET_LE16(ss)    lzo_memops_get_le16(ss)
++#endif
++
++__lzo_static_forceinline lzo_uint32_t lzo_memops_get_le32(const lzo_voidp ss)
++{
++    lzo_uint32_t v;
++#if (LZO_ABI_LITTLE_ENDIAN)
++    LZO_MEMOPS_COPY4(&v, ss);
++#elif (LZO_OPT_UNALIGNED32 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC)
++    const lzo_memops_TU4p s = (const lzo_memops_TU4p) ss;
++    unsigned long vv;
++    __asm__("lwbrx %0,0,%1" : "=r" (vv) : "r" (s), "m" (*s));
++    v = (lzo_uint32_t) vv;
++#else
++    const lzo_memops_TU1p s = (const lzo_memops_TU1p) ss;
++    v = (lzo_uint32_t) (((lzo_uint32_t)s[0]) | ((lzo_uint32_t)s[1] << 8) | ((lzo_uint32_t)s[2] << 16) | ((lzo_uint32_t)s[3] << 24));
++#endif
++    return v;
++}
++#if (LZO_OPT_UNALIGNED32) && (LZO_ABI_LITTLE_ENDIAN)
++#define LZO_MEMOPS_GET_LE32(ss)    * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss)
++#else
++#define LZO_MEMOPS_GET_LE32(ss)    lzo_memops_get_le32(ss)
++#endif
++
++#if (LZO_OPT_UNALIGNED64) && (LZO_ABI_LITTLE_ENDIAN)
++#define LZO_MEMOPS_GET_LE64(ss)    * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss)
++#endif
++
++__lzo_static_forceinline lzo_uint16_t lzo_memops_get_ne16(const lzo_voidp ss)
++{
++    lzo_uint16_t v;
++    LZO_MEMOPS_COPY2(&v, ss);
++    return v;
++}
++#if (LZO_OPT_UNALIGNED16)
++#define LZO_MEMOPS_GET_NE16(ss)    * (const lzo_memops_TU2p) (const lzo_memops_TU0p) (ss)
++#else
++#define LZO_MEMOPS_GET_NE16(ss)    lzo_memops_get_ne16(ss)
++#endif
++
++__lzo_static_forceinline lzo_uint32_t lzo_memops_get_ne32(const lzo_voidp ss)
++{
++    lzo_uint32_t v;
++    LZO_MEMOPS_COPY4(&v, ss);
++    return v;
++}
++#if (LZO_OPT_UNALIGNED32)
++#define LZO_MEMOPS_GET_NE32(ss)    * (const lzo_memops_TU4p) (const lzo_memops_TU0p) (ss)
++#else
++#define LZO_MEMOPS_GET_NE32(ss)    lzo_memops_get_ne32(ss)
++#endif
++
++#if (LZO_OPT_UNALIGNED64)
++#define LZO_MEMOPS_GET_NE64(ss)    * (const lzo_memops_TU8p) (const lzo_memops_TU0p) (ss)
++#endif
++
++__lzo_static_forceinline void lzo_memops_put_le16(lzo_voidp dd, lzo_uint16_t vv)
++{
++#if (LZO_ABI_LITTLE_ENDIAN)
++    LZO_MEMOPS_COPY2(dd, &vv);
++#elif (LZO_OPT_UNALIGNED16 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC)
++    lzo_memops_TU2p d = (lzo_memops_TU2p) dd;
++    unsigned long v = vv;
++    __asm__("sthbrx %2,0,%1" : "=m" (*d) : "r" (d), "r" (v));
++#else
++    lzo_memops_TU1p d = (lzo_memops_TU1p) dd;
++    d[0] = LZO_BYTE((vv      ) & 0xff);
++    d[1] = LZO_BYTE((vv >>  8) & 0xff);
++#endif
++}
++#if (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)
++#define LZO_MEMOPS_PUT_LE16(dd,vv) (* (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = (vv))
++#else
++#define LZO_MEMOPS_PUT_LE16(dd,vv) lzo_memops_put_le16(dd,vv)
++#endif
++
++__lzo_static_forceinline void lzo_memops_put_le32(lzo_voidp dd, lzo_uint32_t vv)
++{
++#if (LZO_ABI_LITTLE_ENDIAN)
++    LZO_MEMOPS_COPY4(dd, &vv);
++#elif (LZO_OPT_UNALIGNED32 && LZO_ARCH_POWERPC && LZO_ABI_BIG_ENDIAN) && (LZO_ASM_SYNTAX_GNUC)
++    lzo_memops_TU4p d = (lzo_memops_TU4p) dd;
++    unsigned long v = vv;
++    __asm__("stwbrx %2,0,%1" : "=m" (*d) : "r" (d), "r" (v));
++#else
++    lzo_memops_TU1p d = (lzo_memops_TU1p) dd;
++    d[0] = LZO_BYTE((vv      ) & 0xff);
++    d[1] = LZO_BYTE((vv >>  8) & 0xff);
++    d[2] = LZO_BYTE((vv >> 16) & 0xff);
++    d[3] = LZO_BYTE((vv >> 24) & 0xff);
++#endif
++}
++#if (LZO_OPT_UNALIGNED32) && (LZO_ABI_LITTLE_ENDIAN)
++#define LZO_MEMOPS_PUT_LE32(dd,vv) (* (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = (vv))
++#else
++#define LZO_MEMOPS_PUT_LE32(dd,vv) lzo_memops_put_le32(dd,vv)
++#endif
++
++__lzo_static_forceinline void lzo_memops_put_ne16(lzo_voidp dd, lzo_uint16_t vv)
++{
++    LZO_MEMOPS_COPY2(dd, &vv);
++}
++#if (LZO_OPT_UNALIGNED16)
++#define LZO_MEMOPS_PUT_NE16(dd,vv) (* (lzo_memops_TU2p) (lzo_memops_TU0p) (dd) = (vv))
++#else
++#define LZO_MEMOPS_PUT_NE16(dd,vv) lzo_memops_put_ne16(dd,vv)
++#endif
++
++__lzo_static_forceinline void lzo_memops_put_ne32(lzo_voidp dd, lzo_uint32_t vv)
++{
++    LZO_MEMOPS_COPY4(dd, &vv);
++}
++#if (LZO_OPT_UNALIGNED32)
++#define LZO_MEMOPS_PUT_NE32(dd,vv) (* (lzo_memops_TU4p) (lzo_memops_TU0p) (dd) = (vv))
++#else
++#define LZO_MEMOPS_PUT_NE32(dd,vv) lzo_memops_put_ne32(dd,vv)
++#endif
++
++#if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
++static void __attribute__((__unused__))
++#else
++__lzo_static_forceinline void
++#endif
++lzo_memops_unused_funcs(void)
++{
++    LZO_UNUSED_FUNC(lzo_memops_get_le16);
++    LZO_UNUSED_FUNC(lzo_memops_get_le32);
++    LZO_UNUSED_FUNC(lzo_memops_get_ne16);
++    LZO_UNUSED_FUNC(lzo_memops_get_ne32);
++    LZO_UNUSED_FUNC(lzo_memops_put_le16);
++    LZO_UNUSED_FUNC(lzo_memops_put_le32);
++    LZO_UNUSED_FUNC(lzo_memops_put_ne16);
++    LZO_UNUSED_FUNC(lzo_memops_put_ne32);
++    LZO_UNUSED_FUNC(lzo_memops_unused_funcs);
++}
++
++#endif
++
++#ifndef UA_SET1
++#define UA_SET1             LZO_MEMOPS_SET1
++#endif
++#ifndef UA_SET2
++#define UA_SET2             LZO_MEMOPS_SET2
++#endif
++#ifndef UA_SET3
++#define UA_SET3             LZO_MEMOPS_SET3
++#endif
++#ifndef UA_SET4
++#define UA_SET4             LZO_MEMOPS_SET4
++#endif
++#ifndef UA_MOVE1
++#define UA_MOVE1            LZO_MEMOPS_MOVE1
++#endif
++#ifndef UA_MOVE2
++#define UA_MOVE2            LZO_MEMOPS_MOVE2
++#endif
++#ifndef UA_MOVE3
++#define UA_MOVE3            LZO_MEMOPS_MOVE3
++#endif
++#ifndef UA_MOVE4
++#define UA_MOVE4            LZO_MEMOPS_MOVE4
++#endif
++#ifndef UA_MOVE8
++#define UA_MOVE8            LZO_MEMOPS_MOVE8
++#endif
++#ifndef UA_COPY1
++#define UA_COPY1            LZO_MEMOPS_COPY1
++#endif
++#ifndef UA_COPY2
++#define UA_COPY2            LZO_MEMOPS_COPY2
++#endif
++#ifndef UA_COPY3
++#define UA_COPY3            LZO_MEMOPS_COPY3
++#endif
++#ifndef UA_COPY4
++#define UA_COPY4            LZO_MEMOPS_COPY4
++#endif
++#ifndef UA_COPY8
++#define UA_COPY8            LZO_MEMOPS_COPY8
++#endif
++#ifndef UA_COPYN
++#define UA_COPYN            LZO_MEMOPS_COPYN
++#endif
++#ifndef UA_COPYN_X
++#define UA_COPYN_X          LZO_MEMOPS_COPYN
++#endif
++#ifndef UA_GET_LE16
++#define UA_GET_LE16         LZO_MEMOPS_GET_LE16
++#endif
++#ifndef UA_GET_LE32
++#define UA_GET_LE32         LZO_MEMOPS_GET_LE32
++#endif
++#ifdef LZO_MEMOPS_GET_LE64
++#ifndef UA_GET_LE64
++#define UA_GET_LE64         LZO_MEMOPS_GET_LE64
++#endif
++#endif
++#ifndef UA_GET_NE16
++#define UA_GET_NE16         LZO_MEMOPS_GET_NE16
++#endif
++#ifndef UA_GET_NE32
++#define UA_GET_NE32         LZO_MEMOPS_GET_NE32
++#endif
++#ifdef LZO_MEMOPS_GET_NE64
++#ifndef UA_GET_NE64
++#define UA_GET_NE64         LZO_MEMOPS_GET_NE64
++#endif
++#endif
++#ifndef UA_PUT_LE16
++#define UA_PUT_LE16         LZO_MEMOPS_PUT_LE16
++#endif
++#ifndef UA_PUT_LE32
++#define UA_PUT_LE32         LZO_MEMOPS_PUT_LE32
++#endif
++#ifndef UA_PUT_NE16
++#define UA_PUT_NE16         LZO_MEMOPS_PUT_NE16
++#endif
++#ifndef UA_PUT_NE32
++#define UA_PUT_NE32         LZO_MEMOPS_PUT_NE32
+ #endif
+ 
+ #define MEMCPY8_DS(dest,src,len) \
+@@ -2195,25 +3782,10 @@ LZO_EXTERN(const lzo_bytep) lzo_copyright(void);
+ extern "C" {
+ #endif
+ 
+-#if !defined(lzo_uintptr_t)
+-#  if (__LZO_MMODEL_HUGE)
+-#    define lzo_uintptr_t   unsigned long
+-#  else
+-#    define lzo_uintptr_t   acc_uintptr_t
+-#    ifdef __ACC_INTPTR_T_IS_POINTER
+-#      define __LZO_UINTPTR_T_IS_POINTER 1
+-#    endif
+-#  endif
+-#endif
+-
+ #if (LZO_ARCH_I086)
+-#define PTR(a)              ((lzo_bytep) (a))
+-#define PTR_ALIGNED_4(a)    ((ACC_PTR_FP_OFF(a) & 3) == 0)
+-#define PTR_ALIGNED2_4(a,b) (((ACC_PTR_FP_OFF(a) | ACC_PTR_FP_OFF(b)) & 3) == 0)
++#error "LZO_ARCH_I086 is unsupported"
+ #elif (LZO_MM_PVP)
+-#define PTR(a)              ((lzo_bytep) (a))
+-#define PTR_ALIGNED_8(a)    ((((lzo_uintptr_t)(a)) >> 61) == 0)
+-#define PTR_ALIGNED2_8(a,b) ((((lzo_uintptr_t)(a)|(lzo_uintptr_t)(b)) >> 61) == 0)
++#error "LZO_MM_PVP is unsupported"
+ #else
+ #define PTR(a)              ((lzo_uintptr_t) (a))
+ #define PTR_LINEAR(a)       PTR(a)
+@@ -2243,24 +3815,28 @@ typedef union
+     unsigned long   a_ulong;
+     lzo_int         a_lzo_int;
+     lzo_uint        a_lzo_uint;
+-    lzo_int32       a_lzo_int32;
+-    lzo_uint32      a_lzo_uint32;
+-#if defined(LZO_UINT64_MAX)
+-    lzo_int64       a_lzo_int64;
+-    lzo_uint64      a_lzo_uint64;
++    lzo_xint        a_lzo_xint;
++    lzo_int16_t     a_lzo_int16_t;
++    lzo_uint16_t    a_lzo_uint16_t;
++    lzo_int32_t     a_lzo_int32_t;
++    lzo_uint32_t    a_lzo_uint32_t;
++#if defined(lzo_uint64_t)
++    lzo_int64_t     a_lzo_int64_t;
++    lzo_uint64_t    a_lzo_uint64_t;
+ #endif
++    size_t          a_size_t;
+     ptrdiff_t       a_ptrdiff_t;
+     lzo_uintptr_t   a_lzo_uintptr_t;
+-    lzo_voidp       a_lzo_voidp;
+     void *          a_void_p;
+-    lzo_bytep       a_lzo_bytep;
+-    lzo_bytepp      a_lzo_bytepp;
+-    lzo_uintp       a_lzo_uintp;
+-    lzo_uint *      a_lzo_uint_p;
+-    lzo_uint32p     a_lzo_uint32p;
+-    lzo_uint32 *    a_lzo_uint32_p;
+-    unsigned char * a_uchar_p;
+     char *          a_char_p;
++    unsigned char * a_uchar_p;
++    const void *          a_c_void_p;
++    const char *          a_c_char_p;
++    const unsigned char * a_c_uchar_p;
++    lzo_voidp       a_lzo_voidp;
++    lzo_bytep       a_lzo_bytep;
++    const lzo_voidp a_c_lzo_voidp;
++    const lzo_bytep a_c_lzo_bytep;
+ }
+ lzo_full_align_t;
+ 
+@@ -2276,18 +3852,14 @@ lzo_full_align_t;
+ 
+ #ifndef LZO_DICT_USE_PTR
+ #define LZO_DICT_USE_PTR 1
+-#if 0 && (LZO_ARCH_I086)
+-#  undef LZO_DICT_USE_PTR
+-#  define LZO_DICT_USE_PTR 0
+-#endif
+ #endif
+ 
+ #if (LZO_DICT_USE_PTR)
+ #  define lzo_dict_t    const lzo_bytep
+-#  define lzo_dict_p    lzo_dict_t __LZO_MMODEL *
++#  define lzo_dict_p    lzo_dict_t *
+ #else
+ #  define lzo_dict_t    lzo_uint
+-#  define lzo_dict_p    lzo_dict_t __LZO_MMODEL *
++#  define lzo_dict_p    lzo_dict_t *
+ #endif
+ 
+ #endif
+@@ -2300,10 +3872,9 @@ __lzo_ptr_linear(const lzo_voidp ptr)
+     lzo_uintptr_t p;
+ 
+ #if (LZO_ARCH_I086)
+-    p = (((lzo_uintptr_t)(ACC_PTR_FP_SEG(ptr))) << (16 - ACC_MM_AHSHIFT)) + (ACC_PTR_FP_OFF(ptr));
++#error "LZO_ARCH_I086 is unsupported"
+ #elif (LZO_MM_PVP)
+-    p = (lzo_uintptr_t) (ptr);
+-    p = (p << 3) | (p >> 61);
++#error "LZO_MM_PVP is unsupported"
+ #else
+     p = (lzo_uintptr_t) PTR_LINEAR(ptr);
+ #endif
+@@ -2314,9 +3885,8 @@ __lzo_ptr_linear(const lzo_voidp ptr)
+ LZO_PUBLIC(unsigned)
+ __lzo_align_gap(const lzo_voidp ptr, lzo_uint size)
+ {
+-#if defined(__LZO_UINTPTR_T_IS_POINTER)
+-    size_t n = (size_t) ptr;
+-    n = (((n + size - 1) / size) * size) - n;
++#if (__LZO_UINTPTR_T_IS_POINTER)
++#error "__LZO_UINTPTR_T_IS_POINTER is unsupported"
+ #else
+     lzo_uintptr_t p, n;
+     p = __lzo_ptr_linear(ptr);
+@@ -2342,7 +3912,7 @@ static const char __lzo_copyright[] =
+ #else
+     "\r\n\n"
+     "LZO data compression library.\n"
+-    "$Copyright: LZO Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\n"
++    "$Copyright: LZO Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer\n"
+     "<markus@oberhumer.com>\n"
+     "http://www.oberhumer.com $\n\n"
+     "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n"
+@@ -2352,11 +3922,7 @@ static const char __lzo_copyright[] =
+ LZO_PUBLIC(const lzo_bytep)
+ lzo_copyright(void)
+ {
+-#if (LZO_OS_DOS16 && LZO_CC_TURBOC)
+-    return (lzo_voidp) __lzo_copyright;
+-#else
+     return (const lzo_bytep) __lzo_copyright;
+-#endif
+ }
+ 
+ LZO_PUBLIC(unsigned)
+@@ -2393,16 +3959,16 @@ _lzo_version_date(void)
+ #define LZO_NMAX 5552
+ 
+ #define LZO_DO1(buf,i)  s1 += buf[i]; s2 += s1
+-#define LZO_DO2(buf,i)  LZO_DO1(buf,i); LZO_DO1(buf,i+1);
+-#define LZO_DO4(buf,i)  LZO_DO2(buf,i); LZO_DO2(buf,i+2);
+-#define LZO_DO8(buf,i)  LZO_DO4(buf,i); LZO_DO4(buf,i+4);
+-#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
++#define LZO_DO2(buf,i)  LZO_DO1(buf,i); LZO_DO1(buf,i+1)
++#define LZO_DO4(buf,i)  LZO_DO2(buf,i); LZO_DO2(buf,i+2)
++#define LZO_DO8(buf,i)  LZO_DO4(buf,i); LZO_DO4(buf,i+4)
++#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8)
+ 
+-LZO_PUBLIC(lzo_uint32)
+-lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len)
++LZO_PUBLIC(lzo_uint32_t)
++lzo_adler32(lzo_uint32_t adler, const lzo_bytep buf, lzo_uint len)
+ {
+-    lzo_uint32 s1 = adler & 0xffff;
+-    lzo_uint32 s2 = (adler >> 16) & 0xffff;
++    lzo_uint32_t s1 = adler & 0xffff;
++    lzo_uint32_t s2 = (adler >> 16) & 0xffff;
+     unsigned k;
+ 
+     if (buf == NULL)
+@@ -2459,8 +4025,8 @@ lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len)
+ LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len)
+ {
+ #if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCMP)
+-    const lzo_hbyte_p p1 = (const lzo_hbyte_p) s1;
+-    const lzo_hbyte_p p2 = (const lzo_hbyte_p) s2;
++    const lzo_hbyte_p p1 = LZO_STATIC_CAST(const lzo_hbyte_p, s1);
++    const lzo_hbyte_p p2 = LZO_STATIC_CAST(const lzo_hbyte_p, s2);
+     if __lzo_likely(len > 0) do
+     {
+         int d = *p1 - *p2;
+@@ -2476,8 +4042,8 @@ LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo
+ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)
+ {
+ #if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCPY)
+-    lzo_hbyte_p p1 = (lzo_hbyte_p) dest;
+-    const lzo_hbyte_p p2 = (const lzo_hbyte_p) src;
++    lzo_hbyte_p p1 = LZO_STATIC_CAST(lzo_hbyte_p, dest);
++    const lzo_hbyte_p p2 = LZO_STATIC_CAST(const lzo_hbyte_p, src);
+     if (!(len > 0) || p1 == p2)
+         return dest;
+     do
+@@ -2491,8 +4057,8 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src
+ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)
+ {
+ #if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMMOVE)
+-    lzo_hbyte_p p1 = (lzo_hbyte_p) dest;
+-    const lzo_hbyte_p p2 = (const lzo_hbyte_p) src;
++    lzo_hbyte_p p1 = LZO_STATIC_CAST(lzo_hbyte_p, dest);
++    const lzo_hbyte_p p2 = LZO_STATIC_CAST(const lzo_hbyte_p, src);
+     if (!(len > 0) || p1 == p2)
+         return dest;
+     if (p1 < p2)
+@@ -2514,16 +4080,17 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p sr
+     return memmove(dest, src, len);
+ #endif
+ }
+-LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
++LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int cc, lzo_hsize_t len)
+ {
+ #if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMSET)
+-    lzo_hbyte_p p = (lzo_hbyte_p) s;
++    lzo_hbyte_p p = LZO_STATIC_CAST(lzo_hbyte_p, s);
++    unsigned char c = LZO_ITRUNC(unsigned char, cc);
+     if __lzo_likely(len > 0) do
+-        *p++ = (unsigned char) c;
++        *p++ = c;
+     while __lzo_likely(--len > 0);
+     return s;
+ #else
+-    return memset(s, c, len);
++    return memset(s, cc, len);
+ #endif
+ }
+ #undef LZOLIB_PUBLIC
+@@ -2532,105 +4099,28 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
+ 
+ #if !defined(__LZO_IN_MINILZO)
+ 
+-#define ACC_WANT_ACC_CHK_CH 1
+-#undef ACCCHK_ASSERT
++#define LZO_WANT_ACC_CHK_CH 1
++#undef LZOCHK_ASSERT
+ 
+-    ACCCHK_ASSERT_IS_SIGNED_T(lzo_int)
+-    ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint)
+-
+-    ACCCHK_ASSERT_IS_SIGNED_T(lzo_int32)
+-    ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint32)
+-    ACCCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0)
+-    ACCCHK_ASSERT(sizeof(lzo_uint32) >= 4)
+-#if defined(LZO_UINT64_MAX)
+-    ACCCHK_ASSERT(sizeof(lzo_uint64) == 8)
+-    ACCCHK_ASSERT_IS_SIGNED_T(lzo_int64)
+-    ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint64)
++    LZOCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0)
++    LZOCHK_ASSERT_IS_SIGNED_T(lzo_int)
++    LZOCHK_ASSERT_IS_UNSIGNED_T(lzo_uint)
++#if !(__LZO_UINTPTR_T_IS_POINTER)
++    LZOCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t)
+ #endif
++    LZOCHK_ASSERT(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
++    LZOCHK_ASSERT_IS_UNSIGNED_T(lzo_xint)
+ 
+-#if !defined(__LZO_UINTPTR_T_IS_POINTER)
+-    ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t)
+ #endif
+-    ACCCHK_ASSERT(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
+-
+-    ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_xint)
+-    ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint32))
+-    ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint))
+-    ACCCHK_ASSERT(sizeof(lzo_xint) == sizeof(lzo_uint32) || sizeof(lzo_xint) == sizeof(lzo_uint))
++#undef LZOCHK_ASSERT
+ 
++union lzo_config_check_union {
++    lzo_uint a[2];
++    unsigned char b[2*LZO_MAX(8,sizeof(lzo_uint))];
++#if defined(lzo_uint64_t)
++    lzo_uint64_t c[2];
+ #endif
+-#undef ACCCHK_ASSERT
+-
+-#if 0
+-#define WANT_lzo_bitops_clz32 1
+-#define WANT_lzo_bitops_clz64 1
+-#endif
+-#define WANT_lzo_bitops_ctz32 1
+-#define WANT_lzo_bitops_ctz64 1
+-
+-#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400)))
+-#include <intrin.h>
+-#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0
+-#pragma intrinsic(_BitScanReverse)
+-static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v)
+-{
+-    unsigned long r;
+-    (void) _BitScanReverse(&r, v);
+-    return (unsigned) r;
+-}
+-#define lzo_bitops_clz32 lzo_bitops_clz32
+-#endif
+-#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0
+-#pragma intrinsic(_BitScanReverse64)
+-static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v)
+-{
+-    unsigned long r;
+-    (void) _BitScanReverse64(&r, v);
+-    return (unsigned) r;
+-}
+-#define lzo_bitops_clz64 lzo_bitops_clz64
+-#endif
+-#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+-#pragma intrinsic(_BitScanForward)
+-static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v)
+-{
+-    unsigned long r;
+-    (void) _BitScanForward(&r, v);
+-    return (unsigned) r;
+-}
+-#define lzo_bitops_ctz32 lzo_bitops_ctz32
+-#endif
+-#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+-#pragma intrinsic(_BitScanForward64)
+-static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v)
+-{
+-    unsigned long r;
+-    (void) _BitScanForward64(&r, v);
+-    return (unsigned) r;
+-}
+-#define lzo_bitops_ctz64 lzo_bitops_ctz64
+-#endif
+-
+-#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || LZO_CC_LLVM)
+-#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32)
+-#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v))
+-#endif
+-#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX)
+-#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v))
+-#endif
+-#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+-#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v))
+-#endif
+-#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+-#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v))
+-#endif
+-#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32)
+-#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v))
+-#endif
+-#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX)
+-#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v))
+-#endif
+-#endif
++};
+ 
+ #if 0
+ #define u2p(ptr,off) ((lzo_voidp) (((lzo_bytep)(lzo_voidp)(ptr)) + (off)))
+@@ -2644,73 +4134,101 @@ static __lzo_noinline lzo_voidp u2p(lzo_voidp ptr, lzo_uint off)
+ LZO_PUBLIC(int)
+ _lzo_config_check(void)
+ {
+-    lzo_bool r = 1;
+-    union {
+-        lzo_xint a[2]; unsigned char b[2*LZO_MAX(8,sizeof(lzo_xint))];
+-#if defined(LZO_UNALIGNED_OK_8)
+-        lzo_uint64 c[2];
++#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030100ul && LZO_CC_CLANG < 0x030300ul))
++# if 0
++    volatile
++# endif
+ #endif
+-        unsigned short x[2]; lzo_uint32 y[2]; lzo_uint z[2];
+-    } u;
++    union lzo_config_check_union u;
+     lzo_voidp p;
++    unsigned r = 1;
+ 
+     u.a[0] = u.a[1] = 0;
+     p = u2p(&u, 0);
+     r &= ((* (lzo_bytep) p) == 0);
+-#if !defined(LZO_CFG_NO_CONFIG_CHECK)
+-#if defined(LZO_ABI_BIG_ENDIAN)
++#if !(LZO_CFG_NO_CONFIG_CHECK)
++#if (LZO_ABI_BIG_ENDIAN)
+     u.a[0] = u.a[1] = 0; u.b[sizeof(lzo_uint) - 1] = 128;
+     p = u2p(&u, 0);
+     r &= ((* (lzo_uintp) p) == 128);
+ #endif
+-#if defined(LZO_ABI_LITTLE_ENDIAN)
++#if (LZO_ABI_LITTLE_ENDIAN)
+     u.a[0] = u.a[1] = 0; u.b[0] = 128;
+     p = u2p(&u, 0);
+     r &= ((* (lzo_uintp) p) == 128);
+ #endif
+-#if defined(LZO_UNALIGNED_OK_2)
+     u.a[0] = u.a[1] = 0;
+-    u.b[0] = 1; u.b[sizeof(unsigned short) + 1] = 2;
++    u.b[0] = 1; u.b[3] = 2;
+     p = u2p(&u, 1);
+-    r &= ((* (lzo_ushortp) p) == 0);
++    r &= UA_GET_NE16(p) == 0;
++    r &= UA_GET_LE16(p) == 0;
++    u.b[1] = 128;
++    r &= UA_GET_LE16(p) == 128;
++    u.b[2] = 129;
++    r &= UA_GET_LE16(p) == LZO_UINT16_C(0x8180);
++#if (LZO_ABI_BIG_ENDIAN)
++    r &= UA_GET_NE16(p) == LZO_UINT16_C(0x8081);
++#endif
++#if (LZO_ABI_LITTLE_ENDIAN)
++    r &= UA_GET_NE16(p) == LZO_UINT16_C(0x8180);
+ #endif
+-#if defined(LZO_UNALIGNED_OK_4)
+     u.a[0] = u.a[1] = 0;
+-    u.b[0] = 3; u.b[sizeof(lzo_uint32) + 1] = 4;
++    u.b[0] = 3; u.b[5] = 4;
+     p = u2p(&u, 1);
+-    r &= ((* (lzo_uint32p) p) == 0);
++    r &= UA_GET_NE32(p) == 0;
++    r &= UA_GET_LE32(p) == 0;
++    u.b[1] = 128;
++    r &= UA_GET_LE32(p) == 128;
++    u.b[2] = 129; u.b[3] = 130; u.b[4] = 131;
++    r &= UA_GET_LE32(p) == LZO_UINT32_C(0x83828180);
++#if (LZO_ABI_BIG_ENDIAN)
++    r &= UA_GET_NE32(p) == LZO_UINT32_C(0x80818283);
++#endif
++#if (LZO_ABI_LITTLE_ENDIAN)
++    r &= UA_GET_NE32(p) == LZO_UINT32_C(0x83828180);
+ #endif
+-#if defined(LZO_UNALIGNED_OK_8)
++#if defined(UA_GET_NE64)
+     u.c[0] = u.c[1] = 0;
+-    u.b[0] = 5; u.b[sizeof(lzo_uint64) + 1] = 6;
++    u.b[0] = 5; u.b[9] = 6;
+     p = u2p(&u, 1);
+-    r &= ((* (lzo_uint64p) p) == 0);
++    u.c[0] = u.c[1] = 0;
++    r &= UA_GET_NE64(p) == 0;
++#if defined(UA_GET_LE64)
++    r &= UA_GET_LE64(p) == 0;
++    u.b[1] = 128;
++    r &= UA_GET_LE64(p) == 128;
++#endif
+ #endif
+-#if defined(lzo_bitops_clz32)
+-    { unsigned i; lzo_uint32 v = 1;
+-    for (i = 0; i < 31; i++, v <<= 1)
+-        r &= lzo_bitops_clz32(v) == 31 - i;
+-    }
++#if defined(lzo_bitops_ctlz32)
++    { unsigned i = 0; lzo_uint32_t v;
++    for (v = 1; v != 0 && r == 1; v <<= 1, i++) {
++        r &= lzo_bitops_ctlz32(v) == 31 - i;
++        r &= lzo_bitops_ctlz32_func(v) == 31 - i;
++    }}
+ #endif
+-#if defined(lzo_bitops_clz64)
+-    { unsigned i; lzo_uint64 v = 1;
+-    for (i = 0; i < 63; i++, v <<= 1)
+-        r &= lzo_bitops_clz64(v) == 63 - i;
+-    }
++#if defined(lzo_bitops_ctlz64)
++    { unsigned i = 0; lzo_uint64_t v;
++    for (v = 1; v != 0 && r == 1; v <<= 1, i++) {
++        r &= lzo_bitops_ctlz64(v) == 63 - i;
++        r &= lzo_bitops_ctlz64_func(v) == 63 - i;
++    }}
+ #endif
+-#if defined(lzo_bitops_ctz32)
+-    { unsigned i; lzo_uint32 v = 1;
+-    for (i = 0; i < 31; i++, v <<= 1)
+-        r &= lzo_bitops_ctz32(v) == i;
+-    }
++#if defined(lzo_bitops_cttz32)
++    { unsigned i = 0; lzo_uint32_t v;
++    for (v = 1; v != 0 && r == 1; v <<= 1, i++) {
++        r &= lzo_bitops_cttz32(v) == i;
++        r &= lzo_bitops_cttz32_func(v) == i;
++    }}
+ #endif
+-#if defined(lzo_bitops_ctz64)
+-    { unsigned i; lzo_uint64 v = 1;
+-    for (i = 0; i < 63; i++, v <<= 1)
+-        r &= lzo_bitops_ctz64(v) == i;
+-    }
++#if defined(lzo_bitops_cttz64)
++    { unsigned i = 0; lzo_uint64_t v;
++    for (v = 1; v != 0 && r == 1; v <<= 1, i++) {
++        r &= lzo_bitops_cttz64(v) == i;
++        r &= lzo_bitops_cttz64_func(v) == i;
++    }}
+ #endif
+ #endif
++    LZO_UNUSED_FUNC(lzo_bitops_unused_funcs);
+ 
+     return r == 1 ? LZO_E_OK : LZO_E_ERROR;
+ }
+@@ -2724,11 +4242,11 @@ __lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5,
+ #if defined(__LZO_IN_MINILZO)
+ #elif (LZO_CC_MSC && ((_MSC_VER) < 700))
+ #else
+-#define ACC_WANT_ACC_CHK_CH 1
+-#undef ACCCHK_ASSERT
+-#define ACCCHK_ASSERT(expr)  LZO_COMPILE_TIME_ASSERT(expr)
++#define LZO_WANT_ACC_CHK_CH 1
++#undef LZOCHK_ASSERT
++#define LZOCHK_ASSERT(expr)  LZO_COMPILE_TIME_ASSERT(expr)
+ #endif
+-#undef ACCCHK_ASSERT
++#undef LZOCHK_ASSERT
+ 
+     if (v == 0)
+         return LZO_E_ERROR;
+@@ -2736,7 +4254,7 @@ __lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5,
+     r = (s1 == -1 || s1 == (int) sizeof(short)) &&
+         (s2 == -1 || s2 == (int) sizeof(int)) &&
+         (s3 == -1 || s3 == (int) sizeof(long)) &&
+-        (s4 == -1 || s4 == (int) sizeof(lzo_uint32)) &&
++        (s4 == -1 || s4 == (int) sizeof(lzo_uint32_t)) &&
+         (s5 == -1 || s5 == (int) sizeof(lzo_uint)) &&
+         (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) &&
+         (s7 == -1 || s7 == (int) sizeof(char *)) &&
+@@ -2779,11 +4297,11 @@ int __far __pascal LibMain ( int a, short b, short c, long d )
+ 
+ #if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS)
+ 
+-#if 1 && defined(UA_GET32)
++#if 1 && defined(UA_GET_LE32)
+ #undef  LZO_DICT_USE_PTR
+ #define LZO_DICT_USE_PTR 0
+ #undef  lzo_dict_t
+-#define lzo_dict_t unsigned short
++#define lzo_dict_t lzo_uint16_t
+ #endif
+ 
+ #define LZO_NEED_DICT_H 1
+@@ -3088,77 +4606,7 @@ DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
+ #endif
+ 
+ #if 1 && defined(DO_COMPRESS) && !defined(do_compress)
+-#  define do_compress       LZO_CPP_ECONCAT2(DO_COMPRESS,_core)
+-#endif
+-
+-#if defined(UA_GET64)
+-#  define WANT_lzo_bitops_ctz64 1
+-#elif defined(UA_GET32)
+-#  define WANT_lzo_bitops_ctz32 1
+-#endif
+-
+-#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400)))
+-#include <intrin.h>
+-#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0
+-#pragma intrinsic(_BitScanReverse)
+-static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v)
+-{
+-    unsigned long r;
+-    (void) _BitScanReverse(&r, v);
+-    return (unsigned) r;
+-}
+-#define lzo_bitops_clz32 lzo_bitops_clz32
+-#endif
+-#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0
+-#pragma intrinsic(_BitScanReverse64)
+-static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v)
+-{
+-    unsigned long r;
+-    (void) _BitScanReverse64(&r, v);
+-    return (unsigned) r;
+-}
+-#define lzo_bitops_clz64 lzo_bitops_clz64
+-#endif
+-#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+-#pragma intrinsic(_BitScanForward)
+-static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v)
+-{
+-    unsigned long r;
+-    (void) _BitScanForward(&r, v);
+-    return (unsigned) r;
+-}
+-#define lzo_bitops_ctz32 lzo_bitops_ctz32
+-#endif
+-#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+-#pragma intrinsic(_BitScanForward64)
+-static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v)
+-{
+-    unsigned long r;
+-    (void) _BitScanForward64(&r, v);
+-    return (unsigned) r;
+-}
+-#define lzo_bitops_ctz64 lzo_bitops_ctz64
+-#endif
+-
+-#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || LZO_CC_LLVM)
+-#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32)
+-#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v))
+-#endif
+-#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX)
+-#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v))
+-#endif
+-#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+-#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v))
+-#endif
+-#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+-#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v))
+-#endif
+-#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32)
+-#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v))
+-#endif
+-#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX)
+-#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v))
+-#endif
++#  define do_compress       LZO_PP_ECONCAT2(DO_COMPRESS,_core)
+ #endif
+ 
+ static __lzo_noinline lzo_uint
+@@ -3166,7 +4614,7 @@ do_compress ( const lzo_bytep in , lzo_uint  in_len,
+                     lzo_bytep out, lzo_uintp out_len,
+                     lzo_uint  ti,  lzo_voidp wrkmem)
+ {
+-    register const lzo_bytep ip;
++    const lzo_bytep ip;
+     lzo_bytep op;
+     const lzo_bytep const in_end = in + in_len;
+     const lzo_bytep const ip_end = in + in_len - 20;
+@@ -3175,7 +4623,7 @@ do_compress ( const lzo_bytep in , lzo_uint  in_len,
+ 
+     op = out;
+     ip = in;
+-    ii = ip - ti;
++    ii = ip;
+ 
+     ip += ti < 4 ? 4 - ti : 0;
+     for (;;)
+@@ -3205,8 +4653,8 @@ next:
+         goto literal;
+ 
+ try_match:
+-#if defined(UA_GET32)
+-        if (UA_GET32(m_pos) != UA_GET32(ip))
++#if (LZO_OPT_UNALIGNED32)
++        if (UA_GET_NE32(m_pos) != UA_GET_NE32(ip))
+ #else
+         if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3])
+ #endif
+@@ -3221,49 +4669,43 @@ literal:
+         lzo_uint m_off;
+         lzo_uint m_len;
+         {
+-        lzo_uint32 dv;
++        lzo_uint32_t dv;
+         lzo_uint dindex;
+ literal:
+         ip += 1 + ((ip - ii) >> 5);
+ next:
+         if __lzo_unlikely(ip >= ip_end)
+             break;
+-        dv = UA_GET32(ip);
++        dv = UA_GET_LE32(ip);
+         dindex = DINDEX(dv,ip);
+         GINDEX(m_off,m_pos,in+dict,dindex,in);
+         UPDATE_I(dict,0,dindex,ip,in);
+-        if __lzo_unlikely(dv != UA_GET32(m_pos))
++        if __lzo_unlikely(dv != UA_GET_LE32(m_pos))
+             goto literal;
+         }
+ #endif
+ 
++        ii -= ti; ti = 0;
+         {
+-        register lzo_uint t = pd(ip,ii);
++        lzo_uint t = pd(ip,ii);
+         if (t != 0)
+         {
+             if (t <= 3)
+             {
+-                op[-2] |= LZO_BYTE(t);
+-#if defined(UA_COPY32)
+-                UA_COPY32(op, ii);
++                op[-2] = LZO_BYTE(op[-2] | t);
++#if (LZO_OPT_UNALIGNED32)
++                UA_COPY4(op, ii);
+                 op += t;
+ #else
+                 { do *op++ = *ii++; while (--t > 0); }
+ #endif
+             }
+-#if defined(UA_COPY32) || defined(UA_COPY64)
++#if (LZO_OPT_UNALIGNED32) || (LZO_OPT_UNALIGNED64)
+             else if (t <= 16)
+             {
+                 *op++ = LZO_BYTE(t - 3);
+-#if defined(UA_COPY64)
+-                UA_COPY64(op, ii);
+-                UA_COPY64(op+8, ii+8);
+-#else
+-                UA_COPY32(op, ii);
+-                UA_COPY32(op+4, ii+4);
+-                UA_COPY32(op+8, ii+8);
+-                UA_COPY32(op+12, ii+12);
+-#endif
++                UA_COPY8(op, ii);
++                UA_COPY8(op+8, ii+8);
+                 op += t;
+             }
+ #endif
+@@ -3273,31 +4715,21 @@ next:
+                     *op++ = LZO_BYTE(t - 3);
+                 else
+                 {
+-                    register lzo_uint tt = t - 18;
++                    lzo_uint tt = t - 18;
+                     *op++ = 0;
+                     while __lzo_unlikely(tt > 255)
+                     {
+                         tt -= 255;
+-#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+-                        * (volatile unsigned char *) op++ = 0;
+-#else
+-                        *op++ = 0;
+-#endif
++                        UA_SET1(op, 0);
++                        op++;
+                     }
+                     assert(tt > 0);
+                     *op++ = LZO_BYTE(tt);
+                 }
+-#if defined(UA_COPY32) || defined(UA_COPY64)
++#if (LZO_OPT_UNALIGNED32) || (LZO_OPT_UNALIGNED64)
+                 do {
+-#if defined(UA_COPY64)
+-                    UA_COPY64(op, ii);
+-                    UA_COPY64(op+8, ii+8);
+-#else
+-                    UA_COPY32(op, ii);
+-                    UA_COPY32(op+4, ii+4);
+-                    UA_COPY32(op+8, ii+8);
+-                    UA_COPY32(op+12, ii+12);
+-#endif
++                    UA_COPY8(op, ii);
++                    UA_COPY8(op+8, ii+8);
+                     op += 16; ii += 16; t -= 16;
+                 } while (t >= 16); if (t > 0)
+ #endif
+@@ -3307,19 +4739,26 @@ next:
+         }
+         m_len = 4;
+         {
+-#if defined(UA_GET64)
+-        lzo_uint64 v;
+-        v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len);
++#if (LZO_OPT_UNALIGNED64)
++        lzo_uint64_t v;
++        v = UA_GET_NE64(ip + m_len) ^ UA_GET_NE64(m_pos + m_len);
+         if __lzo_unlikely(v == 0) {
+             do {
+                 m_len += 8;
+-                v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len);
++                v = UA_GET_NE64(ip + m_len) ^ UA_GET_NE64(m_pos + m_len);
+                 if __lzo_unlikely(ip + m_len >= ip_end)
+                     goto m_len_done;
+             } while (v == 0);
+         }
+-#if (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz64)
+-        m_len += lzo_bitops_ctz64(v) / CHAR_BIT;
++#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_ctlz64)
++        m_len += lzo_bitops_ctlz64(v) / CHAR_BIT;
++#elif (LZO_ABI_BIG_ENDIAN)
++        if ((v >> (64 - CHAR_BIT)) == 0) do {
++            v <<= CHAR_BIT;
++            m_len += 1;
++        } while ((v >> (64 - CHAR_BIT)) == 0);
++#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_cttz64)
++        m_len += lzo_bitops_cttz64(v) / CHAR_BIT;
+ #elif (LZO_ABI_LITTLE_ENDIAN)
+         if ((v & UCHAR_MAX) == 0) do {
+             v >>= CHAR_BIT;
+@@ -3330,19 +4769,30 @@ next:
+             m_len += 1;
+         } while (ip[m_len] == m_pos[m_len]);
+ #endif
+-#elif defined(UA_GET32)
+-        lzo_uint32 v;
+-        v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len);
++#elif (LZO_OPT_UNALIGNED32)
++        lzo_uint32_t v;
++        v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len);
+         if __lzo_unlikely(v == 0) {
+             do {
+                 m_len += 4;
+-                v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len);
++                v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len);
++                if (v != 0)
++                    break;
++                m_len += 4;
++                v = UA_GET_NE32(ip + m_len) ^ UA_GET_NE32(m_pos + m_len);
+                 if __lzo_unlikely(ip + m_len >= ip_end)
+                     goto m_len_done;
+             } while (v == 0);
+         }
+-#if (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz32)
+-        m_len += lzo_bitops_ctz32(v) / CHAR_BIT;
++#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_ctlz32)
++        m_len += lzo_bitops_ctlz32(v) / CHAR_BIT;
++#elif (LZO_ABI_BIG_ENDIAN)
++        if ((v >> (32 - CHAR_BIT)) == 0) do {
++            v <<= CHAR_BIT;
++            m_len += 1;
++        } while ((v >> (32 - CHAR_BIT)) == 0);
++#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_cttz32)
++        m_len += lzo_bitops_cttz32(v) / CHAR_BIT;
+ #elif (LZO_ABI_LITTLE_ENDIAN)
+         if ((v & UCHAR_MAX) == 0) do {
+             v >>= CHAR_BIT;
+@@ -3357,6 +4807,27 @@ next:
+         if __lzo_unlikely(ip[m_len] == m_pos[m_len]) {
+             do {
+                 m_len += 1;
++                if (ip[m_len] != m_pos[m_len])
++                    break;
++                m_len += 1;
++                if (ip[m_len] != m_pos[m_len])
++                    break;
++                m_len += 1;
++                if (ip[m_len] != m_pos[m_len])
++                    break;
++                m_len += 1;
++                if (ip[m_len] != m_pos[m_len])
++                    break;
++                m_len += 1;
++                if (ip[m_len] != m_pos[m_len])
++                    break;
++                m_len += 1;
++                if (ip[m_len] != m_pos[m_len])
++                    break;
++                m_len += 1;
++                if (ip[m_len] != m_pos[m_len])
++                    break;
++                m_len += 1;
+                 if __lzo_unlikely(ip + m_len >= ip_end)
+                     goto m_len_done;
+             } while (ip[m_len] == m_pos[m_len]);
+@@ -3390,11 +4861,8 @@ m_len_done:
+                 while __lzo_unlikely(m_len > 255)
+                 {
+                     m_len -= 255;
+-#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+-                    * (volatile unsigned char *) op++ = 0;
+-#else
+-                    *op++ = 0;
+-#endif
++                    UA_SET1(op, 0);
++                    op++;
+                 }
+                 *op++ = LZO_BYTE(m_len);
+             }
+@@ -3413,11 +4881,8 @@ m_len_done:
+                 while __lzo_unlikely(m_len > 255)
+                 {
+                     m_len -= 255;
+-#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+-                    * (volatile unsigned char *) op++ = 0;
+-#else
+-                    *op++ = 0;
+-#endif
++                    UA_SET1(op, 0);
++                    op++;
+                 }
+                 *op++ = LZO_BYTE(m_len);
+             }
+@@ -3428,7 +4893,7 @@ m_len_done:
+     }
+ 
+     *out_len = pd(op, out);
+-    return pd(in_end,ii);
++    return pd(in_end,ii-ti);
+ }
+ 
+ LZO_PUBLIC(int)
+@@ -3468,7 +4933,7 @@ DO_COMPRESS      ( const lzo_bytep in , lzo_uint  in_len,
+         if (op == out && t <= 238)
+             *op++ = LZO_BYTE(17 + t);
+         else if (t <= 3)
+-            op[-2] |= LZO_BYTE(t);
++            op[-2] = LZO_BYTE(op[-2] | t);
+         else if (t <= 18)
+             *op++ = LZO_BYTE(t - 3);
+         else
+@@ -3479,17 +4944,14 @@ DO_COMPRESS      ( const lzo_bytep in , lzo_uint  in_len,
+             while (tt > 255)
+             {
+                 tt -= 255;
+-#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+-
+-                * (volatile unsigned char *) op++ = 0;
+-#else
+-                *op++ = 0;
+-#endif
++                UA_SET1(op, 0);
++                op++;
+             }
+             assert(tt > 0);
+             *op++ = LZO_BYTE(tt);
+         }
+-        do *op++ = *ii++; while (--t > 0);
++        UA_COPYN(op, ii, t);
++        op += t;
+     }
+ 
+     *op++ = M4_MARKER | 1;
+@@ -3526,10 +4988,13 @@ DO_COMPRESS      ( const lzo_bytep in , lzo_uint  in_len,
+ 
+ #undef TEST_IP
+ #undef TEST_OP
++#undef TEST_IP_AND_TEST_OP
+ #undef TEST_LB
+ #undef TEST_LBO
+ #undef NEED_IP
+ #undef NEED_OP
++#undef TEST_IV
++#undef TEST_OV
+ #undef HAVE_TEST_IP
+ #undef HAVE_TEST_OP
+ #undef HAVE_NEED_IP
+@@ -3544,6 +5009,7 @@ DO_COMPRESS      ( const lzo_bytep in , lzo_uint  in_len,
+ #  if (LZO_TEST_OVERRUN_INPUT >= 2)
+ #    define NEED_IP(x) \
+             if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
++#    define TEST_IV(x)          if ((x) >  (lzo_uint)0 - (511)) goto input_overrun
+ #  endif
+ #endif
+ 
+@@ -3555,12 +5021,13 @@ DO_COMPRESS      ( const lzo_bytep in , lzo_uint  in_len,
+ #    undef TEST_OP
+ #    define NEED_OP(x) \
+             if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
++#    define TEST_OV(x)          if ((x) >  (lzo_uint)0 - (511)) goto output_overrun
+ #  endif
+ #endif
+ 
+ #if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+-#  define TEST_LB(m_pos)        if (m_pos < out || m_pos >= op) goto lookbehind_overrun
+-#  define TEST_LBO(m_pos,o)     if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun
++#  define TEST_LB(m_pos)        if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op)) goto lookbehind_overrun
++#  define TEST_LBO(m_pos,o)     if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op-(o))) goto lookbehind_overrun
+ #else
+ #  define TEST_LB(m_pos)        ((void) 0)
+ #  define TEST_LBO(m_pos,o)     ((void) 0)
+@@ -3581,15 +5048,27 @@ DO_COMPRESS      ( const lzo_bytep in , lzo_uint  in_len,
+ #  define TEST_OP               1
+ #endif
+ 
++#if defined(HAVE_TEST_IP) && defined(HAVE_TEST_OP)
++#  define TEST_IP_AND_TEST_OP   (TEST_IP && TEST_OP)
++#elif defined(HAVE_TEST_IP)
++#  define TEST_IP_AND_TEST_OP   TEST_IP
++#elif defined(HAVE_TEST_OP)
++#  define TEST_IP_AND_TEST_OP   TEST_OP
++#else
++#  define TEST_IP_AND_TEST_OP   1
++#endif
++
+ #if defined(NEED_IP)
+ #  define HAVE_NEED_IP 1
+ #else
+ #  define NEED_IP(x)            ((void) 0)
++#  define TEST_IV(x)            ((void) 0)
+ #endif
+ #if defined(NEED_OP)
+ #  define HAVE_NEED_OP 1
+ #else
+ #  define NEED_OP(x)            ((void) 0)
++#  define TEST_OV(x)            ((void) 0)
+ #endif
+ 
+ #if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+@@ -3606,14 +5085,14 @@ DO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,
+                        lzo_voidp wrkmem )
+ #endif
+ {
+-    register lzo_bytep op;
+-    register const lzo_bytep ip;
+-    register lzo_uint t;
++    lzo_bytep op;
++    const lzo_bytep ip;
++    lzo_uint t;
+ #if defined(COPY_DICT)
+     lzo_uint m_off;
+     const lzo_bytep dict_end;
+ #else
+-    register const lzo_bytep m_pos;
++    const lzo_bytep m_pos;
+ #endif
+ 
+     const lzo_bytep const ip_end = in + in_len;
+@@ -3648,43 +5127,45 @@ DO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,
+     op = out;
+     ip = in;
+ 
++    NEED_IP(1);
+     if (*ip > 17)
+     {
+         t = *ip++ - 17;
+         if (t < 4)
+             goto match_next;
+-        assert(t > 0); NEED_OP(t); NEED_IP(t+1);
++        assert(t > 0); NEED_OP(t); NEED_IP(t+3);
+         do *op++ = *ip++; while (--t > 0);
+         goto first_literal_run;
+     }
+ 
+-    while (TEST_IP && TEST_OP)
++    for (;;)
+     {
++        NEED_IP(3);
+         t = *ip++;
+         if (t >= 16)
+             goto match;
+         if (t == 0)
+         {
+-            NEED_IP(1);
+             while (*ip == 0)
+             {
+                 t += 255;
+                 ip++;
++                TEST_IV(t);
+                 NEED_IP(1);
+             }
+             t += 15 + *ip++;
+         }
+-        assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
+-#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
++        assert(t > 0); NEED_OP(t+3); NEED_IP(t+6);
++#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)
+         t += 3;
+         if (t >= 8) do
+         {
+-            UA_COPY64(op,ip);
++            UA_COPY8(op,ip);
+             op += 8; ip += 8; t -= 8;
+         } while (t >= 8);
+         if (t >= 4)
+         {
+-            UA_COPY32(op,ip);
++            UA_COPY4(op,ip);
+             op += 4; ip += 4; t -= 4;
+         }
+         if (t > 0)
+@@ -3692,19 +5173,19 @@ DO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,
+             *op++ = *ip++;
+             if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+         }
+-#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+-#if !defined(LZO_UNALIGNED_OK_4)
++#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4)
++#if !(LZO_OPT_UNALIGNED32)
+         if (PTR_ALIGNED2_4(op,ip))
+         {
+ #endif
+-        UA_COPY32(op,ip);
++        UA_COPY4(op,ip);
+         op += 4; ip += 4;
+         if (--t > 0)
+         {
+             if (t >= 4)
+             {
+                 do {
+-                    UA_COPY32(op,ip);
++                    UA_COPY4(op,ip);
+                     op += 4; ip += 4; t -= 4;
+                 } while (t >= 4);
+                 if (t > 0) do *op++ = *ip++; while (--t > 0);
+@@ -3712,12 +5193,12 @@ DO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,
+             else
+                 do *op++ = *ip++; while (--t > 0);
+         }
+-#if !defined(LZO_UNALIGNED_OK_4)
++#if !(LZO_OPT_UNALIGNED32)
+         }
+         else
+ #endif
+ #endif
+-#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8)
++#if !(LZO_OPT_UNALIGNED32)
+         {
+             *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+             do *op++ = *ip++; while (--t > 0);
+@@ -3753,7 +5234,7 @@ first_literal_run:
+ #endif
+         goto match_done;
+ 
+-        do {
++        for (;;) {
+ match:
+             if (t >= 64)
+             {
+@@ -3813,14 +5294,15 @@ match:
+                 t &= 31;
+                 if (t == 0)
+                 {
+-                    NEED_IP(1);
+                     while (*ip == 0)
+                     {
+                         t += 255;
+                         ip++;
++                        TEST_OV(t);
+                         NEED_IP(1);
+                     }
+                     t += 31 + *ip++;
++                    NEED_IP(2);
+                 }
+ #if defined(COPY_DICT)
+ #if defined(LZO1Z)
+@@ -3836,9 +5318,9 @@ match:
+                     m_pos = op - off;
+                     last_m_off = off;
+                 }
+-#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
++#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)
+                 m_pos = op - 1;
+-                m_pos -= UA_GET16(ip) >> 2;
++                m_pos -= UA_GET_LE16(ip) >> 2;
+ #else
+                 m_pos = op - 1;
+                 m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+@@ -3857,14 +5339,15 @@ match:
+                 t &= 7;
+                 if (t == 0)
+                 {
+-                    NEED_IP(1);
+                     while (*ip == 0)
+                     {
+                         t += 255;
+                         ip++;
++                        TEST_OV(t);
+                         NEED_IP(1);
+                     }
+                     t += 7 + *ip++;
++                    NEED_IP(2);
+                 }
+ #if defined(COPY_DICT)
+ #if defined(LZO1Z)
+@@ -3882,8 +5365,8 @@ match:
+ #else
+ #if defined(LZO1Z)
+                 m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+-#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+-                m_pos -= UA_GET16(ip) >> 2;
++#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)
++                m_pos -= UA_GET_LE16(ip) >> 2;
+ #else
+                 m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+ #endif
+@@ -3931,18 +5414,18 @@ match:
+ #else
+ 
+             TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+-#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
++#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)
+             if (op - m_pos >= 8)
+             {
+                 t += (3 - 1);
+                 if (t >= 8) do
+                 {
+-                    UA_COPY64(op,m_pos);
++                    UA_COPY8(op,m_pos);
+                     op += 8; m_pos += 8; t -= 8;
+                 } while (t >= 8);
+                 if (t >= 4)
+                 {
+-                    UA_COPY32(op,m_pos);
++                    UA_COPY4(op,m_pos);
+                     op += 4; m_pos += 4; t -= 4;
+                 }
+                 if (t > 0)
+@@ -3952,8 +5435,8 @@ match:
+                 }
+             }
+             else
+-#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+-#if !defined(LZO_UNALIGNED_OK_4)
++#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4)
++#if !(LZO_OPT_UNALIGNED32)
+             if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+             {
+                 assert((op - m_pos) >= 4);
+@@ -3961,10 +5444,10 @@ match:
+             if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+             {
+ #endif
+-                UA_COPY32(op,m_pos);
++                UA_COPY4(op,m_pos);
+                 op += 4; m_pos += 4; t -= 4 - (3 - 1);
+                 do {
+-                    UA_COPY32(op,m_pos);
++                    UA_COPY4(op,m_pos);
+                     op += 4; m_pos += 4; t -= 4;
+                 } while (t >= 4);
+                 if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+@@ -3989,7 +5472,7 @@ match_done:
+                 break;
+ 
+ match_next:
+-            assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1);
++            assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+3);
+ #if 0
+             do *op++ = *ip++; while (--t > 0);
+ #else
+@@ -3997,16 +5480,10 @@ match_next:
+             if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+ #endif
+             t = *ip++;
+-        } while (TEST_IP && TEST_OP);
++        }
+     }
+ 
+-#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+-    *out_len = pd(op, out);
+-    return LZO_E_EOF_NOT_FOUND;
+-#endif
+-
+ eof_found:
+-    assert(t == 1);
+     *out_len = pd(op, out);
+     return (ip == ip_end ? LZO_E_OK :
+            (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+@@ -4052,10 +5529,13 @@ lookbehind_overrun:
+ 
+ #undef TEST_IP
+ #undef TEST_OP
++#undef TEST_IP_AND_TEST_OP
+ #undef TEST_LB
+ #undef TEST_LBO
+ #undef NEED_IP
+ #undef NEED_OP
++#undef TEST_IV
++#undef TEST_OV
+ #undef HAVE_TEST_IP
+ #undef HAVE_TEST_OP
+ #undef HAVE_NEED_IP
+@@ -4070,6 +5550,7 @@ lookbehind_overrun:
+ #  if (LZO_TEST_OVERRUN_INPUT >= 2)
+ #    define NEED_IP(x) \
+             if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun
++#    define TEST_IV(x)          if ((x) >  (lzo_uint)0 - (511)) goto input_overrun
+ #  endif
+ #endif
+ 
+@@ -4081,12 +5562,13 @@ lookbehind_overrun:
+ #    undef TEST_OP
+ #    define NEED_OP(x) \
+             if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun
++#    define TEST_OV(x)          if ((x) >  (lzo_uint)0 - (511)) goto output_overrun
+ #  endif
+ #endif
+ 
+ #if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+-#  define TEST_LB(m_pos)        if (m_pos < out || m_pos >= op) goto lookbehind_overrun
+-#  define TEST_LBO(m_pos,o)     if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun
++#  define TEST_LB(m_pos)        if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op)) goto lookbehind_overrun
++#  define TEST_LBO(m_pos,o)     if (PTR_LT(m_pos,out) || PTR_GE(m_pos,op-(o))) goto lookbehind_overrun
+ #else
+ #  define TEST_LB(m_pos)        ((void) 0)
+ #  define TEST_LBO(m_pos,o)     ((void) 0)
+@@ -4107,15 +5589,27 @@ lookbehind_overrun:
+ #  define TEST_OP               1
+ #endif
+ 
++#if defined(HAVE_TEST_IP) && defined(HAVE_TEST_OP)
++#  define TEST_IP_AND_TEST_OP   (TEST_IP && TEST_OP)
++#elif defined(HAVE_TEST_IP)
++#  define TEST_IP_AND_TEST_OP   TEST_IP
++#elif defined(HAVE_TEST_OP)
++#  define TEST_IP_AND_TEST_OP   TEST_OP
++#else
++#  define TEST_IP_AND_TEST_OP   1
++#endif
++
+ #if defined(NEED_IP)
+ #  define HAVE_NEED_IP 1
+ #else
+ #  define NEED_IP(x)            ((void) 0)
++#  define TEST_IV(x)            ((void) 0)
+ #endif
+ #if defined(NEED_OP)
+ #  define HAVE_NEED_OP 1
+ #else
+ #  define NEED_OP(x)            ((void) 0)
++#  define TEST_OV(x)            ((void) 0)
+ #endif
+ 
+ #if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+@@ -4132,14 +5626,14 @@ DO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,
+                        lzo_voidp wrkmem )
+ #endif
+ {
+-    register lzo_bytep op;
+-    register const lzo_bytep ip;
+-    register lzo_uint t;
++    lzo_bytep op;
++    const lzo_bytep ip;
++    lzo_uint t;
+ #if defined(COPY_DICT)
+     lzo_uint m_off;
+     const lzo_bytep dict_end;
+ #else
+-    register const lzo_bytep m_pos;
++    const lzo_bytep m_pos;
+ #endif
+ 
+     const lzo_bytep const ip_end = in + in_len;
+@@ -4174,43 +5668,45 @@ DO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,
+     op = out;
+     ip = in;
+ 
++    NEED_IP(1);
+     if (*ip > 17)
+     {
+         t = *ip++ - 17;
+         if (t < 4)
+             goto match_next;
+-        assert(t > 0); NEED_OP(t); NEED_IP(t+1);
++        assert(t > 0); NEED_OP(t); NEED_IP(t+3);
+         do *op++ = *ip++; while (--t > 0);
+         goto first_literal_run;
+     }
+ 
+-    while (TEST_IP && TEST_OP)
++    for (;;)
+     {
++        NEED_IP(3);
+         t = *ip++;
+         if (t >= 16)
+             goto match;
+         if (t == 0)
+         {
+-            NEED_IP(1);
+             while (*ip == 0)
+             {
+                 t += 255;
+                 ip++;
++                TEST_IV(t);
+                 NEED_IP(1);
+             }
+             t += 15 + *ip++;
+         }
+-        assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
+-#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
++        assert(t > 0); NEED_OP(t+3); NEED_IP(t+6);
++#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)
+         t += 3;
+         if (t >= 8) do
+         {
+-            UA_COPY64(op,ip);
++            UA_COPY8(op,ip);
+             op += 8; ip += 8; t -= 8;
+         } while (t >= 8);
+         if (t >= 4)
+         {
+-            UA_COPY32(op,ip);
++            UA_COPY4(op,ip);
+             op += 4; ip += 4; t -= 4;
+         }
+         if (t > 0)
+@@ -4218,19 +5714,19 @@ DO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,
+             *op++ = *ip++;
+             if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+         }
+-#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+-#if !defined(LZO_UNALIGNED_OK_4)
++#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4)
++#if !(LZO_OPT_UNALIGNED32)
+         if (PTR_ALIGNED2_4(op,ip))
+         {
+ #endif
+-        UA_COPY32(op,ip);
++        UA_COPY4(op,ip);
+         op += 4; ip += 4;
+         if (--t > 0)
+         {
+             if (t >= 4)
+             {
+                 do {
+-                    UA_COPY32(op,ip);
++                    UA_COPY4(op,ip);
+                     op += 4; ip += 4; t -= 4;
+                 } while (t >= 4);
+                 if (t > 0) do *op++ = *ip++; while (--t > 0);
+@@ -4238,12 +5734,12 @@ DO_DECOMPRESS  ( const lzo_bytep in , lzo_uint  in_len,
+             else
+                 do *op++ = *ip++; while (--t > 0);
+         }
+-#if !defined(LZO_UNALIGNED_OK_4)
++#if !(LZO_OPT_UNALIGNED32)
+         }
+         else
+ #endif
+ #endif
+-#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8)
++#if !(LZO_OPT_UNALIGNED32)
+         {
+             *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+             do *op++ = *ip++; while (--t > 0);
+@@ -4279,7 +5775,7 @@ first_literal_run:
+ #endif
+         goto match_done;
+ 
+-        do {
++        for (;;) {
+ match:
+             if (t >= 64)
+             {
+@@ -4339,14 +5835,15 @@ match:
+                 t &= 31;
+                 if (t == 0)
+                 {
+-                    NEED_IP(1);
+                     while (*ip == 0)
+                     {
+                         t += 255;
+                         ip++;
++                        TEST_OV(t);
+                         NEED_IP(1);
+                     }
+                     t += 31 + *ip++;
++                    NEED_IP(2);
+                 }
+ #if defined(COPY_DICT)
+ #if defined(LZO1Z)
+@@ -4362,9 +5859,9 @@ match:
+                     m_pos = op - off;
+                     last_m_off = off;
+                 }
+-#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
++#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)
+                 m_pos = op - 1;
+-                m_pos -= UA_GET16(ip) >> 2;
++                m_pos -= UA_GET_LE16(ip) >> 2;
+ #else
+                 m_pos = op - 1;
+                 m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+@@ -4383,14 +5880,15 @@ match:
+                 t &= 7;
+                 if (t == 0)
+                 {
+-                    NEED_IP(1);
+                     while (*ip == 0)
+                     {
+                         t += 255;
+                         ip++;
++                        TEST_OV(t);
+                         NEED_IP(1);
+                     }
+                     t += 7 + *ip++;
++                    NEED_IP(2);
+                 }
+ #if defined(COPY_DICT)
+ #if defined(LZO1Z)
+@@ -4408,8 +5906,8 @@ match:
+ #else
+ #if defined(LZO1Z)
+                 m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+-#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+-                m_pos -= UA_GET16(ip) >> 2;
++#elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)
++                m_pos -= UA_GET_LE16(ip) >> 2;
+ #else
+                 m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+ #endif
+@@ -4457,18 +5955,18 @@ match:
+ #else
+ 
+             TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+-#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
++#if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)
+             if (op - m_pos >= 8)
+             {
+                 t += (3 - 1);
+                 if (t >= 8) do
+                 {
+-                    UA_COPY64(op,m_pos);
++                    UA_COPY8(op,m_pos);
+                     op += 8; m_pos += 8; t -= 8;
+                 } while (t >= 8);
+                 if (t >= 4)
+                 {
+-                    UA_COPY32(op,m_pos);
++                    UA_COPY4(op,m_pos);
+                     op += 4; m_pos += 4; t -= 4;
+                 }
+                 if (t > 0)
+@@ -4478,8 +5976,8 @@ match:
+                 }
+             }
+             else
+-#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+-#if !defined(LZO_UNALIGNED_OK_4)
++#elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4)
++#if !(LZO_OPT_UNALIGNED32)
+             if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+             {
+                 assert((op - m_pos) >= 4);
+@@ -4487,10 +5985,10 @@ match:
+             if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+             {
+ #endif
+-                UA_COPY32(op,m_pos);
++                UA_COPY4(op,m_pos);
+                 op += 4; m_pos += 4; t -= 4 - (3 - 1);
+                 do {
+-                    UA_COPY32(op,m_pos);
++                    UA_COPY4(op,m_pos);
+                     op += 4; m_pos += 4; t -= 4;
+                 } while (t >= 4);
+                 if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+@@ -4515,7 +6013,7 @@ match_done:
+                 break;
+ 
+ match_next:
+-            assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1);
++            assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+3);
+ #if 0
+             do *op++ = *ip++; while (--t > 0);
+ #else
+@@ -4523,16 +6021,10 @@ match_next:
+             if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+ #endif
+             t = *ip++;
+-        } while (TEST_IP && TEST_OP);
++        }
+     }
+ 
+-#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+-    *out_len = pd(op, out);
+-    return LZO_E_EOF_NOT_FOUND;
+-#endif
+-
+ eof_found:
+-    assert(t == 1);
+     *out_len = pd(op, out);
+     return (ip == ip_end ? LZO_E_OK :
+            (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+@@ -4559,4 +6051,3 @@ lookbehind_overrun:
+ #endif
+ 
+ /***** End of minilzo.c *****/
+-
+diff --git a/grub-core/lib/minilzo/lzoconf.h b/grub-core/lib/minilzo/lzoconf.h
+index 1d0fe14fcda..61be29c5dc2 100644
+--- a/grub-core/lib/minilzo/lzoconf.h
++++ b/grub-core/lib/minilzo/lzoconf.h
+@@ -2,22 +2,7 @@
+ 
+    This file is part of the LZO real-time data compression library.
+ 
+-   Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
++   Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
+    All Rights Reserved.
+ 
+    The LZO library is free software; you can redistribute it and/or
+@@ -44,9 +29,9 @@
+ #ifndef __LZOCONF_H_INCLUDED
+ #define __LZOCONF_H_INCLUDED 1
+ 
+-#define LZO_VERSION             0x2050
+-#define LZO_VERSION_STRING      "2.05"
+-#define LZO_VERSION_DATE        "Apr 23 2011"
++#define LZO_VERSION             0x2080
++#define LZO_VERSION_STRING      "2.08"
++#define LZO_VERSION_DATE        "Jun 29 2014"
+ 
+ /* internal Autoconf configuration file - only used when building LZO */
+ #if defined(LZO_HAVE_CONFIG_H)
+@@ -63,7 +48,7 @@
+ #if !defined(CHAR_BIT) || (CHAR_BIT != 8)
+ #  error "invalid CHAR_BIT"
+ #endif
+-#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
++#if !defined(UCHAR_MAX) || !defined(USHRT_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
+ #  error "check your compiler installation"
+ #endif
+ #if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
+@@ -85,14 +70,6 @@ extern "C" {
+ // some core defines
+ ************************************************************************/
+ 
+-#if !defined(LZO_UINT32_C)
+-#  if (UINT_MAX < LZO_0xffffffffL)
+-#    define LZO_UINT32_C(c)     c ## UL
+-#  else
+-#    define LZO_UINT32_C(c)     ((c) + 0U)
+-#  endif
+-#endif
+-
+ /* memory checkers */
+ #if !defined(__LZO_CHECKER)
+ #  if defined(__BOUNDS_CHECKING_ON)
+@@ -111,28 +88,31 @@ extern "C" {
+ // integral and pointer types
+ ************************************************************************/
+ 
+-/* lzo_uint should match size_t */
++/* lzo_uint must match size_t */
+ #if !defined(LZO_UINT_MAX)
+-#  if defined(LZO_ABI_LLP64) /* WIN64 */
+-#    if defined(LZO_OS_WIN64)
++#  if (LZO_ABI_LLP64)
++#    if (LZO_OS_WIN64)
+      typedef unsigned __int64   lzo_uint;
+      typedef __int64            lzo_int;
+ #    else
+-     typedef unsigned long long lzo_uint;
+-     typedef long long          lzo_int;
++     typedef lzo_ullong_t       lzo_uint;
++     typedef lzo_llong_t        lzo_int;
+ #    endif
++#    define LZO_SIZEOF_LZO_UINT 8
+ #    define LZO_UINT_MAX        0xffffffffffffffffull
+ #    define LZO_INT_MAX         9223372036854775807LL
+ #    define LZO_INT_MIN         (-1LL - LZO_INT_MAX)
+-#  elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */
++#  elif (LZO_ABI_IP32L64) /* MIPS R5900 */
+      typedef unsigned int       lzo_uint;
+      typedef int                lzo_int;
++#    define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_INT
+ #    define LZO_UINT_MAX        UINT_MAX
+ #    define LZO_INT_MAX         INT_MAX
+ #    define LZO_INT_MIN         INT_MIN
+ #  elif (ULONG_MAX >= LZO_0xffffffffL)
+      typedef unsigned long      lzo_uint;
+      typedef long               lzo_int;
++#    define LZO_SIZEOF_LZO_UINT LZO_SIZEOF_LONG
+ #    define LZO_UINT_MAX        ULONG_MAX
+ #    define LZO_INT_MAX         LONG_MAX
+ #    define LZO_INT_MIN         LONG_MIN
+@@ -141,63 +121,22 @@ extern "C" {
+ #  endif
+ #endif
+ 
+-/* Integral types with 32 bits or more. */
+-#if !defined(LZO_UINT32_MAX)
+-#  if (UINT_MAX >= LZO_0xffffffffL)
+-     typedef unsigned int       lzo_uint32;
+-     typedef int                lzo_int32;
+-#    define LZO_UINT32_MAX      UINT_MAX
+-#    define LZO_INT32_MAX       INT_MAX
+-#    define LZO_INT32_MIN       INT_MIN
+-#  elif (ULONG_MAX >= LZO_0xffffffffL)
+-     typedef unsigned long      lzo_uint32;
+-     typedef long               lzo_int32;
+-#    define LZO_UINT32_MAX      ULONG_MAX
+-#    define LZO_INT32_MAX       LONG_MAX
+-#    define LZO_INT32_MIN       LONG_MIN
+-#  else
+-#    error "lzo_uint32"
+-#  endif
+-#endif
+-
+-/* Integral types with exactly 64 bits. */
+-#if !defined(LZO_UINT64_MAX)
+-#  if (LZO_UINT_MAX >= LZO_0xffffffffL)
+-#   if ((((LZO_UINT_MAX) >> 31) >> 31) == 3)
+-#    define lzo_uint64          lzo_uint
+-#    define lzo_int64           lzo_int
+-#    define LZO_UINT64_MAX      LZO_UINT_MAX
+-#    define LZO_INT64_MAX       LZO_INT_MAX
+-#    define LZO_INT64_MIN       LZO_INT_MIN
+-#   endif
+-#  elif (ULONG_MAX >= LZO_0xffffffffL)
+-#   if ((((ULONG_MAX) >> 31) >> 31) == 3)
+-     typedef unsigned long      lzo_uint64;
+-     typedef long               lzo_int64;
+-#    define LZO_UINT64_MAX      ULONG_MAX
+-#    define LZO_INT64_MAX       LONG_MAX
+-#    define LZO_INT64_MIN       LONG_MIN
+-#   endif
+-#  endif
+-#endif
+-
+-/* The larger type of lzo_uint and lzo_uint32. */
+-#if (LZO_UINT_MAX >= LZO_UINT32_MAX)
++/* The larger type of lzo_uint and lzo_uint32_t. */
++#if (LZO_SIZEOF_LZO_UINT >= 4)
+ #  define lzo_xint              lzo_uint
+ #else
+-#  define lzo_xint              lzo_uint32
++#  define lzo_xint              lzo_uint32_t
+ #endif
+ 
+-/* Memory model that allows to access memory at offsets of lzo_uint. */
+-#if !defined(__LZO_MMODEL)
+-#  if (LZO_UINT_MAX <= UINT_MAX)
+-#    define __LZO_MMODEL        /*empty*/
+-#  elif defined(LZO_HAVE_MM_HUGE_PTR)
+-#    define __LZO_MMODEL_HUGE   1
+-#    define __LZO_MMODEL        __huge
+-#  else
+-#    define __LZO_MMODEL        /*empty*/
+-#  endif
++typedef int lzo_bool;
++
++/* sanity checks */
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == LZO_SIZEOF_LZO_UINT)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint))
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_xint) >= sizeof(lzo_uint32_t))
++
++#ifndef __LZO_MMODEL
++#define __LZO_MMODEL            /*empty*/
+ #endif
+ 
+ /* no typedef here because of const-pointer issues */
+@@ -206,21 +145,52 @@ extern "C" {
+ #define lzo_voidp               void __LZO_MMODEL *
+ #define lzo_shortp              short __LZO_MMODEL *
+ #define lzo_ushortp             unsigned short __LZO_MMODEL *
+-#define lzo_uint32p             lzo_uint32 __LZO_MMODEL *
+-#define lzo_int32p              lzo_int32 __LZO_MMODEL *
+-#if defined(LZO_UINT64_MAX)
+-#define lzo_uint64p             lzo_uint64 __LZO_MMODEL *
+-#define lzo_int64p              lzo_int64 __LZO_MMODEL *
+-#endif
+-#define lzo_uintp               lzo_uint __LZO_MMODEL *
+ #define lzo_intp                lzo_int __LZO_MMODEL *
++#define lzo_uintp               lzo_uint __LZO_MMODEL *
+ #define lzo_xintp               lzo_xint __LZO_MMODEL *
+ #define lzo_voidpp              lzo_voidp __LZO_MMODEL *
+ #define lzo_bytepp              lzo_bytep __LZO_MMODEL *
+-/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */
+-#define lzo_byte                unsigned char __LZO_MMODEL
+ 
+-typedef int lzo_bool;
++#define lzo_int8_tp             lzo_int8_t __LZO_MMODEL *
++#define lzo_uint8_tp            lzo_uint8_t __LZO_MMODEL *
++#define lzo_int16_tp            lzo_int16_t __LZO_MMODEL *
++#define lzo_uint16_tp           lzo_uint16_t __LZO_MMODEL *
++#define lzo_int32_tp            lzo_int32_t __LZO_MMODEL *
++#define lzo_uint32_tp           lzo_uint32_t __LZO_MMODEL *
++#if defined(lzo_int64_t)
++#define lzo_int64_tp            lzo_int64_t __LZO_MMODEL *
++#define lzo_uint64_tp           lzo_uint64_t __LZO_MMODEL *
++#endif
++
++/* Older LZO versions used to support ancient systems and memory models
++ * like 16-bit MSDOS with __huge pointers and Cray PVP, but these
++ * obsolete configurations are not supported any longer.
++ */
++#if defined(__LZO_MMODEL_HUGE)
++#error "__LZO_MMODEL_HUGE is unsupported"
++#endif
++#if (LZO_MM_PVP)
++#error "LZO_MM_PVP is unsupported"
++#endif
++#if (LZO_SIZEOF_INT < 4)
++#error "LZO_SIZEOF_INT < 4 is unsupported"
++#endif
++#if (__LZO_UINTPTR_T_IS_POINTER)
++#error "__LZO_UINTPTR_T_IS_POINTER is unsupported"
++#endif
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int) >= 4)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) >= 4)
++/* Strange configurations where sizeof(lzo_uint) != sizeof(size_t) should
++ * work but have not received much testing lately, so be strict here.
++ */
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(size_t))
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(ptrdiff_t))
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint) == sizeof(lzo_uintptr_t))
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *)   == sizeof(lzo_uintptr_t))
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *)   == sizeof(lzo_uintptr_t))
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long *)   == sizeof(lzo_uintptr_t))
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(void *)   == sizeof(lzo_voidp))
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(char *)   == sizeof(lzo_bytep))
+ 
+ 
+ /***********************************************************************
+@@ -315,7 +285,7 @@ struct lzo_callback_t
+     /* a progress indicator callback function (set to 0 to disable) */
+     lzo_progress_func_t nprogress;
+ 
+-    /* NOTE: the first parameter "self" of the nalloc/nfree/nprogress
++    /* INFO: the first parameter "self" of the nalloc/nfree/nprogress
+      * callbacks points back to this struct, so you are free to store
+      * some extra info in the following variables. */
+     lzo_voidp user1;
+@@ -343,6 +313,9 @@ struct lzo_callback_t
+ #define LZO_E_INPUT_NOT_CONSUMED    (-8)
+ #define LZO_E_NOT_YET_IMPLEMENTED   (-9)    /* [not used right now] */
+ #define LZO_E_INVALID_ARGUMENT      (-10)
++#define LZO_E_INVALID_ALIGNMENT     (-11)   /* pointer argument is not properly aligned */
++#define LZO_E_OUTPUT_NOT_CONSUMED   (-12)
++#define LZO_E_INTERNAL_ERROR        (-99)
+ 
+ 
+ #ifndef lzo_sizeof_dict_t
+@@ -356,7 +329,7 @@ struct lzo_callback_t
+  * compiler's view of various types are consistent.
+  */
+ #define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
+-    (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\
++    (int)sizeof(long),(int)sizeof(lzo_uint32_t),(int)sizeof(lzo_uint),\
+     (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
+     (int)sizeof(lzo_callback_t))
+ LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int);
+@@ -379,18 +352,22 @@ LZO_EXTERN(lzo_voidp)
+     lzo_memset(lzo_voidp buf, int c, lzo_uint len);
+ 
+ /* checksum functions */
+-LZO_EXTERN(lzo_uint32)
+-    lzo_adler32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
+-LZO_EXTERN(lzo_uint32)
+-    lzo_crc32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
+-LZO_EXTERN(const lzo_uint32p)
++LZO_EXTERN(lzo_uint32_t)
++    lzo_adler32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len);
++LZO_EXTERN(lzo_uint32_t)
++    lzo_crc32(lzo_uint32_t c, const lzo_bytep buf, lzo_uint len);
++LZO_EXTERN(const lzo_uint32_tp)
+     lzo_get_crc32_table(void);
+ 
+ /* misc. */
+ LZO_EXTERN(int) _lzo_config_check(void);
+-typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
+-typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
+-typedef union { void *vp; lzo_bytep bp; lzo_uint u; lzo_uint32 u32; unsigned long l; } lzo_align_t;
++typedef union {
++    lzo_voidp a00; lzo_bytep a01; lzo_uint a02; lzo_xint a03; lzo_uintptr_t a04;
++    void *a05; unsigned char *a06; unsigned long a07; size_t a08; ptrdiff_t a09;
++#if defined(lzo_int64_t)
++    lzo_uint64_t a10;
++#endif
++} lzo_align_t;
+ 
+ /* align a char pointer on a boundary that is a multiple of 'size' */
+ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
+@@ -399,9 +376,30 @@ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
+ 
+ 
+ /***********************************************************************
+-// deprecated macros - only for backward compatibility with LZO v1.xx
++// deprecated macros - only for backward compatibility
+ ************************************************************************/
+ 
++/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */
++#define lzo_byte                unsigned char
++/* deprecated type names */
++#define lzo_int32               lzo_int32_t
++#define lzo_uint32              lzo_uint32_t
++#define lzo_int32p              lzo_int32_t __LZO_MMODEL *
++#define lzo_uint32p             lzo_uint32_t __LZO_MMODEL *
++#define LZO_INT32_MAX           LZO_INT32_C(2147483647)
++#define LZO_UINT32_MAX          LZO_UINT32_C(4294967295)
++#if defined(lzo_int64_t)
++#define lzo_int64               lzo_int64_t
++#define lzo_uint64              lzo_uint64_t
++#define lzo_int64p              lzo_int64_t __LZO_MMODEL *
++#define lzo_uint64p             lzo_uint64_t __LZO_MMODEL *
++#define LZO_INT64_MAX           LZO_INT64_C(9223372036854775807)
++#define LZO_UINT64_MAX          LZO_UINT64_C(18446744073709551615)
++#endif
++/* deprecated types */
++typedef union { lzo_bytep a; lzo_uint b; } __lzo_pu_u;
++typedef union { lzo_bytep a; lzo_uint32_t b; } __lzo_pu32_u;
++
+ #if defined(LZO_CFG_COMPAT)
+ 
+ #define __LZOCONF_H 1
+@@ -443,4 +441,4 @@ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
+ #endif /* already included */
+ 
+ 
+-/* vim:set ts=4 et: */
++/* vim:set ts=4 sw=4 et: */
+diff --git a/grub-core/lib/minilzo/lzodefs.h b/grub-core/lib/minilzo/lzodefs.h
+index 0e40e332a8d..f4ae9487ebe 100644
+--- a/grub-core/lib/minilzo/lzodefs.h
++++ b/grub-core/lib/minilzo/lzodefs.h
+@@ -2,22 +2,7 @@
+ 
+    This file is part of the LZO real-time data compression library.
+ 
+-   Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
++   Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
+    All Rights Reserved.
+ 
+    The LZO library is free software; you can redistribute it and/or
+@@ -47,12 +32,6 @@
+ #if defined(__CYGWIN32__) && !defined(__CYGWIN__)
+ #  define __CYGWIN__ __CYGWIN32__
+ #endif
+-#if defined(__IBMCPP__) && !defined(__IBMC__)
+-#  define __IBMC__ __IBMCPP__
+-#endif
+-#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER)
+-#  define __INTEL_COMPILER __ICL
+-#endif
+ #if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE)
+ #  define _ALL_SOURCE 1
+ #endif
+@@ -61,19 +40,30 @@
+ #    define __LONG_MAX__ 9223372036854775807L
+ #  endif
+ #endif
+-#if defined(__INTEL_COMPILER) && defined(__linux__)
++#if !defined(LZO_CFG_NO_DISABLE_WUNDEF)
++#if defined(__ARMCC_VERSION)
++#  pragma diag_suppress 193
++#elif defined(__clang__) && defined(__clang_minor__)
++#  pragma clang diagnostic ignored "-Wundef"
++#elif defined(__INTEL_COMPILER)
+ #  pragma warning(disable: 193)
+-#endif
+-#if defined(__KEIL__) && defined(__C166__)
++#elif defined(__KEIL__) && defined(__C166__)
+ #  pragma warning disable = 322
+-#elif 0 && defined(__C251__)
+-#  pragma warning disable = 322
+-#endif
+-#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__)
+-#  if (_MSC_VER >= 1300)
++#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__PATHSCALE__)
++#  if ((__GNUC__-0) >= 5 || ((__GNUC__-0) == 4 && (__GNUC_MINOR__-0) >= 2))
++#    pragma GCC diagnostic ignored "-Wundef"
++#  endif
++#elif defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__)
++#  if ((_MSC_VER-0) >= 1300)
+ #    pragma warning(disable: 4668)
+ #  endif
+ #endif
++#endif
++#if 0 && defined(__POCC__) && defined(_WIN32)
++#  if (__POCC__ >= 400)
++#    pragma warn(disable: 2216)
++#  endif
++#endif
+ #if 0 && defined(__WATCOMC__)
+ #  if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060)
+ #    pragma warning 203 9
+@@ -82,13 +72,29 @@
+ #if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__)
+ #  pragma option -h
+ #endif
++#if !(LZO_CFG_NO_DISABLE_WCRTNONSTDC)
++#ifndef _CRT_NONSTDC_NO_DEPRECATE
++#define _CRT_NONSTDC_NO_DEPRECATE 1
++#endif
++#ifndef _CRT_NONSTDC_NO_WARNINGS
++#define _CRT_NONSTDC_NO_WARNINGS 1
++#endif
++#ifndef _CRT_SECURE_NO_DEPRECATE
++#define _CRT_SECURE_NO_DEPRECATE 1
++#endif
++#ifndef _CRT_SECURE_NO_WARNINGS
++#define _CRT_SECURE_NO_WARNINGS 1
++#endif
++#endif
+ #if 0
+-#define LZO_0xffffL             0xfffful
+-#define LZO_0xffffffffL         0xfffffffful
++#define LZO_0xffffUL            0xfffful
++#define LZO_0xffffffffUL        0xfffffffful
+ #else
+-#define LZO_0xffffL             65535ul
+-#define LZO_0xffffffffL         4294967295ul
++#define LZO_0xffffUL            65535ul
++#define LZO_0xffffffffUL        4294967295ul
+ #endif
++#define LZO_0xffffL             LZO_0xffffUL
++#define LZO_0xffffffffL         LZO_0xffffffffUL
+ #if (LZO_0xffffL == LZO_0xffffffffL)
+ #  error "your preprocessor is broken 1"
+ #endif
+@@ -103,6 +109,13 @@
+ #  error "your preprocessor is broken 4"
+ #endif
+ #endif
++#if defined(__COUNTER__)
++#  ifndef LZO_CFG_USE_COUNTER
++#  define LZO_CFG_USE_COUNTER 1
++#  endif
++#else
++#  undef LZO_CFG_USE_COUNTER
++#endif
+ #if (UINT_MAX == LZO_0xffffL)
+ #if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__)
+ #  if !defined(MSDOS)
+@@ -233,14 +246,31 @@
+ #endif
+ #define LZO_PP_STRINGIZE(x)             #x
+ #define LZO_PP_MACRO_EXPAND(x)          LZO_PP_STRINGIZE(x)
++#define LZO_PP_CONCAT0()                /*empty*/
++#define LZO_PP_CONCAT1(a)               a
+ #define LZO_PP_CONCAT2(a,b)             a ## b
+ #define LZO_PP_CONCAT3(a,b,c)           a ## b ## c
+ #define LZO_PP_CONCAT4(a,b,c,d)         a ## b ## c ## d
+ #define LZO_PP_CONCAT5(a,b,c,d,e)       a ## b ## c ## d ## e
++#define LZO_PP_CONCAT6(a,b,c,d,e,f)     a ## b ## c ## d ## e ## f
++#define LZO_PP_CONCAT7(a,b,c,d,e,f,g)   a ## b ## c ## d ## e ## f ## g
++#define LZO_PP_ECONCAT0()               LZO_PP_CONCAT0()
++#define LZO_PP_ECONCAT1(a)              LZO_PP_CONCAT1(a)
+ #define LZO_PP_ECONCAT2(a,b)            LZO_PP_CONCAT2(a,b)
+ #define LZO_PP_ECONCAT3(a,b,c)          LZO_PP_CONCAT3(a,b,c)
+ #define LZO_PP_ECONCAT4(a,b,c,d)        LZO_PP_CONCAT4(a,b,c,d)
+ #define LZO_PP_ECONCAT5(a,b,c,d,e)      LZO_PP_CONCAT5(a,b,c,d,e)
++#define LZO_PP_ECONCAT6(a,b,c,d,e,f)    LZO_PP_CONCAT6(a,b,c,d,e,f)
++#define LZO_PP_ECONCAT7(a,b,c,d,e,f,g)  LZO_PP_CONCAT7(a,b,c,d,e,f,g)
++#define LZO_PP_EMPTY                    /*empty*/
++#define LZO_PP_EMPTY0()                 /*empty*/
++#define LZO_PP_EMPTY1(a)                /*empty*/
++#define LZO_PP_EMPTY2(a,b)              /*empty*/
++#define LZO_PP_EMPTY3(a,b,c)            /*empty*/
++#define LZO_PP_EMPTY4(a,b,c,d)          /*empty*/
++#define LZO_PP_EMPTY5(a,b,c,d,e)        /*empty*/
++#define LZO_PP_EMPTY6(a,b,c,d,e,f)      /*empty*/
++#define LZO_PP_EMPTY7(a,b,c,d,e,f,g)    /*empty*/
+ #if 1
+ #define LZO_CPP_STRINGIZE(x)            #x
+ #define LZO_CPP_MACRO_EXPAND(x)         LZO_CPP_STRINGIZE(x)
+@@ -248,12 +278,16 @@
+ #define LZO_CPP_CONCAT3(a,b,c)          a ## b ## c
+ #define LZO_CPP_CONCAT4(a,b,c,d)        a ## b ## c ## d
+ #define LZO_CPP_CONCAT5(a,b,c,d,e)      a ## b ## c ## d ## e
++#define LZO_CPP_CONCAT6(a,b,c,d,e,f)    a ## b ## c ## d ## e ## f
++#define LZO_CPP_CONCAT7(a,b,c,d,e,f,g)  a ## b ## c ## d ## e ## f ## g
+ #define LZO_CPP_ECONCAT2(a,b)           LZO_CPP_CONCAT2(a,b)
+ #define LZO_CPP_ECONCAT3(a,b,c)         LZO_CPP_CONCAT3(a,b,c)
+ #define LZO_CPP_ECONCAT4(a,b,c,d)       LZO_CPP_CONCAT4(a,b,c,d)
+ #define LZO_CPP_ECONCAT5(a,b,c,d,e)     LZO_CPP_CONCAT5(a,b,c,d,e)
++#define LZO_CPP_ECONCAT6(a,b,c,d,e,f)   LZO_CPP_CONCAT6(a,b,c,d,e,f)
++#define LZO_CPP_ECONCAT7(a,b,c,d,e,f,g) LZO_CPP_CONCAT7(a,b,c,d,e,f,g)
+ #endif
+-#define __LZO_MASK_GEN(o,b)     (((((o) << ((b)-1)) - (o)) << 1) + (o))
++#define __LZO_MASK_GEN(o,b)     (((((o) << ((b)-!!(b))) - (o)) << 1) + (o)*!!(b))
+ #if 1 && defined(__cplusplus)
+ #  if !defined(__STDC_CONSTANT_MACROS)
+ #    define __STDC_CONSTANT_MACROS 1
+@@ -263,9 +297,13 @@
+ #  endif
+ #endif
+ #if defined(__cplusplus)
+-#  define LZO_EXTERN_C extern "C"
++#  define LZO_EXTERN_C          extern "C"
++#  define LZO_EXTERN_C_BEGIN    extern "C" {
++#  define LZO_EXTERN_C_END      }
+ #else
+-#  define LZO_EXTERN_C extern
++#  define LZO_EXTERN_C          extern
++#  define LZO_EXTERN_C_BEGIN    /*empty*/
++#  define LZO_EXTERN_C_END      /*empty*/
+ #endif
+ #if !defined(__LZO_OS_OVERRIDE)
+ #if (LZO_OS_FREESTANDING)
+@@ -366,12 +404,12 @@
+ #elif defined(__VMS)
+ #  define LZO_OS_VMS            1
+ #  define LZO_INFO_OS           "vms"
+-#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
++#elif (defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)
+ #  define LZO_OS_CONSOLE        1
+ #  define LZO_OS_CONSOLE_PS2    1
+ #  define LZO_INFO_OS           "console"
+ #  define LZO_INFO_OS_CONSOLE   "ps2"
+-#elif (defined(__mips__) && defined(__psp__))
++#elif defined(__mips__) && defined(__psp__)
+ #  define LZO_OS_CONSOLE        1
+ #  define LZO_OS_CONSOLE_PSP    1
+ #  define LZO_INFO_OS           "console"
+@@ -399,9 +437,18 @@
+ #  elif defined(__linux__) || defined(__linux) || defined(__LINUX__)
+ #    define LZO_OS_POSIX_LINUX      1
+ #    define LZO_INFO_OS_POSIX       "linux"
+-#  elif defined(__APPLE__) || defined(__MACOS__)
+-#    define LZO_OS_POSIX_MACOSX     1
+-#    define LZO_INFO_OS_POSIX       "macosx"
++#  elif defined(__APPLE__) && defined(__MACH__)
++#    if ((__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__-0) >= 20000)
++#      define LZO_OS_POSIX_DARWIN     1040
++#      define LZO_INFO_OS_POSIX       "darwin_iphone"
++#    elif ((__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0) >= 1040)
++#      define LZO_OS_POSIX_DARWIN     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
++#      define LZO_INFO_OS_POSIX       "darwin"
++#    else
++#      define LZO_OS_POSIX_DARWIN     1
++#      define LZO_INFO_OS_POSIX       "darwin"
++#    endif
++#    define LZO_OS_POSIX_MACOSX     LZO_OS_POSIX_DARWIN
+ #  elif defined(__minix__) || defined(__minix)
+ #    define LZO_OS_POSIX_MINIX      1
+ #    define LZO_INFO_OS_POSIX       "minix"
+@@ -436,18 +483,18 @@
+ #endif
+ #if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+ #  if (UINT_MAX != LZO_0xffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #  if (ULONG_MAX != LZO_0xffffffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #endif
+ #if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64)
+ #  if (UINT_MAX != LZO_0xffffffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #  if (ULONG_MAX != LZO_0xffffffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #endif
+ #if defined(CIL) && defined(_GNUCC) && defined(__GNUC__)
+@@ -463,59 +510,65 @@
+ #  define LZO_INFO_CC           "sdcc"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(SDCC)
+ #elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__)
+-#  define LZO_CC_PATHSCALE      (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__)
++#  define LZO_CC_PATHSCALE      (__PATHCC__ * 0x10000L + (__PATHCC_MINOR__-0) * 0x100 + (__PATHCC_PATCHLEVEL__-0))
+ #  define LZO_INFO_CC           "Pathscale C"
+ #  define LZO_INFO_CCVER        __PATHSCALE__
+-#elif defined(__INTEL_COMPILER)
+-#  define LZO_CC_INTELC         1
++#  if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
++#    define LZO_CC_PATHSCALE_GNUC (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
++#  endif
++#elif defined(__INTEL_COMPILER) && ((__INTEL_COMPILER-0) > 0)
++#  define LZO_CC_INTELC         __INTEL_COMPILER
+ #  define LZO_INFO_CC           "Intel C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__INTEL_COMPILER)
+-#  if defined(_WIN32) || defined(_WIN64)
+-#    define LZO_CC_SYNTAX_MSC 1
+-#  else
+-#    define LZO_CC_SYNTAX_GNUC 1
++#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)
++#    define LZO_CC_INTELC_MSC   _MSC_VER
++#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
++#    define LZO_CC_INTELC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+ #  endif
+ #elif defined(__POCC__) && defined(_WIN32)
+ #  define LZO_CC_PELLESC        1
+ #  define LZO_INFO_CC           "Pelles C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__POCC__)
+-#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
++#elif defined(__ARMCC_VERSION) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+ #  if defined(__GNUC_PATCHLEVEL__)
+-#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
++#    define LZO_CC_ARMCC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+ #  else
+-#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
++#    define LZO_CC_ARMCC_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)
+ #  endif
++#  define LZO_CC_ARMCC          __ARMCC_VERSION
++#  define LZO_INFO_CC           "ARM C Compiler"
++#  define LZO_INFO_CCVER        __VERSION__
++#elif defined(__clang__) && defined(__llvm__) && defined(__VERSION__)
+ #  if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)
+-#    define LZO_CC_CLANG_CLANG  (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__)
++#    define LZO_CC_CLANG        (__clang_major__ * 0x10000L + (__clang_minor__-0) * 0x100 + (__clang_patchlevel__-0))
+ #  else
+-#    define LZO_CC_CLANG_CLANG  0x010000L
++#    define LZO_CC_CLANG        0x010000L
++#  endif
++#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)
++#    define LZO_CC_CLANG_MSC    _MSC_VER
++#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
++#    define LZO_CC_CLANG_GNUC   (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+ #  endif
+-#  define LZO_CC_CLANG          LZO_CC_CLANG_GNUC
+ #  define LZO_INFO_CC           "clang"
+ #  define LZO_INFO_CCVER        __VERSION__
+ #elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+ #  if defined(__GNUC_PATCHLEVEL__)
+-#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
++#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
+ #  else
+-#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
++#    define LZO_CC_LLVM_GNUC    (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)
+ #  endif
+ #  define LZO_CC_LLVM           LZO_CC_LLVM_GNUC
+ #  define LZO_INFO_CC           "llvm-gcc"
+ #  define LZO_INFO_CCVER        __VERSION__
+-#elif defined(__GNUC__) && defined(__VERSION__)
+-#  if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+-#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+-#  elif defined(__GNUC_MINOR__)
+-#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+-#  else
+-#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L)
+-#  endif
+-#  define LZO_INFO_CC           "gcc"
+-#  define LZO_INFO_CCVER        __VERSION__
+ #elif defined(__ACK__) && defined(_ACK)
+ #  define LZO_CC_ACK            1
+ #  define LZO_INFO_CC           "Amsterdam Compiler Kit C"
+ #  define LZO_INFO_CCVER        "unknown"
++#elif defined(__ARMCC_VERSION) && !defined(__GNUC__)
++#  define LZO_CC_ARMCC          __ARMCC_VERSION
++#  define LZO_CC_ARMCC_ARMCC    __ARMCC_VERSION
++#  define LZO_INFO_CC           "ARM C Compiler"
++#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__ARMCC_VERSION)
+ #elif defined(__AZTEC_C__)
+ #  define LZO_CC_AZTECC         1
+ #  define LZO_INFO_CC           "Aztec C"
+@@ -540,10 +593,23 @@
+ #  define LZO_CC_DECC           1
+ #  define LZO_INFO_CC           "DEC C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__DECC)
++#elif (defined(__ghs) || defined(__ghs__)) && defined(__GHS_VERSION_NUMBER) && ((__GHS_VERSION_NUMBER-0) > 0)
++#  define LZO_CC_GHS            1
++#  define LZO_INFO_CC           "Green Hills C"
++#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__GHS_VERSION_NUMBER)
++#  if defined(_MSC_VER) && ((_MSC_VER-0) > 0)
++#    define LZO_CC_GHS_MSC      _MSC_VER
++#  elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
++#    define LZO_CC_GHS_GNUC     (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
++#  endif
+ #elif defined(__HIGHC__)
+ #  define LZO_CC_HIGHC          1
+ #  define LZO_INFO_CC           "MetaWare High C"
+ #  define LZO_INFO_CCVER        "unknown"
++#elif defined(__HP_aCC) && ((__HP_aCC-0) > 0)
++#  define LZO_CC_HPACC          __HP_aCC
++#  define LZO_INFO_CC           "HP aCC"
++#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__HP_aCC)
+ #elif defined(__IAR_SYSTEMS_ICC__)
+ #  define LZO_CC_IARC           1
+ #  define LZO_INFO_CC           "IAR C"
+@@ -552,10 +618,14 @@
+ #  else
+ #    define LZO_INFO_CCVER      "unknown"
+ #  endif
+-#elif defined(__IBMC__)
+-#  define LZO_CC_IBMC           1
++#elif defined(__IBMC__) && ((__IBMC__-0) > 0)
++#  define LZO_CC_IBMC           __IBMC__
+ #  define LZO_INFO_CC           "IBM C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__IBMC__)
++#elif defined(__IBMCPP__) && ((__IBMCPP__-0) > 0)
++#  define LZO_CC_IBMC           __IBMCPP__
++#  define LZO_INFO_CC           "IBM C"
++#  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__IBMCPP__)
+ #elif defined(__KEIL__) && defined(__C166__)
+ #  define LZO_CC_KEILC          1
+ #  define LZO_INFO_CC           "Keil C"
+@@ -572,16 +642,8 @@
+ #  else
+ #    define LZO_INFO_CCVER      "unknown"
+ #  endif
+-#elif defined(_MSC_VER)
+-#  define LZO_CC_MSC            1
+-#  define LZO_INFO_CC           "Microsoft C"
+-#  if defined(_MSC_FULL_VER)
+-#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER)
+-#  else
+-#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER)
+-#  endif
+-#elif defined(__MWERKS__)
+-#  define LZO_CC_MWERKS         1
++#elif defined(__MWERKS__) && ((__MWERKS__-0) > 0)
++#  define LZO_CC_MWERKS         __MWERKS__
+ #  define LZO_INFO_CC           "Metrowerks C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__MWERKS__)
+ #elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386)
+@@ -592,6 +654,15 @@
+ #  define LZO_CC_PACIFICC       1
+ #  define LZO_INFO_CC           "Pacific C"
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__PACIFIC__)
++#elif defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__)
++#  if defined(__PGIC_PATCHLEVEL__)
++#    define LZO_CC_PGI          (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100 + (__PGIC_PATCHLEVEL__-0))
++#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__PGIC__) "." LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) "." LZO_PP_MACRO_EXPAND(__PGIC_PATCHLEVEL__)
++#  else
++#    define LZO_CC_PGI          (__PGIC__ * 0x10000L + (__PGIC_MINOR__-0) * 0x100)
++#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__PGIC__) "." LZO_PP_MACRO_EXPAND(__PGIC_MINOR__) ".0"
++#  endif
++#  define LZO_INFO_CC           "Portland Group PGI C"
+ #elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__))
+ #  define LZO_CC_PGI            1
+ #  define LZO_INFO_CC           "Portland Group PGI C"
+@@ -606,7 +677,7 @@
+ #  define LZO_INFO_CCVER        LZO_PP_MACRO_EXPAND(__SC__)
+ #elif defined(__SUNPRO_C)
+ #  define LZO_INFO_CC           "SunPro C"
+-#  if ((__SUNPRO_C)+0 > 0)
++#  if ((__SUNPRO_C-0) > 0)
+ #    define LZO_CC_SUNPROC      __SUNPRO_C
+ #    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_C)
+ #  else
+@@ -615,7 +686,7 @@
+ #  endif
+ #elif defined(__SUNPRO_CC)
+ #  define LZO_INFO_CC           "SunPro C"
+-#  if ((__SUNPRO_CC)+0 > 0)
++#  if ((__SUNPRO_CC-0) > 0)
+ #    define LZO_CC_SUNPROC      __SUNPRO_CC
+ #    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__SUNPRO_CC)
+ #  else
+@@ -641,16 +712,46 @@
+ #elif defined(__ZTC__)
+ #  define LZO_CC_ZORTECHC       1
+ #  define LZO_INFO_CC           "Zortech C"
+-#  if (__ZTC__ == 0x310)
++#  if ((__ZTC__-0) == 0x310)
+ #    define LZO_INFO_CCVER      "0x310"
+ #  else
+ #    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(__ZTC__)
+ #  endif
++#elif defined(__GNUC__) && defined(__VERSION__)
++#  if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
++#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100 + (__GNUC_PATCHLEVEL__-0))
++#  elif defined(__GNUC_MINOR__)
++#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L + (__GNUC_MINOR__-0) * 0x100)
++#  else
++#    define LZO_CC_GNUC         (__GNUC__ * 0x10000L)
++#  endif
++#  define LZO_INFO_CC           "gcc"
++#  define LZO_INFO_CCVER        __VERSION__
++#elif defined(_MSC_VER) && ((_MSC_VER-0) > 0)
++#  define LZO_CC_MSC            _MSC_VER
++#  define LZO_INFO_CC           "Microsoft C"
++#  if defined(_MSC_FULL_VER)
++#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER)
++#  else
++#    define LZO_INFO_CCVER      LZO_PP_MACRO_EXPAND(_MSC_VER)
++#  endif
+ #else
+ #  define LZO_CC_UNKNOWN        1
+ #  define LZO_INFO_CC           "unknown"
+ #  define LZO_INFO_CCVER        "unknown"
+ #endif
++#if (LZO_CC_GNUC) && defined(__OPEN64__)
++#  if defined(__OPENCC__) && defined(__OPENCC_MINOR__) && defined(__OPENCC_PATCHLEVEL__)
++#    define LZO_CC_OPEN64       (__OPENCC__ * 0x10000L + (__OPENCC_MINOR__-0) * 0x100 + (__OPENCC_PATCHLEVEL__-0))
++#    define LZO_CC_OPEN64_GNUC  LZO_CC_GNUC
++#  endif
++#endif
++#if (LZO_CC_GNUC) && defined(__PCC__)
++#  if defined(__PCC__) && defined(__PCC_MINOR__) && defined(__PCC_MINORMINOR__)
++#    define LZO_CC_PCC          (__PCC__ * 0x10000L + (__PCC_MINOR__-0) * 0x100 + (__PCC_MINORMINOR__-0))
++#    define LZO_CC_PCC_GNUC     LZO_CC_GNUC
++#  endif
++#endif
+ #if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)
+ #  error "LZO_CC_MSC: _MSC_FULL_VER is not defined"
+ #endif
+@@ -668,8 +769,10 @@
+ #  define LZO_INFO_ARCH             "generic"
+ #elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+ #  define LZO_ARCH_I086             1
+-#  define LZO_ARCH_IA16             1
+ #  define LZO_INFO_ARCH             "i086"
++#elif defined(__aarch64__)
++#  define LZO_ARCH_ARM64            1
++#  define LZO_INFO_ARCH             "arm64"
+ #elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)
+ #  define LZO_ARCH_ALPHA            1
+ #  define LZO_INFO_ARCH             "alpha"
+@@ -685,10 +788,10 @@
+ #  define LZO_INFO_ARCH             "arm_thumb"
+ #elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__)
+ #  define LZO_ARCH_ARM              1
+-#  if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1)
++#  if defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 1)
+ #    define LZO_ARCH_ARM_THUMB      1
+ #    define LZO_INFO_ARCH           "arm_thumb"
+-#  elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2)
++#  elif defined(__CPU_MODE__) && ((__CPU_MODE__-0) == 2)
+ #    define LZO_INFO_ARCH           "arm"
+ #  else
+ #    define LZO_INFO_ARCH           "arm"
+@@ -806,53 +909,147 @@
+ #  error "FIXME - missing define for CPU architecture"
+ #endif
+ #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32)
+-#  error "FIXME - missing WIN32 define for CPU architecture"
++#  error "FIXME - missing LZO_OS_WIN32 define for CPU architecture"
+ #endif
+ #if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64)
+-#  error "FIXME - missing WIN64 define for CPU architecture"
++#  error "FIXME - missing LZO_OS_WIN64 define for CPU architecture"
+ #endif
+ #if (LZO_OS_OS216 || LZO_OS_WIN16)
+ #  define LZO_ARCH_I086PM           1
+-#  define LZO_ARCH_IA16PM           1
+ #elif 1 && (LZO_OS_DOS16 && defined(BLX286))
+ #  define LZO_ARCH_I086PM           1
+-#  define LZO_ARCH_IA16PM           1
+ #elif 1 && (LZO_OS_DOS16 && defined(DOSX286))
+ #  define LZO_ARCH_I086PM           1
+-#  define LZO_ARCH_IA16PM           1
+ #elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__))
+ #  define LZO_ARCH_I086PM           1
+-#  define LZO_ARCH_IA16PM           1
+ #endif
+-#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM)
+-#  error "this should not happen"
++#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64)
++#  define LZO_ARCH_X64              1
++#elif (!LZO_ARCH_AMD64 && LZO_ARCH_X64) && defined(__LZO_ARCH_OVERRIDE)
++#  define LZO_ARCH_AMD64            1
+ #endif
+-#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086)
+-#  error "this should not happen"
++#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64)
++#  define LZO_ARCH_AARCH64          1
++#elif (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64) && defined(__LZO_ARCH_OVERRIDE)
++#  define LZO_ARCH_ARM64            1
++#endif
++#if (LZO_ARCH_I386 && !LZO_ARCH_X86)
++#  define LZO_ARCH_X86              1
++#elif (!LZO_ARCH_I386 && LZO_ARCH_X86) && defined(__LZO_ARCH_OVERRIDE)
++#  define LZO_ARCH_I386            1
++#endif
++#if (LZO_ARCH_AMD64 && !LZO_ARCH_X64) || (!LZO_ARCH_AMD64 && LZO_ARCH_X64)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM64 && !LZO_ARCH_AARCH64) || (!LZO_ARCH_ARM64 && LZO_ARCH_AARCH64)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_I386 && !LZO_ARCH_X86) || (!LZO_ARCH_I386 && LZO_ARCH_X86)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM_THUMB && !LZO_ARCH_ARM)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM_THUMB1 && !LZO_ARCH_ARM_THUMB)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM_THUMB2 && !LZO_ARCH_ARM_THUMB)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM_THUMB1 && LZO_ARCH_ARM_THUMB2)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_I086PM && !LZO_ARCH_I086)
++#  error "unexpected configuration - check your compiler defines"
+ #endif
+ #if (LZO_ARCH_I086)
+ #  if (UINT_MAX != LZO_0xffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #  if (ULONG_MAX != LZO_0xffffffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #endif
+ #if (LZO_ARCH_I386)
+ #  if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #  if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #  if (ULONG_MAX != LZO_0xffffffffL)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #endif
+-#if !defined(__LZO_MM_OVERRIDE)
++#if (LZO_ARCH_AMD64 || LZO_ARCH_I386)
++#  if !defined(LZO_TARGET_FEATURE_SSE2)
++#    if defined(__SSE2__)
++#      define LZO_TARGET_FEATURE_SSE2       1
++#    elif defined(_MSC_VER) && ((defined(_M_IX86_FP) && ((_M_IX86_FP)+0 >= 2)) || defined(_M_AMD64))
++#      define LZO_TARGET_FEATURE_SSE2       1
++#    endif
++#  endif
++#  if !defined(LZO_TARGET_FEATURE_SSSE3)
++#  if (LZO_TARGET_FEATURE_SSE2)
++#    if defined(__SSSE3__)
++#      define LZO_TARGET_FEATURE_SSSE3      1
++#    elif defined(_MSC_VER) && defined(__AVX__)
++#      define LZO_TARGET_FEATURE_SSSE3      1
++#    endif
++#  endif
++#  endif
++#  if !defined(LZO_TARGET_FEATURE_SSE4_2)
++#  if (LZO_TARGET_FEATURE_SSSE3)
++#    if defined(__SSE4_2__)
++#      define LZO_TARGET_FEATURE_SSE4_2     1
++#    endif
++#  endif
++#  endif
++#  if !defined(LZO_TARGET_FEATURE_AVX)
++#  if (LZO_TARGET_FEATURE_SSSE3)
++#    if defined(__AVX__)
++#      define LZO_TARGET_FEATURE_AVX        1
++#    endif
++#  endif
++#  endif
++#  if !defined(LZO_TARGET_FEATURE_AVX2)
++#  if (LZO_TARGET_FEATURE_AVX)
++#    if defined(__AVX2__)
++#      define LZO_TARGET_FEATURE_AVX2       1
++#    endif
++#  endif
++#  endif
++#endif
++#if (LZO_TARGET_FEATURE_SSSE3 && !(LZO_TARGET_FEATURE_SSE2))
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_TARGET_FEATURE_SSE4_2 && !(LZO_TARGET_FEATURE_SSSE3))
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_TARGET_FEATURE_AVX && !(LZO_TARGET_FEATURE_SSSE3))
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_TARGET_FEATURE_AVX2 && !(LZO_TARGET_FEATURE_AVX))
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if (LZO_ARCH_ARM)
++#  if !defined(LZO_TARGET_FEATURE_NEON)
++#    if defined(__ARM_NEON__)
++#      define LZO_TARGET_FEATURE_NEON       1
++#    endif
++#  endif
++#elif (LZO_ARCH_ARM64)
++#  if !defined(LZO_TARGET_FEATURE_NEON)
++#    if 1
++#      define LZO_TARGET_FEATURE_NEON       1
++#    endif
++#  endif
++#endif
++#if 0
++#elif !defined(__LZO_MM_OVERRIDE)
+ #if (LZO_ARCH_I086)
+ #if (UINT_MAX != LZO_0xffffL)
+-#  error "this should not happen"
++#  error "unexpected configuration - check your compiler defines"
+ #endif
+ #if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM)
+ #  define LZO_MM_TINY           1
+@@ -879,7 +1076,7 @@
+ #elif (LZO_CC_ZORTECHC && defined(__VCM__))
+ #  define LZO_MM_LARGE          1
+ #else
+-#  error "unknown memory model"
++#  error "unknown LZO_ARCH_I086 memory model"
+ #endif
+ #if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+ #define LZO_HAVE_MM_HUGE_PTR        1
+@@ -902,10 +1099,10 @@
+ #endif
+ #if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR)
+ #  if (LZO_OS_DOS16)
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  elif (LZO_CC_ZORTECHC)
+ #  else
+-#    error "this should not happen"
++#    error "unexpected configuration - check your compiler defines"
+ #  endif
+ #endif
+ #ifdef __cplusplus
+@@ -937,7 +1134,7 @@ extern "C" {
+ #endif
+ #elif (LZO_ARCH_C166)
+ #if !defined(__MODEL__)
+-#  error "FIXME - C166 __MODEL__"
++#  error "FIXME - LZO_ARCH_C166 __MODEL__"
+ #elif ((__MODEL__) == 0)
+ #  define LZO_MM_SMALL          1
+ #elif ((__MODEL__) == 1)
+@@ -951,11 +1148,11 @@ extern "C" {
+ #elif ((__MODEL__) == 5)
+ #  define LZO_MM_XSMALL         1
+ #else
+-#  error "FIXME - C166 __MODEL__"
++#  error "FIXME - LZO_ARCH_C166 __MODEL__"
+ #endif
+ #elif (LZO_ARCH_MCS251)
+ #if !defined(__MODEL__)
+-#  error "FIXME - MCS251 __MODEL__"
++#  error "FIXME - LZO_ARCH_MCS251 __MODEL__"
+ #elif ((__MODEL__) == 0)
+ #  define LZO_MM_SMALL          1
+ #elif ((__MODEL__) == 2)
+@@ -967,11 +1164,11 @@ extern "C" {
+ #elif ((__MODEL__) == 5)
+ #  define LZO_MM_XSMALL         1
+ #else
+-#  error "FIXME - MCS251 __MODEL__"
++#  error "FIXME - LZO_ARCH_MCS251 __MODEL__"
+ #endif
+ #elif (LZO_ARCH_MCS51)
+ #if !defined(__MODEL__)
+-#  error "FIXME - MCS51 __MODEL__"
++#  error "FIXME - LZO_ARCH_MCS51 __MODEL__"
+ #elif ((__MODEL__) == 1)
+ #  define LZO_MM_SMALL          1
+ #elif ((__MODEL__) == 2)
+@@ -983,7 +1180,7 @@ extern "C" {
+ #elif ((__MODEL__) == 5)
+ #  define LZO_MM_XSMALL         1
+ #else
+-#  error "FIXME - MCS51 __MODEL__"
++#  error "FIXME - LZO_ARCH_MCS51 __MODEL__"
+ #endif
+ #elif (LZO_ARCH_CRAY_PVP)
+ #  define LZO_MM_PVP            1
+@@ -1010,35 +1207,818 @@ extern "C" {
+ #  error "unknown memory model"
+ #endif
+ #endif
++#if !defined(__lzo_gnuc_extension__)
++#if (LZO_CC_GNUC >= 0x020800ul)
++#  define __lzo_gnuc_extension__    __extension__
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_gnuc_extension__    __extension__
++#elif (LZO_CC_IBMC >= 600)
++#  define __lzo_gnuc_extension__    __extension__
++#else
++#endif
++#endif
++#if !defined(__lzo_gnuc_extension__)
++#  define __lzo_gnuc_extension__    /*empty*/
++#endif
++#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS) && defined(__cplusplus) && 0
++#  if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul))
++#    define LZO_CFG_USE_NEW_STYLE_CASTS 0
++#  elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1200))
++#    define LZO_CFG_USE_NEW_STYLE_CASTS 0
++#  else
++#    define LZO_CFG_USE_NEW_STYLE_CASTS 1
++#  endif
++#endif
++#if !defined(LZO_CFG_USE_NEW_STYLE_CASTS)
++#  define LZO_CFG_USE_NEW_STYLE_CASTS 0
++#endif
++#if !defined(__cplusplus)
++#  if defined(LZO_CFG_USE_NEW_STYLE_CASTS)
++#    undef LZO_CFG_USE_NEW_STYLE_CASTS
++#  endif
++#  define LZO_CFG_USE_NEW_STYLE_CASTS 0
++#endif
++#if !defined(LZO_REINTERPRET_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_REINTERPRET_CAST(t,e)       (reinterpret_cast<t> (e))
++#  endif
++#endif
++#if !defined(LZO_REINTERPRET_CAST)
++#  define LZO_REINTERPRET_CAST(t,e)         ((t) (e))
++#endif
++#if !defined(LZO_STATIC_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_STATIC_CAST(t,e)            (static_cast<t> (e))
++#  endif
++#endif
++#if !defined(LZO_STATIC_CAST)
++#  define LZO_STATIC_CAST(t,e)              ((t) (e))
++#endif
++#if !defined(LZO_STATIC_CAST2)
++#  define LZO_STATIC_CAST2(t1,t2,e)         LZO_STATIC_CAST(t1, LZO_STATIC_CAST(t2, e))
++#endif
++#if !defined(LZO_UNCONST_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_UNCONST_CAST(t,e)           (const_cast<t> (e))
++#  elif (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_UNCONST_CAST(t,e)           ((t) (e))
++#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#    define LZO_UNCONST_CAST(t,e)           ((t) ((void *) ((lzo_uintptr_t) ((const void *) (e)))))
++#  endif
++#endif
++#if !defined(LZO_UNCONST_CAST)
++#  define LZO_UNCONST_CAST(t,e)             ((t) ((void *) ((const void *) (e))))
++#endif
++#if !defined(LZO_UNCONST_VOLATILE_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_UNCONST_VOLATILE_CAST(t,e)  (const_cast<t> (e))
++#  elif (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_UNCONST_VOLATILE_CAST(t,e)  ((t) (e))
++#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#    define LZO_UNCONST_VOLATILE_CAST(t,e)  ((t) ((volatile void *) ((lzo_uintptr_t) ((volatile const void *) (e)))))
++#  endif
++#endif
++#if !defined(LZO_UNCONST_VOLATILE_CAST)
++#  define LZO_UNCONST_VOLATILE_CAST(t,e)    ((t) ((volatile void *) ((volatile const void *) (e))))
++#endif
++#if !defined(LZO_UNVOLATILE_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_UNVOLATILE_CAST(t,e)        (const_cast<t> (e))
++#  elif (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_UNVOLATILE_CAST(t,e)        ((t) (e))
++#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#    define LZO_UNVOLATILE_CAST(t,e)        ((t) ((void *) ((lzo_uintptr_t) ((volatile void *) (e)))))
++#  endif
++#endif
++#if !defined(LZO_UNVOLATILE_CAST)
++#  define LZO_UNVOLATILE_CAST(t,e)          ((t) ((void *) ((volatile void *) (e))))
++#endif
++#if !defined(LZO_UNVOLATILE_CONST_CAST)
++#  if (LZO_CFG_USE_NEW_STYLE_CASTS)
++#    define LZO_UNVOLATILE_CONST_CAST(t,e)  (const_cast<t> (e))
++#  elif (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_UNVOLATILE_CONST_CAST(t,e)  ((t) (e))
++#  elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#    define LZO_UNVOLATILE_CONST_CAST(t,e)  ((t) ((const void *) ((lzo_uintptr_t) ((volatile const void *) (e)))))
++#  endif
++#endif
++#if !defined(LZO_UNVOLATILE_CONST_CAST)
++#  define LZO_UNVOLATILE_CONST_CAST(t,e)    ((t) ((const void *) ((volatile const void *) (e))))
++#endif
++#if !defined(LZO_PCAST)
++#  if (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_PCAST(t,e)                  ((t) (e))
++#  endif
++#endif
++#if !defined(LZO_PCAST)
++#  define LZO_PCAST(t,e)                    LZO_STATIC_CAST(t, LZO_STATIC_CAST(void *, e))
++#endif
++#if !defined(LZO_CCAST)
++#  if (LZO_HAVE_MM_HUGE_PTR)
++#    define LZO_CCAST(t,e)                  ((t) (e))
++#  endif
++#endif
++#if !defined(LZO_CCAST)
++#  define LZO_CCAST(t,e)                    LZO_STATIC_CAST(t, LZO_STATIC_CAST(const void *, e))
++#endif
++#if !defined(LZO_ICONV)
++#  define LZO_ICONV(t,e)                    LZO_STATIC_CAST(t, e)
++#endif
++#if !defined(LZO_ICAST)
++#  define LZO_ICAST(t,e)                    LZO_STATIC_CAST(t, e)
++#endif
++#if !defined(LZO_ITRUNC)
++#  define LZO_ITRUNC(t,e)                   LZO_STATIC_CAST(t, e)
++#endif
++#if !defined(__lzo_cte)
++#  if (LZO_CC_MSC || LZO_CC_WATCOMC)
++#    define __lzo_cte(e)            ((void)0,(e))
++#  elif 1
++#    define __lzo_cte(e)            ((void)0,(e))
++#  endif
++#endif
++#if !defined(__lzo_cte)
++#  define __lzo_cte(e)              (e)
++#endif
++#if !defined(LZO_BLOCK_BEGIN)
++#  define LZO_BLOCK_BEGIN           do {
++#  define LZO_BLOCK_END             } while __lzo_cte(0)
++#endif
++#if !defined(LZO_UNUSED)
++#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
++#    define LZO_UNUSED(var)         ((void) &var)
++#  elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
++#    define LZO_UNUSED(var)         if (&var) ; else
++#  elif (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x030200ul))
++#    define LZO_UNUSED(var)         ((void) &var)
++#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#    define LZO_UNUSED(var)         ((void) var)
++#  elif (LZO_CC_MSC && (_MSC_VER < 900))
++#    define LZO_UNUSED(var)         if (&var) ; else
++#  elif (LZO_CC_KEILC)
++#    define LZO_UNUSED(var)         {LZO_EXTERN_C int lzo_unused__[1-2*!(sizeof(var)>0)];}
++#  elif (LZO_CC_PACIFICC)
++#    define LZO_UNUSED(var)         ((void) sizeof(var))
++#  elif (LZO_CC_WATCOMC) && defined(__cplusplus)
++#    define LZO_UNUSED(var)         ((void) var)
++#  else
++#    define LZO_UNUSED(var)         ((void) &var)
++#  endif
++#endif
++#if !defined(LZO_UNUSED_FUNC)
++#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
++#    define LZO_UNUSED_FUNC(func)   ((void) func)
++#  elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
++#    define LZO_UNUSED_FUNC(func)   if (func) ; else
++#  elif (LZO_CC_CLANG || LZO_CC_LLVM)
++#    define LZO_UNUSED_FUNC(func)   ((void) &func)
++#  elif (LZO_CC_MSC && (_MSC_VER < 900))
++#    define LZO_UNUSED_FUNC(func)   if (func) ; else
++#  elif (LZO_CC_MSC)
++#    define LZO_UNUSED_FUNC(func)   ((void) &func)
++#  elif (LZO_CC_KEILC || LZO_CC_PELLESC)
++#    define LZO_UNUSED_FUNC(func)   {LZO_EXTERN_C int lzo_unused_func__[1-2*!(sizeof((int)func)>0)];}
++#  else
++#    define LZO_UNUSED_FUNC(func)   ((void) func)
++#  endif
++#endif
++#if !defined(LZO_UNUSED_LABEL)
++#  if (LZO_CC_CLANG >= 0x020800ul)
++#    define LZO_UNUSED_LABEL(l)     (__lzo_gnuc_extension__ ((void) ((const void *) &&l)))
++#  elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)
++#    define LZO_UNUSED_LABEL(l)     if __lzo_cte(0) goto l
++#  else
++#    define LZO_UNUSED_LABEL(l)     switch (0) case 1:goto l
++#  endif
++#endif
++#if !defined(LZO_DEFINE_UNINITIALIZED_VAR)
++#  if 0
++#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var
++#  elif 0 && (LZO_CC_GNUC)
++#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = var
++#  else
++#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = init
++#  endif
++#endif
++#if !defined(__lzo_inline)
++#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295))
++#elif defined(__cplusplus)
++#  define __lzo_inline          inline
++#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L)
++#  define __lzo_inline          inline
++#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
++#  define __lzo_inline          __inline
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
++#  define __lzo_inline          __inline__
++#elif (LZO_CC_DMC)
++#  define __lzo_inline          __inline
++#elif (LZO_CC_GHS)
++#  define __lzo_inline          __inline__
++#elif (LZO_CC_IBMC >= 600)
++#  define __lzo_inline          __inline__
++#elif (LZO_CC_INTELC)
++#  define __lzo_inline          __inline
++#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405))
++#  define __lzo_inline          __inline
++#elif (LZO_CC_MSC && (_MSC_VER >= 900))
++#  define __lzo_inline          __inline
++#elif (LZO_CC_SUNPROC >= 0x5100)
++#  define __lzo_inline          __inline__
++#endif
++#endif
++#if defined(__lzo_inline)
++#  ifndef __lzo_HAVE_inline
++#  define __lzo_HAVE_inline 1
++#  endif
++#else
++#  define __lzo_inline          /*empty*/
++#endif
++#if !defined(__lzo_forceinline)
++#if (LZO_CC_GNUC >= 0x030200ul)
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#elif (LZO_CC_IBMC >= 700)
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450))
++#  define __lzo_forceinline     __forceinline
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
++#  define __lzo_forceinline     __forceinline
++#elif (LZO_CC_PGI >= 0x0d0a00ul)
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#elif (LZO_CC_SUNPROC >= 0x5100)
++#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
++#endif
++#endif
++#if defined(__lzo_forceinline)
++#  ifndef __lzo_HAVE_forceinline
++#  define __lzo_HAVE_forceinline 1
++#  endif
++#else
++#  define __lzo_forceinline     __lzo_inline
++#endif
++#if !defined(__lzo_noinline)
++#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
++#  define __lzo_noinline        __attribute__((__noinline__,__used__))
++#elif (LZO_CC_GNUC >= 0x030200ul)
++#  define __lzo_noinline        __attribute__((__noinline__))
++#elif (LZO_CC_IBMC >= 700)
++#  define __lzo_noinline        __attribute__((__noinline__))
++#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600))
++#  define __lzo_noinline        __declspec(noinline)
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))
++#  define __lzo_noinline        __attribute__((__noinline__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_noinline        __attribute__((__noinline__))
++#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
++#  define __lzo_noinline        __declspec(noinline)
++#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64))
++#  if defined(__cplusplus)
++#  else
++#    define __lzo_noinline      __declspec(noinline)
++#  endif
++#elif (LZO_CC_PGI >= 0x0d0a00ul)
++#  define __lzo_noinline        __attribute__((__noinline__))
++#elif (LZO_CC_SUNPROC >= 0x5100)
++#  define __lzo_noinline        __attribute__((__noinline__))
++#endif
++#endif
++#if defined(__lzo_noinline)
++#  ifndef __lzo_HAVE_noinline
++#  define __lzo_HAVE_noinline 1
++#  endif
++#else
++#  define __lzo_noinline        /*empty*/
++#endif
++#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if !defined(__lzo_static_inline)
++#if (LZO_CC_IBMC)
++#  define __lzo_static_inline       __lzo_gnuc_extension__ static __lzo_inline
++#endif
++#endif
++#if !defined(__lzo_static_inline)
++#  define __lzo_static_inline       static __lzo_inline
++#endif
++#if !defined(__lzo_static_forceinline)
++#if (LZO_CC_IBMC)
++#  define __lzo_static_forceinline  __lzo_gnuc_extension__ static __lzo_forceinline
++#endif
++#endif
++#if !defined(__lzo_static_forceinline)
++#  define __lzo_static_forceinline  static __lzo_forceinline
++#endif
++#if !defined(__lzo_static_noinline)
++#if (LZO_CC_IBMC)
++#  define __lzo_static_noinline     __lzo_gnuc_extension__ static __lzo_noinline
++#endif
++#endif
++#if !defined(__lzo_static_noinline)
++#  define __lzo_static_noinline     static __lzo_noinline
++#endif
++#if !defined(__lzo_c99_extern_inline)
++#if defined(__GNUC_GNU_INLINE__)
++#  define __lzo_c99_extern_inline   __lzo_inline
++#elif defined(__GNUC_STDC_INLINE__)
++#  define __lzo_c99_extern_inline   extern __lzo_inline
++#elif defined(__STDC_VERSION__) && (__STDC_VERSION__-0 >= 199901L)
++#  define __lzo_c99_extern_inline   extern __lzo_inline
++#endif
++#if !defined(__lzo_c99_extern_inline) && (__lzo_HAVE_inline)
++#  define __lzo_c99_extern_inline   __lzo_inline
++#endif
++#endif
++#if defined(__lzo_c99_extern_inline)
++#  ifndef __lzo_HAVE_c99_extern_inline
++#  define __lzo_HAVE_c99_extern_inline 1
++#  endif
++#else
++#  define __lzo_c99_extern_inline   /*empty*/
++#endif
++#if !defined(__lzo_may_alias)
++#if (LZO_CC_GNUC >= 0x030400ul)
++#  define __lzo_may_alias       __attribute__((__may_alias__))
++#elif (LZO_CC_CLANG >= 0x020900ul)
++#  define __lzo_may_alias       __attribute__((__may_alias__))
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1210)) && 0
++#  define __lzo_may_alias       __attribute__((__may_alias__))
++#elif (LZO_CC_PGI >= 0x0d0a00ul) && 0
++#  define __lzo_may_alias       __attribute__((__may_alias__))
++#endif
++#endif
++#if defined(__lzo_may_alias)
++#  ifndef __lzo_HAVE_may_alias
++#  define __lzo_HAVE_may_alias 1
++#  endif
++#else
++#  define __lzo_may_alias       /*empty*/
++#endif
++#if !defined(__lzo_noreturn)
++#if (LZO_CC_GNUC >= 0x020700ul)
++#  define __lzo_noreturn        __attribute__((__noreturn__))
++#elif (LZO_CC_IBMC >= 700)
++#  define __lzo_noreturn        __attribute__((__noreturn__))
++#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450))
++#  define __lzo_noreturn        __declspec(noreturn)
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600))
++#  define __lzo_noreturn        __attribute__((__noreturn__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_noreturn        __attribute__((__noreturn__))
++#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
++#  define __lzo_noreturn        __declspec(noreturn)
++#elif (LZO_CC_PGI >= 0x0d0a00ul)
++#  define __lzo_noreturn        __attribute__((__noreturn__))
++#endif
++#endif
++#if defined(__lzo_noreturn)
++#  ifndef __lzo_HAVE_noreturn
++#  define __lzo_HAVE_noreturn 1
++#  endif
++#else
++#  define __lzo_noreturn        /*empty*/
++#endif
++#if !defined(__lzo_nothrow)
++#if (LZO_CC_GNUC >= 0x030300ul)
++#  define __lzo_nothrow         __attribute__((__nothrow__))
++#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 450)) && defined(__cplusplus)
++#  define __lzo_nothrow         __declspec(nothrow)
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 900))
++#  define __lzo_nothrow         __attribute__((__nothrow__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_nothrow         __attribute__((__nothrow__))
++#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
++#  define __lzo_nothrow         __declspec(nothrow)
++#endif
++#endif
++#if defined(__lzo_nothrow)
++#  ifndef __lzo_HAVE_nothrow
++#  define __lzo_HAVE_nothrow 1
++#  endif
++#else
++#  define __lzo_nothrow         /*empty*/
++#endif
++#if !defined(__lzo_restrict)
++#if (LZO_CC_GNUC >= 0x030400ul)
++#  define __lzo_restrict        __restrict__
++#elif (LZO_CC_IBMC >= 800) && !defined(__cplusplus)
++#  define __lzo_restrict        __restrict__
++#elif (LZO_CC_IBMC >= 1210)
++#  define __lzo_restrict        __restrict__
++#elif (LZO_CC_INTELC_MSC && (__INTEL_COMPILER >= 600))
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 600))
++#  define __lzo_restrict        __restrict__
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM)
++#  define __lzo_restrict        __restrict__
++#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
++#  define __lzo_restrict        __restrict
++#elif (LZO_CC_PGI >= 0x0d0a00ul)
++#  define __lzo_restrict        __restrict__
++#endif
++#endif
++#if defined(__lzo_restrict)
++#  ifndef __lzo_HAVE_restrict
++#  define __lzo_HAVE_restrict 1
++#  endif
++#else
++#  define __lzo_restrict        /*empty*/
++#endif
++#if !defined(__lzo_alignof)
++#if (LZO_CC_ARMCC || LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
++#  define __lzo_alignof(e)      __alignof__(e)
++#elif (LZO_CC_GHS) && !defined(__cplusplus)
++#  define __lzo_alignof(e)      __alignof__(e)
++#elif (LZO_CC_IBMC >= 600)
++#  define __lzo_alignof(e)      (__lzo_gnuc_extension__ __alignof__(e))
++#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
++#  define __lzo_alignof(e)      __alignof__(e)
++#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
++#  define __lzo_alignof(e)      __alignof(e)
++#elif (LZO_CC_SUNPROC >= 0x5100)
++#  define __lzo_alignof(e)      __alignof__(e)
++#endif
++#endif
++#if defined(__lzo_alignof)
++#  ifndef __lzo_HAVE_alignof
++#  define __lzo_HAVE_alignof 1
++#  endif
++#endif
++#if !defined(__lzo_struct_packed)
++#if   (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)
++#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul))
++#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus)
++#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul))
++#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus)
++#elif (LZO_CC_GNUC >= 0x030400ul) && !(LZO_CC_PCC_GNUC) && (LZO_ARCH_AMD64 || LZO_ARCH_I386)
++#  define __lzo_struct_packed(s)        struct s {
++#  define __lzo_struct_packed_end()     } __attribute__((__gcc_struct__,__packed__));
++#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__gcc_struct__,__packed__));
++#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100))
++#  define __lzo_struct_packed(s)        struct s {
++#  define __lzo_struct_packed_end()     } __attribute__((__packed__));
++#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__packed__));
++#elif (LZO_CC_IBMC >= 700)
++#  define __lzo_struct_packed(s)        __lzo_gnuc_extension__ struct s {
++#  define __lzo_struct_packed_end()     } __attribute__((__packed__));
++#  define __lzo_struct_packed_ma_end()  } __lzo_may_alias __attribute__((__packed__));
++#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))
++#  define __lzo_struct_packed(s)        __pragma(pack(push,1)) struct s {
++#  define __lzo_struct_packed_end()     } __pragma(pack(pop));
++#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900))
++#  define __lzo_struct_packed(s)        _Packed struct s {
++#  define __lzo_struct_packed_end()     };
++#endif
++#endif
++#if defined(__lzo_struct_packed) && !defined(__lzo_struct_packed_ma)
++#  define __lzo_struct_packed_ma(s)     __lzo_struct_packed(s)
++#endif
++#if defined(__lzo_struct_packed_end) && !defined(__lzo_struct_packed_ma_end)
++#  define __lzo_struct_packed_ma_end()  __lzo_struct_packed_end()
++#endif
++#if !defined(__lzo_byte_struct)
++#if defined(__lzo_struct_packed)
++#  define __lzo_byte_struct(s,n)        __lzo_struct_packed(s) unsigned char a[n]; __lzo_struct_packed_end()
++#  define __lzo_byte_struct_ma(s,n)     __lzo_struct_packed_ma(s) unsigned char a[n]; __lzo_struct_packed_ma_end()
++#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_PGI || (LZO_CC_SUNPROC >= 0x5100))
++#  define __lzo_byte_struct(s,n)        struct s { unsigned char a[n]; } __attribute__((__packed__));
++#  define __lzo_byte_struct_ma(s,n)     struct s { unsigned char a[n]; } __lzo_may_alias __attribute__((__packed__));
++#endif
++#endif
++#if defined(__lzo_byte_struct) &&  !defined(__lzo_byte_struct_ma)
++#  define __lzo_byte_struct_ma(s,n)     __lzo_byte_struct(s,n)
++#endif
++#if !defined(__lzo_struct_align16) && (__lzo_HAVE_alignof)
++#if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x030000ul))
++#elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)
++#elif (LZO_CC_CILLY || LZO_CC_PCC)
++#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))
++#  define __lzo_struct_align16(s)       struct __declspec(align(16)) s {
++#  define __lzo_struct_align16_end()    };
++#  define __lzo_struct_align32(s)       struct __declspec(align(32)) s {
++#  define __lzo_struct_align32_end()    };
++#  define __lzo_struct_align64(s)       struct __declspec(align(64)) s {
++#  define __lzo_struct_align64_end()    };
++#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || (LZO_CC_IBMC >= 700) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_struct_align16(s)       struct s {
++#  define __lzo_struct_align16_end()    } __attribute__((__aligned__(16)));
++#  define __lzo_struct_align32(s)       struct s {
++#  define __lzo_struct_align32_end()    } __attribute__((__aligned__(32)));
++#  define __lzo_struct_align64(s)       struct s {
++#  define __lzo_struct_align64_end()    } __attribute__((__aligned__(64)));
++#endif
++#endif
++#if !defined(__lzo_union_um)
++#if   (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020800ul)) && defined(__cplusplus)
++#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020700ul))
++#elif (LZO_CC_GNUC && (LZO_CC_GNUC < 0x020800ul)) && defined(__cplusplus)
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER < 810))
++#elif (LZO_CC_PCC && (LZO_CC_PCC < 0x010100ul))
++#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC < 0x5110)) && !defined(__cplusplus)
++#elif (LZO_CC_ARMCC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || (LZO_CC_PGI >= 0x0d0a00ul) || (LZO_CC_SUNPROC >= 0x5100))
++#  define __lzo_union_am(s)             union s {
++#  define __lzo_union_am_end()          } __lzo_may_alias;
++#  define __lzo_union_um(s)             union s {
++#  define __lzo_union_um_end()          } __lzo_may_alias __attribute__((__packed__));
++#elif (LZO_CC_IBMC >= 700)
++#  define __lzo_union_am(s)             __lzo_gnuc_extension__ union s {
++#  define __lzo_union_am_end()          } __lzo_may_alias;
++#  define __lzo_union_um(s)             __lzo_gnuc_extension__ union s {
++#  define __lzo_union_um_end()          } __lzo_may_alias __attribute__((__packed__));
++#elif (LZO_CC_INTELC_MSC) || (LZO_CC_MSC && (_MSC_VER >= 1300))
++#  define __lzo_union_um(s)             __pragma(pack(push,1)) union s {
++#  define __lzo_union_um_end()          } __pragma(pack(pop));
++#elif (LZO_CC_WATCOMC && (__WATCOMC__ >= 900))
++#  define __lzo_union_um(s)             _Packed union s {
++#  define __lzo_union_um_end()          };
++#endif
++#endif
++#if !defined(__lzo_union_am)
++#  define __lzo_union_am(s)             union s {
++#  define __lzo_union_am_end()          };
++#endif
++#if !defined(__lzo_constructor)
++#if (LZO_CC_GNUC >= 0x030400ul)
++#  define __lzo_constructor     __attribute__((__constructor__,__used__))
++#elif (LZO_CC_GNUC >= 0x020700ul)
++#  define __lzo_constructor     __attribute__((__constructor__))
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))
++#  define __lzo_constructor     __attribute__((__constructor__,__used__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_constructor     __attribute__((__constructor__))
++#endif
++#endif
++#if defined(__lzo_constructor)
++#  ifndef __lzo_HAVE_constructor
++#  define __lzo_HAVE_constructor 1
++#  endif
++#endif
++#if !defined(__lzo_destructor)
++#if (LZO_CC_GNUC >= 0x030400ul)
++#  define __lzo_destructor      __attribute__((__destructor__,__used__))
++#elif (LZO_CC_GNUC >= 0x020700ul)
++#  define __lzo_destructor      __attribute__((__destructor__))
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 800))
++#  define __lzo_destructor      __attribute__((__destructor__,__used__))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_destructor      __attribute__((__destructor__))
++#endif
++#endif
++#if defined(__lzo_destructor)
++#  ifndef __lzo_HAVE_destructor
++#  define __lzo_HAVE_destructor 1
++#  endif
++#endif
++#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)
++#  error "unexpected configuration - check your compiler defines"
++#endif
++#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
++#if (LZO_CC_GNUC >= 0x030200ul)
++#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
++#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
++#elif (LZO_CC_IBMC >= 1010)
++#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
++#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
++#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
++#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
++#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
++#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
++#endif
++#endif
++#if defined(__lzo_likely)
++#  ifndef __lzo_HAVE_likely
++#  define __lzo_HAVE_likely 1
++#  endif
++#else
++#  define __lzo_likely(e)       (e)
++#endif
++#if defined(__lzo_unlikely)
++#  ifndef __lzo_HAVE_unlikely
++#  define __lzo_HAVE_unlikely 1
++#  endif
++#else
++#  define __lzo_unlikely(e)     (e)
++#endif
++#if !defined(__lzo_static_unused_void_func)
++#  if 1 && (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_INTELC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
++#    define __lzo_static_unused_void_func(f)    static void __attribute__((__unused__)) f(void)
++#  else
++#    define __lzo_static_unused_void_func(f)    static __lzo_inline void f(void)
++#  endif
++#endif
++#if !defined(__lzo_loop_forever)
++#  if (LZO_CC_IBMC)
++#    define __lzo_loop_forever()    LZO_BLOCK_BEGIN for (;;) { ; } LZO_BLOCK_END
++#  else
++#    define __lzo_loop_forever()    do { ; } while __lzo_cte(1)
++#  endif
++#endif
++#if !defined(__lzo_unreachable)
++#if (LZO_CC_CLANG && (LZO_CC_CLANG >= 0x020800ul))
++#  define __lzo_unreachable()       __builtin_unreachable();
++#elif (LZO_CC_GNUC >= 0x040500ul)
++#  define __lzo_unreachable()       __builtin_unreachable();
++#elif (LZO_CC_INTELC_GNUC && (__INTEL_COMPILER >= 1300)) && 1
++#  define __lzo_unreachable()       __builtin_unreachable();
++#endif
++#endif
++#if defined(__lzo_unreachable)
++#  ifndef __lzo_HAVE_unreachable
++#  define __lzo_HAVE_unreachable 1
++#  endif
++#else
++#  if 0
++#  define __lzo_unreachable()       ((void)0);
++#  else
++#  define __lzo_unreachable()       __lzo_loop_forever();
++#  endif
++#endif
++#ifndef __LZO_CTA_NAME
++#if (LZO_CFG_USE_COUNTER)
++#  define __LZO_CTA_NAME(a)         LZO_PP_ECONCAT2(a,__COUNTER__)
++#else
++#  define __LZO_CTA_NAME(a)         LZO_PP_ECONCAT2(a,__LINE__)
++#endif
++#endif
++#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
++#  if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END
++#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1u-2*!(e)]; LZO_EXTERN_C_END
++#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-!(e)]; LZO_EXTERN_C_END
++#  elif (LZO_CC_CLANG && (LZO_CC_CLANG < 0x020900ul)) && defined(__cplusplus)
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN int __LZO_CTA_NAME(lzo_cta_f__)(int [1-2*!(e)]); LZO_EXTERN_C_END
++#  elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__)
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__)); LZO_EXTERN_C_END
++#  else
++#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  LZO_EXTERN_C_BEGIN extern int __LZO_CTA_NAME(lzo_cta__)[1-2*!(e)]; LZO_EXTERN_C_END
++#  endif
++#endif
++#if !defined(LZO_COMPILE_TIME_ASSERT)
++#  if (LZO_CC_AZTECC)
++#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-!(e)];}
++#  elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
++#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
++#  elif (LZO_CC_GNUC) && defined(__CHECKER__) && defined(__SPARSE_CHECKER__)
++#    define LZO_COMPILE_TIME_ASSERT(e)  {(void) (0/!!(e));}
++#  elif (LZO_CC_GNUC >= 0x040700ul) && (LZO_CFG_USE_COUNTER) && defined(__cplusplus)
++#    define LZO_COMPILE_TIME_ASSERT(e)  {enum {__LZO_CTA_NAME(lzo_cta_e__)=1/!!(e)} __attribute__((__unused__));}
++#  elif (LZO_CC_GNUC >= 0x040700ul)
++#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)] __attribute__((__unused__));}
++#  elif (LZO_CC_MSC && (_MSC_VER < 900))
++#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
++#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
++#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
++#  else
++#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __LZO_CTA_NAME(lzo_cta_t__)[1-2*!(e)];}
++#  endif
++#endif
++LZO_COMPILE_TIME_ASSERT_HEADER(1 == 1)
++#if defined(__cplusplus)
++extern "C" { LZO_COMPILE_TIME_ASSERT_HEADER(2 == 2) }
++#endif
++LZO_COMPILE_TIME_ASSERT_HEADER(3 == 3)
++#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)
++#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
++#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
++#    define __lzo_cdecl                 __cdecl
++#    define __lzo_cdecl_atexit          /*empty*/
++#    define __lzo_cdecl_main            __cdecl
++#    if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
++#      define __lzo_cdecl_qsort         __pascal
++#    elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
++#      define __lzo_cdecl_qsort         _stdcall
++#    else
++#      define __lzo_cdecl_qsort         __cdecl
++#    endif
++#  elif (LZO_CC_WATCOMC)
++#    define __lzo_cdecl                 __cdecl
++#  else
++#    define __lzo_cdecl                 __cdecl
++#    define __lzo_cdecl_atexit          __cdecl
++#    define __lzo_cdecl_main            __cdecl
++#    define __lzo_cdecl_qsort           __cdecl
++#  endif
++#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC)
++#  elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
++#    define __lzo_cdecl_sighandler      __pascal
++#  elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
++#    define __lzo_cdecl_sighandler      _stdcall
++#  elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE)
++#    define __lzo_cdecl_sighandler      __clrcall
++#  elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700))
++#    if defined(_DLL)
++#      define __lzo_cdecl_sighandler    _far _cdecl _loadds
++#    elif defined(_MT)
++#      define __lzo_cdecl_sighandler    _far _cdecl
++#    else
++#      define __lzo_cdecl_sighandler    _cdecl
++#    endif
++#  else
++#    define __lzo_cdecl_sighandler      __cdecl
++#  endif
++#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC)
++#  define __lzo_cdecl                   __cdecl
++#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC))
++#  define __lzo_cdecl                   cdecl
++#endif
++#if !defined(__lzo_cdecl)
++#  define __lzo_cdecl                   /*empty*/
++#endif
++#if !defined(__lzo_cdecl_atexit)
++#  define __lzo_cdecl_atexit            /*empty*/
++#endif
++#if !defined(__lzo_cdecl_main)
++#  define __lzo_cdecl_main              /*empty*/
++#endif
++#if !defined(__lzo_cdecl_qsort)
++#  define __lzo_cdecl_qsort             /*empty*/
++#endif
++#if !defined(__lzo_cdecl_sighandler)
++#  define __lzo_cdecl_sighandler        /*empty*/
++#endif
++#if !defined(__lzo_cdecl_va)
++#  define __lzo_cdecl_va                __lzo_cdecl
++#endif
++#if !(LZO_CFG_NO_WINDOWS_H)
++#if !defined(LZO_HAVE_WINDOWS_H)
++#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
++#  if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
++#  elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
++#  elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))
++#  else
++#    define LZO_HAVE_WINDOWS_H 1
++#  endif
++#endif
++#endif
++#endif
++#ifndef LZO_SIZEOF_SHORT
+ #if defined(SIZEOF_SHORT)
+ #  define LZO_SIZEOF_SHORT          (SIZEOF_SHORT)
++#elif defined(__SIZEOF_SHORT__)
++#  define LZO_SIZEOF_SHORT          (__SIZEOF_SHORT__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_INT
+ #if defined(SIZEOF_INT)
+ #  define LZO_SIZEOF_INT            (SIZEOF_INT)
++#elif defined(__SIZEOF_INT__)
++#  define LZO_SIZEOF_INT            (__SIZEOF_INT__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_LONG
+ #if defined(SIZEOF_LONG)
+ #  define LZO_SIZEOF_LONG           (SIZEOF_LONG)
++#elif defined(__SIZEOF_LONG__)
++#  define LZO_SIZEOF_LONG           (__SIZEOF_LONG__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_LONG_LONG
+ #if defined(SIZEOF_LONG_LONG)
+ #  define LZO_SIZEOF_LONG_LONG      (SIZEOF_LONG_LONG)
++#elif defined(__SIZEOF_LONG_LONG__)
++#  define LZO_SIZEOF_LONG_LONG      (__SIZEOF_LONG_LONG__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF___INT16
+ #if defined(SIZEOF___INT16)
+ #  define LZO_SIZEOF___INT16        (SIZEOF___INT16)
+ #endif
++#endif
++#ifndef LZO_SIZEOF___INT32
+ #if defined(SIZEOF___INT32)
+ #  define LZO_SIZEOF___INT32        (SIZEOF___INT32)
+ #endif
++#endif
++#ifndef LZO_SIZEOF___INT64
+ #if defined(SIZEOF___INT64)
+ #  define LZO_SIZEOF___INT64        (SIZEOF___INT64)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_VOID_P
+ #if defined(SIZEOF_VOID_P)
+ #  define LZO_SIZEOF_VOID_P         (SIZEOF_VOID_P)
++#elif defined(__SIZEOF_POINTER__)
++#  define LZO_SIZEOF_VOID_P         (__SIZEOF_POINTER__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_SIZE_T
+ #if defined(SIZEOF_SIZE_T)
+ #  define LZO_SIZEOF_SIZE_T         (SIZEOF_SIZE_T)
++#elif defined(__SIZEOF_SIZE_T__)
++#  define LZO_SIZEOF_SIZE_T         (__SIZEOF_SIZE_T__)
+ #endif
++#endif
++#ifndef LZO_SIZEOF_PTRDIFF_T
+ #if defined(SIZEOF_PTRDIFF_T)
+ #  define LZO_SIZEOF_PTRDIFF_T      (SIZEOF_PTRDIFF_T)
++#elif defined(__SIZEOF_PTRDIFF_T__)
++#  define LZO_SIZEOF_PTRDIFF_T      (__SIZEOF_PTRDIFF_T__)
++#endif
+ #endif
+ #define __LZO_LSR(x,b)    (((x)+0ul) >> (b))
+ #if !defined(LZO_SIZEOF_SHORT)
+@@ -1060,6 +2040,7 @@ extern "C" {
+ #    error "LZO_SIZEOF_SHORT"
+ #  endif
+ #endif
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SHORT == sizeof(short))
+ #if !defined(LZO_SIZEOF_INT)
+ #  if (LZO_ARCH_CRAY_PVP)
+ #    define LZO_SIZEOF_INT          8
+@@ -1081,6 +2062,7 @@ extern "C" {
+ #    error "LZO_SIZEOF_INT"
+ #  endif
+ #endif
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_INT == sizeof(int))
+ #if !defined(LZO_SIZEOF_LONG)
+ #  if (ULONG_MAX == LZO_0xffffffffL)
+ #    define LZO_SIZEOF_LONG         4
+@@ -1090,6 +2072,8 @@ extern "C" {
+ #    define LZO_SIZEOF_LONG         2
+ #  elif (__LZO_LSR(ULONG_MAX,31) == 1)
+ #    define LZO_SIZEOF_LONG         4
++#  elif (__LZO_LSR(ULONG_MAX,39) == 1)
++#    define LZO_SIZEOF_LONG         5
+ #  elif (__LZO_LSR(ULONG_MAX,63) == 1)
+ #    define LZO_SIZEOF_LONG         8
+ #  elif (__LZO_LSR(ULONG_MAX,127) == 1)
+@@ -1098,11 +2082,12 @@ extern "C" {
+ #    error "LZO_SIZEOF_LONG"
+ #  endif
+ #endif
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_LONG == sizeof(long))
+ #if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)
+ #if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)
+ #  if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__)
+ #    if (LZO_CC_GNUC >= 0x030300ul)
+-#      if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0)
++#      if ((__LONG_MAX__-0) == (__LONG_LONG_MAX__-0))
+ #        define LZO_SIZEOF_LONG_LONG      LZO_SIZEOF_LONG
+ #      elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1)
+ #        define LZO_SIZEOF_LONG_LONG      4
+@@ -1116,7 +2101,7 @@ extern "C" {
+ #if (LZO_ARCH_I086 && LZO_CC_DMC)
+ #elif (LZO_CC_CILLY) && defined(__GNUC__)
+ #  define LZO_SIZEOF_LONG_LONG      8
+-#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
++#elif (LZO_CC_ARMCC_GNUC || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+ #  define LZO_SIZEOF_LONG_LONG      8
+ #elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))
+ #  define LZO_SIZEOF_LONG_LONG      8
+@@ -1138,11 +2123,13 @@ extern "C" {
+ #  define LZO_SIZEOF___INT64        8
+ #elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100)))
+ #  define LZO_SIZEOF___INT64        8
+-#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64))
++#elif (LZO_CC_GHS && defined(__LLONG_BIT) && ((__LLONG_BIT-0) == 64))
++#  define LZO_SIZEOF_LONG_LONG      8
++#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && ((_INTEGRAL_MAX_BITS-0) == 64))
+ #  define LZO_SIZEOF___INT64        8
+ #elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+ #  define LZO_SIZEOF_LONG_LONG      8
+-#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
++#elif (defined(__vms) || defined(__VMS)) && ((__INITIAL_POINTER_SIZE-0) == 64)
+ #  define LZO_SIZEOF_LONG_LONG      8
+ #elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2)
+ #elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+@@ -1155,87 +2142,127 @@ extern "C" {
+ #    undef LZO_SIZEOF_LONG_LONG
+ #  endif
+ #endif
+-#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
++#if (LZO_CFG_NO_LONG_LONG)
++#  undef LZO_SIZEOF_LONG_LONG
++#elif defined(__NO_LONG_LONG)
++#  undef LZO_SIZEOF_LONG_LONG
++#elif defined(_NO_LONGLONG)
+ #  undef LZO_SIZEOF_LONG_LONG
+ #endif
+-#if !defined(LZO_SIZEOF_VOID_P)
+-#if (LZO_ARCH_I086)
+-#  define __LZO_WORDSIZE            2
+-#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM)
+-#    define LZO_SIZEOF_VOID_P       2
+-#  elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE)
+-#    define LZO_SIZEOF_VOID_P       4
++#if !defined(LZO_WORDSIZE)
++#if (LZO_ARCH_ALPHA)
++#  define LZO_WORDSIZE              8
++#elif (LZO_ARCH_AMD64)
++#  define LZO_WORDSIZE              8
++#elif (LZO_ARCH_AVR)
++#  define LZO_WORDSIZE              1
++#elif (LZO_ARCH_H8300)
++#  if defined(__NORMAL_MODE__)
++#    define LZO_WORDSIZE            4
++#  elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
++#    define LZO_WORDSIZE            4
+ #  else
+-#    error "LZO_MM"
++#    define LZO_WORDSIZE            2
+ #  endif
+-#elif (LZO_ARCH_AVR || LZO_ARCH_Z80)
+-#  define __LZO_WORDSIZE            1
++#elif (LZO_ARCH_I086)
++#  define LZO_WORDSIZE              2
++#elif (LZO_ARCH_IA64)
++#  define LZO_WORDSIZE              8
++#elif (LZO_ARCH_M16C)
++#  define LZO_WORDSIZE              2
++#elif (LZO_ARCH_SPU)
++#  define LZO_WORDSIZE              4
++#elif (LZO_ARCH_Z80)
++#  define LZO_WORDSIZE              1
++#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
++#  define LZO_WORDSIZE              8
++#elif (LZO_OS_OS400 || defined(__OS400__))
++#  define LZO_WORDSIZE              8
++#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
++#  define LZO_WORDSIZE              8
++#endif
++#endif
++#if !defined(LZO_SIZEOF_VOID_P)
++#if defined(__ILP32__) || defined(__ILP32) || defined(_ILP32)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int)  == 4)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)
++#  define LZO_SIZEOF_VOID_P         4
++#elif defined(__ILP64__) || defined(__ILP64) || defined(_ILP64)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(int)  == 8)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8)
++#  define LZO_SIZEOF_VOID_P         8
++#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)
++#  define LZO_SIZEOF_VOID_P         8
++#elif defined(__LP64__) || defined(__LP64) || defined(_LP64)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 8)
++#  define LZO_SIZEOF_VOID_P         8
++#elif (LZO_ARCH_AVR)
+ #  define LZO_SIZEOF_VOID_P         2
+ #elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430)
+ #  define LZO_SIZEOF_VOID_P         2
+ #elif (LZO_ARCH_H8300)
+ #  if defined(__NORMAL_MODE__)
+-#    define __LZO_WORDSIZE          4
+ #    define LZO_SIZEOF_VOID_P       2
+ #  elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+-#    define __LZO_WORDSIZE          4
+ #    define LZO_SIZEOF_VOID_P       4
+ #  else
+-#    define __LZO_WORDSIZE          2
+ #    define LZO_SIZEOF_VOID_P       2
+ #  endif
+ #  if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4)
+ #    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_INT
+ #    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_INT
+ #  endif
++#elif (LZO_ARCH_I086)
++#  if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM)
++#    define LZO_SIZEOF_VOID_P       2
++#  elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE)
++#    define LZO_SIZEOF_VOID_P       4
++#  else
++#    error "invalid LZO_ARCH_I086 memory model"
++#  endif
+ #elif (LZO_ARCH_M16C)
+-#  define __LZO_WORDSIZE            2
+ #  if defined(__m32c_cpu__) || defined(__m32cm_cpu__)
+ #    define LZO_SIZEOF_VOID_P       4
+ #  else
+ #    define LZO_SIZEOF_VOID_P       2
+ #  endif
++#elif (LZO_ARCH_SPU)
++#  define LZO_SIZEOF_VOID_P         4
++#elif (LZO_ARCH_Z80)
++#  define LZO_SIZEOF_VOID_P         2
+ #elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
+-#  define __LZO_WORDSIZE            8
+ #  define LZO_SIZEOF_VOID_P         4
+-#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64)
+-#  define __LZO_WORDSIZE            8
+-#  define LZO_SIZEOF_VOID_P         8
+-#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+-#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG
+-#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+-#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+ #elif (LZO_OS_OS400 || defined(__OS400__))
+-#  define __LZO_WORDSIZE            LZO_SIZEOF_LONG
+-#  define LZO_SIZEOF_VOID_P         16
+-#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+-#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+-#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
+-#  define LZO_SIZEOF_VOID_P         8
+-#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
+-#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+-#elif (LZO_ARCH_SPU)
+-# if 0
+-#  define __LZO_WORDSIZE            16
+-# endif
+-#  define LZO_SIZEOF_VOID_P         4
+-#else
+-#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG
+-#endif
+-#endif
+-#if !defined(LZO_WORDSIZE)
+-#  if defined(__LZO_WORDSIZE)
+-#    define LZO_WORDSIZE            __LZO_WORDSIZE
++#  if defined(__LLP64_IFC__)
++#    define LZO_SIZEOF_VOID_P       8
++#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_LONG
++#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_LONG
+ #  else
+-#    define LZO_WORDSIZE            LZO_SIZEOF_VOID_P
++#    define LZO_SIZEOF_VOID_P       16
++#    define LZO_SIZEOF_SIZE_T       LZO_SIZEOF_LONG
++#    define LZO_SIZEOF_PTRDIFF_T    LZO_SIZEOF_LONG
+ #  endif
++#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
++#  define LZO_SIZEOF_VOID_P         8
++#  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_LONG
++#  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_LONG
+ #endif
++#endif
++#if !defined(LZO_SIZEOF_VOID_P)
++#  define LZO_SIZEOF_VOID_P         LZO_SIZEOF_LONG
++#endif
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_VOID_P == sizeof(void *))
+ #if !defined(LZO_SIZEOF_SIZE_T)
+ #if (LZO_ARCH_I086 || LZO_ARCH_M16C)
+ #  define LZO_SIZEOF_SIZE_T         2
+-#else
++#endif
++#endif
++#if !defined(LZO_SIZEOF_SIZE_T)
+ #  define LZO_SIZEOF_SIZE_T         LZO_SIZEOF_VOID_P
+ #endif
++#if defined(offsetof)
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_SIZE_T == sizeof(size_t))
+ #endif
+ #if !defined(LZO_SIZEOF_PTRDIFF_T)
+ #if (LZO_ARCH_I086)
+@@ -1248,11 +2275,18 @@ extern "C" {
+ #      define LZO_SIZEOF_PTRDIFF_T  2
+ #    endif
+ #  else
+-#    error "LZO_MM"
++#    error "invalid LZO_ARCH_I086 memory model"
+ #  endif
+-#else
++#endif
++#endif
++#if !defined(LZO_SIZEOF_PTRDIFF_T)
+ #  define LZO_SIZEOF_PTRDIFF_T      LZO_SIZEOF_SIZE_T
+ #endif
++#if defined(offsetof)
++LZO_COMPILE_TIME_ASSERT_HEADER(LZO_SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t))
++#endif
++#if !defined(LZO_WORDSIZE)
++#  define LZO_WORDSIZE              LZO_SIZEOF_VOID_P
+ #endif
+ #if (LZO_ABI_NEUTRAL_ENDIAN)
+ #  undef LZO_ABI_BIG_ENDIAN
+@@ -1264,7 +2298,7 @@ extern "C" {
+ #  define LZO_ABI_LITTLE_ENDIAN     1
+ #elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
+ #  define LZO_ABI_LITTLE_ENDIAN     1
+-#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390)
++#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390 || LZO_ARCH_SPU)
+ #  define LZO_ABI_BIG_ENDIAN        1
+ #elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)
+ #  if (__LITTLE_ENDIAN__ == 1)
+@@ -1280,6 +2314,19 @@ extern "C" {
+ #  define LZO_ABI_BIG_ENDIAN        1
+ #elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__)
+ #  define LZO_ABI_LITTLE_ENDIAN     1
++#elif 1 && (LZO_ARCH_ARM && LZO_CC_ARMCC_ARMCC)
++#  if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN)
++#    error "unexpected configuration - check your compiler defines"
++#  elif defined(__BIG_ENDIAN)
++#    define LZO_ABI_BIG_ENDIAN      1
++#  else
++#    define LZO_ABI_LITTLE_ENDIAN   1
++#  endif
++#  define LZO_ABI_LITTLE_ENDIAN     1
++#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EB__) && !defined(__AARCH64EL__)
++#  define LZO_ABI_BIG_ENDIAN        1
++#elif 1 && (LZO_ARCH_ARM64) && defined(__AARCH64EL__) && !defined(__AARCH64EB__)
++#  define LZO_ABI_LITTLE_ENDIAN     1
+ #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__)
+ #  define LZO_ABI_BIG_ENDIAN        1
+ #elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__)
+@@ -1287,7 +2334,7 @@ extern "C" {
+ #endif
+ #endif
+ #if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN)
+-#  error "this should not happen"
++#  error "unexpected configuration - check your compiler defines"
+ #endif
+ #if (LZO_ABI_BIG_ENDIAN)
+ #  define LZO_INFO_ABI_ENDIAN       "be"
+@@ -1302,6 +2349,9 @@ extern "C" {
+ #elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
+ #  define LZO_ABI_ILP16         1
+ #  define LZO_INFO_ABI_PM       "ilp16"
++#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)
++#  define LZO_ABI_LP32          1
++#  define LZO_INFO_ABI_PM       "lp32"
+ #elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)
+ #  define LZO_ABI_ILP32         1
+ #  define LZO_INFO_ABI_PM       "ilp32"
+@@ -1318,7 +2368,8 @@ extern "C" {
+ #  define LZO_ABI_IP32L64       1
+ #  define LZO_INFO_ABI_PM       "ip32l64"
+ #endif
+-#if !defined(__LZO_LIBC_OVERRIDE)
++#if 0
++#elif !defined(__LZO_LIBC_OVERRIDE)
+ #if (LZO_LIBC_NAKED)
+ #  define LZO_INFO_LIBC         "naked"
+ #elif (LZO_LIBC_FREESTANDING)
+@@ -1329,6 +2380,9 @@ extern "C" {
+ #  define LZO_INFO_LIBC         "isoc90"
+ #elif (LZO_LIBC_ISOC99)
+ #  define LZO_INFO_LIBC         "isoc99"
++#elif (LZO_CC_ARMCC_ARMCC) && defined(__ARMCLIB_VERSION)
++#  define LZO_LIBC_ISOC90       1
++#  define LZO_INFO_LIBC         "isoc90"
+ #elif defined(__dietlibc__)
+ #  define LZO_LIBC_DIETLIBC     1
+ #  define LZO_INFO_LIBC         "dietlibc"
+@@ -1337,13 +2391,13 @@ extern "C" {
+ #  define LZO_INFO_LIBC         "newlib"
+ #elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__)
+ #  if defined(__UCLIBC_SUBLEVEL__)
+-#    define LZO_LIBC_UCLIBC     (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__)
++#    define LZO_LIBC_UCLIBC     (__UCLIBC_MAJOR__ * 0x10000L + (__UCLIBC_MINOR__-0) * 0x100 + (__UCLIBC_SUBLEVEL__-0))
+ #  else
+ #    define LZO_LIBC_UCLIBC     0x00090bL
+ #  endif
+-#  define LZO_INFO_LIBC         "uclibc"
++#  define LZO_INFO_LIBC         "uc" "libc"
+ #elif defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+-#  define LZO_LIBC_GLIBC        (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100)
++#  define LZO_LIBC_GLIBC        (__GLIBC__ * 0x10000L + (__GLIBC_MINOR__-0) * 0x100)
+ #  define LZO_INFO_LIBC         "glibc"
+ #elif (LZO_CC_MWERKS) && defined(__MSL__)
+ #  define LZO_LIBC_MSL          __MSL__
+@@ -1356,423 +2410,159 @@ extern "C" {
+ #  define LZO_INFO_LIBC         "default"
+ #endif
+ #endif
+-#if !defined(__lzo_gnuc_extension__)
+-#if (LZO_CC_GNUC >= 0x020800ul)
+-#  define __lzo_gnuc_extension__    __extension__
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_gnuc_extension__    __extension__
+-#else
+-#  define __lzo_gnuc_extension__    /*empty*/
+-#endif
+-#endif
+-#if !defined(__lzo_ua_volatile)
+-#  define __lzo_ua_volatile     volatile
+-#endif
+-#if !defined(__lzo_alignof)
+-#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+-#  define __lzo_alignof(e)      __alignof__(e)
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
+-#  define __lzo_alignof(e)      __alignof__(e)
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+-#  define __lzo_alignof(e)      __alignof(e)
+-#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+-#  define __lzo_alignof(e)      __alignof__(e)
+-#endif
+-#endif
+-#if defined(__lzo_alignof)
+-#  define __lzo_HAVE_alignof 1
+-#endif
+-#if !defined(__lzo_constructor)
+-#if (LZO_CC_GNUC >= 0x030400ul)
+-#  define __lzo_constructor     __attribute__((__constructor__,__used__))
+-#elif (LZO_CC_GNUC >= 0x020700ul)
+-#  define __lzo_constructor     __attribute__((__constructor__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_constructor     __attribute__((__constructor__))
+-#endif
+-#endif
+-#if defined(__lzo_constructor)
+-#  define __lzo_HAVE_constructor 1
+-#endif
+-#if !defined(__lzo_destructor)
+-#if (LZO_CC_GNUC >= 0x030400ul)
+-#  define __lzo_destructor      __attribute__((__destructor__,__used__))
+-#elif (LZO_CC_GNUC >= 0x020700ul)
+-#  define __lzo_destructor      __attribute__((__destructor__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_destructor      __attribute__((__destructor__))
+-#endif
+-#endif
+-#if defined(__lzo_destructor)
+-#  define __lzo_HAVE_destructor 1
+-#endif
+-#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)
+-#  error "this should not happen"
+-#endif
+-#if !defined(__lzo_inline)
+-#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295))
+-#elif defined(__cplusplus)
+-#  define __lzo_inline          inline
+-#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
+-#  define __lzo_inline          __inline
+-#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+-#  define __lzo_inline          __inline__
+-#elif (LZO_CC_DMC)
+-#  define __lzo_inline          __inline
+-#elif (LZO_CC_INTELC)
+-#  define __lzo_inline          __inline
+-#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405))
+-#  define __lzo_inline          __inline
+-#elif (LZO_CC_MSC && (_MSC_VER >= 900))
+-#  define __lzo_inline          __inline
+-#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+-#  define __lzo_inline          __inline__
+-#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+-#  define __lzo_inline          inline
+-#endif
+-#endif
+-#if defined(__lzo_inline)
+-#  define __lzo_HAVE_inline 1
+-#else
+-#  define __lzo_inline          /*empty*/
+-#endif
+-#if !defined(__lzo_forceinline)
+-#if (LZO_CC_GNUC >= 0x030200ul)
+-#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+-#  define __lzo_forceinline     __forceinline
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+-#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+-#  define __lzo_forceinline     __forceinline
+-#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+-#  define __lzo_forceinline     __inline__ __attribute__((__always_inline__))
+-#endif
+-#endif
+-#if defined(__lzo_forceinline)
+-#  define __lzo_HAVE_forceinline 1
+-#else
+-#  define __lzo_forceinline     /*empty*/
+-#endif
+-#if !defined(__lzo_noinline)
+-#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
+-#  define __lzo_noinline        __attribute__((__noinline__,__used__))
+-#elif (LZO_CC_GNUC >= 0x030200ul)
+-#  define __lzo_noinline        __attribute__((__noinline__))
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC)
+-#  define __lzo_noinline        __declspec(noinline)
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+-#  define __lzo_noinline        __attribute__((__noinline__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_noinline        __attribute__((__noinline__))
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+-#  define __lzo_noinline        __declspec(noinline)
+-#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64))
+-#  if defined(__cplusplus)
+-#  else
+-#    define __lzo_noinline      __declspec(noinline)
+-#  endif
+-#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+-#  define __lzo_noinline        __attribute__((__noinline__))
+-#endif
+-#endif
+-#if defined(__lzo_noinline)
+-#  define __lzo_HAVE_noinline 1
+-#else
+-#  define __lzo_noinline        /*empty*/
+-#endif
+-#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)
+-#  error "this should not happen"
+-#endif
+-#if !defined(__lzo_noreturn)
+-#if (LZO_CC_GNUC >= 0x020700ul)
+-#  define __lzo_noreturn        __attribute__((__noreturn__))
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+-#  define __lzo_noreturn        __declspec(noreturn)
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+-#  define __lzo_noreturn        __attribute__((__noreturn__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_noreturn        __attribute__((__noreturn__))
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+-#  define __lzo_noreturn        __declspec(noreturn)
+-#endif
+-#endif
+-#if defined(__lzo_noreturn)
+-#  define __lzo_HAVE_noreturn 1
+-#else
+-#  define __lzo_noreturn        /*empty*/
+-#endif
+-#if !defined(__lzo_nothrow)
+-#if (LZO_CC_GNUC >= 0x030300ul)
+-#  define __lzo_nothrow         __attribute__((__nothrow__))
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus)
+-#  define __lzo_nothrow         __declspec(nothrow)
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC)
+-#  define __lzo_nothrow         __attribute__((__nothrow__))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_nothrow         __attribute__((__nothrow__))
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
+-#  define __lzo_nothrow         __declspec(nothrow)
+-#endif
+-#endif
+-#if defined(__lzo_nothrow)
+-#  define __lzo_HAVE_nothrow 1
+-#else
+-#  define __lzo_nothrow         /*empty*/
+-#endif
+-#if !defined(__lzo_restrict)
+-#if (LZO_CC_GNUC >= 0x030400ul)
+-#  define __lzo_restrict        __restrict__
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+-#  define __lzo_restrict        __restrict__
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM)
+-#  define __lzo_restrict        __restrict__
+-#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
+-#  define __lzo_restrict        __restrict
+-#endif
+-#endif
+-#if defined(__lzo_restrict)
+-#  define __lzo_HAVE_restrict 1
+-#else
+-#  define __lzo_restrict        /*empty*/
+-#endif
+-#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
+-#if (LZO_CC_GNUC >= 0x030200ul)
+-#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+-#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
+-#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+-#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+-#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#  define __lzo_likely(e)       (__builtin_expect(!!(e),1))
+-#  define __lzo_unlikely(e)     (__builtin_expect(!!(e),0))
+-#endif
+-#endif
+-#if defined(__lzo_likely)
+-#  define __lzo_HAVE_likely 1
+-#else
+-#  define __lzo_likely(e)       (e)
+-#endif
+-#if defined(__lzo_unlikely)
+-#  define __lzo_HAVE_unlikely 1
+-#else
+-#  define __lzo_unlikely(e)     (e)
+-#endif
+-#if !defined(LZO_UNUSED)
+-#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+-#    define LZO_UNUSED(var)         ((void) &var)
+-#  elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
+-#    define LZO_UNUSED(var)         if (&var) ; else
+-#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#    define LZO_UNUSED(var)         ((void) var)
+-#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+-#    define LZO_UNUSED(var)         if (&var) ; else
+-#  elif (LZO_CC_KEILC)
+-#    define LZO_UNUSED(var)         {extern int __lzo_unused[1-2*!(sizeof(var)>0)];}
+-#  elif (LZO_CC_PACIFICC)
+-#    define LZO_UNUSED(var)         ((void) sizeof(var))
+-#  elif (LZO_CC_WATCOMC) && defined(__cplusplus)
+-#    define LZO_UNUSED(var)         ((void) var)
+-#  else
+-#    define LZO_UNUSED(var)         ((void) &var)
+-#  endif
+-#endif
+-#if !defined(LZO_UNUSED_FUNC)
+-#  if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+-#    define LZO_UNUSED_FUNC(func)   ((void) func)
+-#  elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
+-#    define LZO_UNUSED_FUNC(func)   if (func) ; else
+-#  elif (LZO_CC_CLANG || LZO_CC_LLVM)
+-#    define LZO_UNUSED_FUNC(func)   ((void) &func)
+-#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+-#    define LZO_UNUSED_FUNC(func)   if (func) ; else
+-#  elif (LZO_CC_MSC)
+-#    define LZO_UNUSED_FUNC(func)   ((void) &func)
+-#  elif (LZO_CC_KEILC || LZO_CC_PELLESC)
+-#    define LZO_UNUSED_FUNC(func)   {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];}
+-#  else
+-#    define LZO_UNUSED_FUNC(func)   ((void) func)
+-#  endif
+-#endif
+-#if !defined(LZO_UNUSED_LABEL)
+-#  if (LZO_CC_WATCOMC) && defined(__cplusplus)
+-#    define LZO_UNUSED_LABEL(l)     switch(0) case 1:goto l
+-#  elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)
+-#    define LZO_UNUSED_LABEL(l)     if (0) goto l
+-#  else
+-#    define LZO_UNUSED_LABEL(l)     switch(0) case 1:goto l
+-#  endif
+-#endif
+-#if !defined(LZO_DEFINE_UNINITIALIZED_VAR)
+-#  if 0
+-#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var
+-#  elif 0 && (LZO_CC_GNUC)
+-#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = var
+-#  else
+-#    define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init)  type var = init
+-#  endif
+-#endif
+-#if !defined(LZO_UNCONST_CAST)
+-#  if 0 && defined(__cplusplus)
+-#    define LZO_UNCONST_CAST(t,e)   (const_cast<t> (e))
+-#  elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+-#    define LZO_UNCONST_CAST(t,e)   ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e))))))
+-#  else
+-#    define LZO_UNCONST_CAST(t,e)   ((t) ((void *) ((char *) ((const void *) (e)))))
+-#  endif
+-#endif
+-#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
+-#  if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
+-#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-!(e)];
+-#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
+-#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1u-2*!(e)];
+-#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+-#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-!(e)];
+-#  else
+-#    define LZO_COMPILE_TIME_ASSERT_HEADER(e)  extern int __lzo_cta[1-2*!(e)];
+-#  endif
+-#endif
+-#if !defined(LZO_COMPILE_TIME_ASSERT)
+-#  if (LZO_CC_AZTECC)
+-#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __lzo_cta_t[1-!(e)];}
+-#  elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+-#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+-#  elif (LZO_CC_MSC && (_MSC_VER < 900))
+-#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+-#  elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+-#    define LZO_COMPILE_TIME_ASSERT(e)  switch(0) case 1:case !(e):break;
+-#  else
+-#    define LZO_COMPILE_TIME_ASSERT(e)  {typedef int __lzo_cta_t[1-2*!(e)];}
+-#  endif
+-#endif
+-#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)
+-#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
+-#  elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+-#    define __lzo_cdecl                 __cdecl
+-#    define __lzo_cdecl_atexit          /*empty*/
+-#    define __lzo_cdecl_main            __cdecl
+-#    if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+-#      define __lzo_cdecl_qsort         __pascal
+-#    elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+-#      define __lzo_cdecl_qsort         _stdcall
+-#    else
+-#      define __lzo_cdecl_qsort         __cdecl
+-#    endif
+-#  elif (LZO_CC_WATCOMC)
+-#    define __lzo_cdecl                 __cdecl
+-#  else
+-#    define __lzo_cdecl                 __cdecl
+-#    define __lzo_cdecl_atexit          __cdecl
+-#    define __lzo_cdecl_main            __cdecl
+-#    define __lzo_cdecl_qsort           __cdecl
+-#  endif
+-#  if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC)
+-#  elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+-#    define __lzo_cdecl_sighandler      __pascal
+-#  elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+-#    define __lzo_cdecl_sighandler      _stdcall
+-#  elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE)
+-#    define __lzo_cdecl_sighandler      __clrcall
+-#  elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700))
+-#    if defined(_DLL)
+-#      define __lzo_cdecl_sighandler    _far _cdecl _loadds
+-#    elif defined(_MT)
+-#      define __lzo_cdecl_sighandler    _far _cdecl
+-#    else
+-#      define __lzo_cdecl_sighandler    _cdecl
+-#    endif
+-#  else
+-#    define __lzo_cdecl_sighandler      __cdecl
+-#  endif
+-#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC)
+-#  define __lzo_cdecl                   __cdecl
+-#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC))
+-#  define __lzo_cdecl                   cdecl
+-#endif
+-#if !defined(__lzo_cdecl)
+-#  define __lzo_cdecl                   /*empty*/
+-#endif
+-#if !defined(__lzo_cdecl_atexit)
+-#  define __lzo_cdecl_atexit            /*empty*/
+-#endif
+-#if !defined(__lzo_cdecl_main)
+-#  define __lzo_cdecl_main              /*empty*/
+-#endif
+-#if !defined(__lzo_cdecl_qsort)
+-#  define __lzo_cdecl_qsort             /*empty*/
+-#endif
+-#if !defined(__lzo_cdecl_sighandler)
+-#  define __lzo_cdecl_sighandler        /*empty*/
+-#endif
+-#if !defined(__lzo_cdecl_va)
+-#  define __lzo_cdecl_va                __lzo_cdecl
+-#endif
+-#if !(LZO_CFG_NO_WINDOWS_H)
+-#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
+-#  if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
+-#  elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
+-#  elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))
+-#  else
+-#    define LZO_HAVE_WINDOWS_H 1
+-#  endif
++#if (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
++#  define LZO_ASM_SYNTAX_MSC 1
++#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
++#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))
++#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
++#  define LZO_ASM_SYNTAX_GNUC 1
++#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
++#  define LZO_ASM_SYNTAX_GNUC 1
++#elif (LZO_CC_GNUC)
++#  define LZO_ASM_SYNTAX_GNUC 1
++#endif
++#if (LZO_ASM_SYNTAX_GNUC)
++#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul))
++#  define __LZO_ASM_CLOBBER                     "ax"
++#  define __LZO_ASM_CLOBBER_LIST_CC             /*empty*/
++#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      /*empty*/
++#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/
++#elif (LZO_CC_INTELC && (__INTEL_COMPILER < 1000))
++#  define __LZO_ASM_CLOBBER                     "memory"
++#  define __LZO_ASM_CLOBBER_LIST_CC             /*empty*/
++#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      : "memory"
++#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/
++#else
++#  define __LZO_ASM_CLOBBER                     "cc", "memory"
++#  define __LZO_ASM_CLOBBER_LIST_CC             : "cc"
++#  define __LZO_ASM_CLOBBER_LIST_CC_MEMORY      : "cc", "memory"
++#  define __LZO_ASM_CLOBBER_LIST_EMPTY          /*empty*/
+ #endif
+ #endif
+ #if (LZO_ARCH_ALPHA)
+-#  define LZO_OPT_AVOID_UINT_INDEX  1
+-#  define LZO_OPT_AVOID_SHORT       1
+-#  define LZO_OPT_AVOID_USHORT      1
++#  define LZO_OPT_AVOID_UINT_INDEX          1
+ #elif (LZO_ARCH_AMD64)
+-#  define LZO_OPT_AVOID_INT_INDEX   1
+-#  define LZO_OPT_AVOID_UINT_INDEX  1
+-#  define LZO_OPT_UNALIGNED16       1
+-#  define LZO_OPT_UNALIGNED32       1
+-#  define LZO_OPT_UNALIGNED64       1
+-#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB)
++#  define LZO_OPT_AVOID_INT_INDEX           1
++#  define LZO_OPT_AVOID_UINT_INDEX          1
++#  ifndef LZO_OPT_UNALIGNED16
++#  define LZO_OPT_UNALIGNED16               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED32
++#  define LZO_OPT_UNALIGNED32               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED64
++#  define LZO_OPT_UNALIGNED64               1
++#  endif
+ #elif (LZO_ARCH_ARM)
+-#  define LZO_OPT_AVOID_SHORT       1
+-#  define LZO_OPT_AVOID_USHORT      1
++#  if defined(__ARM_FEATURE_UNALIGNED)
++#    ifndef LZO_OPT_UNALIGNED16
++#    define LZO_OPT_UNALIGNED16             1
++#    endif
++#    ifndef LZO_OPT_UNALIGNED32
++#    define LZO_OPT_UNALIGNED32             1
++#    endif
++#  elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 7)
++#    ifndef LZO_OPT_UNALIGNED16
++#    define LZO_OPT_UNALIGNED16             1
++#    endif
++#    ifndef LZO_OPT_UNALIGNED32
++#    define LZO_OPT_UNALIGNED32             1
++#    endif
++#  elif defined(__TARGET_ARCH_ARM) && ((__TARGET_ARCH_ARM+0) >= 6) && !defined(__TARGET_PROFILE_M)
++#    ifndef LZO_OPT_UNALIGNED16
++#    define LZO_OPT_UNALIGNED16             1
++#    endif
++#    ifndef LZO_OPT_UNALIGNED32
++#    define LZO_OPT_UNALIGNED32             1
++#    endif
++#  endif
++#elif (LZO_ARCH_ARM64)
++#  ifndef LZO_OPT_UNALIGNED16
++#  define LZO_OPT_UNALIGNED16               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED32
++#  define LZO_OPT_UNALIGNED32               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED64
++#  define LZO_OPT_UNALIGNED64               1
++#  endif
+ #elif (LZO_ARCH_CRIS)
+-#  define LZO_OPT_UNALIGNED16       1
+-#  define LZO_OPT_UNALIGNED32       1
++#  ifndef LZO_OPT_UNALIGNED16
++#  define LZO_OPT_UNALIGNED16               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED32
++#  define LZO_OPT_UNALIGNED32               1
++#  endif
+ #elif (LZO_ARCH_I386)
+-#  define LZO_OPT_UNALIGNED16       1
+-#  define LZO_OPT_UNALIGNED32       1
++#  ifndef LZO_OPT_UNALIGNED16
++#  define LZO_OPT_UNALIGNED16               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED32
++#  define LZO_OPT_UNALIGNED32               1
++#  endif
+ #elif (LZO_ARCH_IA64)
+-#  define LZO_OPT_AVOID_INT_INDEX   1
+-#  define LZO_OPT_AVOID_UINT_INDEX  1
+-#  define LZO_OPT_PREFER_POSTINC    1
++#  define LZO_OPT_AVOID_INT_INDEX           1
++#  define LZO_OPT_AVOID_UINT_INDEX          1
++#  define LZO_OPT_PREFER_POSTINC            1
+ #elif (LZO_ARCH_M68K)
+-#  define LZO_OPT_PREFER_POSTINC    1
+-#  define LZO_OPT_PREFER_PREDEC     1
++#  define LZO_OPT_PREFER_POSTINC            1
++#  define LZO_OPT_PREFER_PREDEC             1
+ #  if defined(__mc68020__) && !defined(__mcoldfire__)
+-#    define LZO_OPT_UNALIGNED16     1
+-#    define LZO_OPT_UNALIGNED32     1
++#    ifndef LZO_OPT_UNALIGNED16
++#    define LZO_OPT_UNALIGNED16             1
++#    endif
++#    ifndef LZO_OPT_UNALIGNED32
++#    define LZO_OPT_UNALIGNED32             1
++#    endif
+ #  endif
+ #elif (LZO_ARCH_MIPS)
+-#  define LZO_OPT_AVOID_UINT_INDEX  1
++#  define LZO_OPT_AVOID_UINT_INDEX          1
+ #elif (LZO_ARCH_POWERPC)
+-#  define LZO_OPT_PREFER_PREINC     1
+-#  define LZO_OPT_PREFER_PREDEC     1
++#  define LZO_OPT_PREFER_PREINC             1
++#  define LZO_OPT_PREFER_PREDEC             1
+ #  if (LZO_ABI_BIG_ENDIAN)
+-#    define LZO_OPT_UNALIGNED16     1
+-#    define LZO_OPT_UNALIGNED32     1
++#    ifndef LZO_OPT_UNALIGNED16
++#    define LZO_OPT_UNALIGNED16             1
++#    endif
++#    ifndef LZO_OPT_UNALIGNED32
++#    define LZO_OPT_UNALIGNED32             1
++#    endif
++#    if (LZO_WORDSIZE == 8)
++#      ifndef LZO_OPT_UNALIGNED64
++#      define LZO_OPT_UNALIGNED64           1
++#      endif
++#    endif
+ #  endif
+ #elif (LZO_ARCH_S390)
+-#  define LZO_OPT_UNALIGNED16       1
+-#  define LZO_OPT_UNALIGNED32       1
+-#  if (LZO_SIZEOF_SIZE_T == 8)
+-#    define LZO_OPT_UNALIGNED64     1
++#  ifndef LZO_OPT_UNALIGNED16
++#  define LZO_OPT_UNALIGNED16               1
++#  endif
++#  ifndef LZO_OPT_UNALIGNED32
++#  define LZO_OPT_UNALIGNED32               1
++#  endif
++#  if (LZO_WORDSIZE == 8)
++#    ifndef LZO_OPT_UNALIGNED64
++#    define LZO_OPT_UNALIGNED64             1
++#    endif
+ #  endif
+ #elif (LZO_ARCH_SH)
+-#  define LZO_OPT_PREFER_POSTINC    1
+-#  define LZO_OPT_PREFER_PREDEC     1
++#  define LZO_OPT_PREFER_POSTINC            1
++#  define LZO_OPT_PREFER_PREDEC             1
+ #endif
+ #ifndef LZO_CFG_NO_INLINE_ASM
+-#if (LZO_CC_LLVM)
++#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)
+ #  define LZO_CFG_NO_INLINE_ASM 1
++#elif (LZO_CC_LLVM)
++#  define LZO_CFG_NO_INLINE_ASM 1
++#endif
+ #endif
++#if (LZO_CFG_NO_INLINE_ASM)
++#  undef LZO_ASM_SYNTAX_MSC
++#  undef LZO_ASM_SYNTAX_GNUC
++#  undef __LZO_ASM_CLOBBER
++#  undef __LZO_ASM_CLOBBER_LIST_CC
++#  undef __LZO_ASM_CLOBBER_LIST_CC_MEMORY
++#  undef __LZO_ASM_CLOBBER_LIST_EMPTY
+ #endif
+ #ifndef LZO_CFG_NO_UNALIGNED
+ #if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)
+@@ -1784,25 +2574,6 @@ extern "C" {
+ #  undef LZO_OPT_UNALIGNED32
+ #  undef LZO_OPT_UNALIGNED64
+ #endif
+-#if (LZO_CFG_NO_INLINE_ASM)
+-#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+-#  define LZO_ASM_SYNTAX_MSC 1
+-#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+-#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))
+-#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+-#  define LZO_ASM_SYNTAX_GNUC 1
+-#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+-#  define LZO_ASM_SYNTAX_GNUC 1
+-#endif
+-#if (LZO_ASM_SYNTAX_GNUC)
+-#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul))
+-#  define __LZO_ASM_CLOBBER         "ax"
+-#elif (LZO_CC_INTELC)
+-#  define __LZO_ASM_CLOBBER         "memory"
+-#else
+-#  define __LZO_ASM_CLOBBER         "cc", "memory"
+-#endif
+-#endif
+ #if defined(__LZO_INFOSTR_MM)
+ #elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM))
+ #  define __LZO_INFOSTR_MM          ""
+@@ -1846,7 +2617,382 @@ extern "C" {
+ #define LZO_INFO_STRING \
+     LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \
+     " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER
++#if !(LZO_CFG_SKIP_LZO_TYPES)
++#if (!(LZO_SIZEOF_SHORT+0 > 0 && LZO_SIZEOF_INT+0 > 0 && LZO_SIZEOF_LONG+0 > 0))
++#  error "missing defines for sizes"
++#endif
++#if (!(LZO_SIZEOF_PTRDIFF_T+0 > 0 && LZO_SIZEOF_SIZE_T+0 > 0 && LZO_SIZEOF_VOID_P+0 > 0))
++#  error "missing defines for sizes"
++#endif
++#if !defined(lzo_llong_t)
++#if (LZO_SIZEOF_LONG_LONG+0 > 0)
++__lzo_gnuc_extension__ typedef long long lzo_llong_t__;
++__lzo_gnuc_extension__ typedef unsigned long long lzo_ullong_t__;
++#  define lzo_llong_t               lzo_llong_t__
++#  define lzo_ullong_t              lzo_ullong_t__
++#endif
++#endif
++#if !defined(lzo_int16e_t)
++#if (LZO_SIZEOF_LONG == 2)
++#  define lzo_int16e_t              long
++#  define lzo_uint16e_t             unsigned long
++#elif (LZO_SIZEOF_INT == 2)
++#  define lzo_int16e_t              int
++#  define lzo_uint16e_t             unsigned int
++#elif (LZO_SIZEOF_SHORT == 2)
++#  define lzo_int16e_t              short int
++#  define lzo_uint16e_t             unsigned short int
++#elif 1 && !(LZO_CFG_TYPE_NO_MODE_HI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM)
++   typedef int lzo_int16e_hi_t__ __attribute__((__mode__(__HI__)));
++   typedef unsigned int lzo_uint16e_hi_t__ __attribute__((__mode__(__HI__)));
++#  define lzo_int16e_t              lzo_int16e_hi_t__
++#  define lzo_uint16e_t             lzo_uint16e_hi_t__
++#elif (LZO_SIZEOF___INT16 == 2)
++#  define lzo_int16e_t              __int16
++#  define lzo_uint16e_t             unsigned __int16
++#else
++#endif
++#endif
++#if defined(lzo_int16e_t)
++#  define LZO_SIZEOF_LZO_INT16E_T   2
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == 2)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16e_t) == LZO_SIZEOF_LZO_INT16E_T)
++#endif
++#if !defined(lzo_int32e_t)
++#if (LZO_SIZEOF_LONG == 4)
++#  define lzo_int32e_t              long int
++#  define lzo_uint32e_t             unsigned long int
++#elif (LZO_SIZEOF_INT == 4)
++#  define lzo_int32e_t              int
++#  define lzo_uint32e_t             unsigned int
++#elif (LZO_SIZEOF_SHORT == 4)
++#  define lzo_int32e_t              short int
++#  define lzo_uint32e_t             unsigned short int
++#elif (LZO_SIZEOF_LONG_LONG == 4)
++#  define lzo_int32e_t              lzo_llong_t
++#  define lzo_uint32e_t             lzo_ullong_t
++#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x025f00ul) || LZO_CC_LLVM) && (__INT_MAX__+0 > 2147483647L)
++   typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
++   typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
++#  define lzo_int32e_t              lzo_int32e_si_t__
++#  define lzo_uint32e_t             lzo_uint32e_si_t__
++#elif 1 && !(LZO_CFG_TYPE_NO_MODE_SI) && (LZO_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L)
++   typedef int lzo_int32e_si_t__ __attribute__((__mode__(__SI__)));
++   typedef unsigned int lzo_uint32e_si_t__ __attribute__((__mode__(__SI__)));
++#  define lzo_int32e_t              lzo_int32e_si_t__
++#  define lzo_uint32e_t             lzo_uint32e_si_t__
++#  define LZO_INT32_C(c)            (c##LL)
++#  define LZO_UINT32_C(c)           (c##ULL)
++#elif (LZO_SIZEOF___INT32 == 4)
++#  define lzo_int32e_t              __int32
++#  define lzo_uint32e_t             unsigned __int32
++#else
++#endif
++#endif
++#if defined(lzo_int32e_t)
++#  define LZO_SIZEOF_LZO_INT32E_T   4
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == 4)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32e_t) == LZO_SIZEOF_LZO_INT32E_T)
++#endif
++#if !defined(lzo_int64e_t)
++#if (LZO_SIZEOF___INT64 == 8)
++#  if (LZO_CC_BORLANDC) && !(LZO_CFG_TYPE_PREFER___INT64)
++#    define LZO_CFG_TYPE_PREFER___INT64 1
++#  endif
++#endif
++#if (LZO_SIZEOF_INT == 8) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
++#  define lzo_int64e_t              int
++#  define lzo_uint64e_t             unsigned int
++#  define LZO_SIZEOF_LZO_INT64E_T   LZO_SIZEOF_INT
++#elif (LZO_SIZEOF_LONG == 8)
++#  define lzo_int64e_t              long int
++#  define lzo_uint64e_t             unsigned long int
++#  define LZO_SIZEOF_LZO_INT64E_T   LZO_SIZEOF_LONG
++#elif (LZO_SIZEOF_LONG_LONG == 8) && !(LZO_CFG_TYPE_PREFER___INT64)
++#  define lzo_int64e_t              lzo_llong_t
++#  define lzo_uint64e_t             lzo_ullong_t
++#  if (LZO_CC_BORLANDC)
++#    define LZO_INT64_C(c)          ((c) + 0ll)
++#    define LZO_UINT64_C(c)         ((c) + 0ull)
++#  elif 0
++#    define LZO_INT64_C(c)          (__lzo_gnuc_extension__ (c##LL))
++#    define LZO_UINT64_C(c)         (__lzo_gnuc_extension__ (c##ULL))
++#  else
++#    define LZO_INT64_C(c)          (c##LL)
++#    define LZO_UINT64_C(c)         (c##ULL)
++#  endif
++#  define LZO_SIZEOF_LZO_INT64E_T   LZO_SIZEOF_LONG_LONG
++#elif (LZO_SIZEOF___INT64 == 8)
++#  define lzo_int64e_t              __int64
++#  define lzo_uint64e_t             unsigned __int64
++#  if (LZO_CC_BORLANDC)
++#    define LZO_INT64_C(c)          ((c) + 0i64)
++#    define LZO_UINT64_C(c)         ((c) + 0ui64)
++#  else
++#    define LZO_INT64_C(c)          (c##i64)
++#    define LZO_UINT64_C(c)         (c##ui64)
++#  endif
++#  define LZO_SIZEOF_LZO_INT64E_T   LZO_SIZEOF___INT64
++#else
++#endif
++#endif
++#if defined(lzo_int64e_t)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == 8)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64e_t) == LZO_SIZEOF_LZO_INT64E_T)
++#endif
++#if !defined(lzo_int32l_t)
++#if defined(lzo_int32e_t)
++#  define lzo_int32l_t              lzo_int32e_t
++#  define lzo_uint32l_t             lzo_uint32e_t
++#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_LZO_INT32E_T
++#elif (LZO_SIZEOF_INT >= 4) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
++#  define lzo_int32l_t              int
++#  define lzo_uint32l_t             unsigned int
++#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_INT
++#elif (LZO_SIZEOF_LONG >= 4)
++#  define lzo_int32l_t              long int
++#  define lzo_uint32l_t             unsigned long int
++#  define LZO_SIZEOF_LZO_INT32L_T   LZO_SIZEOF_LONG
++#else
++#  error "lzo_int32l_t"
++#endif
++#endif
++#if 1
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) >= 4)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32l_t) == LZO_SIZEOF_LZO_INT32L_T)
++#endif
++#if !defined(lzo_int64l_t)
++#if defined(lzo_int64e_t)
++#  define lzo_int64l_t              lzo_int64e_t
++#  define lzo_uint64l_t             lzo_uint64e_t
++#  define LZO_SIZEOF_LZO_INT64L_T   LZO_SIZEOF_LZO_INT64E_T
++#else
++#endif
++#endif
++#if defined(lzo_int64l_t)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) >= 8)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64l_t) == LZO_SIZEOF_LZO_INT64L_T)
++#endif
++#if !defined(lzo_int32f_t)
++#if (LZO_SIZEOF_SIZE_T >= 8)
++#  define lzo_int32f_t              lzo_int64l_t
++#  define lzo_uint32f_t             lzo_uint64l_t
++#  define LZO_SIZEOF_LZO_INT32F_T   LZO_SIZEOF_LZO_INT64L_T
++#else
++#  define lzo_int32f_t              lzo_int32l_t
++#  define lzo_uint32f_t             lzo_uint32l_t
++#  define LZO_SIZEOF_LZO_INT32F_T   LZO_SIZEOF_LZO_INT32L_T
++#endif
++#endif
++#if 1
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) >= 4)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32f_t) == LZO_SIZEOF_LZO_INT32F_T)
++#endif
++#if !defined(lzo_int64f_t)
++#if defined(lzo_int64l_t)
++#  define lzo_int64f_t              lzo_int64l_t
++#  define lzo_uint64f_t             lzo_uint64l_t
++#  define LZO_SIZEOF_LZO_INT64F_T   LZO_SIZEOF_LZO_INT64L_T
++#else
++#endif
++#endif
++#if defined(lzo_int64f_t)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) >= 8)
++   LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64f_t) == LZO_SIZEOF_LZO_INT64F_T)
++#endif
++#if !defined(lzo_intptr_t)
++#if 1 && (LZO_OS_OS400 && (LZO_SIZEOF_VOID_P == 16))
++#  define __LZO_INTPTR_T_IS_POINTER 1
++   typedef char*                    lzo_intptr_t;
++   typedef char*                    lzo_uintptr_t;
++#  define lzo_intptr_t              lzo_intptr_t
++#  define lzo_uintptr_t             lzo_uintptr_t
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_VOID_P
++#elif (LZO_CC_MSC && (_MSC_VER >= 1300) && (LZO_SIZEOF_VOID_P == 4) && (LZO_SIZEOF_INT == 4))
++   typedef __w64 int                lzo_intptr_t;
++   typedef __w64 unsigned int       lzo_uintptr_t;
++#  define lzo_intptr_t              lzo_intptr_t
++#  define lzo_uintptr_t             lzo_uintptr_t
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_INT
++#elif (LZO_SIZEOF_SHORT == LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT > LZO_SIZEOF_VOID_P)
++#  define lzo_intptr_t              short
++#  define lzo_uintptr_t             unsigned short
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_SHORT
++#elif (LZO_SIZEOF_INT >= LZO_SIZEOF_VOID_P) && (LZO_SIZEOF_INT < LZO_SIZEOF_LONG)
++#  define lzo_intptr_t              int
++#  define lzo_uintptr_t             unsigned int
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_INT
++#elif (LZO_SIZEOF_LONG >= LZO_SIZEOF_VOID_P)
++#  define lzo_intptr_t              long
++#  define lzo_uintptr_t             unsigned long
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_LONG
++#elif (LZO_SIZEOF_LZO_INT64L_T >= LZO_SIZEOF_VOID_P)
++#  define lzo_intptr_t              lzo_int64l_t
++#  define lzo_uintptr_t             lzo_uint64l_t
++#  define LZO_SIZEOF_LZO_INTPTR_T   LZO_SIZEOF_LZO_INT64L_T
++#else
++#  error "lzo_intptr_t"
++#endif
++#endif
++#if 1
++    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) >= sizeof(void *))
++    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_intptr_t) == sizeof(lzo_uintptr_t))
++#endif
++#if !defined(lzo_word_t)
++#if defined(LZO_WORDSIZE) && (LZO_WORDSIZE+0 > 0)
++#if (LZO_WORDSIZE == LZO_SIZEOF_LZO_INTPTR_T) && !(__LZO_INTPTR_T_IS_POINTER)
++#  define lzo_word_t                lzo_uintptr_t
++#  define lzo_sword_t               lzo_intptr_t
++#  define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INTPTR_T
++#elif (LZO_WORDSIZE == LZO_SIZEOF_LONG)
++#  define lzo_word_t                unsigned long
++#  define lzo_sword_t               long
++#  define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LONG
++#elif (LZO_WORDSIZE == LZO_SIZEOF_INT)
++#  define lzo_word_t                unsigned int
++#  define lzo_sword_t               int
++#  define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_INT
++#elif (LZO_WORDSIZE == LZO_SIZEOF_SHORT)
++#  define lzo_word_t                unsigned short
++#  define lzo_sword_t               short
++#  define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_SHORT
++#elif (LZO_WORDSIZE == 1)
++#  define lzo_word_t                unsigned char
++#  define lzo_sword_t               signed char
++#  define LZO_SIZEOF_LZO_WORD_T 1
++#elif (LZO_WORDSIZE == LZO_SIZEOF_LZO_INT64L_T)
++#  define lzo_word_t                lzo_uint64l_t
++#  define lzo_sword_t               lzo_int64l_t
++#  define LZO_SIZEOF_LZO_WORD_T LZO_SIZEOF_LZO_INT64L_T
++#elif (LZO_ARCH_SPU) && (LZO_CC_GNUC)
++#if 0
++   typedef unsigned lzo_word_t  __attribute__((__mode__(__V16QI__)));
++   typedef int      lzo_sword_t __attribute__((__mode__(__V16QI__)));
++#  define lzo_word_t                lzo_word_t
++#  define lzo_sword_t               lzo_sword_t
++#  define LZO_SIZEOF_LZO_WORD_T     16
++#endif
++#else
++#  error "lzo_word_t"
++#endif
++#endif
++#endif
++#if 1 && defined(lzo_word_t)
++    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_word_t)  == LZO_WORDSIZE)
++    LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_sword_t) == LZO_WORDSIZE)
++#endif
++#if 1
++#define lzo_int8_t                  signed char
++#define lzo_uint8_t                 unsigned char
++#define LZO_SIZEOF_LZO_INT8_T       1
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == 1)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int8_t) == sizeof(lzo_uint8_t))
++#endif
++#if defined(lzo_int16e_t)
++#define lzo_int16_t                 lzo_int16e_t
++#define lzo_uint16_t                lzo_uint16e_t
++#define LZO_SIZEOF_LZO_INT16_T      LZO_SIZEOF_LZO_INT16E_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == 2)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int16_t) == sizeof(lzo_uint16_t))
++#endif
++#if defined(lzo_int32e_t)
++#define lzo_int32_t                 lzo_int32e_t
++#define lzo_uint32_t                lzo_uint32e_t
++#define LZO_SIZEOF_LZO_INT32_T      LZO_SIZEOF_LZO_INT32E_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == 4)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int32_t) == sizeof(lzo_uint32_t))
++#endif
++#if defined(lzo_int64e_t)
++#define lzo_int64_t                 lzo_int64e_t
++#define lzo_uint64_t                lzo_uint64e_t
++#define LZO_SIZEOF_LZO_INT64_T      LZO_SIZEOF_LZO_INT64E_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == 8)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int64_t) == sizeof(lzo_uint64_t))
++#endif
++#if 1
++#define lzo_int_least32_t           lzo_int32l_t
++#define lzo_uint_least32_t          lzo_uint32l_t
++#define LZO_SIZEOF_LZO_INT_LEAST32_T LZO_SIZEOF_LZO_INT32L_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) >= 4)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least32_t) == sizeof(lzo_uint_least32_t))
++#endif
++#if defined(lzo_int64l_t)
++#define lzo_int_least64_t           lzo_int64l_t
++#define lzo_uint_least64_t          lzo_uint64l_t
++#define LZO_SIZEOF_LZO_INT_LEAST64_T LZO_SIZEOF_LZO_INT64L_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) >= 8)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_least64_t) == sizeof(lzo_uint_least64_t))
++#endif
++#if 1
++#define lzo_int_fast32_t           lzo_int32f_t
++#define lzo_uint_fast32_t          lzo_uint32f_t
++#define LZO_SIZEOF_LZO_INT_FAST32_T LZO_SIZEOF_LZO_INT32F_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) >= 4)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast32_t) == sizeof(lzo_uint_fast32_t))
++#endif
++#if defined(lzo_int64f_t)
++#define lzo_int_fast64_t           lzo_int64f_t
++#define lzo_uint_fast64_t          lzo_uint64f_t
++#define LZO_SIZEOF_LZO_INT_FAST64_T LZO_SIZEOF_LZO_INT64F_T
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) >= 8)
++LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_int_fast64_t) == sizeof(lzo_uint_fast64_t))
++#endif
++#if !defined(LZO_INT16_C)
++#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 2)
++#    define LZO_INT16_C(c)          ((c) + 0)
++#    define LZO_UINT16_C(c)         ((c) + 0U)
++#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 2)
++#    define LZO_INT16_C(c)          ((c) + 0L)
++#    define LZO_UINT16_C(c)         ((c) + 0UL)
++#  elif (LZO_SIZEOF_INT >= 2)
++#    define LZO_INT16_C(c)          (c)
++#    define LZO_UINT16_C(c)         (c##U)
++#  elif (LZO_SIZEOF_LONG >= 2)
++#    define LZO_INT16_C(c)          (c##L)
++#    define LZO_UINT16_C(c)         (c##UL)
++#  else
++#    error "LZO_INT16_C"
++#  endif
++#endif
++#if !defined(LZO_INT32_C)
++#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 4)
++#    define LZO_INT32_C(c)          ((c) + 0)
++#    define LZO_UINT32_C(c)         ((c) + 0U)
++#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 4)
++#    define LZO_INT32_C(c)          ((c) + 0L)
++#    define LZO_UINT32_C(c)         ((c) + 0UL)
++#  elif (LZO_SIZEOF_INT >= 4)
++#    define LZO_INT32_C(c)          (c)
++#    define LZO_UINT32_C(c)         (c##U)
++#  elif (LZO_SIZEOF_LONG >= 4)
++#    define LZO_INT32_C(c)          (c##L)
++#    define LZO_UINT32_C(c)         (c##UL)
++#  elif (LZO_SIZEOF_LONG_LONG >= 4)
++#    define LZO_INT32_C(c)          (c##LL)
++#    define LZO_UINT32_C(c)         (c##ULL)
++#  else
++#    error "LZO_INT32_C"
++#  endif
++#endif
++#if !defined(LZO_INT64_C) && defined(lzo_int64l_t)
++#  if (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_INT >= 8)
++#    define LZO_INT64_C(c)          ((c) + 0)
++#    define LZO_UINT64_C(c)         ((c) + 0U)
++#  elif (LZO_BROKEN_INTEGRAL_CONSTANTS) && (LZO_SIZEOF_LONG >= 8)
++#    define LZO_INT64_C(c)          ((c) + 0L)
++#    define LZO_UINT64_C(c)         ((c) + 0UL)
++#  elif (LZO_SIZEOF_INT >= 8)
++#    define LZO_INT64_C(c)          (c)
++#    define LZO_UINT64_C(c)         (c##U)
++#  elif (LZO_SIZEOF_LONG >= 8)
++#    define LZO_INT64_C(c)          (c##L)
++#    define LZO_UINT64_C(c)         (c##UL)
++#  else
++#    error "LZO_INT64_C"
++#  endif
++#endif
++#endif
+ 
+ #endif /* already included */
+ 
+-/* vim:set ts=4 et: */
++/* vim:set ts=4 sw=4 et: */
+diff --git a/grub-core/lib/minilzo/minilzo.h b/grub-core/lib/minilzo/minilzo.h
+index 74fefa9fe20..79374546748 100644
+--- a/grub-core/lib/minilzo/minilzo.h
++++ b/grub-core/lib/minilzo/minilzo.h
+@@ -2,22 +2,7 @@
+ 
+    This file is part of the LZO real-time data compression library.
+ 
+-   Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+-   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
++   Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer
+    All Rights Reserved.
+ 
+    The LZO library is free software; you can redistribute it and/or
+@@ -50,7 +35,7 @@
+ #ifndef __MINILZO_H
+ #define __MINILZO_H 1
+ 
+-#define MINILZO_VERSION         0x2050
++#define MINILZO_VERSION         0x2080
+ 
+ #ifdef __LZOCONF_H
+ #  error "you cannot use both LZO and miniLZO"
+@@ -78,7 +63,7 @@ extern "C" {
+  */
+ 
+ #define LZO1X_MEM_COMPRESS      LZO1X_1_MEM_COMPRESS
+-#define LZO1X_1_MEM_COMPRESS    ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
++#define LZO1X_1_MEM_COMPRESS    ((lzo_uint32_t) (16384L * lzo_sizeof_dict_t))
+ #define LZO1X_MEM_DECOMPRESS    (0)
+ 
+ 
diff --git a/SOURCES/0014-Allow-fallback-to-include-entries-by-title-not-just-.patch b/SOURCES/0014-Allow-fallback-to-include-entries-by-title-not-just-.patch
new file mode 100644
index 0000000..bee65ed
--- /dev/null
+++ b/SOURCES/0014-Allow-fallback-to-include-entries-by-title-not-just-.patch
@@ -0,0 +1,141 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 5 Sep 2014 10:07:04 -0400
+Subject: [PATCH] Allow "fallback" to include entries by title, not just
+ number.
+
+Resolves: rhbz#1026084
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/normal/menu.c | 85 +++++++++++++++++++++++++++++++++----------------
+ 1 file changed, 58 insertions(+), 27 deletions(-)
+
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index e7a83c2d6e2..d2f64b05e0a 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -163,16 +163,41 @@ grub_menu_set_timeout (int timeout)
+     }
+ }
+ 
++static int
++menuentry_eq (const char *id, const char *spec)
++{
++  const char *ptr1, *ptr2;
++  ptr1 = id;
++  ptr2 = spec;
++  while (1)
++    {
++      if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0)
++	return ptr2 - spec;
++      if (*ptr2 == '>' && ptr2[1] != '>')
++	return 0;
++      if (*ptr2 == '>')
++	ptr2++;
++      if (*ptr1 != *ptr2)
++	return 0;
++      if (*ptr1 == 0)
++	return ptr1 - id;
++      ptr1++;
++      ptr2++;
++    }
++  return 0;
++}
++
+ /* Get the first entry number from the value of the environment variable NAME,
+    which is a space-separated list of non-negative integers.  The entry number
+    which is returned is stripped from the value of NAME.  If no entry number
+    can be found, -1 is returned.  */
+ static int
+-get_and_remove_first_entry_number (const char *name)
++get_and_remove_first_entry_number (grub_menu_t menu, const char *name)
+ {
+   const char *val;
+   char *tail;
+   int entry;
++  int sz = 0;
+ 
+   val = grub_env_get (name);
+   if (! val)
+@@ -182,9 +207,39 @@ get_and_remove_first_entry_number (const char *name)
+ 
+   entry = (int) grub_strtoul (val, &tail, 0);
+ 
++  if (grub_errno == GRUB_ERR_BAD_NUMBER)
++    {
++      /* See if the variable matches the title of a menu entry.  */
++      grub_menu_entry_t e = menu->entry_list;
++      int i;
++
++      for (i = 0; e; i++)
++	{
++	  sz = menuentry_eq (e->title, val);
++	  if (sz < 1)
++	    sz = menuentry_eq (e->id, val);
++
++	  if (sz >= 1)
++	    {
++	      entry = i;
++	      break;
++	    }
++	  e = e->next;
++	}
++
++      if (sz > 0)
++	grub_errno = GRUB_ERR_NONE;
++
++      if (! e)
++	entry = -1;
++    }
++
+   if (grub_errno == GRUB_ERR_NONE)
+     {
+-      /* Skip whitespace to find the next digit.  */
++      if (sz > 0)
++	tail += sz;
++
++      /* Skip whitespace to find the next entry.  */
+       while (*tail && grub_isspace (*tail))
+ 	tail++;
+       grub_env_set (name, tail);
+@@ -347,7 +402,7 @@ grub_menu_execute_with_fallback (grub_menu_t menu,
+   grub_menu_execute_entry (entry, 1);
+ 
+   /* Deal with fallback entries.  */
+-  while ((fallback_entry = get_and_remove_first_entry_number ("fallback"))
++  while ((fallback_entry = get_and_remove_first_entry_number (menu, "fallback"))
+ 	 >= 0)
+     {
+       grub_print_error ();
+@@ -465,30 +520,6 @@ grub_menu_register_viewer (struct grub_menu_viewer *viewer)
+   viewers = viewer;
+ }
+ 
+-static int
+-menuentry_eq (const char *id, const char *spec)
+-{
+-  const char *ptr1, *ptr2;
+-  ptr1 = id;
+-  ptr2 = spec;
+-  while (1)
+-    {
+-      if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0)
+-	return 1;
+-      if (*ptr2 == '>' && ptr2[1] != '>')
+-	return 0;
+-      if (*ptr2 == '>')
+-	ptr2++;
+-      if (*ptr1 != *ptr2)
+-	return 0;
+-      if (*ptr1 == 0)
+-	return 1;
+-      ptr1++;
+-      ptr2++;
+-    }
+-}
+-
+-
+ /* Get the entry number from the variable NAME.  */
+ static int
+ get_entry_number (grub_menu_t menu, const char *name)
diff --git a/SOURCES/0015-Add-GRUB_DISABLE_UUID.patch b/SOURCES/0015-Add-GRUB_DISABLE_UUID.patch
new file mode 100644
index 0000000..a6856d2
--- /dev/null
+++ b/SOURCES/0015-Add-GRUB_DISABLE_UUID.patch
@@ -0,0 +1,106 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 4 Sep 2014 16:49:25 -0400
+Subject: [PATCH] Add GRUB_DISABLE_UUID.
+
+This will cause "search --fs-uuid --set=root ..." not to be generated by
+grub2-mkconfig, and instead simply attempt to use the grub device name
+as it understands it.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ docs/grub.texi            |  7 +++++++
+ util/grub-mkconfig.in     | 22 +++++++++++++++++++---
+ util/grub-mkconfig_lib.in |  4 ++--
+ 3 files changed, 28 insertions(+), 5 deletions(-)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 2adfa97bee8..2fd32608c01 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -1441,6 +1441,13 @@ enable the use of partition UUIDs, set this option to @samp{false}.
+ If this option is set to @samp{true}, disable the generation of recovery
+ mode menu entries.
+ 
++@item GRUB_DISABLE_UUID
++Normally, @command{grub-mkconfig} will generate menu entries that use
++universally-unique identifiers (UUIDs) to identify various filesystems to
++search for files.  This is usually more reliable, but in some cases it may
++not be appropriate.  To disable this use of UUIDs, set this option to
++@samp{true}.
++
+ @item GRUB_VIDEO_BACKEND
+ If graphical video support is required, either because the @samp{gfxterm}
+ graphical terminal is in use or because @samp{GRUB_GFXPAYLOAD_LINUX} is set,
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index bc5a3f17541..b0a8626dd1c 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -133,12 +133,12 @@ fi
+ 
+ # Device containing our userland.  Typically used for root= parameter.
+ GRUB_DEVICE="`${grub_probe} --target=device /`"
+-GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true
+-GRUB_DEVICE_PARTUUID="`${grub_probe} --device ${GRUB_DEVICE} --target=partuuid 2> /dev/null`" || true
++GRUB_DEVICE_UUID_GENERATED="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true
++GRUB_DEVICE_PARTUUID_GENERATED="`${grub_probe} --device ${GRUB_DEVICE} --target=partuuid 2> /dev/null`" || true
+ 
+ # Device containing our /boot partition.  Usually the same as GRUB_DEVICE.
+ GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`"
+-GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true
++GRUB_DEVICE_BOOT_UUID_GENERATED="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true
+ 
+ # Filesystem for the device containing our userland.  Used for stuff like
+ # choosing Hurd filesystem module.
+@@ -158,6 +158,21 @@ if test -f ${sysconfdir}/default/grub ; then
+   . ${sysconfdir}/default/grub
+ fi
+ 
++if [ "x$GRUB_DISABLE_UUID" != "xtrue" ]; then
++  if [ -z "$GRUB_DEVICE_UUID" ]; then
++    GRUB_DEVICE_UUID="$GRUB_DEVICE_UUID_GENERATED"
++  fi
++  if [ -z "$GRUB_DEVICE_BOOT_UUID" ]; then
++    GRUB_DEVICE_BOOT_UUID="$GRUB_DEVICE_BOOT_UUID_GENERATED"
++  fi
++  if [ -z "$GRUB_DEVICE_UUID" ]; then
++    GRUB_DEVICE_UUID="$GRUB_DEVICE_UUID_GENERATED"
++  fi
++  if [ -z "$GRUB_DEVICE_PART_UUID" ]; then
++    GRUB_DEVICE_PART_UUID="$GRUB_DEVICE_PART_UUID_GENERATED"
++  fi
++fi
++
+ # XXX: should this be deprecated at some point?
+ if [ "x${GRUB_TERMINAL}" != "x" ] ; then
+   GRUB_TERMINAL_INPUT="${GRUB_TERMINAL}"
+@@ -227,6 +242,7 @@ export GRUB_DEFAULT \
+   GRUB_DISABLE_LINUX_UUID \
+   GRUB_DISABLE_LINUX_PARTUUID \
+   GRUB_DISABLE_RECOVERY \
++  GRUB_DISABLE_UUID \
+   GRUB_VIDEO_BACKEND \
+   GRUB_GFXMODE \
+   GRUB_BACKGROUND \
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index 0f801cab3e4..1001a12232b 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -156,7 +156,7 @@ prepare_grub_to_access_device ()
+   if [ "x$fs_hint" != x ]; then
+     echo "set root='$fs_hint'"
+   fi
+-  if fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then
++  if [ "x$GRUB_DISABLE_UUID" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then
+     hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints=
+     echo "if [ x\$feature_platform_search_hint = xy ]; then"
+     echo "  search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}"
+@@ -173,7 +173,7 @@ grub_get_device_id ()
+   IFS='
+ '
+   device="$1"
+-  if fs_uuid="`"${grub_probe}" --device ${device} --target=fs_uuid 2> /dev/null`" ; then
++  if [ "x$GRUB_DISABLE_UUID" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device ${device} --target=fs_uuid 2> /dev/null`" ; then
+     echo "$fs_uuid";
+   else
+     echo $device |sed 's, ,_,g'
diff --git a/SOURCES/0016-Make-exit-take-a-return-code.patch b/SOURCES/0016-Make-exit-take-a-return-code.patch
new file mode 100644
index 0000000..937c774
--- /dev/null
+++ b/SOURCES/0016-Make-exit-take-a-return-code.patch
@@ -0,0 +1,256 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 26 Feb 2014 21:49:12 -0500
+Subject: [PATCH] Make "exit" take a return code.
+
+This adds "exit" with a return code.  With this patch, any "exit"
+command /may/ include a return code, and on platforms that support
+returning with an exit status, we will do so.  By default we return the
+same exit status we did before this patch.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/commands/minicmd.c         | 20 ++++++++++++++++----
+ grub-core/kern/efi/efi.c             |  9 +++++++--
+ grub-core/kern/emu/main.c            |  2 +-
+ grub-core/kern/emu/misc.c            |  5 +++--
+ grub-core/kern/i386/coreboot/init.c  |  2 +-
+ grub-core/kern/i386/qemu/init.c      |  2 +-
+ grub-core/kern/ieee1275/init.c       |  2 +-
+ grub-core/kern/mips/arc/init.c       |  2 +-
+ grub-core/kern/mips/loongson/init.c  |  2 +-
+ grub-core/kern/mips/qemu_mips/init.c |  2 +-
+ grub-core/kern/misc.c                |  2 +-
+ grub-core/kern/uboot/init.c          |  6 +++---
+ grub-core/kern/xen/init.c            |  2 +-
+ include/grub/misc.h                  |  2 +-
+ 14 files changed, 39 insertions(+), 21 deletions(-)
+
+diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
+index a3a11824172..b25ca4b9f17 100644
+--- a/grub-core/commands/minicmd.c
++++ b/grub-core/commands/minicmd.c
+@@ -176,12 +176,24 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)),
+ }
+ 
+ /* exit */
+-static grub_err_t __attribute__ ((noreturn))
++static grub_err_t
+ grub_mini_cmd_exit (struct grub_command *cmd __attribute__ ((unused)),
+-		    int argc __attribute__ ((unused)),
+-		    char *argv[] __attribute__ ((unused)))
++		    int argc, char *argv[])
+ {
+-  grub_exit ();
++  int retval = -1;
++  unsigned long n;
++
++  if (argc < 0 || argc > 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
++
++  if (argc == 1)
++    {
++      n = grub_strtoul (argv[0], 0, 10);
++      if (n != ~0UL)
++	retval = n;
++    }
++
++  grub_exit (retval);
+   /* Not reached.  */
+ }
+ 
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index 708581fcbde..e339f264b3a 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -164,11 +164,16 @@ grub_reboot (void)
+ }
+ 
+ void
+-grub_exit (void)
++grub_exit (int retval)
+ {
++  int rc = GRUB_EFI_LOAD_ERROR;
++
++  if (retval == 0)
++    rc = GRUB_EFI_SUCCESS;
++
+   grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
+   efi_call_4 (grub_efi_system_table->boot_services->exit,
+-              grub_efi_image_handle, GRUB_EFI_SUCCESS, 0, 0);
++              grub_efi_image_handle, rc, 0, 0);
+   for (;;) ;
+ }
+ 
+diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c
+index 425bb960347..55ea5a11ccd 100644
+--- a/grub-core/kern/emu/main.c
++++ b/grub-core/kern/emu/main.c
+@@ -67,7 +67,7 @@ grub_reboot (void)
+ }
+ 
+ void
+-grub_exit (void)
++grub_exit (int retval __attribute__((unused)))
+ {
+   grub_reboot ();
+ }
+diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c
+index 76661337f10..82012a72fcb 100644
+--- a/grub-core/kern/emu/misc.c
++++ b/grub-core/kern/emu/misc.c
+@@ -137,9 +137,10 @@ xasprintf (const char *fmt, ...)
+ 
+ #if !defined (GRUB_MACHINE_EMU) || defined (GRUB_UTIL)
+ void
+-grub_exit (void)
++__attribute__ ((noreturn))
++grub_exit (int rc)
+ {
+-  exit (1);
++  exit (rc < 0 ? 1 : rc);
+ }
+ #endif
+ 
+diff --git a/grub-core/kern/i386/coreboot/init.c b/grub-core/kern/i386/coreboot/init.c
+index 3314f027fec..36f9134b7b7 100644
+--- a/grub-core/kern/i386/coreboot/init.c
++++ b/grub-core/kern/i386/coreboot/init.c
+@@ -41,7 +41,7 @@ extern grub_uint8_t _end[];
+ extern grub_uint8_t _edata[];
+ 
+ void  __attribute__ ((noreturn))
+-grub_exit (void)
++grub_exit (int rc __attribute__((unused)))
+ {
+   /* We can't use grub_fatal() in this function.  This would create an infinite
+      loop, since grub_fatal() calls grub_abort() which in turn calls grub_exit().  */
+diff --git a/grub-core/kern/i386/qemu/init.c b/grub-core/kern/i386/qemu/init.c
+index 271b6fbfabd..9fafe98f015 100644
+--- a/grub-core/kern/i386/qemu/init.c
++++ b/grub-core/kern/i386/qemu/init.c
+@@ -42,7 +42,7 @@ extern grub_uint8_t _end[];
+ extern grub_uint8_t _edata[];
+ 
+ void  __attribute__ ((noreturn))
+-grub_exit (void)
++grub_exit (int rc __attribute__((unused)))
+ {
+   /* We can't use grub_fatal() in this function.  This would create an infinite
+      loop, since grub_fatal() calls grub_abort() which in turn calls grub_exit().  */
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index 0d8ebf58b95..f5423ce27d9 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -68,7 +68,7 @@ grub_addr_t grub_ieee1275_original_stack;
+ #endif
+ 
+ void
+-grub_exit (void)
++grub_exit (int rc __attribute__((unused)))
+ {
+   grub_ieee1275_exit ();
+ }
+diff --git a/grub-core/kern/mips/arc/init.c b/grub-core/kern/mips/arc/init.c
+index 3834a149093..86b3a25ec40 100644
+--- a/grub-core/kern/mips/arc/init.c
++++ b/grub-core/kern/mips/arc/init.c
+@@ -276,7 +276,7 @@ grub_halt (void)
+ }
+ 
+ void
+-grub_exit (void)
++grub_exit (int rc __attribute__((unused)))
+ {
+   GRUB_ARC_FIRMWARE_VECTOR->exit ();
+ 
+diff --git a/grub-core/kern/mips/loongson/init.c b/grub-core/kern/mips/loongson/init.c
+index 7b96531b983..dff598ca7b0 100644
+--- a/grub-core/kern/mips/loongson/init.c
++++ b/grub-core/kern/mips/loongson/init.c
+@@ -304,7 +304,7 @@ grub_halt (void)
+ }
+ 
+ void
+-grub_exit (void)
++grub_exit (int rc __attribute__((unused)))
+ {
+   grub_halt ();
+ }
+diff --git a/grub-core/kern/mips/qemu_mips/init.c b/grub-core/kern/mips/qemu_mips/init.c
+index be88b77d22d..8b6c55ffc01 100644
+--- a/grub-core/kern/mips/qemu_mips/init.c
++++ b/grub-core/kern/mips/qemu_mips/init.c
+@@ -75,7 +75,7 @@ grub_machine_fini (int flags __attribute__ ((unused)))
+ }
+ 
+ void
+-grub_exit (void)
++grub_exit (int rc __attribute__((unused)))
+ {
+   grub_halt ();
+ }
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 3b633d51f4c..952411d5dc6 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -1095,7 +1095,7 @@ grub_abort (void)
+       grub_getkey ();
+     }
+ 
+-  grub_exit ();
++  grub_exit (1);
+ }
+ 
+ void
+diff --git a/grub-core/kern/uboot/init.c b/grub-core/kern/uboot/init.c
+index 3e338645c57..be2a5be1d07 100644
+--- a/grub-core/kern/uboot/init.c
++++ b/grub-core/kern/uboot/init.c
+@@ -39,9 +39,9 @@ extern grub_size_t grub_total_module_size;
+ static unsigned long timer_start;
+ 
+ void
+-grub_exit (void)
++grub_exit (int rc)
+ {
+-  grub_uboot_return (0);
++  grub_uboot_return (rc < 0 ? 1 : rc);
+ }
+ 
+ static grub_uint64_t
+@@ -78,7 +78,7 @@ grub_machine_init (void)
+   if (!ver)
+     {
+       /* Don't even have a console to log errors to... */
+-      grub_exit ();
++      grub_exit (-1);
+     }
+   else if (ver > API_SIG_VERSION)
+     {
+diff --git a/grub-core/kern/xen/init.c b/grub-core/kern/xen/init.c
+index 0559c033c3d..fce526d417b 100644
+--- a/grub-core/kern/xen/init.c
++++ b/grub-core/kern/xen/init.c
+@@ -549,7 +549,7 @@ grub_machine_init (void)
+ }
+ 
+ void
+-grub_exit (void)
++grub_exit (int rc __attribute__((unused)))
+ {
+   struct sched_shutdown arg;
+ 
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index 372f009e84f..83fd69f4ada 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -334,7 +334,7 @@ int EXPORT_FUNC(grub_vsnprintf) (char *str, grub_size_t n, const char *fmt,
+ char *EXPORT_FUNC(grub_xasprintf) (const char *fmt, ...)
+      __attribute__ ((format (GNU_PRINTF, 1, 2))) WARN_UNUSED_RESULT;
+ char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args) WARN_UNUSED_RESULT;
+-void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn));
++void EXPORT_FUNC(grub_exit) (int rc) __attribute__ ((noreturn));
+ grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n,
+ 					  grub_uint64_t d,
+ 					  grub_uint64_t *r);
diff --git a/SOURCES/0017-Mark-po-exclude.pot-as-binary-so-git-won-t-try-to-di.patch b/SOURCES/0017-Mark-po-exclude.pot-as-binary-so-git-won-t-try-to-di.patch
new file mode 100644
index 0000000..942116a
--- /dev/null
+++ b/SOURCES/0017-Mark-po-exclude.pot-as-binary-so-git-won-t-try-to-di.patch
@@ -0,0 +1,19 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 22 Jul 2015 11:21:01 -0400
+Subject: [PATCH] Mark po/exclude.pot as binary so git won't try to diff
+ nonprintables.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ .gitattributes | 1 +
+ 1 file changed, 1 insertion(+)
+ create mode 100644 .gitattributes
+
+diff --git a/.gitattributes b/.gitattributes
+new file mode 100644
+index 00000000000..33ffaa40460
+--- /dev/null
++++ b/.gitattributes
+@@ -0,0 +1 @@
++po/exclude.pot binary
diff --git a/SOURCES/0018-Make-efi-machines-load-an-env-block-from-a-variable.patch b/SOURCES/0018-Make-efi-machines-load-an-env-block-from-a-variable.patch
new file mode 100644
index 0000000..2748c1c
--- /dev/null
+++ b/SOURCES/0018-Make-efi-machines-load-an-env-block-from-a-variable.patch
@@ -0,0 +1,81 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 7 Dec 2015 14:20:49 -0500
+Subject: [PATCH] Make efi machines load an env block from a variable
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/Makefile.core.def |  1 +
+ grub-core/kern/efi/init.c   | 34 +++++++++++++++++++++++++++++++++-
+ 2 files changed, 34 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index e92a7ef322f..f8065388213 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -191,6 +191,7 @@ kernel = {
+   efi = term/efi/console.c;
+   efi = kern/acpi.c;
+   efi = kern/efi/acpi.c;
++  efi = lib/envblk.c;
+   i386_coreboot = kern/i386/pc/acpi.c;
+   i386_multiboot = kern/i386/pc/acpi.c;
+   i386_coreboot = kern/acpi.c;
+diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
+index 3dfdf2d22b0..71d2279a0c1 100644
+--- a/grub-core/kern/efi/init.c
++++ b/grub-core/kern/efi/init.c
+@@ -25,9 +25,40 @@
+ #include <grub/env.h>
+ #include <grub/mm.h>
+ #include <grub/kernel.h>
++#include <grub/lib/envblk.h>
+ 
+ grub_addr_t grub_modbase;
+ 
++#define GRUB_EFI_GRUB_VARIABLE_GUID \
++  { 0x91376aff, 0xcba6, 0x42be, \
++    { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \
++  }
++
++/* Helper for grub_efi_env_init */
++static int
++set_var (const char *name, const char *value,
++	 void *whitelist __attribute__((__unused__)))
++{
++  grub_env_set (name, value);
++  return 0;
++}
++
++static void
++grub_efi_env_init (void)
++{
++  grub_efi_guid_t efi_grub_guid = GRUB_EFI_GRUB_VARIABLE_GUID;
++  struct grub_envblk envblk_s = { NULL, 0 };
++  grub_envblk_t envblk = &envblk_s;
++
++  envblk_s.buf = grub_efi_get_variable ("GRUB_ENV", &efi_grub_guid,
++					&envblk_s.size);
++  if (!envblk_s.buf || envblk_s.size < 1)
++    return;
++
++  grub_envblk_iterate (envblk, NULL, set_var);
++  grub_free (envblk_s.buf);
++}
++
+ void
+ grub_efi_init (void)
+ {
+@@ -42,10 +73,11 @@ grub_efi_init (void)
+   efi_call_4 (grub_efi_system_table->boot_services->set_watchdog_timer,
+ 	      0, 0, 0, NULL);
+ 
++  grub_efi_env_init ();
+   grub_efidisk_init ();
+ }
+ 
+-void (*grub_efi_net_config) (grub_efi_handle_t hnd, 
++void (*grub_efi_net_config) (grub_efi_handle_t hnd,
+ 			     char **device,
+ 			     char **path);
+ 
diff --git a/SOURCES/0019-DHCP-client-ID-and-UUID-options-added.patch b/SOURCES/0019-DHCP-client-ID-and-UUID-options-added.patch
new file mode 100644
index 0000000..ddc17fe
--- /dev/null
+++ b/SOURCES/0019-DHCP-client-ID-and-UUID-options-added.patch
@@ -0,0 +1,142 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Date: Tue, 27 Nov 2012 17:18:53 -0200
+Subject: [PATCH] DHCP client ID and UUID options added.
+
+---
+ grub-core/net/bootp.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++-----
+ include/grub/net.h    |  2 ++
+ 2 files changed, 81 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index 9e2fdb795f5..f03eeab2fb4 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -25,6 +25,49 @@
+ #include <grub/net/udp.h>
+ #include <grub/datetime.h>
+ 
++static char *
++grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
++			 const char *val __attribute__ ((unused)))
++{
++  return NULL;
++}
++
++static void
++set_env_limn_ro (const char *intername, const char *suffix,
++		 const char *value, grub_size_t len)
++{
++  char *varname, *varvalue;
++  char *ptr;
++  varname = grub_xasprintf ("net_%s_%s", intername, suffix);
++  if (!varname)
++    return;
++  for (ptr = varname; *ptr; ptr++)
++    if (*ptr == ':')
++      *ptr = '_';
++  varvalue = grub_malloc (len + 1);
++  if (!varvalue)
++    {
++      grub_free (varname);
++      return;
++    }
++
++  grub_memcpy (varvalue, value, len);
++  varvalue[len] = 0;
++  grub_env_set (varname, varvalue);
++  grub_register_variable_hook (varname, 0, grub_env_write_readonly);
++  grub_env_export (varname);
++  grub_free (varname);
++  grub_free (varvalue);
++}
++
++static char
++hexdigit (grub_uint8_t val)
++{
++  if (val < 10)
++    return val + '0';
++  return val + 'a' - 10;
++}
++
+ static void
+ parse_dhcp_vendor (const char *name, const void *vend, int limit, int *mask)
+ {
+@@ -55,6 +98,9 @@ parse_dhcp_vendor (const char *name, const void *vend, int limit, int *mask)
+ 
+       taglength = *ptr++;
+ 
++      grub_dprintf("net", "DHCP option %u (0x%02x) found with length %u.\n",
++                   tagtype, tagtype, taglength);
++
+       switch (tagtype)
+ 	{
+ 	case GRUB_NET_BOOTP_NETMASK:
+@@ -120,6 +166,39 @@ parse_dhcp_vendor (const char *name, const void *vend, int limit, int *mask)
+                                      taglength);
+           break;
+ 
++        case GRUB_NET_BOOTP_CLIENT_ID:
++	  set_env_limn_ro (name, "clientid", (char *) ptr, taglength);
++          break;
++
++        case GRUB_NET_BOOTP_CLIENT_UUID:
++            {
++              if (taglength != 17)
++                break;
++
++              /* The format is 9cfe245e-d0c8-bd45-a79f-54ea5fbd3d97 */
++
++              ptr += 1;
++              taglength -= 1;
++
++              char *val = grub_malloc (2 * taglength + 4 + 1);
++              int i = 0;
++              int j = 0;
++              for (i = 0; i < taglength; i++)
++                {
++                  val[2 * i + j] = hexdigit (ptr[i] >> 4);
++                  val[2 * i + 1 + j] = hexdigit (ptr[i] & 0xf);
++
++                  if ((i == 3) || (i == 5) || (i == 7) || (i == 9))
++                    {
++                      j++;
++                      val[2 * i + 1+ j] = '-';
++                    }
++                }
++
++              set_env_limn_ro (name, "clientuuid", (char *) val, 2 * taglength + 4);
++            }
++          break;
++
+ 	  /* If you need any other options please contact GRUB
+ 	     development team.  */
+ 	}
+@@ -302,14 +381,6 @@ grub_net_process_dhcp (struct grub_net_buff *nb,
+     }
+ }
+ 
+-static char
+-hexdigit (grub_uint8_t val)
+-{
+-  if (val < 10)
+-    return val + '0';
+-  return val + 'a' - 10;
+-}
+-
+ static grub_err_t
+ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
+ 		  int argc, char **args)
+diff --git a/include/grub/net.h b/include/grub/net.h
+index 1096b24322e..e266bae23f4 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -457,6 +457,8 @@ enum
+     GRUB_NET_BOOTP_DOMAIN = 0x0f,
+     GRUB_NET_BOOTP_ROOT_PATH = 0x11,
+     GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12,
++    GRUB_NET_BOOTP_CLIENT_ID = 0x3d,
++    GRUB_NET_BOOTP_CLIENT_UUID = 0x61,
+     GRUB_NET_BOOTP_END = 0xff
+   };
+ 
diff --git a/SOURCES/0020-trim-arp-packets-with-abnormal-size.patch b/SOURCES/0020-trim-arp-packets-with-abnormal-size.patch
new file mode 100644
index 0000000..1a6990a
--- /dev/null
+++ b/SOURCES/0020-trim-arp-packets-with-abnormal-size.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Date: Wed, 5 Feb 2014 09:42:42 -0200
+Subject: [PATCH] trim arp packets with abnormal size
+
+GRUB uses arp request to create the arp response. If the incoming packet
+is foobared, GRUB needs to trim the arp response packet before sending it.
+---
+ grub-core/net/arp.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c
+index 54306e3b16d..d1c69ed2b55 100644
+--- a/grub-core/net/arp.c
++++ b/grub-core/net/arp.c
+@@ -150,6 +150,12 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
+     if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
+ 	&& arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
+       {
++        if ((nb->tail - nb->data) > 50)
++          {
++            grub_dprintf ("net", "arp packet with abnormal size (%ld bytes).\n",
++                         nb->tail - nb->data);
++            nb->tail = nb->data + 50;
++          }
+ 	grub_net_link_level_address_t target;
+ 	struct grub_net_buff nb_reply;
+ 	struct arppkt *arp_reply;
diff --git a/SOURCES/0021-Fix-bad-test-on-GRUB_DISABLE_SUBMENU.patch b/SOURCES/0021-Fix-bad-test-on-GRUB_DISABLE_SUBMENU.patch
new file mode 100644
index 0000000..e219fa5
--- /dev/null
+++ b/SOURCES/0021-Fix-bad-test-on-GRUB_DISABLE_SUBMENU.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Prarit Bhargava <prarit@redhat.com>
+Date: Wed, 12 Mar 2014 10:58:16 -0400
+Subject: [PATCH] Fix bad test on GRUB_DISABLE_SUBMENU.
+
+The file /etc/grub.d/10_linux does
+
+if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xy ]; then
+
+when it should do
+
+if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then
+
+which results in submenus in /boot/grub2/grub.cfg when
+GRUB_DISABLE_SUBMENU="yes".
+
+Resolves: rhbz#1063414
+---
+ util/grub.d/10_linux.in | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 61ebd7dc714..87a7da34982 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -261,7 +261,11 @@ while [ "x$list" != "x" ] ; do
+     fi
+   fi
+ 
+-  if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xy ]; then
++  if [ "x${GRUB_DISABLE_SUBMENU}" = "xyes" ] || [ "x${GRUB_DISABLE_SUBMENU}" = "xy" ]; then
++    GRUB_DISABLE_SUBMENU="true"
++  fi
++
++  if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then
+     linux_entry "${OS}" "${version}" simple \
+     "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
+ 
diff --git a/SOURCES/0022-Add-support-for-UEFI-operating-systems-returned-by-o.patch b/SOURCES/0022-Add-support-for-UEFI-operating-systems-returned-by-o.patch
new file mode 100644
index 0000000..6ddda34
--- /dev/null
+++ b/SOURCES/0022-Add-support-for-UEFI-operating-systems-returned-by-o.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <matthew.garrett@nebula.com>
+Date: Wed, 12 Jun 2013 11:51:49 -0400
+Subject: [PATCH] Add support for UEFI operating systems returned by os-prober
+
+os-prober returns UEFI operating systems in the form:
+
+path:long-name:name
+
+where path is the path under the EFI directory on the ESP. This is in
+contrast to legacy OSes, where path is the device string. Handle this case.
+---
+ util/grub.d/30_os-prober.in | 21 ++++++++++++++++++---
+ 1 file changed, 18 insertions(+), 3 deletions(-)
+
+diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
+index 515a68c7aa0..9b8f5968e2d 100644
+--- a/util/grub.d/30_os-prober.in
++++ b/util/grub.d/30_os-prober.in
+@@ -328,8 +328,23 @@ EOF
+ EOF
+     ;;
+     *)
+-      # TRANSLATORS: %s is replaced by OS name.
+-      gettext_printf "%s is not yet supported by grub-mkconfig.\n" "  ${LONGNAME}" >&2
+-    ;;
++      case ${DEVICE} in
++	*.efi)
++	  cat << EOF
++menuentry '$(echo "${LONGNAME}" | grub_quote)' {
++EOF
++	  save_default_entry | grub_add_tab
++	  cat << EOF
++	  chainloader /EFI/${DEVICE}
++	  boot
++}
++EOF
++	  ;;
++	*)
++          echo -n "  "
++          # TRANSLATORS: %s is replaced by OS name.
++          gettext_printf "%s is not yet supported by grub-mkconfig.\n" "${LONGNAME}" >&2
++        ;;
++      esac
+   esac
+ done
diff --git a/SOURCES/0023-Migrate-PPC-from-Yaboot-to-Grub2.patch b/SOURCES/0023-Migrate-PPC-from-Yaboot-to-Grub2.patch
new file mode 100644
index 0000000..7008926
--- /dev/null
+++ b/SOURCES/0023-Migrate-PPC-from-Yaboot-to-Grub2.patch
@@ -0,0 +1,151 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Mark Hamzy <hamzy@us.ibm.com>
+Date: Wed, 28 Mar 2012 14:46:41 -0500
+Subject: [PATCH] Migrate PPC from Yaboot to Grub2
+
+Add configuration support for serial terminal consoles.  This will set the
+maximum screen size so that text is not overwritten.
+---
+ Makefile.util.def              |   7 +++
+ util/grub.d/20_ppc_terminfo.in | 114 +++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 121 insertions(+)
+ create mode 100644 util/grub.d/20_ppc_terminfo.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 3180ac880a9..c7b775bce73 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -487,6 +487,13 @@ script = {
+   condition = COND_HOST_LINUX;
+ };
+ 
++script = {
++  name = '20_ppc_terminfo';
++  common = util/grub.d/20_ppc_terminfo.in;
++  installdir = grubconf;
++  condition = COND_HOST_LINUX;
++};
++
+ script = {
+   name = '30_os-prober';
+   common = util/grub.d/30_os-prober.in;
+diff --git a/util/grub.d/20_ppc_terminfo.in b/util/grub.d/20_ppc_terminfo.in
+new file mode 100644
+index 00000000000..10d66586820
+--- /dev/null
++++ b/util/grub.d/20_ppc_terminfo.in
+@@ -0,0 +1,114 @@
++#! /bin/sh
++set -e
++
++# grub-mkconfig helper script.
++# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
++#
++# GRUB is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# GRUB is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++bindir=@bindir@
++libdir=@libdir@
++. "@datadir@/@PACKAGE@/grub-mkconfig_lib"
++
++export TEXTDOMAIN=@PACKAGE@
++export TEXTDOMAINDIR=@localedir@
++
++X=80
++Y=24
++TERMINAL=ofconsole
++
++argument () {
++  opt=$1
++  shift
++
++  if test $# -eq 0; then
++      echo "$0: option requires an argument -- '$opt'" 1>&2
++      exit 1
++  fi
++  echo $1
++}
++
++check_terminfo () {
++
++  while test $# -gt 0
++  do
++    option=$1
++    shift
++
++    case "$option" in
++    terminfo | TERMINFO)
++        ;;
++
++    -g)
++        NEWXY=`argument $option "$@"`
++        NEWX=`echo $NEWXY | cut -d x -f 1`
++        NEWY=`echo $NEWXY | cut -d x -f 2`
++
++        if [ ${NEWX} -ge 80 ] ; then
++          X=${NEWX}
++        else
++          echo "Warning: ${NEWX} is less than the minimum size of 80"
++        fi
++
++        if [ ${NEWY} -ge 24 ] ; then
++          Y=${NEWY}
++        else
++          echo "Warning: ${NEWY} is less than the minimum size of 24"
++        fi
++
++        shift
++        ;;
++
++    *)
++#       # accept console or ofconsole
++#       if [ "$option" != "console" -a "$option" != "ofconsole" ] ; then
++#         echo "Error: GRUB_TERMINFO unknown console: $option"
++#         exit 1
++#       fi
++#       # perfer console
++#       TERMINAL=console
++        # accept ofconsole
++        if [ "$option" != "ofconsole" ] ; then
++          echo "Error: GRUB_TERMINFO unknown console: $option"
++          exit 1
++        fi
++        # perfer console
++        TERMINAL=ofconsole
++        ;;
++    esac
++
++  done
++
++}
++
++if ! uname -m | grep -q ppc ; then
++  exit 0
++fi
++
++if [ "x${GRUB_TERMINFO}" != "x" ] ; then
++  F1=`echo ${GRUB_TERMINFO} | cut -d " " -f 1`
++
++  if [ "${F1}" != "terminfo" ] ; then
++    echo "Error: GRUB_TERMINFO is set to \"${GRUB_TERMINFO}\" The first word should be terminfo."
++    exit 1
++  fi
++
++  check_terminfo ${GRUB_TERMINFO}
++fi
++
++cat << EOF
++  terminfo -g ${X}x${Y} ${TERMINAL}
++EOF
diff --git a/SOURCES/0024-Add-fw_path-variable-revised.patch b/SOURCES/0024-Add-fw_path-variable-revised.patch
new file mode 100644
index 0000000..3126d2e
--- /dev/null
+++ b/SOURCES/0024-Add-fw_path-variable-revised.patch
@@ -0,0 +1,78 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Date: Wed, 19 Sep 2012 21:22:55 -0300
+Subject: [PATCH] Add fw_path variable (revised)
+
+This patch makes grub look for its config file on efi where the app was
+found. It was originally written by Matthew Garrett, and adapted to fix the
+"No modules are loaded on grub2 network boot" issue:
+
+https://bugzilla.redhat.com/show_bug.cgi?id=857936
+---
+ grub-core/kern/main.c   | 13 ++++++-------
+ grub-core/normal/main.c | 25 ++++++++++++++++++++++++-
+ 2 files changed, 30 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
+index 9cad0c4485c..8ab7794c47b 100644
+--- a/grub-core/kern/main.c
++++ b/grub-core/kern/main.c
+@@ -127,16 +127,15 @@ grub_set_prefix_and_root (void)
+ 
+   grub_machine_get_bootlocation (&fwdevice, &fwpath);
+ 
+-  if (fwdevice)
++  if (fwdevice && fwpath)
+     {
+-      char *cmdpath;
++      char *fw_path;
+ 
+-      cmdpath = grub_xasprintf ("(%s)%s", fwdevice, fwpath ? : "");
+-      if (cmdpath)
++      fw_path = grub_xasprintf ("(%s)/%s", fwdevice, fwpath);
++      if (fw_path)
+ 	{
+-	  grub_env_set ("cmdpath", cmdpath);
+-	  grub_env_export ("cmdpath");
+-	  grub_free (cmdpath);
++	  grub_env_set ("fw_path", fw_path);
++	  grub_free (fw_path);
+ 	}
+     }
+ 
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 249e19bc788..759c475c4d9 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -338,7 +338,30 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+       /* Guess the config filename. It is necessary to make CONFIG static,
+ 	 so that it won't get broken by longjmp.  */
+       char *config;
+-      const char *prefix;
++      const char *prefix, *fw_path;
++
++      fw_path = grub_env_get ("fw_path");
++      if (fw_path)
++	{
++	  config = grub_xasprintf ("%s/grub.cfg", fw_path);
++	  if (config)
++	    {
++	      grub_file_t file;
++
++	      file = grub_file_open (config);
++	      if (file)
++		{
++		  grub_file_close (file);
++		  grub_enter_normal_mode (config);
++		}
++              else
++                {
++                  /*  Ignore all errors.  */
++                  grub_errno = 0;
++                }
++	      grub_free (config);
++	    }
++	}
+ 
+       prefix = grub_env_get ("prefix");
+       if (prefix)
diff --git a/SOURCES/0025-Pass-x-hex-hex-straight-through-unmolested.patch b/SOURCES/0025-Pass-x-hex-hex-straight-through-unmolested.patch
new file mode 100644
index 0000000..5f4884d
--- /dev/null
+++ b/SOURCES/0025-Pass-x-hex-hex-straight-through-unmolested.patch
@@ -0,0 +1,179 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 1 Oct 2012 13:24:37 -0400
+Subject: [PATCH] Pass "\x[[:hex:]][[:hex:]]" straight through unmolested.
+
+---
+ grub-core/commands/wildcard.c | 16 +++++++++++++++-
+ grub-core/lib/cmdline.c       | 34 ++++++++++++++++++++++++++++++++--
+ grub-core/script/execute.c    | 43 +++++++++++++++++++++++++++++++++++++------
+ 3 files changed, 84 insertions(+), 9 deletions(-)
+
+diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c
+index 9b4e72766ff..02c46f9fdfa 100644
+--- a/grub-core/commands/wildcard.c
++++ b/grub-core/commands/wildcard.c
+@@ -462,6 +462,12 @@ check_file (const char *dir, const char *basename)
+   return ctx.found;
+ }
+ 
++static int
++is_hex(char c)
++{
++  return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
++}
++
+ static void
+ unescape (char *out, const char *in, const char *end)
+ {
+@@ -470,7 +476,15 @@ unescape (char *out, const char *in, const char *end)
+ 
+   for (optr = out, iptr = in; iptr < end;)
+     {
+-      if (*iptr == '\\' && iptr + 1 < end)
++      if (*iptr == '\\' && iptr + 3 < end && iptr[1] == 'x' && is_hex(iptr[2]) && is_hex(iptr[3]))
++	{
++	  *optr++ = *iptr++;
++	  *optr++ = *iptr++;
++	  *optr++ = *iptr++;
++	  *optr++ = *iptr++;
++	  continue;
++	}
++      else if (*iptr == '\\' && iptr + 1 < end)
+ 	{
+ 	  *optr++ = iptr[1];
+ 	  iptr += 2;
+diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c
+index d5e10ee8798..0a5b2afb94b 100644
+--- a/grub-core/lib/cmdline.c
++++ b/grub-core/lib/cmdline.c
+@@ -20,6 +20,12 @@
+ #include <grub/lib/cmdline.h>
+ #include <grub/misc.h>
+ 
++static int
++is_hex(char c)
++{
++  return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
++}
++
+ static unsigned int check_arg (char *c, int *has_space)
+ {
+   int space = 0;
+@@ -27,7 +33,13 @@ static unsigned int check_arg (char *c, int *has_space)
+ 
+   while (*c)
+     {
+-      if (*c == '\\' || *c == '\'' || *c == '"')
++      if (*c == '\\' && *(c+1) == 'x' && is_hex(*(c+2)) && is_hex(*(c+3)))
++	{
++	  size += 4;
++	  c += 4;
++	  continue;
++	}
++      else if (*c == '\\' || *c == '\'' || *c == '"')
+ 	size++;
+       else if (*c == ' ')
+ 	space = 1;
+@@ -85,7 +97,25 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+ 
+       while (*c)
+ 	{
+-	  if (*c == '\\' || *c == '\'' || *c == '"')
++	  if (*c == ' ')
++	    {
++	      *buf++ = '\\';
++	      *buf++ = 'x';
++	      *buf++ = '2';
++	      *buf++ = '0';
++	      c++;
++	      continue;
++	    }
++	  else if (*c == '\\' && *(c+1) == 'x' &&
++		   is_hex(*(c+2)) && is_hex(*(c+3)))
++	    {
++	      *buf++ = *c++;
++	      *buf++ = *c++;
++	      *buf++ = *c++;
++	      *buf++ = *c++;
++	      continue;
++	    }
++	  else if (*c == '\\' || *c == '\'' || *c == '"')
+ 	    *buf++ = '\\';
+ 
+ 	  *buf++ = *c;
+diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
+index ab78ca87f90..cf6cd6601d6 100644
+--- a/grub-core/script/execute.c
++++ b/grub-core/script/execute.c
+@@ -55,6 +55,12 @@ static struct grub_script_scope *scope = 0;
+ /* Wildcard translator for GRUB script.  */
+ struct grub_script_wildcard_translator *grub_wildcard_translator;
+ 
++static int
++is_hex(char c)
++{
++  return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
++}
++
+ static char*
+ wildcard_escape (const char *s)
+ {
+@@ -71,7 +77,15 @@ wildcard_escape (const char *s)
+   i = 0;
+   while ((ch = *s++))
+     {
+-      if (ch == '*' || ch == '\\' || ch == '?')
++      if (ch == '\\' && s[0] == 'x' && is_hex(s[1]) && is_hex(s[2]))
++	{
++	  p[i++] = ch;
++	  p[i++] = *s++;
++	  p[i++] = *s++;
++	  p[i++] = *s++;
++	  continue;
++	}
++      else if (ch == '*' || ch == '\\' || ch == '?')
+ 	p[i++] = '\\';
+       p[i++] = ch;
+     }
+@@ -95,7 +109,14 @@ wildcard_unescape (const char *s)
+   i = 0;
+   while ((ch = *s++))
+     {
+-      if (ch == '\\')
++      if (ch == '\\' && s[0] == 'x' && is_hex(s[1]) && is_hex(s[2]))
++	{
++	  p[i++] = '\\';
++	  p[i++] = *s++;
++	  p[i++] = *s++;
++	  p[i++] = *s++;
++	}
++      else if (ch == '\\')
+ 	p[i++] = *s++;
+       else
+ 	p[i++] = ch;
+@@ -397,10 +418,20 @@ parse_string (const char *str,
+     switch (*ptr)
+       {
+       case '\\':
+-	escaped = !escaped;
+-	if (!escaped && put)
+-	  *(put++) = '\\';
+-	ptr++;
++	if (!escaped && put && *(ptr+1) == 'x' && is_hex(*(ptr+2)) && is_hex(*(ptr+3)))
++	  {
++	    *(put++) = *ptr++;
++	    *(put++) = *ptr++;
++	    *(put++) = *ptr++;
++	    *(put++) = *ptr++;
++	  }
++	else
++	  {
++	    escaped = !escaped;
++	    if (!escaped && put)
++	      *(put++) = '\\';
++	    ptr++;
++	  }
+ 	break;
+       case '$':
+ 	if (escaped)
diff --git a/SOURCES/0026-Add-X-option-to-printf-functions.patch b/SOURCES/0026-Add-X-option-to-printf-functions.patch
new file mode 100644
index 0000000..4fd28fc
--- /dev/null
+++ b/SOURCES/0026-Add-X-option-to-printf-functions.patch
@@ -0,0 +1,55 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Date: Tue, 27 Nov 2012 16:58:39 -0200
+Subject: [PATCH] Add %X option to printf functions.
+
+---
+ grub-core/kern/misc.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 952411d5dc6..8344526be7f 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -588,7 +588,7 @@ grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r)
+ static inline char *
+ grub_lltoa (char *str, int c, unsigned long long n)
+ {
+-  unsigned base = (c == 'x') ? 16 : 10;
++  unsigned base = ((c == 'x') || (c == 'X')) ? 16 : 10;
+   char *p;
+ 
+   if ((long long) n < 0 && c == 'd')
+@@ -603,7 +603,7 @@ grub_lltoa (char *str, int c, unsigned long long n)
+     do
+       {
+ 	unsigned d = (unsigned) (n & 0xf);
+-	*p++ = (d > 9) ? d + 'a' - 10 : d + '0';
++	*p++ = (d > 9) ? d + ((c == 'x') ? 'a' : 'A') - 10 : d + '0';
+       }
+     while (n >>= 4);
+   else
+@@ -676,6 +676,7 @@ parse_printf_args (const char *fmt0, struct printf_args *args,
+ 	{
+ 	case 'p':
+ 	case 'x':
++	case 'X':
+ 	case 'u':
+ 	case 'd':
+ 	case 'c':
+@@ -762,6 +763,7 @@ parse_printf_args (const char *fmt0, struct printf_args *args,
+       switch (c)
+ 	{
+ 	case 'x':
++	case 'X':
+ 	case 'u':
+ 	  args->ptr[curn].type = UNSIGNED_INT + longfmt;
+ 	  break;
+@@ -900,6 +902,7 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0,
+ 	  c = 'x';
+ 	  /* Fall through. */
+ 	case 'x':
++	case 'X':
+ 	case 'u':
+ 	case 'd':
+ 	  {
diff --git a/SOURCES/0027-Search-for-specific-config-file-for-netboot.patch b/SOURCES/0027-Search-for-specific-config-file-for-netboot.patch
new file mode 100644
index 0000000..7436e03
--- /dev/null
+++ b/SOURCES/0027-Search-for-specific-config-file-for-netboot.patch
@@ -0,0 +1,200 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Paulo Flabiano Smorigo <pfsmorigo@br.ibm.com>
+Date: Tue, 27 Nov 2012 17:22:07 -0200
+Subject: [PATCH] Search for specific config file for netboot
+
+This patch implements a search for a specific configuration when the config
+file is on a remoteserver. It uses the following order:
+   1) DHCP client UUID option.
+   2) MAC address (in lower case hexadecimal with dash separators);
+   3) IP (in upper case hexadecimal) or IPv6;
+   4) The original grub.cfg file.
+
+This procedure is similar to what is used by pxelinux and yaboot:
+http://www.syslinux.org/wiki/index.php/PXELINUX#config
+
+This should close the bugzilla:
+https://bugzilla.redhat.com/show_bug.cgi?id=873406
+---
+ grub-core/net/net.c     | 118 ++++++++++++++++++++++++++++++++++++++++++++++++
+ grub-core/normal/main.c |  18 ++++++--
+ include/grub/net.h      |   3 ++
+ 3 files changed, 135 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 10773fc3435..0769bf850d3 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -1735,6 +1735,124 @@ grub_net_restore_hw (void)
+   return GRUB_ERR_NONE;
+ }
+ 
++grub_err_t
++grub_net_search_configfile (char *config)
++{
++  grub_size_t config_len;
++  char *suffix;
++
++  auto int search_through (grub_size_t num_tries, grub_size_t slice_size);
++  int search_through (grub_size_t num_tries, grub_size_t slice_size)
++    {
++      while (num_tries-- > 0)
++        {
++	  grub_dprintf ("net", "probe %s\n", config);
++
++          grub_file_t file;
++          file = grub_file_open (config);
++
++          if (file)
++            {
++              grub_file_close (file);
++              grub_dprintf ("net", "found!\n");
++              return 0;
++            }
++          else
++            {
++              if (grub_errno == GRUB_ERR_IO)
++                grub_errno = GRUB_ERR_NONE;
++            }
++
++          if (grub_strlen (suffix) < slice_size)
++            break;
++
++          config[grub_strlen (config) - slice_size] = '\0';
++        }
++
++      return 1;
++    }
++
++  config_len = grub_strlen (config);
++  config[config_len] = '-';
++  suffix = config + config_len + 1;
++
++  struct grub_net_network_level_interface *inf;
++  FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
++    {
++      /* By the Client UUID. */
++
++      char client_uuid_var[sizeof ("net_") + grub_strlen (inf->name) +
++                           sizeof ("_clientuuid") + 1];
++      grub_snprintf (client_uuid_var, sizeof (client_uuid_var),
++                     "net_%s_clientuuid", inf->name);
++
++      const char *client_uuid;
++      client_uuid = grub_env_get (client_uuid_var);
++
++      if (client_uuid)
++        {
++          grub_strcpy (suffix, client_uuid);
++          if (search_through (1, 0) == 0) return GRUB_ERR_NONE;
++        }
++
++      /* By the MAC address. */
++
++      /* Add ethernet type */
++      grub_strcpy (suffix, "01-");
++
++      grub_net_hwaddr_to_str (&inf->hwaddress, suffix + 3);
++
++      char *ptr;
++      for (ptr = suffix; *ptr; ptr++)
++        if (*ptr == ':')
++          *ptr = '-';
++
++      if (search_through (1, 0) == 0) return GRUB_ERR_NONE;
++
++      /* By IP address */
++
++      switch ((&inf->address)->type)
++        {
++        case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
++            {
++              grub_uint32_t n = grub_be_to_cpu32 ((&inf->address)->ipv4);
++              grub_snprintf (suffix, GRUB_NET_MAX_STR_ADDR_LEN, "%02X%02X%02X%02X", \
++                             ((n >> 24) & 0xff), ((n >> 16) & 0xff), \
++                             ((n >> 8) & 0xff), ((n >> 0) & 0xff));
++
++              if (search_through (8, 1) == 0) return GRUB_ERR_NONE;
++              break;
++            }
++        case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
++            {
++              char buf[GRUB_NET_MAX_STR_ADDR_LEN];
++              struct grub_net_network_level_address base;
++              base.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++              grub_memcpy (&base.ipv6, ((&inf->address)->ipv6), 16);
++              grub_net_addr_to_str (&base, buf);
++
++              for (ptr = buf; *ptr; ptr++)
++                if (*ptr == ':')
++                  *ptr = '-';
++
++              grub_snprintf (suffix, GRUB_NET_MAX_STR_ADDR_LEN, "%s", buf);
++              if (search_through (1, 0) == 0) return GRUB_ERR_NONE;
++              break;
++            }
++        case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
++          return grub_error (GRUB_ERR_BUG, "shouldn't reach here");
++        default:
++          return grub_error (GRUB_ERR_BUG,
++                             "unsupported address type %d", (&inf->address)->type);
++        }
++    }
++
++  /* Remove the remaining minus sign at the end. */
++  config[config_len] = '\0';
++
++  return GRUB_ERR_NONE;
++}
++
+ static struct grub_preboot *fini_hnd;
+ 
+ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 759c475c4d9..b2654ef62e8 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -33,6 +33,7 @@
+ #include <grub/charset.h>
+ #include <grub/script_sh.h>
+ #include <grub/bufio.h>
++#include <grub/net.h>
+ #ifdef GRUB_MACHINE_IEEE1275
+ #include <grub/ieee1275/ieee1275.h>
+ #endif
+@@ -365,10 +366,19 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+ 
+       prefix = grub_env_get ("prefix");
+       if (prefix)
+-	{
+-	  config = grub_xasprintf ("%s/grub.cfg", prefix);
+-	  if (! config)
+-	    goto quit;
++        {
++          grub_size_t config_len;
++          config_len = grub_strlen (prefix) +
++                      sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
++          config = grub_malloc (config_len);
++
++          if (! config)
++            goto quit;
++
++          grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
++
++          if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0)
++            grub_net_search_configfile (config);
+ 
+ 	  grub_enter_normal_mode (config);
+ 	  grub_free (config);
+diff --git a/include/grub/net.h b/include/grub/net.h
+index e266bae23f4..50d62ab0c8c 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -566,4 +566,7 @@ extern char *grub_net_default_server;
+ 
+ #define VLANTAG_IDENTIFIER 0x8100
+ 
++grub_err_t
++grub_net_search_configfile (char *config);
++
+ #endif /* ! GRUB_NET_HEADER */
diff --git a/SOURCES/0028-blscfg-add-blscfg-module-to-parse-Boot-Loader-Specif.patch b/SOURCES/0028-blscfg-add-blscfg-module-to-parse-Boot-Loader-Specif.patch
new file mode 100644
index 0000000..fd63493
--- /dev/null
+++ b/SOURCES/0028-blscfg-add-blscfg-module-to-parse-Boot-Loader-Specif.patch
@@ -0,0 +1,248 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Fedora Ninjas <grub2-owner@fedoraproject.org>
+Date: Tue, 22 Jan 2013 06:31:38 +0100
+Subject: [PATCH] blscfg: add blscfg module to parse Boot Loader Specification
+ snippets
+
+http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec
+
+Works like this:
+
+ insmod blscfg
+ bls_import
+
+Done! You should now have menu items for your snippets in place.
+
+Signed-off-by: Peter Jones <grub2-owner@fedoraproject.org>
+---
+ grub-core/Makefile.core.def |   8 ++
+ grub-core/commands/blscfg.c | 201 ++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 209 insertions(+)
+ create mode 100644 grub-core/commands/blscfg.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index f8065388213..cd0902b46b8 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -768,6 +768,14 @@ module = {
+   common = commands/blocklist.c;
+ };
+ 
++module = {
++  name = blscfg;
++  common = commands/blscfg.c;
++  enable = i386_efi;
++  enable = x86_64_efi;
++  enable = i386_pc;
++};
++
+ module = {
+   name = boot;
+   common = commands/boot.c;
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+new file mode 100644
+index 00000000000..4274aca5a9d
+--- /dev/null
++++ b/grub-core/commands/blscfg.c
+@@ -0,0 +1,201 @@
++/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/
++
++/* bls.c - implementation of the boot loader spec */
++
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/types.h>
++#include <grub/misc.h>
++#include <grub/mm.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/extcmd.h>
++#include <grub/i18n.h>
++#include <grub/fs.h>
++#include <grub/env.h>
++#include <grub/file.h>
++#include <grub/normal.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++#ifdef GRUB_MACHINE_EFI
++#define GRUB_LINUX_CMD "linuxefi"
++#define GRUB_INITRD_CMD "initrdefi"
++#define GRUB_BLS_CONFIG_PATH "/EFI/fedora/loader/entries/"
++#define GRUB_BOOT_DEVICE "($boot)"
++#else
++#define GRUB_LINUX_CMD "linux"
++#define GRUB_INITRD_CMD "initrd"
++#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
++#define GRUB_BOOT_DEVICE "($root)"
++#endif
++
++static int parse_entry (
++    const char *filename,
++    const struct grub_dirhook_info *info __attribute__ ((unused)),
++    void *data __attribute__ ((unused)))
++{
++  grub_size_t n;
++  char *p;
++  grub_file_t f = NULL;
++  grub_off_t sz;
++  char *title = NULL, *options = NULL, *clinux = NULL, *initrd = NULL, *src = NULL;
++  const char *args[2] = { NULL, NULL };
++
++  if (filename[0] == '.')
++    return 0;
++
++  n = grub_strlen (filename);
++  if (n <= 5)
++    return 0;
++
++  if (grub_strcmp (filename + n - 5, ".conf") != 0)
++    return 0;
++
++  p = grub_xasprintf (GRUB_BLS_CONFIG_PATH "%s", filename);
++
++  f = grub_file_open (p);
++  if (!f)
++    goto finish;
++
++  sz = grub_file_size (f);
++  if (sz == GRUB_FILE_SIZE_UNKNOWN || sz > 1024*1024)
++    goto finish;
++
++  for (;;)
++    {
++      char *buf;
++
++      buf = grub_file_getline (f);
++      if (!buf)
++	break;
++
++      if (grub_strncmp (buf, "title ", 6) == 0)
++	{
++	  grub_free (title);
++	  title = grub_strdup (buf + 6);
++	  if (!title)
++	    goto finish;
++	}
++      else if (grub_strncmp (buf, "options ", 8) == 0)
++	{
++	  grub_free (options);
++	  options = grub_strdup (buf + 8);
++	  if (!options)
++	    goto finish;
++	}
++      else if (grub_strncmp (buf, "linux ", 6) == 0)
++	{
++	  grub_free (clinux);
++	  clinux = grub_strdup (buf + 6);
++	  if (!clinux)
++	    goto finish;
++	}
++      else if (grub_strncmp (buf, "initrd ", 7) == 0)
++	{
++	  grub_free (initrd);
++	  initrd = grub_strdup (buf + 7);
++	  if (!initrd)
++	    goto finish;
++	}
++
++      grub_free(buf);
++    }
++
++  if (!linux)
++    {
++      grub_printf ("Skipping file %s with no 'linux' key.", p);
++      goto finish;
++    }
++
++  args[0] = title ? title : filename;
++
++  src = grub_xasprintf ("load_video\n"
++			"set gfx_payload=keep\n"
++			"insmod gzio\n"
++			GRUB_LINUX_CMD " %s%s%s%s\n"
++			"%s%s%s%s",
++			GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "",
++			initrd ? GRUB_INITRD_CMD " " : "", initrd ? GRUB_BOOT_DEVICE : "", initrd ? initrd : "", initrd ? "\n" : "");
++
++  grub_normal_add_menu_entry (1, args, NULL, NULL, "bls", NULL, NULL, src, 0);
++
++finish:
++  grub_free (p);
++  grub_free (title);
++  grub_free (options);
++  grub_free (clinux);
++  grub_free (initrd);
++  grub_free (src);
++
++  if (f)
++    grub_file_close (f);
++
++  return 0;
++}
++
++static grub_err_t
++grub_cmd_bls_import (grub_extcmd_context_t ctxt __attribute__ ((unused)),
++		     int argc __attribute__ ((unused)),
++		     char **args __attribute__ ((unused)))
++{
++  grub_fs_t fs;
++  grub_device_t dev;
++  static grub_err_t r;
++  const char *devid;
++
++  devid = grub_env_get ("root");
++  if (!devid)
++    return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "root");
++
++  dev = grub_device_open (devid);
++  if (!dev)
++    return grub_errno;
++
++  fs = grub_fs_probe (dev);
++  if (!fs)
++    {
++      r = grub_errno;
++      goto finish;
++    }
++
++  r = fs->dir (dev, GRUB_BLS_CONFIG_PATH, parse_entry, NULL);
++
++finish:
++  if (dev)
++    grub_device_close (dev);
++
++  return r;
++}
++
++static grub_extcmd_t cmd;
++
++GRUB_MOD_INIT(bls)
++{
++  cmd = grub_register_extcmd ("bls_import",
++			      grub_cmd_bls_import,
++			      0,
++			      NULL,
++			      N_("Import Boot Loader Specification snippets."),
++			      NULL);
++}
++
++GRUB_MOD_FINI(bls)
++{
++  grub_unregister_extcmd (cmd);
++}
diff --git a/SOURCES/0029-Add-devicetree-loading.patch b/SOURCES/0029-Add-devicetree-loading.patch
new file mode 100644
index 0000000..4cb1a2a
--- /dev/null
+++ b/SOURCES/0029-Add-devicetree-loading.patch
@@ -0,0 +1,68 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 14 Jan 2014 13:12:23 -0500
+Subject: [PATCH] Add devicetree loading
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+
+Switch to use APM Mustang device tree, for hardware testing.
+
+Signed-off-by: David A. Marlin <d.marlin@redhat.com>
+
+Use the default device tree from the grub default file
+
+instead of hardcoding a value.
+
+Signed-off-by: David A. Marlin <dmarlin@redhat.com>
+---
+ util/grub-mkconfig.in   |  3 ++-
+ util/grub.d/10_linux.in | 15 +++++++++++++++
+ 2 files changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index b0a8626dd1c..f68d4925ee6 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -254,7 +254,8 @@ export GRUB_DEFAULT \
+   GRUB_ENABLE_CRYPTODISK \
+   GRUB_BADRAM \
+   GRUB_OS_PROBER_SKIP_LIST \
+-  GRUB_DISABLE_SUBMENU
++  GRUB_DISABLE_SUBMENU \
++  GRUB_DEFAULT_DTB
+ 
+ if test "x${grub_cfg}" != "x"; then
+   rm -f "${grub_cfg}.new"
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 87a7da34982..233754ff296 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -153,6 +153,13 @@ EOF
+     sed "s/^/$submenu_indentation/" << EOF
+ 	echo	'$(echo "$message" | grub_quote)'
+ 	initrd	$(echo $initrd_path)
++EOF
++  fi
++  if test -n "${fdt}" ; then
++    message="$(gettext_printf "Loading fdt ...")"
++    sed "s/^/$submenu_indentation/" << EOF
++	echo	'$(echo "$message" | grub_quote)'
++	devicetree	${rel_dirname}/${fdt}
+ EOF
+   fi
+   sed "s/^/$submenu_indentation/" << EOF
+@@ -236,6 +243,14 @@ while [ "x$list" != "x" ] ; do
+     gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
+   fi
+ 
++  fdt=
++  for i in "dtb-${version}" "dtb-${alt_version}"; do
++    if test -f "${dirname}/${i}/${GRUB_DEFAULT_DTB}" ; then
++      fdt="${i}/${GRUB_DEFAULT_DTB}"
++      break
++    fi
++  done
++
+   config=
+   for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do
+     if test -e "${i}" ; then
diff --git a/SOURCES/0030-Don-t-write-messages-to-the-screen.patch b/SOURCES/0030-Don-t-write-messages-to-the-screen.patch
new file mode 100644
index 0000000..e96a234
--- /dev/null
+++ b/SOURCES/0030-Don-t-write-messages-to-the-screen.patch
@@ -0,0 +1,176 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Jon McCann <william.jon.mccann@gmail.com>
+Date: Wed, 15 May 2013 13:30:20 -0400
+Subject: [PATCH] Don't write messages to the screen
+
+Writing messages to the screen before the menus or boot splash
+happens so quickly it looks like something is wrong and isn't
+very appealing.
+---
+ grub-core/gettext/gettext.c       | 25 +++++--------------------
+ grub-core/kern/main.c             |  5 -----
+ grub-core/boot/i386/pc/boot.S     |  3 ---
+ grub-core/boot/i386/pc/diskboot.S |  5 -----
+ util/grub.d/10_linux.in           |  7 -------
+ 5 files changed, 5 insertions(+), 40 deletions(-)
+
+diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c
+index 4880cefe3f8..b22e1bcc94b 100644
+--- a/grub-core/gettext/gettext.c
++++ b/grub-core/gettext/gettext.c
+@@ -434,16 +434,12 @@ static char *
+ grub_gettext_env_write_lang (struct grub_env_var *var
+ 			     __attribute__ ((unused)), const char *val)
+ {
+-  grub_err_t err;
++  grub_err_t __attribute__((__unused__)) err;
+   err = grub_gettext_init_ext (&main_context, val, grub_env_get ("locale_dir"),
+ 			       grub_env_get ("prefix"));
+-  if (err)
+-    grub_print_error ();
+ 
+   err = grub_gettext_init_ext (&secondary_context, val,
+ 			       grub_env_get ("secondary_locale_dir"), 0);
+-  if (err)
+-    grub_print_error ();
+ 
+   return grub_strdup (val);
+ }
+@@ -451,23 +447,19 @@ grub_gettext_env_write_lang (struct grub_env_var *var
+ void
+ grub_gettext_reread_prefix (const char *val)
+ {
+-  grub_err_t err;
++  grub_err_t __attribute__((__unused__)) err;
+   err = grub_gettext_init_ext (&main_context, grub_env_get ("lang"), 
+ 			       grub_env_get ("locale_dir"),
+ 			       val);
+-  if (err)
+-    grub_print_error ();
+ }
+ 
+ static char *
+ read_main (struct grub_env_var *var
+ 	   __attribute__ ((unused)), const char *val)
+ {
+-  grub_err_t err;
++  grub_err_t __attribute__((__unused__)) err;
+   err = grub_gettext_init_ext (&main_context, grub_env_get ("lang"), val,
+ 			       grub_env_get ("prefix"));
+-  if (err)
+-    grub_print_error ();
+   return grub_strdup (val);
+ }
+ 
+@@ -475,12 +467,9 @@ static char *
+ read_secondary (struct grub_env_var *var
+ 		__attribute__ ((unused)), const char *val)
+ {
+-  grub_err_t err;
++  grub_err_t __attribute__((__unused__)) err;
+   err = grub_gettext_init_ext (&secondary_context, grub_env_get ("lang"), val,
+ 			       0);
+-  if (err)
+-    grub_print_error ();
+-
+   return grub_strdup (val);
+ }
+ 
+@@ -500,18 +489,14 @@ grub_cmd_translate (grub_command_t cmd __attribute__ ((unused)),
+ GRUB_MOD_INIT (gettext)
+ {
+   const char *lang;
+-  grub_err_t err;
++  grub_err_t __attribute__((__unused__)) err;
+ 
+   lang = grub_env_get ("lang");
+ 
+   err = grub_gettext_init_ext (&main_context, lang, grub_env_get ("locale_dir"),
+ 			       grub_env_get ("prefix"));
+-  if (err)
+-    grub_print_error ();
+   err = grub_gettext_init_ext (&secondary_context, lang,
+ 			       grub_env_get ("secondary_locale_dir"), 0);
+-  if (err)
+-    grub_print_error ();
+ 
+   grub_register_variable_hook ("locale_dir", NULL, read_main);
+   grub_register_variable_hook ("secondary_locale_dir", NULL, read_secondary);
+diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
+index 8ab7794c47b..da47b18b50e 100644
+--- a/grub-core/kern/main.c
++++ b/grub-core/kern/main.c
+@@ -268,11 +268,6 @@ grub_main (void)
+ 
+   grub_boot_time ("After machine init.");
+ 
+-  /* Hello.  */
+-  grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
+-  grub_printf ("Welcome to GRUB!\n\n");
+-  grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+-
+   grub_load_config ();
+ 
+   grub_boot_time ("Before loading embedded modules.");
+diff --git a/grub-core/boot/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S
+index 2bd0b2d2866..ea167fe1206 100644
+--- a/grub-core/boot/i386/pc/boot.S
++++ b/grub-core/boot/i386/pc/boot.S
+@@ -249,9 +249,6 @@ real_start:
+ 	/* save drive reference first thing! */
+ 	pushw	%dx
+ 
+-	/* print a notification message on the screen */
+-	MSG(notification_string)
+-
+ 	/* set %si to the disk address packet */
+ 	movw	$disk_address_packet, %si
+ 
+diff --git a/grub-core/boot/i386/pc/diskboot.S b/grub-core/boot/i386/pc/diskboot.S
+index c1addc0df29..68d31de0c4c 100644
+--- a/grub-core/boot/i386/pc/diskboot.S
++++ b/grub-core/boot/i386/pc/diskboot.S
+@@ -50,11 +50,6 @@ _start:
+ 	/* save drive reference first thing! */
+ 	pushw	%dx
+ 
+-	/* print a notification message on the screen */
+-	pushw	%si
+-	MSG(notification_string)
+-	popw	%si
+-
+ 	/* this sets up for the first run through "bootloop" */
+ 	movw	$LOCAL(firstlist), %di
+ 
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 233754ff296..3a5aa0f8dc9 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -138,27 +138,20 @@ linux_entry ()
+     fi
+     printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
+   fi
+-  message="$(gettext_printf "Loading Linux %s ..." ${version})"
+   sed "s/^/$submenu_indentation/" << EOF
+-	echo	'$(echo "$message" | grub_quote)'
+ 	linux	${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
+ EOF
+   if test -n "${initrd}" ; then
+-    # TRANSLATORS: ramdisk isn't identifier. Should be translated.
+-    message="$(gettext_printf "Loading initial ramdisk ...")"
+     initrd_path=
+     for i in ${initrd}; do
+       initrd_path="${initrd_path} ${rel_dirname}/${i}"
+     done
+     sed "s/^/$submenu_indentation/" << EOF
+-	echo	'$(echo "$message" | grub_quote)'
+ 	initrd	$(echo $initrd_path)
+ EOF
+   fi
+   if test -n "${fdt}" ; then
+-    message="$(gettext_printf "Loading fdt ...")"
+     sed "s/^/$submenu_indentation/" << EOF
+-	echo	'$(echo "$message" | grub_quote)'
+ 	devicetree	${rel_dirname}/${fdt}
+ EOF
+   fi
diff --git a/SOURCES/0031-Don-t-print-GNU-GRUB-header.patch b/SOURCES/0031-Don-t-print-GNU-GRUB-header.patch
new file mode 100644
index 0000000..cdcdb13
--- /dev/null
+++ b/SOURCES/0031-Don-t-print-GNU-GRUB-header.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Jon McCann <william.jon.mccann@gmail.com>
+Date: Wed, 15 May 2013 13:53:48 -0400
+Subject: [PATCH] Don't print GNU GRUB header
+
+No one cares.
+---
+ grub-core/normal/main.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index b2654ef62e8..f57b7508a76 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -202,15 +202,16 @@ read_config_file (const char *config)
+ /* Initialize the screen.  */
+ void
+ grub_normal_init_page (struct grub_term_output *term,
+-		       int y)
++		       int y __attribute__((__unused__)))
+ {
++  grub_term_cls (term);
++
++#if 0
+   grub_ssize_t msg_len;
+   int posx;
+   char *msg_formatted;
+   grub_uint32_t *unicode_msg;
+   grub_uint32_t *last_position;
+- 
+-  grub_term_cls (term);
+ 
+   msg_formatted = grub_xasprintf (_("GNU GRUB  version %s"), PACKAGE_VERSION);
+   if (!msg_formatted)
+@@ -235,6 +236,7 @@ grub_normal_init_page (struct grub_term_output *term,
+   grub_putcode ('\n', term);
+   grub_putcode ('\n', term);
+   grub_free (unicode_msg);
++#endif
+ }
+ 
+ static void
diff --git a/SOURCES/0032-Don-t-add-to-highlighted-row.patch b/SOURCES/0032-Don-t-add-to-highlighted-row.patch
new file mode 100644
index 0000000..b2d5575
--- /dev/null
+++ b/SOURCES/0032-Don-t-add-to-highlighted-row.patch
@@ -0,0 +1,23 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Jon McCann <william.jon.mccann@gmail.com>
+Date: Wed, 15 May 2013 17:49:45 -0400
+Subject: [PATCH] Don't add '*' to highlighted row
+
+It is already highlighted.
+---
+ grub-core/normal/menu_text.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
+index e22bb91f6e8..a3d1f23f68f 100644
+--- a/grub-core/normal/menu_text.c
++++ b/grub-core/normal/menu_text.c
+@@ -242,7 +242,7 @@ print_entry (int y, int highlight, grub_menu_entry_t entry,
+       unicode_title[i] = ' ';
+ 
+   if (data->geo.num_entries > 1)
+-    grub_putcode (highlight ? '*' : ' ', data->term);
++    grub_putcode (' ', data->term);
+ 
+   grub_print_ucs4_menu (unicode_title,
+ 			unicode_title + len,
diff --git a/SOURCES/0033-Message-string-cleanups.patch b/SOURCES/0033-Message-string-cleanups.patch
new file mode 100644
index 0000000..9b6208e
--- /dev/null
+++ b/SOURCES/0033-Message-string-cleanups.patch
@@ -0,0 +1,68 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Jon McCann <william.jon.mccann@gmail.com>
+Date: Fri, 7 Jun 2013 11:09:04 -0400
+Subject: [PATCH] Message string cleanups
+
+Make use of terminology consistent. Remove jargon.
+---
+ grub-core/normal/menu_text.c | 21 +++++++++------------
+ 1 file changed, 9 insertions(+), 12 deletions(-)
+
+diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
+index a3d1f23f68f..64a83862f66 100644
+--- a/grub-core/normal/menu_text.c
++++ b/grub-core/normal/menu_text.c
+@@ -157,9 +157,8 @@ print_message (int nested, int edit, struct grub_term_output *term, int dry_run)
+ 
+   if (edit)
+     {
+-      ret += grub_print_message_indented_real (_("Minimum Emacs-like screen editing is \
+-supported. TAB lists completions. Press Ctrl-x or F10 to boot, Ctrl-c or F2 for a \
+-command-line or ESC to discard edits and return to the GRUB menu."),
++      ret += grub_print_message_indented_real (_("Press Ctrl-x or F10 to start, Ctrl-c or F2 for a \
++command prompt or Escape to discard edits and return to the menu. Pressing Tab lists possible completions."),
+ 					       STANDARD_MARGIN, STANDARD_MARGIN,
+ 					       term, dry_run);
+     }
+@@ -167,8 +166,8 @@ command-line or ESC to discard edits and return to the GRUB menu."),
+     {
+       char *msg_translated;
+ 
+-      msg_translated = grub_xasprintf (_("Use the %C and %C keys to select which "
+-					 "entry is highlighted."),
++      msg_translated = grub_xasprintf (_("Use the %C and %C keys to change the "
++					 "selection."),
+ 				       GRUB_UNICODE_UPARROW,
+ 				       GRUB_UNICODE_DOWNARROW);
+       if (!msg_translated)
+@@ -181,17 +180,15 @@ command-line or ESC to discard edits and return to the GRUB menu."),
+       if (nested)
+ 	{
+ 	  ret += grub_print_message_indented_real
+-	    (_("Press enter to boot the selected OS, "
+-	       "`e' to edit the commands before booting "
+-	       "or `c' for a command-line. ESC to return previous menu."),
++	    (_("Press 'e' to edit the selected item, "
++	       "or 'c' for a command prompt. Press Escape to return to the previous menu."),
+ 	     STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ 	}
+       else
+ 	{
+ 	  ret += grub_print_message_indented_real
+-	    (_("Press enter to boot the selected OS, "
+-	       "`e' to edit the commands before booting "
+-	       "or `c' for a command-line."),
++	    (_("Press 'e' to edit the selected item, "
++	       "or 'c' for a command prompt."),
+ 	     STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ 	}	
+     }
+@@ -443,7 +440,7 @@ menu_text_print_timeout (int timeout, void *dataptr)
+       || data->timeout_msg == TIMEOUT_TERSE_NO_MARGIN)
+     msg_translated = grub_xasprintf (_("%ds"), timeout);
+   else
+-    msg_translated = grub_xasprintf (_("The highlighted entry will be executed automatically in %ds."), timeout);
++    msg_translated = grub_xasprintf (_("The selected entry will be started automatically in %ds."), timeout);
+   if (!msg_translated)
+     {
+       grub_print_error ();
diff --git a/SOURCES/0034-Fix-border-spacing-now-that-we-aren-t-displaying-it.patch b/SOURCES/0034-Fix-border-spacing-now-that-we-aren-t-displaying-it.patch
new file mode 100644
index 0000000..504f273
--- /dev/null
+++ b/SOURCES/0034-Fix-border-spacing-now-that-we-aren-t-displaying-it.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Jon McCann <william.jon.mccann@gmail.com>
+Date: Fri, 7 Jun 2013 14:08:23 -0400
+Subject: [PATCH] Fix border spacing now that we aren't displaying it
+
+---
+ grub-core/normal/menu_text.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
+index 64a83862f66..1062d64ee29 100644
+--- a/grub-core/normal/menu_text.c
++++ b/grub-core/normal/menu_text.c
+@@ -331,12 +331,12 @@ grub_menu_init_page (int nested, int edit,
+   int empty_lines = 1;
+   int version_msg = 1;
+ 
+-  geo->border = 1;
+-  geo->first_entry_x = 1 /* margin */ + 1 /* border */;
++  geo->border = 0;
++  geo->first_entry_x = 0 /* margin */ + 0 /* border */;
+   geo->entry_width = grub_term_width (term) - 5;
+ 
+   geo->first_entry_y = 2 /* two empty lines*/
+-    + 1 /* GNU GRUB version text  */ + 1 /* top border */;
++    + 0 /* GNU GRUB version text  */ + 1 /* top border */;
+ 
+   geo->timeout_lines = 2;
+ 
diff --git a/SOURCES/0035-Use-the-correct-indentation-for-the-term-help-text.patch b/SOURCES/0035-Use-the-correct-indentation-for-the-term-help-text.patch
new file mode 100644
index 0000000..d2bf366
--- /dev/null
+++ b/SOURCES/0035-Use-the-correct-indentation-for-the-term-help-text.patch
@@ -0,0 +1,25 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Jon McCann <william.jon.mccann@gmail.com>
+Date: Fri, 7 Jun 2013 14:08:49 -0400
+Subject: [PATCH] Use the correct indentation for the term help text
+
+That is consistent with the menu help text
+---
+ grub-core/normal/main.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index f57b7508a76..0ce59fdc3f0 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -426,8 +426,8 @@ grub_normal_reader_init (int nested)
+     grub_normal_init_page (term, 1);
+     grub_term_setcursor (term, 1);
+ 
+-    if (grub_term_width (term) > 3 + STANDARD_MARGIN + 20)
+-      grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term);
++    if (grub_term_width (term) > 2 * STANDARD_MARGIN + 20)
++      grub_print_message_indented (msg_formatted, STANDARD_MARGIN, STANDARD_MARGIN, term);
+     else
+       grub_print_message_indented (msg_formatted, 0, 0, term);
+     grub_putcode ('\n', term);
diff --git a/SOURCES/0036-Indent-menu-entries.patch b/SOURCES/0036-Indent-menu-entries.patch
new file mode 100644
index 0000000..7a843ec
--- /dev/null
+++ b/SOURCES/0036-Indent-menu-entries.patch
@@ -0,0 +1,23 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Jon McCann <william.jon.mccann@gmail.com>
+Date: Fri, 7 Jun 2013 14:30:55 -0400
+Subject: [PATCH] Indent menu entries
+
+---
+ grub-core/normal/menu_text.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
+index 1062d64ee29..ecc60f99fc3 100644
+--- a/grub-core/normal/menu_text.c
++++ b/grub-core/normal/menu_text.c
+@@ -239,7 +239,8 @@ print_entry (int y, int highlight, grub_menu_entry_t entry,
+       unicode_title[i] = ' ';
+ 
+   if (data->geo.num_entries > 1)
+-    grub_putcode (' ', data->term);
++    for (i = 0; i < STANDARD_MARGIN; i++)
++      grub_putcode (' ', data->term);
+ 
+   grub_print_ucs4_menu (unicode_title,
+ 			unicode_title + len,
diff --git a/SOURCES/0037-Fix-margins.patch b/SOURCES/0037-Fix-margins.patch
new file mode 100644
index 0000000..9be1731
--- /dev/null
+++ b/SOURCES/0037-Fix-margins.patch
@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Jon McCann <william.jon.mccann@gmail.com>
+Date: Fri, 7 Jun 2013 14:59:36 -0400
+Subject: [PATCH] Fix margins
+
+---
+ grub-core/normal/menu_text.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
+index ecc60f99fc3..0e43f2c10cc 100644
+--- a/grub-core/normal/menu_text.c
++++ b/grub-core/normal/menu_text.c
+@@ -333,17 +333,15 @@ grub_menu_init_page (int nested, int edit,
+   int version_msg = 1;
+ 
+   geo->border = 0;
+-  geo->first_entry_x = 0 /* margin */ + 0 /* border */;
+-  geo->entry_width = grub_term_width (term) - 5;
++  geo->first_entry_x = 0; /* no margin */
++  geo->entry_width = grub_term_width (term) - 1;
+ 
+-  geo->first_entry_y = 2 /* two empty lines*/
+-    + 0 /* GNU GRUB version text  */ + 1 /* top border */;
++  geo->first_entry_y = 3; /* three empty lines*/
+ 
+   geo->timeout_lines = 2;
+ 
+   /* 3 lines for timeout message and bottom margin.  2 lines for the border.  */
+   geo->num_entries = grub_term_height (term) - geo->first_entry_y
+-    - 1 /* bottom border */
+     - 1 /* empty line before info message*/
+     - geo->timeout_lines /* timeout */
+     - 1 /* empty final line  */;
diff --git a/SOURCES/0038-Use-2-instead-of-1-for-our-right-hand-margin-so-line.patch b/SOURCES/0038-Use-2-instead-of-1-for-our-right-hand-margin-so-line.patch
new file mode 100644
index 0000000..3a37839
--- /dev/null
+++ b/SOURCES/0038-Use-2-instead-of-1-for-our-right-hand-margin-so-line.patch
@@ -0,0 +1,24 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 21 Jun 2013 14:44:08 -0400
+Subject: [PATCH] Use -2 instead of -1 for our right-hand margin, so
+ linewrapping works (#976643).
+
+Signed-off-by: Peter Jones <grub2-owner@fedoraproject.org>
+---
+ grub-core/normal/menu_text.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
+index 0e43f2c10cc..537d4bf86ff 100644
+--- a/grub-core/normal/menu_text.c
++++ b/grub-core/normal/menu_text.c
+@@ -334,7 +334,7 @@ grub_menu_init_page (int nested, int edit,
+ 
+   geo->border = 0;
+   geo->first_entry_x = 0; /* no margin */
+-  geo->entry_width = grub_term_width (term) - 1;
++  geo->entry_width = grub_term_width (term) - 2;
+ 
+   geo->first_entry_y = 3; /* three empty lines*/
+ 
diff --git a/SOURCES/0039-Enable-pager-by-default.-985860.patch b/SOURCES/0039-Enable-pager-by-default.-985860.patch
new file mode 100644
index 0000000..d92fbcc
--- /dev/null
+++ b/SOURCES/0039-Enable-pager-by-default.-985860.patch
@@ -0,0 +1,23 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 28 Oct 2013 10:09:27 -0400
+Subject: [PATCH] Enable pager by default. (#985860)
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/00_header.in | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
+index 93a90233ead..858b526c925 100644
+--- a/util/grub.d/00_header.in
++++ b/util/grub.d/00_header.in
+@@ -43,6 +43,8 @@ if [ "x${GRUB_DEFAULT_BUTTON}" = "xsaved" ] ; then GRUB_DEFAULT_BUTTON='${saved_
+ if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT" ; fi
+ 
+ cat << EOF
++set pager=1
++
+ if [ -s \$prefix/grubenv ]; then
+   load_env
+ fi
diff --git a/SOURCES/0040-F10-doesn-t-work-on-serial-so-don-t-tell-the-user-to.patch b/SOURCES/0040-F10-doesn-t-work-on-serial-so-don-t-tell-the-user-to.patch
new file mode 100644
index 0000000..93233bc
--- /dev/null
+++ b/SOURCES/0040-F10-doesn-t-work-on-serial-so-don-t-tell-the-user-to.patch
@@ -0,0 +1,24 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 28 Oct 2013 10:13:27 -0400
+Subject: [PATCH] F10 doesn't work on serial, so don't tell the user to hit it
+ (#987443)
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/normal/menu_text.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
+index 537d4bf86ff..452d55bf9ff 100644
+--- a/grub-core/normal/menu_text.c
++++ b/grub-core/normal/menu_text.c
+@@ -157,7 +157,7 @@ print_message (int nested, int edit, struct grub_term_output *term, int dry_run)
+ 
+   if (edit)
+     {
+-      ret += grub_print_message_indented_real (_("Press Ctrl-x or F10 to start, Ctrl-c or F2 for a \
++      ret += grub_print_message_indented_real (_("Press Ctrl-x to start, Ctrl-c for a \
+ command prompt or Escape to discard edits and return to the menu. Pressing Tab lists possible completions."),
+ 					       STANDARD_MARGIN, STANDARD_MARGIN,
+ 					       term, dry_run);
diff --git a/SOURCES/0041-Don-t-say-GNU-Linux-in-generated-menus.patch b/SOURCES/0041-Don-t-say-GNU-Linux-in-generated-menus.patch
new file mode 100644
index 0000000..85b0cde
--- /dev/null
+++ b/SOURCES/0041-Don-t-say-GNU-Linux-in-generated-menus.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 14 Mar 2011 14:27:42 -0400
+Subject: [PATCH] Don't say "GNU/Linux" in generated menus.
+
+---
+ util/grub.d/10_linux.in     | 4 ++--
+ util/grub.d/20_linux_xen.in | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 3a5aa0f8dc9..6299836b5cd 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -29,9 +29,9 @@ export TEXTDOMAINDIR="@localedir@"
+ CLASS="--class gnu-linux --class gnu --class os"
+ 
+ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
+-  OS=GNU/Linux
++  OS="$(sed 's, release .*$,,g' /etc/system-release)"
+ else
+-  OS="${GRUB_DISTRIBUTOR} GNU/Linux"
++  OS="${GRUB_DISTRIBUTOR}"
+   CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
+ fi
+ 
+diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
+index e8143b079dc..972a4b5a03d 100644
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -29,9 +29,9 @@ export TEXTDOMAINDIR="@localedir@"
+ CLASS="--class gnu-linux --class gnu --class os --class xen"
+ 
+ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
+-  OS=GNU/Linux
++  OS="$(sed 's, release .*$,,g' /etc/system-release)"
+ else
+-  OS="${GRUB_DISTRIBUTOR} GNU/Linux"
++  OS="${GRUB_DISTRIBUTOR}"
+   CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
+ fi
+ 
diff --git a/SOURCES/0042-Don-t-draw-a-border-around-the-menu.patch b/SOURCES/0042-Don-t-draw-a-border-around-the-menu.patch
new file mode 100644
index 0000000..e5d11ac
--- /dev/null
+++ b/SOURCES/0042-Don-t-draw-a-border-around-the-menu.patch
@@ -0,0 +1,71 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Jon McCann <william.jon.mccann@gmail.com>
+Date: Wed, 15 May 2013 16:47:33 -0400
+Subject: [PATCH] Don't draw a border around the menu
+
+It looks cleaner without it.
+---
+ grub-core/normal/menu_text.c | 43 -------------------------------------------
+ 1 file changed, 43 deletions(-)
+
+diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
+index 452d55bf9ff..1ed2bd92cf8 100644
+--- a/grub-core/normal/menu_text.c
++++ b/grub-core/normal/menu_text.c
+@@ -108,47 +108,6 @@ grub_print_message_indented (const char *msg, int margin_left, int margin_right,
+   grub_print_message_indented_real (msg, margin_left, margin_right, term, 0);
+ }
+ 
+-static void
+-draw_border (struct grub_term_output *term, const struct grub_term_screen_geometry *geo)
+-{
+-  int i;
+-
+-  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
+-
+-  grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
+-	geo->first_entry_y - 1 });
+-  grub_putcode (GRUB_UNICODE_CORNER_UL, term);
+-  for (i = 0; i < geo->entry_width + 1; i++)
+-    grub_putcode (GRUB_UNICODE_HLINE, term);
+-  grub_putcode (GRUB_UNICODE_CORNER_UR, term);
+-
+-  for (i = 0; i < geo->num_entries; i++)
+-    {
+-      grub_term_gotoxy (term, (struct grub_term_coordinate) { geo->first_entry_x - 1,
+-	    geo->first_entry_y + i });
+-      grub_putcode (GRUB_UNICODE_VLINE, term);
+-      grub_term_gotoxy (term,
+-			(struct grub_term_coordinate) { geo->first_entry_x + geo->entry_width + 1,
+-			    geo->first_entry_y + i });
+-      grub_putcode (GRUB_UNICODE_VLINE, term);
+-    }
+-
+-  grub_term_gotoxy (term,
+-		    (struct grub_term_coordinate) { geo->first_entry_x - 1,
+-			geo->first_entry_y - 1 + geo->num_entries + 1 });
+-  grub_putcode (GRUB_UNICODE_CORNER_LL, term);
+-  for (i = 0; i < geo->entry_width + 1; i++)
+-    grub_putcode (GRUB_UNICODE_HLINE, term);
+-  grub_putcode (GRUB_UNICODE_CORNER_LR, term);
+-
+-  grub_term_setcolorstate (term, GRUB_TERM_COLOR_NORMAL);
+-
+-  grub_term_gotoxy (term,
+-		    (struct grub_term_coordinate) { geo->first_entry_x - 1,
+-			(geo->first_entry_y - 1 + geo->num_entries
+-			 + GRUB_TERM_MARGIN + 1) });
+-}
+-
+ static int
+ print_message (int nested, int edit, struct grub_term_output *term, int dry_run)
+ {
+@@ -406,8 +365,6 @@ grub_menu_init_page (int nested, int edit,
+ 
+   grub_term_normal_color = grub_color_menu_normal;
+   grub_term_highlight_color = grub_color_menu_highlight;
+-  if (geo->border)
+-    draw_border (term, geo);
+   grub_term_normal_color = old_color_normal;
+   grub_term_highlight_color = old_color_highlight;
+   geo->timeout_y = geo->first_entry_y + geo->num_entries
diff --git a/SOURCES/0043-Use-the-standard-margin-for-the-timeout-string.patch b/SOURCES/0043-Use-the-standard-margin-for-the-timeout-string.patch
new file mode 100644
index 0000000..c6c770c
--- /dev/null
+++ b/SOURCES/0043-Use-the-standard-margin-for-the-timeout-string.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: William Jon McCann <william.jon.mccann@gmail.com>
+Date: Fri, 7 Jun 2013 10:52:32 -0400
+Subject: [PATCH] Use the standard margin for the timeout string
+
+So that it aligns with the other messages
+---
+ grub-core/normal/menu_text.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
+index 1ed2bd92cf8..7681f7d2893 100644
+--- a/grub-core/normal/menu_text.c
++++ b/grub-core/normal/menu_text.c
+@@ -372,7 +372,7 @@ grub_menu_init_page (int nested, int edit,
+   if (bottom_message)
+     {
+       grub_term_gotoxy (term,
+-			(struct grub_term_coordinate) { GRUB_TERM_MARGIN,
++			(struct grub_term_coordinate) { STANDARD_MARGIN,
+ 			    geo->timeout_y });
+ 
+       print_message (nested, edit, term, 0);
+@@ -407,14 +407,14 @@ menu_text_print_timeout (int timeout, void *dataptr)
+   if (data->timeout_msg == TIMEOUT_UNKNOWN)
+     {
+       data->timeout_msg = grub_print_message_indented_real (msg_translated,
+-							    3, 1, data->term, 1)
++							    STANDARD_MARGIN, 1, data->term, 1)
+ 	<= data->geo.timeout_lines ? TIMEOUT_NORMAL : TIMEOUT_TERSE;
+       if (data->timeout_msg == TIMEOUT_TERSE)
+ 	{
+ 	  grub_free (msg_translated);
+ 	  msg_translated = grub_xasprintf (_("%ds"), timeout);
+ 	  if (grub_term_width (data->term) < 10)
+-	    data->timeout_msg = TIMEOUT_TERSE_NO_MARGIN;
++	    data->timeout_msg = STANDARD_MARGIN;
+ 	}
+     }
+ 
diff --git a/SOURCES/0044-Add-.eh_frame-to-list-of-relocations-stripped.patch b/SOURCES/0044-Add-.eh_frame-to-list-of-relocations-stripped.patch
new file mode 100644
index 0000000..d837061
--- /dev/null
+++ b/SOURCES/0044-Add-.eh_frame-to-list-of-relocations-stripped.patch
@@ -0,0 +1,22 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Fedora Ninjas <grub2-owner@fedoraproject.org>
+Date: Mon, 13 Jan 2014 21:50:59 -0500
+Subject: [PATCH] Add .eh_frame to list of relocations stripped
+
+---
+ conf/Makefile.common | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/conf/Makefile.common b/conf/Makefile.common
+index 311da61c6c5..044ab3abe88 100644
+--- a/conf/Makefile.common
++++ b/conf/Makefile.common
+@@ -38,7 +38,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding
+ LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC)
+ CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1
+ CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
+-STRIPFLAGS_KERNEL = -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx
++STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx
+ 
+ CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding
+ LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
diff --git a/SOURCES/0045-Don-t-munge-raw-spaces-when-we-re-doing-our-cmdline-.patch b/SOURCES/0045-Don-t-munge-raw-spaces-when-we-re-doing-our-cmdline-.patch
new file mode 100644
index 0000000..33bdad2
--- /dev/null
+++ b/SOURCES/0045-Don-t-munge-raw-spaces-when-we-re-doing-our-cmdline-.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 30 Jun 2014 14:16:46 -0400
+Subject: [PATCH] Don't munge raw spaces when we're doing our cmdline escaping
+ (#923374)
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/lib/cmdline.c | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c
+index 0a5b2afb94b..970ea868c14 100644
+--- a/grub-core/lib/cmdline.c
++++ b/grub-core/lib/cmdline.c
+@@ -97,16 +97,7 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+ 
+       while (*c)
+ 	{
+-	  if (*c == ' ')
+-	    {
+-	      *buf++ = '\\';
+-	      *buf++ = 'x';
+-	      *buf++ = '2';
+-	      *buf++ = '0';
+-	      c++;
+-	      continue;
+-	    }
+-	  else if (*c == '\\' && *(c+1) == 'x' &&
++	  if (*c == '\\' && *(c+1) == 'x' &&
+ 		   is_hex(*(c+2)) && is_hex(*(c+3)))
+ 	    {
+ 	      *buf++ = *c++;
diff --git a/SOURCES/0046-Don-t-require-a-password-to-boot-entries-generated-b.patch b/SOURCES/0046-Don-t-require-a-password-to-boot-entries-generated-b.patch
new file mode 100644
index 0000000..b0b2b0e
--- /dev/null
+++ b/SOURCES/0046-Don-t-require-a-password-to-boot-entries-generated-b.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 11 Feb 2014 11:14:50 -0500
+Subject: [PATCH] Don't require a password to boot entries generated by
+ grub-mkconfig.
+
+When we set a password, we just want that to mean you can't /edit/ an entry.
+
+Resolves: rhbz#1030176
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/10_linux.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 6299836b5cd..b744438e04a 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -26,7 +26,7 @@ datarootdir="@datarootdir@"
+ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
+ 
+-CLASS="--class gnu-linux --class gnu --class os"
++CLASS="--class gnu-linux --class gnu --class os --unrestricted"
+ 
+ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
+   OS="$(sed 's, release .*$,,g' /etc/system-release)"
diff --git a/SOURCES/0047-Don-t-emit-Booting-.-message.patch b/SOURCES/0047-Don-t-emit-Booting-.-message.patch
new file mode 100644
index 0000000..725ae09
--- /dev/null
+++ b/SOURCES/0047-Don-t-emit-Booting-.-message.patch
@@ -0,0 +1,49 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 18 Feb 2014 09:37:49 -0500
+Subject: [PATCH] Don't emit "Booting ..." message.
+
+UI team still hates this stuff, so we're disabling it for RHEL 7.
+
+Resolves: rhbz#1023142
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/normal/menu.c       | 4 +++-
+ grub-core/normal/menu_entry.c | 3 ---
+ 2 files changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index d2f64b05e0a..5e2f5283d3d 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -838,12 +838,14 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
+ 
+ /* Callback invoked immediately before a menu entry is executed.  */
+ static void
+-notify_booting (grub_menu_entry_t entry,
++notify_booting (grub_menu_entry_t __attribute__((unused)) entry,
+ 		void *userdata __attribute__((unused)))
+ {
++#if 0
+   grub_printf ("  ");
+   grub_printf_ (N_("Booting `%s'"), entry->title);
+   grub_printf ("\n\n");
++#endif
+ }
+ 
+ /* Callback invoked when a default menu entry executed because of a timeout
+diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c
+index cdf3590a364..5785f67ee1c 100644
+--- a/grub-core/normal/menu_entry.c
++++ b/grub-core/normal/menu_entry.c
+@@ -1167,9 +1167,6 @@ run (struct screen *screen)
+   char *dummy[1] = { NULL };
+ 
+   grub_cls ();
+-  grub_printf ("  ");
+-  grub_printf_ (N_("Booting a command list"));
+-  grub_printf ("\n\n");
+ 
+   errs_before = grub_err_printed_errors;
+ 
diff --git a/SOURCES/0048-Replace-a-lot-of-man-pages-with-slightly-nicer-ones.patch b/SOURCES/0048-Replace-a-lot-of-man-pages-with-slightly-nicer-ones.patch
new file mode 100644
index 0000000..d6169aa
--- /dev/null
+++ b/SOURCES/0048-Replace-a-lot-of-man-pages-with-slightly-nicer-ones.patch
@@ -0,0 +1,1960 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 4 Mar 2014 11:00:23 -0500
+Subject: [PATCH] Replace a lot of man pages with slightly nicer ones.
+
+Replace a bunch of machine generated ones with ones that look nicer.
+---
+ configure.ac                      |  23 ++++++
+ conf/Makefile.extra-dist          |   1 -
+ docs/Makefile.am                  |   2 -
+ docs/man/grub-bios-setup.h2m      |   6 --
+ docs/man/grub-editenv.h2m         |   5 --
+ docs/man/grub-emu.h2m             |   6 --
+ docs/man/grub-file.h2m            |   2 -
+ docs/man/grub-fstest.h2m          |   4 -
+ docs/man/grub-glue-efi.h2m        |   4 -
+ docs/man/grub-install.h2m         |   6 --
+ docs/man/grub-kbdcomp.h2m         |  10 ---
+ docs/man/grub-macbless.h2m        |   4 -
+ docs/man/grub-macho2img.h2m       |   4 -
+ docs/man/grub-menulst2cfg.h2m     |   4 -
+ docs/man/grub-mkconfig.h2m        |   4 -
+ docs/man/grub-mkfont.h2m          |   4 -
+ docs/man/grub-mkimage.h2m         |   6 --
+ docs/man/grub-mklayout.h2m        |  10 ---
+ docs/man/grub-mknetdir.h2m        |   4 -
+ docs/man/grub-mkpasswd-pbkdf2.h2m |   4 -
+ docs/man/grub-mkrelpath.h2m       |   4 -
+ docs/man/grub-mkrescue.h2m        |   4 -
+ docs/man/grub-mkstandalone.h2m    |   4 -
+ docs/man/grub-mount.h2m           |   2 -
+ docs/man/grub-ofpathname.h2m      |   4 -
+ docs/man/grub-pe2elf.h2m          |   4 -
+ docs/man/grub-probe.h2m           |   4 -
+ docs/man/grub-reboot.h2m          |   5 --
+ docs/man/grub-render-label.h2m    |   3 -
+ docs/man/grub-script-check.h2m    |   4 -
+ docs/man/grub-set-default.h2m     |   5 --
+ docs/man/grub-sparc64-setup.h2m   |   6 --
+ docs/man/grub-syslinux2cfg.h2m    |   4 -
+ gentpl.py                         |   5 +-
+ util/grub-bios-setup.8            |  54 +++++++++++++
+ util/grub-editenv.1               |  46 +++++++++++
+ util/grub-file.1                  | 165 ++++++++++++++++++++++++++++++++++++++
+ util/grub-fstest.1                |  99 +++++++++++++++++++++++
+ util/grub-glue-efi.1              |  31 +++++++
+ util/grub-install.8               | 129 +++++++++++++++++++++++++++++
+ util/grub-kbdcomp.1               |  19 +++++
+ util/grub-macbless.1              |  22 +++++
+ util/grub-menulst2cfg.1           |  12 +++
+ util/grub-mkconfig.8              |  17 ++++
+ util/grub-mkfont.1                |  87 ++++++++++++++++++++
+ util/grub-mkimage.1               |  95 ++++++++++++++++++++++
+ util/grub-mklayout.1              |  27 +++++++
+ util/grub-mknetdir.1              |  12 +++
+ util/grub-mkpasswd-pbkdf2.1       |  27 +++++++
+ util/grub-mkrelpath.1             |  12 +++
+ util/grub-mkrescue.1              | 123 ++++++++++++++++++++++++++++
+ util/grub-mkstandalone.1          | 100 +++++++++++++++++++++++
+ util/grub-ofpathname.8            |  12 +++
+ util/grub-probe.8                 |  80 ++++++++++++++++++
+ util/grub-reboot.8                |  21 +++++
+ util/grub-render-label.1          |  51 ++++++++++++
+ util/grub-script-check.1          |  21 +++++
+ util/grub-set-default.8           |  21 +++++
+ util/grub-sparc64-setup.8         |  12 +++
+ 59 files changed, 1319 insertions(+), 147 deletions(-)
+ delete mode 100644 docs/man/grub-bios-setup.h2m
+ delete mode 100644 docs/man/grub-editenv.h2m
+ delete mode 100644 docs/man/grub-emu.h2m
+ delete mode 100644 docs/man/grub-file.h2m
+ delete mode 100644 docs/man/grub-fstest.h2m
+ delete mode 100644 docs/man/grub-glue-efi.h2m
+ delete mode 100644 docs/man/grub-install.h2m
+ delete mode 100644 docs/man/grub-kbdcomp.h2m
+ delete mode 100644 docs/man/grub-macbless.h2m
+ delete mode 100644 docs/man/grub-macho2img.h2m
+ delete mode 100644 docs/man/grub-menulst2cfg.h2m
+ delete mode 100644 docs/man/grub-mkconfig.h2m
+ delete mode 100644 docs/man/grub-mkfont.h2m
+ delete mode 100644 docs/man/grub-mkimage.h2m
+ delete mode 100644 docs/man/grub-mklayout.h2m
+ delete mode 100644 docs/man/grub-mknetdir.h2m
+ delete mode 100644 docs/man/grub-mkpasswd-pbkdf2.h2m
+ delete mode 100644 docs/man/grub-mkrelpath.h2m
+ delete mode 100644 docs/man/grub-mkrescue.h2m
+ delete mode 100644 docs/man/grub-mkstandalone.h2m
+ delete mode 100644 docs/man/grub-mount.h2m
+ delete mode 100644 docs/man/grub-ofpathname.h2m
+ delete mode 100644 docs/man/grub-pe2elf.h2m
+ delete mode 100644 docs/man/grub-probe.h2m
+ delete mode 100644 docs/man/grub-reboot.h2m
+ delete mode 100644 docs/man/grub-render-label.h2m
+ delete mode 100644 docs/man/grub-script-check.h2m
+ delete mode 100644 docs/man/grub-set-default.h2m
+ delete mode 100644 docs/man/grub-sparc64-setup.h2m
+ delete mode 100644 docs/man/grub-syslinux2cfg.h2m
+ create mode 100644 util/grub-bios-setup.8
+ create mode 100644 util/grub-editenv.1
+ create mode 100644 util/grub-file.1
+ create mode 100644 util/grub-fstest.1
+ create mode 100644 util/grub-glue-efi.1
+ create mode 100644 util/grub-install.8
+ create mode 100644 util/grub-kbdcomp.1
+ create mode 100644 util/grub-macbless.1
+ create mode 100644 util/grub-menulst2cfg.1
+ create mode 100644 util/grub-mkconfig.8
+ create mode 100644 util/grub-mkfont.1
+ create mode 100644 util/grub-mkimage.1
+ create mode 100644 util/grub-mklayout.1
+ create mode 100644 util/grub-mknetdir.1
+ create mode 100644 util/grub-mkpasswd-pbkdf2.1
+ create mode 100644 util/grub-mkrelpath.1
+ create mode 100644 util/grub-mkrescue.1
+ create mode 100644 util/grub-mkstandalone.1
+ create mode 100644 util/grub-ofpathname.8
+ create mode 100644 util/grub-probe.8
+ create mode 100644 util/grub-reboot.8
+ create mode 100644 util/grub-render-label.1
+ create mode 100644 util/grub-script-check.1
+ create mode 100644 util/grub-set-default.8
+ create mode 100644 util/grub-sparc64-setup.8
+
+diff --git a/configure.ac b/configure.ac
+index 783118ccdcd..d5db2803ec4 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -70,6 +70,29 @@ grub_TRANSFORM([grub-set-default])
+ grub_TRANSFORM([grub-sparc64-setup])
+ grub_TRANSFORM([grub-render-label])
+ grub_TRANSFORM([grub-file])
++grub_TRANSFORM([grub-bios-setup.3])
++grub_TRANSFORM([grub-editenv.1])
++grub_TRANSFORM([grub-fstest.3])
++grub_TRANSFORM([grub-glue-efi.3])
++grub_TRANSFORM([grub-install.1])
++grub_TRANSFORM([grub-kbdcomp.3])
++grub_TRANSFORM([grub-menulst2cfg.1])
++grub_TRANSFORM([grub-mkconfig.1])
++grub_TRANSFORM([grub-mkfont.3])
++grub_TRANSFORM([grub-mkimage.1])
++grub_TRANSFORM([grub-mklayout.3])
++grub_TRANSFORM([grub-mknetdir.3])
++grub_TRANSFORM([grub-mkpasswd-pbkdf2.3])
++grub_TRANSFORM([grub-mkrelpath.3])
++grub_TRANSFORM([grub-mkrescue.1])
++grub_TRANSFORM([grub-mkstandalone.3])
++grub_TRANSFORM([grub-ofpathname.3])
++grub_TRANSFORM([grub-probe.3])
++grub_TRANSFORM([grub-reboot.3])
++grub_TRANSFORM([grub-render-label.3])
++grub_TRANSFORM([grub-script-check.3])
++grub_TRANSFORM([grub-set-default.1])
++grub_TRANSFORM([grub-sparc64-setup.3])
+ 
+ # Optimization flag.  Allow user to override.
+ if test "x$TARGET_CFLAGS" = x; then
+diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist
+index b16bd925320..39eb94bded6 100644
+--- a/conf/Makefile.extra-dist
++++ b/conf/Makefile.extra-dist
+@@ -11,7 +11,6 @@ EXTRA_DIST += unicode
+ EXTRA_DIST += util/import_gcry.py
+ EXTRA_DIST += util/import_unicode.py
+ 
+-EXTRA_DIST += docs/man
+ EXTRA_DIST += docs/autoiso.cfg
+ EXTRA_DIST += docs/grub.cfg
+ EXTRA_DIST += docs/osdetect.cfg
+diff --git a/docs/Makefile.am b/docs/Makefile.am
+index 93eb3962765..ab28f199694 100644
+--- a/docs/Makefile.am
++++ b/docs/Makefile.am
+@@ -5,5 +5,3 @@ info_TEXINFOS = grub.texi grub-dev.texi
+ grub_TEXINFOS = fdl.texi
+ 
+ EXTRA_DIST = font_char_metrics.png font_char_metrics.txt
+-
+-
+diff --git a/docs/man/grub-bios-setup.h2m b/docs/man/grub-bios-setup.h2m
+deleted file mode 100644
+index ac6ede36296..00000000000
+--- a/docs/man/grub-bios-setup.h2m
++++ /dev/null
+@@ -1,6 +0,0 @@
+-[NAME]
+-grub-bios-setup \- set up a device to boot using GRUB
+-[SEE ALSO]
+-.BR grub-install (8),
+-.BR grub-mkimage (1),
+-.BR grub-mkrescue (1)
+diff --git a/docs/man/grub-editenv.h2m b/docs/man/grub-editenv.h2m
+deleted file mode 100644
+index 3859d3d4c4f..00000000000
+--- a/docs/man/grub-editenv.h2m
++++ /dev/null
+@@ -1,5 +0,0 @@
+-[NAME]
+-grub-editenv \- edit GRUB environment block
+-[SEE ALSO]
+-.BR grub-reboot (8),
+-.BR grub-set-default (8)
+diff --git a/docs/man/grub-emu.h2m b/docs/man/grub-emu.h2m
+deleted file mode 100644
+index ef1c000656a..00000000000
+--- a/docs/man/grub-emu.h2m
++++ /dev/null
+@@ -1,6 +0,0 @@
+-[NAME]
+-grub-emu \- GRUB emulator
+-[SEE ALSO]
+-If you are trying to install GRUB, then you should use
+-.BR grub-install (8)
+-rather than this program.
+diff --git a/docs/man/grub-file.h2m b/docs/man/grub-file.h2m
+deleted file mode 100644
+index e09bb4d3101..00000000000
+--- a/docs/man/grub-file.h2m
++++ /dev/null
+@@ -1,2 +0,0 @@
+-[NAME]
+-grub-file \- check file type
+diff --git a/docs/man/grub-fstest.h2m b/docs/man/grub-fstest.h2m
+deleted file mode 100644
+index 9676b159afd..00000000000
+--- a/docs/man/grub-fstest.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-fstest \- debug tool for GRUB filesystem drivers
+-[SEE ALSO]
+-.BR grub-probe (8)
+diff --git a/docs/man/grub-glue-efi.h2m b/docs/man/grub-glue-efi.h2m
+deleted file mode 100644
+index c1c6ded49ff..00000000000
+--- a/docs/man/grub-glue-efi.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-glue-efi \- generate a fat binary for EFI
+-[DESCRIPTION]
+-grub-glue-efi processes ia32 and amd64 EFI images and glues them according to Apple format.
+diff --git a/docs/man/grub-install.h2m b/docs/man/grub-install.h2m
+deleted file mode 100644
+index 8cbbc87a0f2..00000000000
+--- a/docs/man/grub-install.h2m
++++ /dev/null
+@@ -1,6 +0,0 @@
+-[NAME]
+-grub-install \- install GRUB to a device
+-[SEE ALSO]
+-.BR grub-mkconfig (8),
+-.BR grub-mkimage (1),
+-.BR grub-mkrescue (1)
+diff --git a/docs/man/grub-kbdcomp.h2m b/docs/man/grub-kbdcomp.h2m
+deleted file mode 100644
+index d81f9157e01..00000000000
+--- a/docs/man/grub-kbdcomp.h2m
++++ /dev/null
+@@ -1,10 +0,0 @@
+-[NAME]
+-grub-kbdcomp \- generate a GRUB keyboard layout file
+-[DESCRIPTION]
+-grub-kbdcomp processes a X keyboard layout description in
+-.BR keymaps (5)
+-format into a format that can be used by GRUB's
+-.B keymap
+-command.
+-[SEE ALSO]
+-.BR grub-mklayout (8)
+diff --git a/docs/man/grub-macbless.h2m b/docs/man/grub-macbless.h2m
+deleted file mode 100644
+index 0197c0087d7..00000000000
+--- a/docs/man/grub-macbless.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-macbless \- bless a mac file/directory
+-[SEE ALSO]
+-.BR grub-install (1)
+diff --git a/docs/man/grub-macho2img.h2m b/docs/man/grub-macho2img.h2m
+deleted file mode 100644
+index d79aaeed8f9..00000000000
+--- a/docs/man/grub-macho2img.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-macho2img \- convert Mach-O to raw image
+-[SEE ALSO]
+-.BR grub-mkimage (1)
+diff --git a/docs/man/grub-menulst2cfg.h2m b/docs/man/grub-menulst2cfg.h2m
+deleted file mode 100644
+index c2e0055ed7e..00000000000
+--- a/docs/man/grub-menulst2cfg.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-menulst2cfg \- transform legacy menu.lst into grub.cfg
+-[SEE ALSO]
+-.BR grub-mkconfig (8)
+diff --git a/docs/man/grub-mkconfig.h2m b/docs/man/grub-mkconfig.h2m
+deleted file mode 100644
+index 9b42f813010..00000000000
+--- a/docs/man/grub-mkconfig.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-mkconfig \- generate a GRUB configuration file
+-[SEE ALSO]
+-.BR grub-install (8)
+diff --git a/docs/man/grub-mkfont.h2m b/docs/man/grub-mkfont.h2m
+deleted file mode 100644
+index d46fe600eca..00000000000
+--- a/docs/man/grub-mkfont.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-mkfont \- make GRUB font files
+-[SEE ALSO]
+-.BR grub-mkconfig (8)
+diff --git a/docs/man/grub-mkimage.h2m b/docs/man/grub-mkimage.h2m
+deleted file mode 100644
+index f0fbc2bb197..00000000000
+--- a/docs/man/grub-mkimage.h2m
++++ /dev/null
+@@ -1,6 +0,0 @@
+-[NAME]
+-grub-mkimage \- make a bootable image of GRUB
+-[SEE ALSO]
+-.BR grub-install (8),
+-.BR grub-mkrescue (1),
+-.BR grub-mknetdir (8)
+diff --git a/docs/man/grub-mklayout.h2m b/docs/man/grub-mklayout.h2m
+deleted file mode 100644
+index 1e43409c0ab..00000000000
+--- a/docs/man/grub-mklayout.h2m
++++ /dev/null
+@@ -1,10 +0,0 @@
+-[NAME]
+-grub-mklayout \- generate a GRUB keyboard layout file
+-[DESCRIPTION]
+-grub-mklayout processes a keyboard layout description in
+-.BR keymaps (5)
+-format into a format that can be used by GRUB's
+-.B keymap
+-command.
+-[SEE ALSO]
+-.BR grub-mkconfig (8)
+diff --git a/docs/man/grub-mknetdir.h2m b/docs/man/grub-mknetdir.h2m
+deleted file mode 100644
+index a2ef13ec111..00000000000
+--- a/docs/man/grub-mknetdir.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-mknetdir \- prepare a GRUB netboot directory.
+-[SEE ALSO]
+-.BR grub-mkimage (1)
+diff --git a/docs/man/grub-mkpasswd-pbkdf2.h2m b/docs/man/grub-mkpasswd-pbkdf2.h2m
+deleted file mode 100644
+index 4d202f3da7e..00000000000
+--- a/docs/man/grub-mkpasswd-pbkdf2.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-mkpasswd-pbkdf2 \- generate hashed password for GRUB
+-[SEE ALSO]
+-.BR grub-mkconfig (8)
+diff --git a/docs/man/grub-mkrelpath.h2m b/docs/man/grub-mkrelpath.h2m
+deleted file mode 100644
+index d01f3961e3f..00000000000
+--- a/docs/man/grub-mkrelpath.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-mkrelpath \- make a system path relative to its root
+-[SEE ALSO]
+-.BR grub-probe (8)
+diff --git a/docs/man/grub-mkrescue.h2m b/docs/man/grub-mkrescue.h2m
+deleted file mode 100644
+index a427f02e3c6..00000000000
+--- a/docs/man/grub-mkrescue.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-mkrescue \- make a GRUB rescue image
+-[SEE ALSO]
+-.BR grub-mkimage (1)
+diff --git a/docs/man/grub-mkstandalone.h2m b/docs/man/grub-mkstandalone.h2m
+deleted file mode 100644
+index c77313978ad..00000000000
+--- a/docs/man/grub-mkstandalone.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-mkstandalone \- make a memdisk-based GRUB image
+-[SEE ALSO]
+-.BR grub-mkimage (1)
+diff --git a/docs/man/grub-mount.h2m b/docs/man/grub-mount.h2m
+deleted file mode 100644
+index 8d168982d72..00000000000
+--- a/docs/man/grub-mount.h2m
++++ /dev/null
+@@ -1,2 +0,0 @@
+-[NAME]
+-grub-mount \- export GRUB filesystem with FUSE
+diff --git a/docs/man/grub-ofpathname.h2m b/docs/man/grub-ofpathname.h2m
+deleted file mode 100644
+index 74b43eea039..00000000000
+--- a/docs/man/grub-ofpathname.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-ofpathname \- find OpenBOOT path for a device
+-[SEE ALSO]
+-.BR grub-probe (8)
+diff --git a/docs/man/grub-pe2elf.h2m b/docs/man/grub-pe2elf.h2m
+deleted file mode 100644
+index 7ca29bd703c..00000000000
+--- a/docs/man/grub-pe2elf.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-pe2elf \- convert PE image to ELF
+-[SEE ALSO]
+-.BR grub-mkimage (1)
+diff --git a/docs/man/grub-probe.h2m b/docs/man/grub-probe.h2m
+deleted file mode 100644
+index 6e1ffdcf937..00000000000
+--- a/docs/man/grub-probe.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-probe \- probe device information for GRUB
+-[SEE ALSO]
+-.BR grub-fstest (1)
+diff --git a/docs/man/grub-reboot.h2m b/docs/man/grub-reboot.h2m
+deleted file mode 100644
+index e4acace65ce..00000000000
+--- a/docs/man/grub-reboot.h2m
++++ /dev/null
+@@ -1,5 +0,0 @@
+-[NAME]
+-grub-reboot \- set the default boot entry for GRUB, for the next boot only
+-[SEE ALSO]
+-.BR grub-set-default (8),
+-.BR grub-editenv (1)
+diff --git a/docs/man/grub-render-label.h2m b/docs/man/grub-render-label.h2m
+deleted file mode 100644
+index 50ae5247c05..00000000000
+--- a/docs/man/grub-render-label.h2m
++++ /dev/null
+@@ -1,3 +0,0 @@
+-[NAME]
+-grub-render-label \- generate a .disk_label for Apple Macs.
+-
+diff --git a/docs/man/grub-script-check.h2m b/docs/man/grub-script-check.h2m
+deleted file mode 100644
+index 3653682671a..00000000000
+--- a/docs/man/grub-script-check.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-script-check \- check grub.cfg for syntax errors
+-[SEE ALSO]
+-.BR grub-mkconfig (8)
+diff --git a/docs/man/grub-set-default.h2m b/docs/man/grub-set-default.h2m
+deleted file mode 100644
+index 7945001c154..00000000000
+--- a/docs/man/grub-set-default.h2m
++++ /dev/null
+@@ -1,5 +0,0 @@
+-[NAME]
+-grub-set-default \- set the saved default boot entry for GRUB
+-[SEE ALSO]
+-.BR grub-reboot (8),
+-.BR grub-editenv (1)
+diff --git a/docs/man/grub-sparc64-setup.h2m b/docs/man/grub-sparc64-setup.h2m
+deleted file mode 100644
+index 18f803a50db..00000000000
+--- a/docs/man/grub-sparc64-setup.h2m
++++ /dev/null
+@@ -1,6 +0,0 @@
+-[NAME]
+-grub-sparc64-setup \- set up a device to boot using GRUB
+-[SEE ALSO]
+-.BR grub-install (8),
+-.BR grub-mkimage (1),
+-.BR grub-mkrescue (1)
+diff --git a/docs/man/grub-syslinux2cfg.h2m b/docs/man/grub-syslinux2cfg.h2m
+deleted file mode 100644
+index ad25c8ab753..00000000000
+--- a/docs/man/grub-syslinux2cfg.h2m
++++ /dev/null
+@@ -1,4 +0,0 @@
+-[NAME]
+-grub-syslinux2cfg \- transform syslinux config into grub.cfg
+-[SEE ALSO]
+-.BR grub-menulst2cfg (8)
+diff --git a/gentpl.py b/gentpl.py
+index da67965a41a..bf8439fa743 100644
+--- a/gentpl.py
++++ b/gentpl.py
+@@ -802,10 +802,7 @@ def manpage(defn, adddeps):
+ 
+     output("if COND_MAN_PAGES\n")
+     gvar_add("man_MANS", name + "." + mansection)
+-    rule(name + "." + mansection, name + " " + adddeps, """
+-chmod a+x """ + name + """
+-PATH=$(builddir):$$PATH pkgdatadir=$(builddir) $(HELP2MAN) --section=""" + mansection + """ -i $(top_srcdir)/docs/man/""" + name + """.h2m -o $@ """ + name + """
+-""")
++    rule(name + "." + mansection, name + " " + adddeps, "cat $(top_srcdir)/util/" + name + "." + mansection + " | $(top_builddir)/config.status --file=$@:-")
+     gvar_add("CLEANFILES", name + "." + mansection)
+     output("endif\n")
+ 
+diff --git a/util/grub-bios-setup.8 b/util/grub-bios-setup.8
+new file mode 100644
+index 00000000000..56f582b3d75
+--- /dev/null
++++ b/util/grub-bios-setup.8
+@@ -0,0 +1,54 @@
++.TH GRUB-BIOS-SETUP 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-bios-setup\fR \(em Set up images to boot from a device.
++
++.SH SYNOPSIS
++\fBgrub-bios-setup\fR [-a | --allow-floppy] [-b | --boot-image=\fIFILE\fR]
++.RS 17
++[-c | --core-image=\fIFILE\fR] [-d | --directory=\fIDIR\fR]
++.RE
++.RS 17
++[-f | --force] [-m | --device-map=\fIFILE\fR]
++.RE
++.RS 17
++[-s | --skip-fs-probe] [-v | --verbose] \fIDEVICE\fR
++
++.SH DESCRIPTION
++You should not normally run this program directly.  Use grub-install instead.
++
++.SH OPTIONS
++.TP
++\fB--allow-floppy\fR
++Make the device also bootable as a floppy.  This option is the default for
++/dev/fdX devices.  Some BIOSes will not boot images created with this option.
++
++.TP
++\fB--boot-image\fR=\fIFILE\fR
++Use FILE as the boot image.  The default value is \fBboot.img\fR.
++
++.TP
++\fB--core-image\fR=\fIFILE\fR
++Use FILE as ther core image.  The default value is \fBcore.img\fR.
++
++.TP
++\fB--directory\fR=\fIDIR\fR
++Use GRUB files in the directory DIR.  The default value is \fB/boot/grub\fR.
++
++.TP
++\fB--force\fR
++Install even if problems are detected.
++
++.TP
++\fB--device-map\fR=\fIFILE\fR
++Use FILE as the device map.  The default value is /boot/grub/device.map .
++
++.TP
++\fB--skip-fs-probe\fR
++Do not probe DEVICE for filesystems.
++
++.TP
++\fB--verbose\fR
++Print verbose messages.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-editenv.1 b/util/grub-editenv.1
+new file mode 100644
+index 00000000000..d28ba03ba42
+--- /dev/null
++++ b/util/grub-editenv.1
+@@ -0,0 +1,46 @@
++.TH GRUB-EDITENV 1 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-editenv\fR \(em Manage the GRUB environment block.
++
++.SH SYNOPSIS
++\fBgrub-editenv\fR [-v | --verbose] [\fIFILE\fR]
++.RS 14
++<create | list | set \fINAME\fR=\fIVALUE\fR | unset \fINAME\fR>
++
++.SH DESCRIPTION
++\fBgrub-editenv\fR is a command line tool to manage GRUB's stored environment.
++
++.SH OPTIONS
++.TP
++\fB--verbose\fR
++Print verbose messages.
++
++.TP
++\fBFILE\fR
++.RS 7
++File name to use for grub environment.  Default is /boot/grub/grubenv .
++.RE
++
++.SH COMMANDS
++.TP
++\fBcreate\fR
++.RS 7
++Create a blank environment block file.
++.RE
++
++.TP
++\fBlist\fR
++.RS 7
++List the current variables.
++.RE
++
++.TP
++\fBset\fR [\fINAME\fR=\fIVALUE\fR ...]
++Set variables.
++
++.TP
++\fBunset [\fINAME\fR ...]
++Delete variables.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-file.1 b/util/grub-file.1
+new file mode 100644
+index 00000000000..b29cb327889
+--- /dev/null
++++ b/util/grub-file.1
+@@ -0,0 +1,165 @@
++.TH GRUB-FILE 1 "Web Feb 26 2014"
++.SH NAME
++\fBgrub-file\fR \(em Check if FILE is of specified type.
++
++.SH SYNOPSIS
++\fBgrub-file\fR (--is-i386-xen-pae-domu | --is-x86_64-xen-domu |
++.RS 11
++--is-x86-xen-dom0 | --is-x86-multiboot |
++.RE
++.RS 11
++--is-x86-multiboot2 | --is-arm-linux | --is-arm64-linux |
++.RE
++.RS 11
++--is-ia64-linux | --is-mips-linux | --is-mipsel-linux |
++.RE
++.RS 11
++--is-sparc64-linux | --is-powerpc-linux | --is-x86-linux |
++.RE
++.RS 11
++--is-x86-linux32 | --is-x86-kfreebsd | --is-i386-kfreebsd |
++.RE
++.RS 11
++--is-x86_64-kfreebsd | --is-x86-knetbsd |
++.RE
++.RS 11
++--is-i386-knetbsd | --is-x86_64-knetbsd | --is-i386-efi |
++.RE
++.RS 11
++--is-x86_64-efi | --is-ia64-efi | --is-arm64-efi |
++.RE
++.RS 11
++--is-arm-efi | --is-hibernated-hiberfil | --is-x86_64-xnu |
++.RE
++.RS 11
++--is-i386-xnu | --is-xnu-hibr | --is-x86-bios-bootsector)
++.RE
++.RS 11
++\fIFILE\fR
++
++.SH DESCRIPTION
++\fBgrub-file\fR is used to check if \fIFILE\fR is of a specified type.
++
++.SH OPTIONS
++.TP
++--is-i386-xen-pae-domu
++Check if FILE can be booted as i386 PAE Xen unprivileged guest kernel
++
++.TP
++--is-x86_64-xen-domu
++Check if FILE can be booted as x86_64 Xen unprivileged guest kernel
++
++.TP
++--is-x86-xen-dom0
++Check if FILE can be used as Xen x86 privileged guest kernel
++
++.TP
++--is-x86-multiboot
++Check if FILE can be used as x86 multiboot kernel
++
++.TP
++--is-x86-multiboot2
++Check if FILE can be used as x86 multiboot2 kernel
++
++.TP
++--is-arm-linux
++Check if FILE is ARM Linux
++
++.TP
++--is-arm64-linux
++Check if FILE is ARM64 Linux
++
++.TP
++--is-ia64-linux
++Check if FILE is IA64 Linux
++
++.TP
++--is-mips-linux
++Check if FILE is MIPS Linux
++
++.TP
++--is-mipsel-linux
++Check if FILE is MIPSEL Linux
++
++.TP
++--is-sparc64-linux
++Check if FILE is SPARC64 Linux
++
++.TP
++--is-powerpc-linux
++Check if FILE is POWERPC Linux
++
++.TP
++--is-x86-linux
++Check if FILE is x86 Linux
++
++.TP
++--is-x86-linux32
++Check if FILE is x86 Linux supporting 32-bit protocol
++
++.TP
++--is-x86-kfreebsd
++Check if FILE is x86 kFreeBSD
++
++.TP
++--is-i386-kfreebsd
++Check if FILE is i386 kFreeBSD
++
++.TP
++--is-x86_64-kfreebsd
++Check if FILE is x86_64 kFreeBSD
++
++.TP
++--is-x86-knetbsd
++Check if FILE is x86 kNetBSD
++
++.TP
++--is-i386-knetbsd
++Check if FILE is i386 kNetBSD
++
++.TP
++--is-x86_64-knetbsd
++Check if FILE is x86_64 kNetBSD
++
++.TP
++--is-i386-efi
++Check if FILE is i386 EFI file
++
++.TP
++--is-x86_64-efi
++Check if FILE is x86_64 EFI file
++
++.TP
++--is-ia64-efi
++Check if FILE is IA64 EFI file
++
++.TP
++--is-arm64-efi
++Check if FILE is ARM64 EFI file
++
++.TP
++--is-arm-efi
++Check if FILE is ARM EFI file
++
++.TP
++--is-hibernated-hiberfil
++Check if FILE is hiberfil.sys in hibernated state
++
++.TP
++--is-x86_64-xnu
++Check if FILE is x86_64 XNU (Mac OS X kernel)
++
++.TP
++--is-i386-xnu
++Check if FILE is i386 XNU (Mac OS X kernel)
++
++.TP
++--is-xnu-hibr
++Check if FILE is XNU (Mac OS X kernel) hibernated image
++
++.TP
++--is-x86-bios-bootsector
++Check if FILE is BIOS bootsector
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-fstest.1 b/util/grub-fstest.1
+new file mode 100644
+index 00000000000..792fa78634c
+--- /dev/null
++++ b/util/grub-fstest.1
+@@ -0,0 +1,99 @@
++.TH GRUB-FSTEST 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-fstest\fR — Debug tool for GRUB's filesystem driver.
++
++.SH SYNOPSIS
++\fBgrub-fstest\fR [-c | --diskcount=\fINUM\fR] [-C | --crypto]
++.RS 13
++[-d | --debug=\fISTRING\fR] [-K | --zfs-key=\fIFILE\fR|\fIprompt\fR]
++.RE
++.RS 13
++[-n | --length=\fINUM\fR] [-r | --root=\fIDEVICE_NAME\fR]
++.RE
++.RS 13
++[-s | --skip=\fINUM\fR] [-u | --uncompress] [-v | --verbose]
++.RE
++.RS 13
++\fIIMAGE_PATH\fR <blocklist \fIFILE\fR | cat \fIFILE\fR |
++.RE
++.RS 13
++cmp \fIFILE\fR \fILOCAL\fR | cp \fIFILE\fR \fILOCAL\fR | crc \fIFILE\fR |
++.RE
++.RS 13
++hex \fIFILE\fR | ls \fIPATH\fR | xnu_uuid \fIDEVICE\fR>
++
++.SH DESCRIPTION
++\fBgrub-fstest\fR is a tool for testing GRUB's filesystem drivers.  You should not normally need to run this program.
++
++.SH OPTIONS
++.TP
++\fB--diskcount\fR=\fINUM\fR
++Specify the number of input files.
++
++.TP
++\fB--crypto\fR
++Mount cryptographic devices.
++
++.TP
++\fB--debug\fR=\fISTRING\fR
++Set debug environment variable.
++
++.TP
++\fB--zfs-key\fR=\fIFILE\fR|\fIprompt\fR
++Load ZFS cryptographic key.
++
++.TP
++\fB--length\fR=\fINUM\fR
++Handle NUM bytes in output file.
++
++.TP
++\fB--root\fR=\fIDEVICE_NAME\fR
++Set root device.
++
++.TP
++\fB--skip\fR=\fINUM\fR
++Skip NUM bytes from output file.
++
++.TP
++\fB--uncompress\fR
++Uncompress data.
++
++.TP
++\fB--verbose\fR
++Print verbose messages.
++
++.SH COMMANDS
++.TP
++\fBblocklist\fR \fIFILE\fR
++Display block list of \fIFILE\fR.
++
++.TP
++\fBcat\fR \fIFILE\fR
++Display \fIFILE\fR on standard output.
++
++.TP
++\fBcmp\fR \fIFILE\fR \fILOCAL\fR
++Compare \fIFILE\fR with local file \fILOCAL\fR.
++
++.TP
++\fBcp\fR \fIFILE\fR \fILOCAL\fR
++Copy \fIFILE\fR to local file \fILOCAL\fR.
++
++.TP
++\fBcrc\fR \fIFILE\fR
++Display the CRC-32 checksum of \fIFILE\fR.
++
++.TP
++\fBhex\fR \fIFILE\fR
++Display contents of \fIFILE\fR in hexidecimal.
++
++.TP
++\fBls\fR \fIPATH\fR
++List files at \fIPATH\fR.
++
++.TP
++\fBxnu_uuid\fR \fIDEVICE\fR
++Display the XNU UUID of \fIDEVICE\fR.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-glue-efi.1 b/util/grub-glue-efi.1
+new file mode 100644
+index 00000000000..72bd555d577
+--- /dev/null
++++ b/util/grub-glue-efi.1
+@@ -0,0 +1,31 @@
++.TH GRUB-GLUE-EFI 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-glue-efi\fR \(em Create an Apple fat EFI binary.
++
++.SH SYNOPSIS
++\fBgrub-glue-efi\fR <-3 | --input32=\fIFILE\fR> <-6 | --input64=\fIFILE\fR>
++.RS 15
++<-o | --output=\fIFILE\fR> [-v | --verbose]
++
++.SH DESCRIPTION
++\fBgrub-glue-efi\fR creates an Apple fat EFI binary from two EFI binaries.
++
++.SH OPTIONS
++.TP
++\fB--input32\fR=\fIFILE\fR
++Read 32-bit binary from \fIFILE\fR.
++
++.TP
++\fB--input64\fR=\fIFILE\fR
++Read 64-bit binary from \fIFILE\fR.
++
++.TP
++\fB--output\fR=\fIFILE\fR
++Write resulting fat binary to \fIFILE\fR.
++
++.TP
++\fB--verbose\fR
++Print verbose messages.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-install.8 b/util/grub-install.8
+new file mode 100644
+index 00000000000..76272a39d2e
+--- /dev/null
++++ b/util/grub-install.8
+@@ -0,0 +1,129 @@
++.TH GRUB-INSTALL 1 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-install\fR \(em Install GRUB on a device.
++
++.SH SYNOPSIS
++\fBgrub-install\fR [--modules=\fIMODULES\fR] [--install-modules=\fIMODULES\fR]
++.RS 14
++[--themes=\fITHEMES\fR] [--fonts=\fIFONTS\fR] [--locales=\fILOCALES\fR]
++.RE
++.RS 14
++[--compress[=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR]] [-d | --directory=\fIDIR\fR]
++.RE
++.RS 14
++[--grub-mkimage=\fIFILE\fR] [--boot-directory=\fIDIR\fR]
++.RE
++.RS 14
++[--target=\fITARGET\fR] [--grub-setup=\fIFILE\fR]
++.RE
++.RS 14
++[--grub-mkrelpath=\fIFILE\fR] [--grub-probe=\fIFILE\fR]
++.RE
++.RS 14
++[--allow-floppy] [--recheck] [--force] [--force-file-id]
++.RE
++.RS 14
++[--disk-module=\fIMODULE\fR] [--no-nvram] [--removable]
++.RE
++.RS 14
++[--bootloader-id=\fIID\fR] [--efi-directory=\fIDIR\fR] \fIINSTALL_DEVICE\fR
++
++.SH DESCRIPTION
++\fBgrub-install\fR installs GRUB onto a device.  This includes copying GRUB images into the target directory (generally \fI/boot/grub\fR), and on some platforms may also include installing GRUB onto a boot sector.
++
++.SH OPTIONS
++.TP
++\fB--modules\fR=\fIMODULES\fR\!
++Pre-load modules specified by \fIMODULES\fR.
++
++.TP
++\fB--install-modules\fR=\fIMODULES\fR
++Install only \fIMODULES\fR and their dependencies.  The default is to install all available modules.
++
++.TP
++\fB--themes\fR=\fITHEMES\fR
++Install \fITHEMES\fR.  The default is to install the \fIstarfield\fR theme, if available.
++
++.TP
++\fB--fonts\fR=\fIFONTS\fR
++Install \fIFONTS\fR.  The default is to install the \fIunicode\fR font.
++
++.TP
++\fB--locales\fR=\fILOCALES\fR
++Install only locales listed in \fILOCALES\fR.  The default is to install all available locales.
++
++.TP
++\fB--compress\fR=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR
++Compress GRUB files using the specified compression algorithm.
++
++.TP
++\fB--directory\fR=\fIDIR\fR
++Use images and modules in \fIDIR\fR.
++
++.TP
++\fB--grub-mkimage\fR=\fIFILE\fR
++Use \fIFILE\fR as \fBgrub-mkimage\fR.  The default is \fI/usr/bin/grub-mkimage\fR.
++
++.TP
++\fB--boot-directory\fR=\fIDIR\fR
++Use \fIDIR\fR as the boot directory.  The default is \fI/boot\fR.  GRUB will put its files in a subdirectory of this directory named \fIgrub\fR.
++
++.TP
++\fB--target\fR=\fITARGET\fR
++Install GRUB for \fITARGET\fR platform.  The default is the platform \fBgrub-install\fR is running on.
++
++.TP
++\fB--grub-setup\fR=\fIFILE\fR
++Use \fIFILE\fR as \fBgrub-setup\fR.  The default is \fI/usr/bin/grub-setup\fR.
++
++.TP
++\fB--grub-mkrelpath\fR=\fIFILE\fR
++Use \fIFILE\fR as \fBgrub-mkrelpath\fR.  The default is \fI/usr/bin/grub-mkrelpath\fR.
++
++.TP
++\fB--grub-probe\fR=\fIFILE\fR
++Use \fIFILE\fR as \fBgrub-probe\fR.  The default is \fI/usr/bin/grub-mkrelpath\fR.
++
++.TP
++\fB--allow-floppy
++Make the device also bootable as a floppy.  This option is the default for /dev/fdX devices. Some BIOSes will not boot images created with this option.
++
++.TP
++\fB--recheck
++Delete any existing device map and create a new one if necessary.
++
++.TP
++\fB--force
++Install even if problems are detected.
++
++.TP
++\fB--force-file-id
++Use identifier file even if UUID is available.
++
++.TP
++\fB--disk-module\fR=\fIMODULE\fR
++Use \fIMODULE\fR for disk access.  This allows you to manually specify either \fIbiosdisk\fR or \fInative\fR disk access.  This option is only available on the BIOS target platform.
++
++.TP
++\fB--no-nvram
++Do not update the \fIboot-device\fR NVRAM variable.  This option is only available on IEEE1275 target platforms.
++
++.TP
++\fB--removable
++Treat the target device as if it is removeable.  This option is only available on the EFI target platform.
++
++.TP
++\fB--bootloader-id\fR=\fIID\fR
++Use \fIID\fR as the bootloader ID.  This opption is only available on the EFI target platform.
++
++.TP
++\fB--efi-directory\fR=\fIDIR\fR
++Use \fIDIR\fR as the EFI System Partition root.  This opption is only available on the EFI ta
++rget platform.
++
++.TP
++\fIINSTALL_DEVICE\fR
++Install GRUB to the block device \fIINSTALL_DEVICE\fR.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-kbdcomp.1 b/util/grub-kbdcomp.1
+new file mode 100644
+index 00000000000..0bb969a5b43
+--- /dev/null
++++ b/util/grub-kbdcomp.1
+@@ -0,0 +1,19 @@
++.TH GRUB-KBDCOMP 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-kbdcomp\fR \(em Generate a GRUB keyboard layout file.
++
++.SH SYNOPSIS
++\fBgrub-kbdcomp\fR <-o | --output=\fIFILE\fR> \fICKBMAP_ARGUMENTS\fR
++
++.SH DESCRIPTION
++\fBgrub-kbdcomp\fR processes an X keyboard layout description in
++\fBkeymaps\fR(5) format into a format that can be used by GRUB's \fBkeymap\fR
++command.
++
++.SH OPTIONS
++.TP
++\fB--output\fR=\fIFILE\fR
++Write output to \fIFILE\fR.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-macbless.1 b/util/grub-macbless.1
+new file mode 100644
+index 00000000000..41a96186f70
+--- /dev/null
++++ b/util/grub-macbless.1
+@@ -0,0 +1,22 @@
++.TH GRUB-MACBLESS 1 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-macbless\fR \(em Mac-style bless on HFS or HFS+
++
++.SH SYNOPSIS
++\fBgrub-macbless\fR [-v | --verbose] [-p | --ppc] \fIFILE\fR | [-x | --x86] \fIFILE\fR
++
++.SH OPTIONS
++.TP
++--x86
++Bless for x86 based Macs.
++
++.TP
++--ppc
++Bless for PPC based Macs.
++
++.TP
++--verbose
++Print verbose messages.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-menulst2cfg.1 b/util/grub-menulst2cfg.1
+new file mode 100644
+index 00000000000..91e2ef87113
+--- /dev/null
++++ b/util/grub-menulst2cfg.1
+@@ -0,0 +1,12 @@
++.TH GRUB-MENULST2CFG 1 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-menulst2cfg\fR \(em Convert a configuration file from GRUB 0.xx to GRUB 2.xx format.
++
++.SH SYNOPSIS
++\fBgrub-menulst2cfg\fR [\fIINFILE\fR [\fIOUTFILE\fR]]
++
++.SH DESCRIPTION
++\fBgrub-menulst2cfg\fR converts a configuration file from GRUB 0.xx to the current format.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-mkconfig.8 b/util/grub-mkconfig.8
+new file mode 100644
+index 00000000000..a2d1f577b9b
+--- /dev/null
++++ b/util/grub-mkconfig.8
+@@ -0,0 +1,17 @@
++.TH GRUB-MKCONFIG 1 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-mkconfig\fR \(em Generate a GRUB configuration file.
++
++.SH SYNOPSIS
++\fBgrub-mkconfig\fR [-o | --output=\fIFILE\fR]
++
++.SH DESCRIPTION
++\fBgrub-mkconfig\fR generates a configuration file for GRUB.
++
++.SH OPTIONS
++.TP
++\fB--output\fR=\fIFILE\fR
++Write generated output to \fIFILE\fR.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-mkfont.1 b/util/grub-mkfont.1
+new file mode 100644
+index 00000000000..3494857987d
+--- /dev/null
++++ b/util/grub-mkfont.1
+@@ -0,0 +1,87 @@
++.TH GRUB-MKFONT 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-mkfont\fR \(em Convert common font file formats into the PF2 format.
++
++.SH SYNOPSIS
++\fBgrub-mkfont\fR [--ascii-bitmaps] [-a | --force-autohint]
++.RS 13
++[-b | --bold] [-c | --asce=\fINUM\fR] [-d | --desc=\fINUM\fR]
++.RE
++.RS 13
++[-i | --index=\fINUM\fR] [-n | --name=\fINAME\fR] [--no-bitmap]
++.RE
++.RS 13
++[--no-hinting] <-o | --output=\fIFILE\fR>
++.RE
++.RS 13
++[-r | --range=\fIFROM-TO\fR[\fI,FROM-TO\fR]] [-s | --size=\fISIZE\fR]
++.RE
++.RS 13
++[-v | --verbose] [--width-spec] \fIFONT_FILES\fR
++
++.SH DESCRIPTION
++\fBgrub-mkfont\fR converts font files from common formats into the PF2 format used by GRUB.
++
++.SH OPTIONS
++.TP
++--ascii-bitmaps
++Save only bitmaps for ASCII characters.
++
++.TP
++--force-autohint
++Force generation of automatic hinting.
++
++.TP
++--bold
++Convert font to bold.
++
++.TP
++--asce=\fINUM\fR
++Set font ascent to \fINUM\fR.
++
++.TP
++--desc=\fINUM\fR
++Set font descent to \fINUM\fR.
++
++.TP
++--index=\fINUM\fR
++Select face index \fINUM\fR.
++
++.TP
++--name=\fINAME\fR
++Set font family to \fINAME\fR.
++
++.TP
++--no-bitmap
++Ignore bitmap strikes when loading.
++
++.TP
++--no-hinting
++Disable hinting.
++
++.TP
++--output=\fIFILE\fR
++Save ouptut to \fIFILE\fR.  This argument is required.
++
++.TP
++--range=\fIFROM-TO\fR\fI,FROM-TO\fR
++Set the font ranges to each pair of \fIFROM\fR,\fITO\fR.
++
++.TP
++--size=\fISIZE\fR
++Set font size to \fISIZE\fR.
++
++.TP
++--verbose
++Print verbose messages.
++
++.TP
++--width-spec
++Create a width summary file.
++
++.TP
++\fIFONT_FILES\fR
++The input files to be converted.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-mkimage.1 b/util/grub-mkimage.1
+new file mode 100644
+index 00000000000..4dea4f54597
+--- /dev/null
++++ b/util/grub-mkimage.1
+@@ -0,0 +1,95 @@
++.TH GRUB-MKIMAGE 1 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-mkimage\fR \(em Make a bootable GRUB image.
++
++.SH SYNOPSIS
++\fBgrub-mkimage\fR [-c | --config=\fRFILE\fI] [-C | --compression=(\fIxz\fR,\fInone\fR,\fIauto\fR)]
++.RS 14
++[-d | --directory=\fRDIR\fR] [-k | --pubkey=\fIFILE\fR]
++.RE
++.RS 14
++[-m | --memdisk=\fIFILE\fR] [-n | --note] [-o | --output=\fIFILE\fR]
++.RE
++.RS 14
++[-O | --format=\fIFORMAT\fR] [-p | --prefix=\fIDIR\fR]
++.RE
++.RS 14
++[-v | --verbose] \fIMODULES\fR
++
++.SH DESCRIPTION
++\fBgrub-mkimage\fI builds a bootable image of GRUB.
++
++.SH OPTIONS
++.TP
++--config=\fIFILE\fR
++Embed \fIFILE\fR as the image's initial configuration file.
++
++.TP
++--compression=(\fIxz\fR,\fInone\fR,\fIauto\fR)
++Use one of \fIxz\fR, \fInone\fR, or \fIauto\fR as the compression method for the core image.
++
++.TP
++--directory=\fIDIR\fR
++Use images and modules from \fIDIR\fR.  The default value is \fB/usr/lib/grub/<platform>\fR.
++
++.TP
++--pubkey=\fIFILE\fR
++Embed the public key \fIFILE\fR for signature checking.
++
++.TP
++--memdisk=\fIFILE\fR
++Embed the memdisk image \fIFILE\fR.  If no \fB-p\fR option is also specified, this implies \fI-p (memdisk)/boot/grub\fR.
++
++.TP
++--note
++Add a CHRP \fINOTE\fR section.  This option is only valid on IEEE1275 platforms.
++
++.TP
++--output=\fIFILE\fR
++Write the generated file to \fIFILE\fR.  The default is to write to standard output.
++
++.TP
++--format=\fIFORMAT\fR
++Generate an image in the specified \fIFORMAT\fR.  Valid values are:
++.RS
++.RS 4
++.P
++i386-coreboot,
++i386-multiboot,
++i386-pc,
++i386-pc-pxe,
++i386-efi,
++i386-ieee1275,
++i386-qemu,
++x86_64-efi,
++mipsel-yeeloong-flash,
++mipsel-fuloong2f-flash,
++mipself-loongson-elf,
++powerpc-ieee1275,
++sparc64-ieee1275-raw,
++sparc64-ieee1275-cdcore,
++sparc64-ieee1275-aout,
++ia64-efi,
++mips-arc,
++mipsel-arc,
++mipsel-qemu_mips-elf,
++mips-qemu_mips-flash,
++mipsel-qemu_mips-flash,
++mips-qemu_mips-elf
++.RE
++.RE
++
++.TP
++--prefix=\fIDIR\fR
++Set prefix directory.  The default value is \fI/boot/grub\fR.
++
++.TP
++--verbose
++Print verbose messages.
++
++.TP
++\fIMODULES\fR
++Include \fIMODULES\fR.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-mklayout.1 b/util/grub-mklayout.1
+new file mode 100644
+index 00000000000..d1bbc2ec515
+--- /dev/null
++++ b/util/grub-mklayout.1
+@@ -0,0 +1,27 @@
++.TH GRUB-MKLAYOUT 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-mklayout\fR \(em Generate a GRUB keyboard layout file.
++
++.SH SYNOPSIS
++\fBgrub-mklayout\fR [-i | --input=\fIFILE\fR] [-o | --output=\fIFILE\fR]
++.RS 15
++[-v | --verbose]
++
++.SH DESCRIPTION
++\fBgrub-mklayout\fR generates a GRUB keyboard layout description which corresponds with the Linux console layout description given as input.
++
++.SH OPTIONS
++.TP
++--input=\fIFILE\fR
++Use \fIFILE\fR as the input.  The default value is the standard input device.
++
++.TP
++--output=\fIFILE\fR
++Use \fIFILE\fR as the output.  The default value is the standard output device.
++
++.TP
++--verbose
++Print verbose messages.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-mknetdir.1 b/util/grub-mknetdir.1
+new file mode 100644
+index 00000000000..fa7e8d4ef0d
+--- /dev/null
++++ b/util/grub-mknetdir.1
+@@ -0,0 +1,12 @@
++.TH GRUB-MKNETDIR 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-mknetdir\fR \(em Prepare a GRUB netboot directory.
++
++.SH SYNOPSIS
++\fBgrub-mknetdir\fR
++
++.SH DESCRIPTION
++\fBgrub-mknetdir\fR prepares a directory for GRUB to be netbooted from.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-mkpasswd-pbkdf2.1 b/util/grub-mkpasswd-pbkdf2.1
+new file mode 100644
+index 00000000000..73c437c15d8
+--- /dev/null
++++ b/util/grub-mkpasswd-pbkdf2.1
+@@ -0,0 +1,27 @@
++.TH GRUB-MKPASSWD-PBKDF2 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-mkpasswd-pbkdf2\fR \(em Generate a PBKDF2 password hash.
++
++.SH SYNOPSIS
++\fBgrub-mkpasswd-pbkdf2\fR [-c | --iteration-count=\fINUM\fR] [-l | --buflen=\fINUM\fR]
++.RS 22
++[-s | --salt=\fINUM\fR]
++
++.SH DESCRIPTION
++\fBgrub-mkpasswd-pbkdf2\fR generates a PBKDF2 password string suitable for use in a GRUB configuration file.
++
++.SH OPTIONS
++.TP
++--iteration-count=\fINUM\fR
++Number of PBKDF2 iterations.
++
++.TP
++--buflen=\fINUM\fR
++Length of generated hash.
++
++.TP
++--salt=\fINUM\fR
++Length of salt to use.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-mkrelpath.1 b/util/grub-mkrelpath.1
+new file mode 100644
+index 00000000000..85f1113621d
+--- /dev/null
++++ b/util/grub-mkrelpath.1
+@@ -0,0 +1,12 @@
++.TH GRUB-MKRELPATH 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-mkrelpath\fR \(em Generate a relative GRUB path given an OS path.
++
++.SH SYNOPSIS
++\fBgrub-mkrelpath\fR \fIFILE\fR
++
++.SH DESCRIPTION
++\fBgrub-mkrelpath\fR takes an OS filesystem path for \fIFILE\fR and returns a relative path suitable for use in a GRUB configuration file.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-mkrescue.1 b/util/grub-mkrescue.1
+new file mode 100644
+index 00000000000..4ed9fc723fd
+--- /dev/null
++++ b/util/grub-mkrescue.1
+@@ -0,0 +1,123 @@
++.TH GRUB-MKRESCUE 3 "Wed Feb 26 2014"
++.SH NAME
++grub-mkrescue \(em Generate a GRUB rescue image using GNU Xorriso.
++
++.SH SYNOPSIS
++\fBgrub-mkrescue\fR [-o | --output=\fIFILE\fR] [--modules=\fIMODULES\fR]
++.RS 15
++[--install-modules=\fIMODULES\fR] [--themes=\fITHEMES\fR]
++.RE
++.RS 15
++[--fonts=\fIFONTS\fR] [--locales=\fILOCALES\fR]
++.RE
++.RS 15
++[--compress[=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR]] [-d | --directory=\fIDIR\fR]
++.RE
++.RS 15
++[--grub-mkimage=\fIFILE\fR] [--rom-directory=\fIDIR\fR]
++.RE
++.RS 15
++[--xorriso=\fIFILE\fR] [--grub-glue-efi=\fIFILE\fR]
++.RE
++.RS 15
++[--grub-render-label=\fIFILE\fR] [--label-font=\fIFILE\fR]
++.RE
++.RS 15
++[--label-color=\fICOLOR\fR] [--label-bgcolor=\fIFILE\fR]
++.RE
++.RS 15
++[--product-name=\fISTRING\fR] [--product-version=\fISTRING\fR]
++.RE
++.RS 15
++[--sparc-boot] [--arcs-boot]
++
++.SH DESCRIPTION
++\fBgrub-mkrescue\fR can be used to generate a rescue image with the GRUB bootloader.
++
++.SH OPTIONS
++.TP
++\fB--output\fR=\fIFILE\fR
++Write the generated file to \fIFILE\fR.  The default is to write to standard output.
++
++.TP
++\fB--modules\fR=\fIMODULES\fR
++Pre-load modules specified by \fIMODULES\fR.
++
++.TP
++\fB--install-modules\fR=\fIMODULES\fR
++Install only \fIMODULES\fR and their dependencies.  The default is to install all available modules.
++
++.TP
++\fB--themes\fR=\fITHEMES\fR
++Install \fITHEMES\fR.  The default is to install the \fIstarfield\fR theme, if available.
++
++.TP
++\fB--fonts\fR=\fIFONTS\fR
++Install \fIFONTS\fR.  The default is to install the \fIunicode\fR font.
++
++.TP
++\fB--locales\fR=\fILOCALES\fR
++Install only locales listed in \fILOCALES\fR.  The default is to install all available locales.
++
++.TP
++\fB--compress\fR[=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR]
++Compress GRUB files using the specified compression algorithm.
++
++.TP
++\fB--directory\fR=\fIDIR\fR
++Use images and modules in \fIDIR\fR.
++
++.TP
++\fB--grub-mkimage\fR=\fIFILE\fR
++Use \fIFILE\fR as \fBgrub-mkimage\fR(1).  The default is \fI/usr/bin/grub-mkimage\fR.
++
++.TP
++\fB--rom-directory\fR=\fIDIR\fR
++Save ROM images in \fIDIR\fR.
++
++.TP
++\fB--xorriso\fR=\fIFILE\fR
++Use \fIFILE\fR as \fBxorriso\fI.
++
++.TP
++\fB--grub-glue-efi\fR=\fIFILE\fR
++Use \fIFILE\fR as \fBgrub-glue-efi\fR(3).
++
++.TP
++\fB--grub-render-label\fR=\fIFILE\fR
++Use \fIFILE\fR as \fBgrub-render-label\fR(3).
++
++.TP
++\fB--label-font\fR=\fIFILE\fR
++Use \fIFILE\fR as the font file for generated labels.
++
++.TP
++\fB--label-color\fR=\fICOLOR\fR
++Use \fICOLOR\fI as the color for generated labels.
++
++.TP
++\fB--label-bgcolor\fR=\fICOLOR\fR
++Use \fICOLOR\fR as the background color for generated labels.
++
++.TP
++\fB--product-name\fR=\fISTRING\fR
++Use \fISTRING\fR as the product name in generated labels.
++
++.TP
++\fB--product-version\fR=\fISTRING\fR
++Use \fISTRING\fR as the product version in generated labels.
++
++.TP
++\fB--sparc-boot\fR
++Enable booting the SPARC platform.  This disables HFS+, APM, ARCS, and "boot as disk image" on the \fIi386-pc\fR target platform.
++
++.TP
++\fB--arcs-boot\fR
++Enable ARCS booting.  This is typically for big-endian MIPS machines, and disables HFS+, APM, sparc64, and "boot as disk image" on the \fIi386-pc\fR target platform.
++
++.TP
++\fB--\fR
++All options after a \fB--\fR will be passed directly to xorriso's command line when generating the image.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-mkstandalone.1 b/util/grub-mkstandalone.1
+new file mode 100644
+index 00000000000..ba2d2bdf279
+--- /dev/null
++++ b/util/grub-mkstandalone.1
+@@ -0,0 +1,100 @@
++.TH GRUB-MKSTANDALONE 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-mkstandalone\fR \(em Generate a standalone image in the selected format.
++
++.SH SYNOPSIS
++\fBgrub-mkstandalone\fR [-o | --output=\fIFILE\fR] [-O | --format=\fIFORMAT\fR]
++.RS 19
++[-C | --compression=(\fIxz\fR|\fInone\fR|\fIauto\fR)]
++.RE
++.RS 19
++[--modules=\fIMODULES\fR] [--install-modules=\fIMODULES\fR]
++.RE
++.RS 19
++[--themes=\fITHEMES\fR] [--fonts=\fIFONTS\fR]
++.RE
++.RS 19
++[--locales=\fILOCALES\fR] [--compress[=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR]]
++.RE
++.RS 19
++[-d | --directory=\fIDIR\fR] [--grub-mkimage=\fIFILE\fR]
++.RE
++.RS 19
++\fISOURCE...\fR
++
++.SH DESCRIPTION
++
++.SH OPTIONS
++.TP
++--output=\fIFILE\fR
++Write the generated file to \fIFILE\fR.  The default is to write to standard output.
++
++.TP
++--format=\fIFORMAT\fR
++Generate an image in the specified \fIFORMAT\fR.  Valid values are:
++.RS
++.RS 4
++.P
++i386-coreboot,
++i386-multiboot,
++i386-pc,
++i386-pc-pxe,
++i386-efi,
++i386-ieee1275,
++i386-qemu,
++x86_64-efi,
++mipsel-yeeloong-flash,
++mipsel-fuloong2f-flash,
++mipself-loongson-elf,
++powerpc-ieee1275,
++sparc64-ieee1275-raw,
++sparc64-ieee1275-cdcore,
++sparc64-ieee1275-aout,
++ia64-efi,
++mips-arc,
++mipsel-arc,
++mipsel-qemu_mips-elf,
++mips-qemu_mips-flash,
++mipsel-qemu_mips-flash,
++mips-qemu_mips-elf
++.RE
++.RE
++
++.TP
++--compression=(\fIxz\fR|\fInone\fR|\fIauto\fR)
++Use one of \fIxz\fR, \fInone\fR, or \fIauto\fR as the compression method for the core image.
++
++.TP
++--modules=\fIMODULES\fR
++Pre-load modules specified by \fIMODULES\fR.
++
++.TP
++--install-modules=\fIMODULES\fR
++Install only \fIMODULES\fR and their dependencies.  The default is to install all available modules.
++
++.TP
++--themes=\fITHEMES\fR
++Install \fITHEMES\fR.  The default is to install the \fIstarfield\fR theme, if available.
++
++.TP
++--fonts=\fIFONTS\fR
++Install \fIFONTS\fR.  The default is to install the \fIunicode\fR font.
++
++.TP
++--locales=\fILOCALES\fR
++Install only locales listed in \fILOCALES\fR.  The default is to install all available locales.
++
++.TP
++--compress[=\fIno\fR,\fIxz\fR,\fIgz\fR,\fIlzo\fR]
++Compress GRUB files using the specified compression algorithm.
++
++.TP
++--directory=\fIDIR\fR
++Use images and modules in \fIDIR\fR.
++
++.TP
++--grub-mkimage=\fIFILE\fR
++Use \fIFILE\fR as \fBgrub-mkimage\fR.  The default is \fI/usr/bin/grub-mkimage\fR.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-ofpathname.8 b/util/grub-ofpathname.8
+new file mode 100644
+index 00000000000..bf3743aeba1
+--- /dev/null
++++ b/util/grub-ofpathname.8
+@@ -0,0 +1,12 @@
++.TH GRUB-OFPATHNAME 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-ofpathname\fR \(em Generate an IEEE-1275 device path for a specified device.
++
++.SH SYNOPSIS
++\fBgrub-ofpathname\fR \fIDEVICE\fR
++
++.SH DESCRIPTION
++\fBgrub-ofpathname\fR generates an IEEE-1275 device path for the specified \fIDEVICE\fR.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-probe.8 b/util/grub-probe.8
+new file mode 100644
+index 00000000000..04e26c832bb
+--- /dev/null
++++ b/util/grub-probe.8
+@@ -0,0 +1,80 @@
++.TH GRUB-PROBE 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-probe\fR \(em Probe device information for a given path.
++
++.SH SYNOPSIS
++\fBgrub-probe\fR \[-d | --device] [-m | --device-map=\fIFILE\fR]
++.RS 12
++[-t | --target=(fs|fs_uuid|fs_label|drive|device|partmap|
++.RE
++.RS 28
++abstraction|cryptodisk_uuid|
++.RE
++.RS 28
++msdos_parttype)]
++.RE
++.RS 12
++[-v | --verbose] (PATH|DEVICE)
++
++.SH DESCRIPTION
++\fBgrub-probe\fR probes a path or device for filesystem and related information.
++
++.SH OPTIONS
++.TP
++--device
++Final option represents a \fIDEVICE\fR, rather than a filesystem \fIPATH\fR.
++.TP
++--device-map=\fIFILE\fR
++Use \fIFILE\fR as the device map.  The default value is \fI/boot/grub/device.map\fR.
++
++.TP
++--target=(fs|fs_uuid|fs_label|drive|device|partmap|msdos_parttype)
++Select among various output definitions.  The default is \fIfs\fR.
++.RS
++.TP
++\fIfs\fR
++filesystem module
++
++.TP
++\fIfs_uuid\fR
++filesystem UUID
++
++.TP
++\fIfs_label\fR
++filesystem label
++
++.TP
++\fIdrive\fR
++GRUB drive name
++
++.TP
++\fIdevice\fR
++System device
++
++.TP
++\fIpartmap\fR
++partition map module
++
++.TP
++\fIabstraction\fR
++abstraction module
++
++.TP
++\fIcryptodisk_uuid\fR
++cryptographic container
++
++.TP
++\fImsdos_partmap\fR
++MS-DOS partition map
++.RE
++
++.TP
++--verbose
++Print verbose output.
++
++.TP
++(\fIPATH\fR|\fIDEVICE\fR)
++If --device is passed, a block \fIDEVICE\fR.  Otherwise, the \fIPATH\fR of a file on the filesystem.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-reboot.8 b/util/grub-reboot.8
+new file mode 100644
+index 00000000000..faa5e4eece2
+--- /dev/null
++++ b/util/grub-reboot.8
+@@ -0,0 +1,21 @@
++.TH GRUB-REBOOT 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-reboot\fR \(em Set the default boot menu entry for the next boot only.
++
++.SH SYNOPSIS
++\fBgrub-reboot\fR [--boot-directory=\fIDIR\fR] \fIMENU_ENTRY\fR
++
++.SH DESCRIPTION
++\fBgrub-reboot\fR sets the default boot menu entry for the next boot, but not further boots after that.  This command only works for GRUB configuration files created with \fIGRUB_DEFAULT=saved\fR in \fI/etc/default/grub\fR.
++
++.SH OPTIONS
++.TP
++--boot-directory=\fIDIR\fR
++Find GRUB images under \fIDIR/grub\fR.  The default value is \fI/boot\fR, resulting in grub images being search for at \fI/boot/grub\fR.
++
++.TP
++\fIMENU_ENTRY\fR
++A number, a menu item title or a menu item identifier.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-render-label.1 b/util/grub-render-label.1
+new file mode 100644
+index 00000000000..4d51c8abf01
+--- /dev/null
++++ b/util/grub-render-label.1
+@@ -0,0 +1,51 @@
++.TH GRUB-RENDER-LABEL 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-render-label\fR \(em Render an Apple disk label.
++
++.SH SYNOPSIS
++\fBgrub-render-label\fR [-b | --bgcolor=\fICOLOR\fR] [-c | --color=\fICOLOR\fR]
++.RS 19
++[-f | --font=\fIFILE\fR] [-i | --input=\fIFILE\fR]
++.RE
++.RS 19
++[-o | --output=\fIFILE\fR] [-t | --text=\fISTRING\fR]
++.RE
++.RS 19
++[-v | --verbose]
++
++.SH DESCRIPTION
++\fBgrub-render-label\fR renders an Apple disk label (.disk_label) file.
++
++
++.SH OPTIONS
++.TP
++\fB--color\fR=\fICOLOR\fR
++Use \fICOLOR\fI as the color for generated labels.
++
++.TP
++\fB--bgcolor\fR=\fICOLOR\fR
++Use \fICOLOR\fR as the background color for generated labels.
++
++.TP
++\fB--font\fR=\fIFILE\fR
++Use \fIFILE\fR as the font file for generated labels.
++
++.TP
++--input=\fIFILE\fR
++Read input text from \fIFILE\fR.
++
++.TP
++--output=\fIFILE\fR
++Render output to \fIFILE\fR.
++
++.TP
++--text=\fISTRING\fR
++Use \fISTRING\fR as input text.
++
++.TP
++--verbose
++Print verbose output.
++
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-script-check.1 b/util/grub-script-check.1
+new file mode 100644
+index 00000000000..0f1f625b05d
+--- /dev/null
++++ b/util/grub-script-check.1
+@@ -0,0 +1,21 @@
++.TH GRUB-SCRIPT-CHECK 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-script-check\fR \(em Check GRUB configuration file for syntax errors.
++
++.SH SYNOPSIS
++\fBgrub-script-check\fR [-v | --verbose] \fIPATH\fR
++
++.SH DESCRIPTION
++\fBgrub-script-check\fR verifies that a specified GRUB configuration file does not contain syntax errors.
++
++.SH OPTIONS
++.TP
++--verbose
++Print verbose output.
++
++.TP
++\fIPATH\fR
++Path of the file to use as input.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-set-default.8 b/util/grub-set-default.8
+new file mode 100644
+index 00000000000..a96265a1509
+--- /dev/null
++++ b/util/grub-set-default.8
+@@ -0,0 +1,21 @@
++.TH GRUB-SET-DEFAULT 1 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-set-default\fR \(em Set the default boot menu entry for GRUB.
++
++.SH SYNOPSIS
++\fBgrub-set-default\fR [--boot-directory=\fIDIR\fR] \fIMENU_ENTRY\fR
++
++.SH DESCRIPTION
++\fBgrub-set-default\fR sets the default boot menu entry for all subsequent boots.  This command only works for GRUB configuration files created with \fIGRUB_DEFAULT=saved\fR in \fI/etc/default/grub\fR.
++
++.SH OPTIONS
++.TP
++--boot-directory=\fIDIR\fR
++Find GRUB images under \fIDIR/grub\fR.  The default value is \fI/boot\fR, resulting in grub images being search for at \fI/boot/grub\fR.
++
++.TP
++\fIMENU_ENTRY\fR
++A number, a menu item title or a menu item identifier.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-sparc64-setup.8 b/util/grub-sparc64-setup.8
+new file mode 100644
+index 00000000000..37ea2dd5eaa
+--- /dev/null
++++ b/util/grub-sparc64-setup.8
+@@ -0,0 +1,12 @@
++.TH GRUB-SPARC64-SETUP 3 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-sparc64-setup\fR \(em Set up a device to boot a sparc64 GRUB image.
++
++.SH SYNOPSIS
++\fBgrub-sparc64-setup\fR [OPTIONS].
++
++.SH DESCRIPTION
++You should not normally run this program directly.  Use grub-install instead.
++
++.SH SEE ALSO
++.BR "info grub"
diff --git a/SOURCES/0049-use-fw_path-prefix-when-fallback-searching-for-grub-.patch b/SOURCES/0049-use-fw_path-prefix-when-fallback-searching-for-grub-.patch
new file mode 100644
index 0000000..0035e62
--- /dev/null
+++ b/SOURCES/0049-use-fw_path-prefix-when-fallback-searching-for-grub-.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Fedora Ninjas <grub2-owner@fedoraproject.org>
+Date: Wed, 19 Feb 2014 15:58:43 -0500
+Subject: [PATCH] use fw_path prefix when fallback searching for grub config
+
+When PXE booting via UEFI firmware, grub was searching for grub.cfg
+in the fw_path directory where the grub application was found. If
+that didn't exist, a fallback search would look for config file names
+based on MAC and IP address. However, the search would look in the
+prefix directory which may not be the same fw_path. This patch
+changes that behavior to use the fw_path directory for the fallback
+search. Only if fw_path is NULL will the prefix directory be searched.
+
+Signed-off-by: Mark Salter <msalter@redhat.com>
+---
+ grub-core/normal/main.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 0ce59fdc3f0..a3713efcd90 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -343,7 +343,7 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+       char *config;
+       const char *prefix, *fw_path;
+ 
+-      fw_path = grub_env_get ("fw_path");
++      prefix = fw_path = grub_env_get ("fw_path");
+       if (fw_path)
+ 	{
+ 	  config = grub_xasprintf ("%s/grub.cfg", fw_path);
+@@ -366,7 +366,8 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+ 	    }
+ 	}
+ 
+-      prefix = grub_env_get ("prefix");
++      if (! prefix)
++	      prefix = grub_env_get ("prefix");
+       if (prefix)
+         {
+           grub_size_t config_len;
diff --git a/SOURCES/0050-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch b/SOURCES/0050-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch
new file mode 100644
index 0000000..84b8d7a
--- /dev/null
+++ b/SOURCES/0050-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch
@@ -0,0 +1,111 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 6 Mar 2014 11:51:33 -0500
+Subject: [PATCH] Try mac/guid/etc before grub.cfg on tftp config files.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/normal/main.c | 80 ++++++++++++++++++++++++++-----------------------
+ 1 file changed, 43 insertions(+), 37 deletions(-)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index a3713efcd90..7d9c4f09b9b 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -341,53 +341,59 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+       /* Guess the config filename. It is necessary to make CONFIG static,
+ 	 so that it won't get broken by longjmp.  */
+       char *config;
+-      const char *prefix, *fw_path;
+-
+-      prefix = fw_path = grub_env_get ("fw_path");
+-      if (fw_path)
+-	{
+-	  config = grub_xasprintf ("%s/grub.cfg", fw_path);
+-	  if (config)
+-	    {
+-	      grub_file_t file;
+-
+-	      file = grub_file_open (config);
+-	      if (file)
+-		{
+-		  grub_file_close (file);
+-		  grub_enter_normal_mode (config);
+-		}
+-              else
+-                {
+-                  /*  Ignore all errors.  */
+-                  grub_errno = 0;
+-                }
+-	      grub_free (config);
+-	    }
+-	}
++      const char *prefix;
+ 
++      prefix = grub_env_get ("fw_path");
+       if (! prefix)
+ 	      prefix = grub_env_get ("prefix");
++
+       if (prefix)
+-        {
+-          grub_size_t config_len;
+-          config_len = grub_strlen (prefix) +
+-                      sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
+-          config = grub_malloc (config_len);
++	{
++	  if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0)
++	    {
++	      grub_size_t config_len;
++	      config_len = grub_strlen (prefix) +
++		sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
++	      config = grub_malloc (config_len);
+ 
+-          if (! config)
+-            goto quit;
++	      if (! config)
++		goto quit;
+ 
+-          grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
++	      grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
+ 
+-          if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0)
+-            grub_net_search_configfile (config);
++	      grub_net_search_configfile (config);
+ 
+-	  grub_enter_normal_mode (config);
+-	  grub_free (config);
++	      grub_enter_normal_mode (config);
++	      grub_free (config);
++	      config = NULL;
++	    }
++
++	  if (!config)
++	    {
++	      config = grub_xasprintf ("%s/grub.cfg", prefix);
++	      if (config)
++		{
++		  grub_file_t file;
++
++		  file = grub_file_open (config);
++		  if (file)
++		    {
++		      grub_file_close (file);
++		      grub_enter_normal_mode (config);
++		    }
++		  else
++		    {
++		      /*  Ignore all errors.  */
++		      grub_errno = 0;
++		    }
++		  grub_free (config);
++		}
++	    }
+ 	}
+       else
+-	grub_enter_normal_mode (0);
++	{
++	  grub_enter_normal_mode (0);
++	}
+     }
+   else
+     grub_enter_normal_mode (argv[0]);
diff --git a/SOURCES/0051-Fix-convert-function-to-support-NVMe-devices.patch b/SOURCES/0051-Fix-convert-function-to-support-NVMe-devices.patch
new file mode 100644
index 0000000..0fb6616
--- /dev/null
+++ b/SOURCES/0051-Fix-convert-function-to-support-NVMe-devices.patch
@@ -0,0 +1,56 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 18 Feb 2014 11:34:00 -0500
+Subject: [PATCH] Fix convert function to support NVMe devices
+
+This is adapted from the patch at
+https://bugzilla.redhat.com/show_bug.cgi?id=1019660 , which is against
+the now very old version of convert_system_partition_to_system_disk().
+
+As such, it certainly not the right thing for upstream, but should
+function for now.
+
+Resolves: rhbz#1019660
+
+Signed-off-by: Peter Jones <grub2-owner@fedoraproject.org>
+---
+ util/getroot.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/util/getroot.c b/util/getroot.c
+index 847406fbab0..fa3460d6cd8 100644
+--- a/util/getroot.c
++++ b/util/getroot.c
+@@ -153,6 +153,7 @@ convert_system_partition_to_system_disk (const char *os_dev, int *is_part)
+ {
+ #if GRUB_UTIL_FD_STAT_IS_FUNCTIONAL
+   struct stat st;
++  char *path = xmalloc(PATH_MAX);
+ 
+   if (stat (os_dev, &st) < 0)
+     {
+@@ -165,6 +166,24 @@ convert_system_partition_to_system_disk (const char *os_dev, int *is_part)
+ 
+   *is_part = 0;
+ 
++  if (realpath(os_dev, path))
++    {
++      if ((strncmp ("/dev/nvme", path, 9) == 0))
++	{
++	  char *p = path + 5;
++	  p = strchr(p, 'p');
++	  if (p)
++	    {
++	      *is_part = 1;
++	      *p = '\0';
++	    }
++	  return path;
++	}
++    }
++
++  grub_free (path);
++  *is_part = 0;
++
+   if (grub_util_device_is_mapped_stat (&st))
+     return grub_util_devmapper_part_to_disk (&st, is_part, os_dev);
+ 
diff --git a/SOURCES/0052-reopen-SNP-protocol-for-exclusive-use-by-grub.patch b/SOURCES/0052-reopen-SNP-protocol-for-exclusive-use-by-grub.patch
new file mode 100644
index 0000000..fb2875b
--- /dev/null
+++ b/SOURCES/0052-reopen-SNP-protocol-for-exclusive-use-by-grub.patch
@@ -0,0 +1,43 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Fedora Ninjas <grub2-owner@fedoraproject.org>
+Date: Sat, 15 Feb 2014 15:10:22 -0500
+Subject: [PATCH] reopen SNP protocol for exclusive use by grub
+
+---
+ grub-core/net/drivers/efi/efinet.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 5388f952ba9..ea0e0ca360e 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -330,6 +330,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ {
+   struct grub_net_card *card;
+   grub_efi_device_path_t *dp;
++  grub_efi_simple_network_t *net;
+ 
+   dp = grub_efi_get_device_path (hnd);
+   if (! dp)
+@@ -383,6 +384,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 				    &pxe_mode->dhcp_ack,
+ 				    sizeof (pxe_mode->dhcp_ack),
+ 				    1, device, path);
++    net = grub_efi_open_protocol (card->efi_handle, &net_io_guid,
++				  GRUB_EFI_OPEN_PROTOCOL_BY_EXCLUSIVE);
++    if (net) {
++      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
++	  && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
++	continue;
++
++      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
++	continue;
++
++      if (net->mode->state == GRUB_EFI_NETWORK_STARTED
++	  && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
++	continue;
++      card->efi_net = net;
++    }
+     return;
+   }
+ }
diff --git a/SOURCES/0053-Revert-reopen-SNP-protocol-for-exclusive-use-by-grub.patch b/SOURCES/0053-Revert-reopen-SNP-protocol-for-exclusive-use-by-grub.patch
new file mode 100644
index 0000000..4238b7d
--- /dev/null
+++ b/SOURCES/0053-Revert-reopen-SNP-protocol-for-exclusive-use-by-grub.patch
@@ -0,0 +1,51 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 4 Mar 2016 15:13:59 -0500
+Subject: [PATCH] Revert "reopen SNP protocol for exclusive use by grub"
+
+This reverts commit a3f2c756ce34c9666bddef35e3b3b85ccecdcffc , which is
+obsoleted by these:
+
+49426e9 efinet: open Simple Network Protocol exclusively
+f348aee efinet: enable hardware filters when opening interface
+c52ae40 efinet: skip virtual IPv4 and IPv6 devices when enumerating cards
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/drivers/efi/efinet.c | 16 ----------------
+ 1 file changed, 16 deletions(-)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index ea0e0ca360e..5388f952ba9 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -330,7 +330,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ {
+   struct grub_net_card *card;
+   grub_efi_device_path_t *dp;
+-  grub_efi_simple_network_t *net;
+ 
+   dp = grub_efi_get_device_path (hnd);
+   if (! dp)
+@@ -384,21 +383,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 				    &pxe_mode->dhcp_ack,
+ 				    sizeof (pxe_mode->dhcp_ack),
+ 				    1, device, path);
+-    net = grub_efi_open_protocol (card->efi_handle, &net_io_guid,
+-				  GRUB_EFI_OPEN_PROTOCOL_BY_EXCLUSIVE);
+-    if (net) {
+-      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
+-	  && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
+-	continue;
+-
+-      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
+-	continue;
+-
+-      if (net->mode->state == GRUB_EFI_NETWORK_STARTED
+-	  && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
+-	continue;
+-      card->efi_net = net;
+-    }
+     return;
+   }
+ }
diff --git a/SOURCES/0054-Add-grub_util_readlink.patch b/SOURCES/0054-Add-grub_util_readlink.patch
new file mode 100644
index 0000000..6ea7df1
--- /dev/null
+++ b/SOURCES/0054-Add-grub_util_readlink.patch
@@ -0,0 +1,3731 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 3 Sep 2014 10:01:03 -0400
+Subject: [PATCH] Add grub_util_readlink()
+
+Add grub_util_readlink().  This requires pulling in stat and readlink from
+gnulib, which pulls in stat and related headers, but after that the
+implementation is straightforward.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+Reviewed-by: Adam Jackson <ajax@redhat.com>
+---
+ grub-core/gnulib/gettimeofday.c       | 154 +++++++
+ grub-core/gnulib/readlink.c           |  74 ++++
+ grub-core/gnulib/stat.c               | 138 +++++++
+ grub-core/osdep/windows/hostdisk.c    |   6 +
+ grub-core/gnulib/pathmax.h            |  83 ++++
+ grub-core/gnulib/sys_stat.in.h        | 732 ++++++++++++++++++++++++++++++++++
+ grub-core/gnulib/sys_time.in.h        | 213 ++++++++++
+ grub-core/gnulib/sys_types.in.h       |   2 +
+ grub-core/gnulib/time.h               | 586 +++++++++++++++++++++++++++
+ grub-core/gnulib/time.in.h            | 274 +++++++++++++
+ include/grub/osdep/hostfile_aros.h    |   6 +
+ include/grub/osdep/hostfile_unix.h    |   6 +
+ include/grub/osdep/hostfile_windows.h |   2 +
+ grub-core/gnulib/Makefile.am          | 177 +++++++-
+ m4/gettimeofday.m4                    | 138 +++++++
+ m4/gnulib-cache.m4                    |   3 +-
+ m4/gnulib-comp.m4                     |  49 +++
+ m4/largefile.m4                       | 146 +++++++
+ m4/pathmax.m4                         |  42 ++
+ m4/readlink.m4                        |  71 ++++
+ m4/stat.m4                            |  71 ++++
+ m4/sys_stat_h.m4                      |  96 +++++
+ m4/sys_time_h.m4                      | 110 +++++
+ m4/time_h.m4                          | 118 ++++++
+ 24 files changed, 3295 insertions(+), 2 deletions(-)
+ create mode 100644 grub-core/gnulib/gettimeofday.c
+ create mode 100644 grub-core/gnulib/readlink.c
+ create mode 100644 grub-core/gnulib/stat.c
+ create mode 100644 grub-core/gnulib/pathmax.h
+ create mode 100644 grub-core/gnulib/sys_stat.in.h
+ create mode 100644 grub-core/gnulib/sys_time.in.h
+ create mode 100644 grub-core/gnulib/time.h
+ create mode 100644 grub-core/gnulib/time.in.h
+ create mode 100644 m4/gettimeofday.m4
+ create mode 100644 m4/largefile.m4
+ create mode 100644 m4/pathmax.m4
+ create mode 100644 m4/readlink.m4
+ create mode 100644 m4/stat.m4
+ create mode 100644 m4/sys_stat_h.m4
+ create mode 100644 m4/sys_time_h.m4
+ create mode 100644 m4/time_h.m4
+
+diff --git a/grub-core/gnulib/gettimeofday.c b/grub-core/gnulib/gettimeofday.c
+new file mode 100644
+index 00000000000..8b2058e8c87
+--- /dev/null
++++ b/grub-core/gnulib/gettimeofday.c
+@@ -0,0 +1,154 @@
++/* Provide gettimeofday for systems that don't have it or for which it's broken.
++
++   Copyright (C) 2001-2003, 2005-2007, 2009-2014 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 3, 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, see <http://www.gnu.org/licenses/>.  */
++
++/* written by Jim Meyering */
++
++#include <config.h>
++
++/* Specification.  */
++#include <sys/time.h>
++
++#include <time.h>
++
++#if HAVE_SYS_TIMEB_H
++# include <sys/timeb.h>
++#endif
++
++#if GETTIMEOFDAY_CLOBBERS_LOCALTIME || TZSET_CLOBBERS_LOCALTIME
++
++/* Work around the bug in some systems whereby gettimeofday clobbers
++   the static buffer that localtime uses for its return value.  The
++   gettimeofday function from Mac OS X 10.0.4 (i.e., Darwin 1.3.7) has
++   this problem.  The tzset replacement is necessary for at least
++   Solaris 2.5, 2.5.1, and 2.6.  */
++
++static struct tm tm_zero_buffer;
++static struct tm *localtime_buffer_addr = &tm_zero_buffer;
++
++# undef localtime
++extern struct tm *localtime (time_t const *);
++
++# undef gmtime
++extern struct tm *gmtime (time_t const *);
++
++/* This is a wrapper for localtime.  It is used only on systems for which
++   gettimeofday clobbers the static buffer used for localtime's result.
++
++   On the first call, record the address of the static buffer that
++   localtime uses for its result.  */
++
++struct tm *
++rpl_localtime (time_t const *timep)
++{
++  struct tm *tm = localtime (timep);
++
++  if (localtime_buffer_addr == &tm_zero_buffer)
++    localtime_buffer_addr = tm;
++
++  return tm;
++}
++
++/* Same as above, since gmtime and localtime use the same buffer.  */
++struct tm *
++rpl_gmtime (time_t const *timep)
++{
++  struct tm *tm = gmtime (timep);
++
++  if (localtime_buffer_addr == &tm_zero_buffer)
++    localtime_buffer_addr = tm;
++
++  return tm;
++}
++
++#endif /* GETTIMEOFDAY_CLOBBERS_LOCALTIME || TZSET_CLOBBERS_LOCALTIME */
++
++#if TZSET_CLOBBERS_LOCALTIME
++
++# undef tzset
++extern void tzset (void);
++
++/* This is a wrapper for tzset, for systems on which tzset may clobber
++   the static buffer used for localtime's result.  */
++void
++rpl_tzset (void)
++{
++  /* Save and restore the contents of the buffer used for localtime's
++     result around the call to tzset.  */
++  struct tm save = *localtime_buffer_addr;
++  tzset ();
++  *localtime_buffer_addr = save;
++}
++#endif
++
++/* This is a wrapper for gettimeofday.  It is used only on systems
++   that lack this function, or whose implementation of this function
++   causes problems.  */
++
++int
++gettimeofday (struct timeval *restrict tv, void *restrict tz)
++{
++#undef gettimeofday
++#if HAVE_GETTIMEOFDAY
++# if GETTIMEOFDAY_CLOBBERS_LOCALTIME
++  /* Save and restore the contents of the buffer used for localtime's
++     result around the call to gettimeofday.  */
++  struct tm save = *localtime_buffer_addr;
++# endif
++
++# if defined timeval /* 'struct timeval' overridden by gnulib?  */
++#  undef timeval
++  struct timeval otv;
++  int result = gettimeofday (&otv, (struct timezone *) tz);
++  if (result == 0)
++    {
++      tv->tv_sec = otv.tv_sec;
++      tv->tv_usec = otv.tv_usec;
++    }
++# else
++  int result = gettimeofday (tv, (struct timezone *) tz);
++# endif
++
++# if GETTIMEOFDAY_CLOBBERS_LOCALTIME
++  *localtime_buffer_addr = save;
++# endif
++
++  return result;
++
++#else
++
++# if HAVE__FTIME
++
++  struct _timeb timebuf;
++  _ftime (&timebuf);
++  tv->tv_sec = timebuf.time;
++  tv->tv_usec = timebuf.millitm * 1000;
++
++# else
++
++#  if !defined OK_TO_USE_1S_CLOCK
++#   error "Only 1-second nominal clock resolution found.  Is that intended?" \
++          "If so, compile with the -DOK_TO_USE_1S_CLOCK option."
++#  endif
++  tv->tv_sec = time (NULL);
++  tv->tv_usec = 0;
++
++# endif
++
++  return 0;
++
++#endif
++}
+diff --git a/grub-core/gnulib/readlink.c b/grub-core/gnulib/readlink.c
+new file mode 100644
+index 00000000000..4c496395176
+--- /dev/null
++++ b/grub-core/gnulib/readlink.c
+@@ -0,0 +1,74 @@
++/* Stub for readlink().
++   Copyright (C) 2003-2007, 2009-2014 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 3 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, see <http://www.gnu.org/licenses/>.  */
++
++#include <config.h>
++
++/* Specification.  */
++#include <unistd.h>
++
++#include <errno.h>
++#include <string.h>
++#include <sys/stat.h>
++
++#if !HAVE_READLINK
++
++/* readlink() substitute for systems that don't have a readlink() function,
++   such as DJGPP 2.03 and mingw32.  */
++
++ssize_t
++readlink (const char *name, char *buf _GL_UNUSED,
++          size_t bufsize _GL_UNUSED)
++{
++  struct stat statbuf;
++
++  /* In general we should use lstat() here, not stat().  But on platforms
++     without symbolic links, lstat() - if it exists - would be equivalent to
++     stat(), therefore we can use stat().  This saves us a configure check.  */
++  if (stat (name, &statbuf) >= 0)
++    errno = EINVAL;
++  return -1;
++}
++
++#else /* HAVE_READLINK */
++
++# undef readlink
++
++/* readlink() wrapper that uses correct types, for systems like cygwin
++   1.5.x where readlink returns int, and which rejects trailing slash,
++   for Solaris 9.  */
++
++ssize_t
++rpl_readlink (const char *name, char *buf, size_t bufsize)
++{
++# if READLINK_TRAILING_SLASH_BUG
++  size_t len = strlen (name);
++  if (len && name[len - 1] == '/')
++    {
++      /* Even if name without the slash is a symlink to a directory,
++         both lstat() and stat() must resolve the trailing slash to
++         the directory rather than the symlink.  We can therefore
++         safely use stat() to distinguish between EINVAL and
++         ENOTDIR/ENOENT, avoiding extra overhead of rpl_lstat().  */
++      struct stat st;
++      if (stat (name, &st) == 0)
++        errno = EINVAL;
++      return -1;
++    }
++# endif /* READLINK_TRAILING_SLASH_BUG */
++  return readlink (name, buf, bufsize);
++}
++
++#endif /* HAVE_READLINK */
+diff --git a/grub-core/gnulib/stat.c b/grub-core/gnulib/stat.c
+new file mode 100644
+index 00000000000..35f4b0b1a51
+--- /dev/null
++++ b/grub-core/gnulib/stat.c
+@@ -0,0 +1,138 @@
++/* Work around platform bugs in stat.
++   Copyright (C) 2009-2014 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 3 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, see <http://www.gnu.org/licenses/>.  */
++
++/* written by Eric Blake */
++
++/* If the user's config.h happens to include <sys/stat.h>, let it include only
++   the system's <sys/stat.h> here, so that orig_stat doesn't recurse to
++   rpl_stat.  */
++#define __need_system_sys_stat_h
++#include <config.h>
++
++/* Get the original definition of stat.  It might be defined as a macro.  */
++#include <sys/types.h>
++#include <sys/stat.h>
++#undef __need_system_sys_stat_h
++
++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
++# if _GL_WINDOWS_64_BIT_ST_SIZE
++#  undef stat /* avoid warning on mingw64 with _FILE_OFFSET_BITS=64 */
++#  define stat _stati64
++#  define REPLACE_FUNC_STAT_DIR 1
++#  undef REPLACE_FUNC_STAT_FILE
++# elif REPLACE_FUNC_STAT_FILE
++/* mingw64 has a broken stat() function, based on _stat(), in libmingwex.a.
++   Bypass it.  */
++#  define stat _stat
++#  define REPLACE_FUNC_STAT_DIR 1
++#  undef REPLACE_FUNC_STAT_FILE
++# endif
++#endif
++
++static int
++orig_stat (const char *filename, struct stat *buf)
++{
++  return stat (filename, buf);
++}
++
++/* Specification.  */
++/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
++   eliminates this include because of the preliminary #include <sys/stat.h>
++   above.  */
++#include "sys/stat.h"
++
++#include <errno.h>
++#include <limits.h>
++#include <stdbool.h>
++#include <string.h>
++#include "dosname.h"
++#include "verify.h"
++
++#if REPLACE_FUNC_STAT_DIR
++# include "pathmax.h"
++  /* The only known systems where REPLACE_FUNC_STAT_DIR is needed also
++     have a constant PATH_MAX.  */
++# ifndef PATH_MAX
++#  error "Please port this replacement to your platform"
++# endif
++#endif
++
++/* Store information about NAME into ST.  Work around bugs with
++   trailing slashes.  Mingw has other bugs (such as st_ino always
++   being 0 on success) which this wrapper does not work around.  But
++   at least this implementation provides the ability to emulate fchdir
++   correctly.  */
++
++int
++rpl_stat (char const *name, struct stat *st)
++{
++  int result = orig_stat (name, st);
++#if REPLACE_FUNC_STAT_FILE
++  /* Solaris 9 mistakenly succeeds when given a non-directory with a
++     trailing slash.  */
++  if (result == 0 && !S_ISDIR (st->st_mode))
++    {
++      size_t len = strlen (name);
++      if (ISSLASH (name[len - 1]))
++        {
++          errno = ENOTDIR;
++          return -1;
++        }
++    }
++#endif /* REPLACE_FUNC_STAT_FILE */
++#if REPLACE_FUNC_STAT_DIR
++
++  if (result == -1 && errno == ENOENT)
++    {
++      /* Due to mingw's oddities, there are some directories (like
++         c:\) where stat() only succeeds with a trailing slash, and
++         other directories (like c:\windows) where stat() only
++         succeeds without a trailing slash.  But we want the two to be
++         synonymous, since chdir() manages either style.  Likewise, Mingw also
++         reports ENOENT for names longer than PATH_MAX, when we want
++         ENAMETOOLONG, and for stat("file/"), when we want ENOTDIR.
++         Fortunately, mingw PATH_MAX is small enough for stack
++         allocation.  */
++      char fixed_name[PATH_MAX + 1] = {0};
++      size_t len = strlen (name);
++      bool check_dir = false;
++      verify (PATH_MAX <= 4096);
++      if (PATH_MAX <= len)
++        errno = ENAMETOOLONG;
++      else if (len)
++        {
++          strcpy (fixed_name, name);
++          if (ISSLASH (fixed_name[len - 1]))
++            {
++              check_dir = true;
++              while (len && ISSLASH (fixed_name[len - 1]))
++                fixed_name[--len] = '\0';
++              if (!len)
++                fixed_name[0] = '/';
++            }
++          else
++            fixed_name[len++] = '/';
++          result = orig_stat (fixed_name, st);
++          if (result == 0 && check_dir && !S_ISDIR (st->st_mode))
++            {
++              result = -1;
++              errno = ENOTDIR;
++            }
++        }
++    }
++#endif /* REPLACE_FUNC_STAT_DIR */
++  return result;
++}
+diff --git a/grub-core/osdep/windows/hostdisk.c b/grub-core/osdep/windows/hostdisk.c
+index 85507af88e3..6f49df465d7 100644
+--- a/grub-core/osdep/windows/hostdisk.c
++++ b/grub-core/osdep/windows/hostdisk.c
+@@ -353,6 +353,12 @@ grub_util_mkdir (const char *dir)
+   free (windows_name);
+ }
+ 
++ssize_t
++grub_util_readlink (const char *name, char *buf, size_t bufsize)
++{
++  return readlink(name, buf, bufsize);
++}
++
+ int
+ grub_util_rename (const char *from, const char *to)
+ {
+diff --git a/grub-core/gnulib/pathmax.h b/grub-core/gnulib/pathmax.h
+new file mode 100644
+index 00000000000..33fc3553d75
+--- /dev/null
++++ b/grub-core/gnulib/pathmax.h
+@@ -0,0 +1,83 @@
++/* Define PATH_MAX somehow.  Requires sys/types.h.
++   Copyright (C) 1992, 1999, 2001, 2003, 2005, 2009-2014 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 3, 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, see <http://www.gnu.org/licenses/>.  */
++
++#ifndef _PATHMAX_H
++# define _PATHMAX_H
++
++/* POSIX:2008 defines PATH_MAX to be the maximum number of bytes in a filename,
++   including the terminating NUL byte.
++   <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html>
++   PATH_MAX is not defined on systems which have no limit on filename length,
++   such as GNU/Hurd.
++
++   This file does *not* define PATH_MAX always.  Programs that use this file
++   can handle the GNU/Hurd case in several ways:
++     - Either with a package-wide handling, or with a per-file handling,
++     - Either through a
++         #ifdef PATH_MAX
++       or through a fallback like
++         #ifndef PATH_MAX
++         # define PATH_MAX 8192
++         #endif
++       or through a fallback like
++         #ifndef PATH_MAX
++         # define PATH_MAX pathconf ("/", _PC_PATH_MAX)
++         #endif
++ */
++
++# include <unistd.h>
++
++# include <limits.h>
++
++# ifndef _POSIX_PATH_MAX
++#  define _POSIX_PATH_MAX 256
++# endif
++
++/* Don't include sys/param.h if it already has been.  */
++# if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
++#  include <sys/param.h>
++# endif
++
++# if !defined PATH_MAX && defined MAXPATHLEN
++#  define PATH_MAX MAXPATHLEN
++# endif
++
++# ifdef __hpux
++/* On HP-UX, PATH_MAX designates the maximum number of bytes in a filename,
++   *not* including the terminating NUL byte, and is set to 1023.
++   Additionally, when _XOPEN_SOURCE is defined to 500 or more, PATH_MAX is
++   not defined at all any more.  */
++#  undef PATH_MAX
++#  define PATH_MAX 1024
++# endif
++
++# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
++/* The page "Naming Files, Paths, and Namespaces" on msdn.microsoft.com,
++   section "Maximum Path Length Limitation",
++   <http://msdn.microsoft.com/en-us/library/aa365247(v=vs.85).aspx#maxpath>
++   explains that the maximum size of a filename, including the terminating
++   NUL byte, is 260 = 3 + 256 + 1.
++   This is the same value as
++     - FILENAME_MAX in <stdio.h>,
++     - _MAX_PATH in <stdlib.h>,
++     - MAX_PATH in <windef.h>.
++   Undefine the original value, because mingw's <limits.h> gets it wrong.  */
++#  undef PATH_MAX
++#  define PATH_MAX 260
++# endif
++
++#endif /* _PATHMAX_H */
+diff --git a/grub-core/gnulib/sys_stat.in.h b/grub-core/gnulib/sys_stat.in.h
+new file mode 100644
+index 00000000000..b47a7ff0ae7
+--- /dev/null
++++ b/grub-core/gnulib/sys_stat.in.h
+@@ -0,0 +1,732 @@
++/* Provide a more complete sys/stat header file.
++   Copyright (C) 2005-2014 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 3, 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, see <http://www.gnu.org/licenses/>.  */
++
++/* Written by Eric Blake, Paul Eggert, and Jim Meyering.  */
++
++/* This file is supposed to be used on platforms where <sys/stat.h> is
++   incomplete.  It is intended to provide definitions and prototypes
++   needed by an application.  Start with what the system provides.  */
++
++#if __GNUC__ >= 3
++@PRAGMA_SYSTEM_HEADER@
++#endif
++@PRAGMA_COLUMNS@
++
++#if defined __need_system_sys_stat_h
++/* Special invocation convention.  */
++
++#@INCLUDE_NEXT@ @NEXT_SYS_STAT_H@
++
++#else
++/* Normal invocation convention.  */
++
++#ifndef _@GUARD_PREFIX@_SYS_STAT_H
++
++/* Get nlink_t.
++   May also define off_t to a 64-bit type on native Windows.  */
++#include <sys/types.h>
++
++/* Get struct timespec.  */
++#include <time.h>
++
++/* The include_next requires a split double-inclusion guard.  */
++#@INCLUDE_NEXT@ @NEXT_SYS_STAT_H@
++
++#ifndef _@GUARD_PREFIX@_SYS_STAT_H
++#define _@GUARD_PREFIX@_SYS_STAT_H
++
++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
++
++/* The definition of _GL_ARG_NONNULL is copied here.  */
++
++/* The definition of _GL_WARN_ON_USE is copied here.  */
++
++/* Before doing "#define mkdir rpl_mkdir" below, we need to include all
++   headers that may declare mkdir().  Native Windows platforms declare mkdir
++   in <io.h> and/or <direct.h>, not in <unistd.h>.  */
++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
++# include <io.h>     /* mingw32, mingw64 */
++# include <direct.h> /* mingw64, MSVC 9 */
++#endif
++
++/* Native Windows platforms declare umask() in <io.h>.  */
++#if 0 && ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
++# include <io.h>
++#endif
++
++/* Large File Support on native Windows.  */
++#if @WINDOWS_64_BIT_ST_SIZE@
++# define stat _stati64
++#endif
++
++#ifndef S_IFIFO
++# ifdef _S_IFIFO
++#  define S_IFIFO _S_IFIFO
++# endif
++#endif
++
++#ifndef S_IFMT
++# define S_IFMT 0170000
++#endif
++
++#if STAT_MACROS_BROKEN
++# undef S_ISBLK
++# undef S_ISCHR
++# undef S_ISDIR
++# undef S_ISFIFO
++# undef S_ISLNK
++# undef S_ISNAM
++# undef S_ISMPB
++# undef S_ISMPC
++# undef S_ISNWK
++# undef S_ISREG
++# undef S_ISSOCK
++#endif
++
++#ifndef S_ISBLK
++# ifdef S_IFBLK
++#  define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
++# else
++#  define S_ISBLK(m) 0
++# endif
++#endif
++
++#ifndef S_ISCHR
++# ifdef S_IFCHR
++#  define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
++# else
++#  define S_ISCHR(m) 0
++# endif
++#endif
++
++#ifndef S_ISDIR
++# ifdef S_IFDIR
++#  define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
++# else
++#  define S_ISDIR(m) 0
++# endif
++#endif
++
++#ifndef S_ISDOOR /* Solaris 2.5 and up */
++# define S_ISDOOR(m) 0
++#endif
++
++#ifndef S_ISFIFO
++# ifdef S_IFIFO
++#  define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
++# else
++#  define S_ISFIFO(m) 0
++# endif
++#endif
++
++#ifndef S_ISLNK
++# ifdef S_IFLNK
++#  define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
++# else
++#  define S_ISLNK(m) 0
++# endif
++#endif
++
++#ifndef S_ISMPB /* V7 */
++# ifdef S_IFMPB
++#  define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
++#  define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
++# else
++#  define S_ISMPB(m) 0
++#  define S_ISMPC(m) 0
++# endif
++#endif
++
++#ifndef S_ISMPX /* AIX */
++# define S_ISMPX(m) 0
++#endif
++
++#ifndef S_ISNAM /* Xenix */
++# ifdef S_IFNAM
++#  define S_ISNAM(m) (((m) & S_IFMT) == S_IFNAM)
++# else
++#  define S_ISNAM(m) 0
++# endif
++#endif
++
++#ifndef S_ISNWK /* HP/UX */
++# ifdef S_IFNWK
++#  define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
++# else
++#  define S_ISNWK(m) 0
++# endif
++#endif
++
++#ifndef S_ISPORT /* Solaris 10 and up */
++# define S_ISPORT(m) 0
++#endif
++
++#ifndef S_ISREG
++# ifdef S_IFREG
++#  define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
++# else
++#  define S_ISREG(m) 0
++# endif
++#endif
++
++#ifndef S_ISSOCK
++# ifdef S_IFSOCK
++#  define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
++# else
++#  define S_ISSOCK(m) 0
++# endif
++#endif
++
++
++#ifndef S_TYPEISMQ
++# define S_TYPEISMQ(p) 0
++#endif
++
++#ifndef S_TYPEISTMO
++# define S_TYPEISTMO(p) 0
++#endif
++
++
++#ifndef S_TYPEISSEM
++# ifdef S_INSEM
++#  define S_TYPEISSEM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSEM)
++# else
++#  define S_TYPEISSEM(p) 0
++# endif
++#endif
++
++#ifndef S_TYPEISSHM
++# ifdef S_INSHD
++#  define S_TYPEISSHM(p) (S_ISNAM ((p)->st_mode) && (p)->st_rdev == S_INSHD)
++# else
++#  define S_TYPEISSHM(p) 0
++# endif
++#endif
++
++/* high performance ("contiguous data") */
++#ifndef S_ISCTG
++# define S_ISCTG(p) 0
++#endif
++
++/* Cray DMF (data migration facility): off line, with data  */
++#ifndef S_ISOFD
++# define S_ISOFD(p) 0
++#endif
++
++/* Cray DMF (data migration facility): off line, with no data  */
++#ifndef S_ISOFL
++# define S_ISOFL(p) 0
++#endif
++
++/* 4.4BSD whiteout */
++#ifndef S_ISWHT
++# define S_ISWHT(m) 0
++#endif
++
++/* If any of the following are undefined,
++   define them to their de facto standard values.  */
++#if !S_ISUID
++# define S_ISUID 04000
++#endif
++#if !S_ISGID
++# define S_ISGID 02000
++#endif
++
++/* S_ISVTX is a common extension to POSIX.  */
++#ifndef S_ISVTX
++# define S_ISVTX 01000
++#endif
++
++#if !S_IRUSR && S_IREAD
++# define S_IRUSR S_IREAD
++#endif
++#if !S_IRUSR
++# define S_IRUSR 00400
++#endif
++#if !S_IRGRP
++# define S_IRGRP (S_IRUSR >> 3)
++#endif
++#if !S_IROTH
++# define S_IROTH (S_IRUSR >> 6)
++#endif
++
++#if !S_IWUSR && S_IWRITE
++# define S_IWUSR S_IWRITE
++#endif
++#if !S_IWUSR
++# define S_IWUSR 00200
++#endif
++#if !S_IWGRP
++# define S_IWGRP (S_IWUSR >> 3)
++#endif
++#if !S_IWOTH
++# define S_IWOTH (S_IWUSR >> 6)
++#endif
++
++#if !S_IXUSR && S_IEXEC
++# define S_IXUSR S_IEXEC
++#endif
++#if !S_IXUSR
++# define S_IXUSR 00100
++#endif
++#if !S_IXGRP
++# define S_IXGRP (S_IXUSR >> 3)
++#endif
++#if !S_IXOTH
++# define S_IXOTH (S_IXUSR >> 6)
++#endif
++
++#if !S_IRWXU
++# define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
++#endif
++#if !S_IRWXG
++# define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
++#endif
++#if !S_IRWXO
++# define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
++#endif
++
++/* S_IXUGO is a common extension to POSIX.  */
++#if !S_IXUGO
++# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
++#endif
++
++#ifndef S_IRWXUGO
++# define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO)
++#endif
++
++/* Macros for futimens and utimensat.  */
++#ifndef UTIME_NOW
++# define UTIME_NOW (-1)
++# define UTIME_OMIT (-2)
++#endif
++
++
++#if @GNULIB_FCHMODAT@
++# if !@HAVE_FCHMODAT@
++_GL_FUNCDECL_SYS (fchmodat, int,
++                  (int fd, char const *file, mode_t mode, int flag)
++                  _GL_ARG_NONNULL ((2)));
++# endif
++_GL_CXXALIAS_SYS (fchmodat, int,
++                  (int fd, char const *file, mode_t mode, int flag));
++_GL_CXXALIASWARN (fchmodat);
++#elif defined GNULIB_POSIXCHECK
++# undef fchmodat
++# if HAVE_RAW_DECL_FCHMODAT
++_GL_WARN_ON_USE (fchmodat, "fchmodat is not portable - "
++                 "use gnulib module openat for portability");
++# endif
++#endif
++
++
++#if @GNULIB_FSTAT@
++# if @REPLACE_FSTAT@
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef fstat
++#   define fstat rpl_fstat
++#  endif
++_GL_FUNCDECL_RPL (fstat, int, (int fd, struct stat *buf) _GL_ARG_NONNULL ((2)));
++_GL_CXXALIAS_RPL (fstat, int, (int fd, struct stat *buf));
++# else
++_GL_CXXALIAS_SYS (fstat, int, (int fd, struct stat *buf));
++# endif
++_GL_CXXALIASWARN (fstat);
++#elif @WINDOWS_64_BIT_ST_SIZE@
++/* Above, we define stat to _stati64.  */
++# define fstat _fstati64
++#elif defined GNULIB_POSIXCHECK
++# undef fstat
++# if HAVE_RAW_DECL_FSTAT
++_GL_WARN_ON_USE (fstat, "fstat has portability problems - "
++                 "use gnulib module fstat for portability");
++# endif
++#endif
++
++
++#if @GNULIB_FSTATAT@
++# if @REPLACE_FSTATAT@
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef fstatat
++#   define fstatat rpl_fstatat
++#  endif
++_GL_FUNCDECL_RPL (fstatat, int,
++                  (int fd, char const *name, struct stat *st, int flags)
++                  _GL_ARG_NONNULL ((2, 3)));
++_GL_CXXALIAS_RPL (fstatat, int,
++                  (int fd, char const *name, struct stat *st, int flags));
++# else
++#  if !@HAVE_FSTATAT@
++_GL_FUNCDECL_SYS (fstatat, int,
++                  (int fd, char const *name, struct stat *st, int flags)
++                  _GL_ARG_NONNULL ((2, 3)));
++#  endif
++_GL_CXXALIAS_SYS (fstatat, int,
++                  (int fd, char const *name, struct stat *st, int flags));
++# endif
++_GL_CXXALIASWARN (fstatat);
++#elif defined GNULIB_POSIXCHECK
++# undef fstatat
++# if HAVE_RAW_DECL_FSTATAT
++_GL_WARN_ON_USE (fstatat, "fstatat is not portable - "
++                 "use gnulib module openat for portability");
++# endif
++#endif
++
++
++#if @GNULIB_FUTIMENS@
++/* Use the rpl_ prefix also on Solaris <= 9, because on Solaris 9 our futimens
++   implementation relies on futimesat, which on Solaris 10 makes an invocation
++   to futimens that is meant to invoke the libc's futimens(), not gnulib's
++   futimens().  */
++# if @REPLACE_FUTIMENS@ || (!@HAVE_FUTIMENS@ && defined __sun)
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef futimens
++#   define futimens rpl_futimens
++#  endif
++_GL_FUNCDECL_RPL (futimens, int, (int fd, struct timespec const times[2]));
++_GL_CXXALIAS_RPL (futimens, int, (int fd, struct timespec const times[2]));
++# else
++#  if !@HAVE_FUTIMENS@
++_GL_FUNCDECL_SYS (futimens, int, (int fd, struct timespec const times[2]));
++#  endif
++_GL_CXXALIAS_SYS (futimens, int, (int fd, struct timespec const times[2]));
++# endif
++# if @HAVE_FUTIMENS@
++_GL_CXXALIASWARN (futimens);
++# endif
++#elif defined GNULIB_POSIXCHECK
++# undef futimens
++# if HAVE_RAW_DECL_FUTIMENS
++_GL_WARN_ON_USE (futimens, "futimens is not portable - "
++                 "use gnulib module futimens for portability");
++# endif
++#endif
++
++
++#if @GNULIB_LCHMOD@
++/* Change the mode of FILENAME to MODE, without dereferencing it if FILENAME
++   denotes a symbolic link.  */
++# if !@HAVE_LCHMOD@
++/* The lchmod replacement follows symbolic links.  Callers should take
++   this into account; lchmod should be applied only to arguments that
++   are known to not be symbolic links.  On hosts that lack lchmod,
++   this can lead to race conditions between the check and the
++   invocation of lchmod, but we know of no workarounds that are
++   reliable in general.  You might try requesting support for lchmod
++   from your operating system supplier.  */
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   define lchmod chmod
++#  endif
++/* Need to cast, because on mingw, the second parameter of chmod is
++                                                int mode.  */
++_GL_CXXALIAS_RPL_CAST_1 (lchmod, chmod, int,
++                         (const char *filename, mode_t mode));
++# else
++#  if 0 /* assume already declared */
++_GL_FUNCDECL_SYS (lchmod, int, (const char *filename, mode_t mode)
++                               _GL_ARG_NONNULL ((1)));
++#  endif
++_GL_CXXALIAS_SYS (lchmod, int, (const char *filename, mode_t mode));
++# endif
++# if @HAVE_LCHMOD@
++_GL_CXXALIASWARN (lchmod);
++# endif
++#elif defined GNULIB_POSIXCHECK
++# undef lchmod
++# if HAVE_RAW_DECL_LCHMOD
++_GL_WARN_ON_USE (lchmod, "lchmod is unportable - "
++                 "use gnulib module lchmod for portability");
++# endif
++#endif
++
++
++#if @GNULIB_LSTAT@
++# if ! @HAVE_LSTAT@
++/* mingw does not support symlinks, therefore it does not have lstat.  But
++   without links, stat does just fine.  */
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   define lstat stat
++#  endif
++_GL_CXXALIAS_RPL_1 (lstat, stat, int, (const char *name, struct stat *buf));
++# elif @REPLACE_LSTAT@
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef lstat
++#   define lstat rpl_lstat
++#  endif
++_GL_FUNCDECL_RPL (lstat, int, (const char *name, struct stat *buf)
++                              _GL_ARG_NONNULL ((1, 2)));
++_GL_CXXALIAS_RPL (lstat, int, (const char *name, struct stat *buf));
++# else
++_GL_CXXALIAS_SYS (lstat, int, (const char *name, struct stat *buf));
++# endif
++# if @HAVE_LSTAT@
++_GL_CXXALIASWARN (lstat);
++# endif
++#elif defined GNULIB_POSIXCHECK
++# undef lstat
++# if HAVE_RAW_DECL_LSTAT
++_GL_WARN_ON_USE (lstat, "lstat is unportable - "
++                 "use gnulib module lstat for portability");
++# endif
++#endif
++
++
++#if @REPLACE_MKDIR@
++# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#  undef mkdir
++#  define mkdir rpl_mkdir
++# endif
++_GL_FUNCDECL_RPL (mkdir, int, (char const *name, mode_t mode)
++                              _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode));
++#else
++/* mingw's _mkdir() function has 1 argument, but we pass 2 arguments.
++   Additionally, it declares _mkdir (and depending on compile flags, an
++   alias mkdir), only in the nonstandard includes <direct.h> and <io.h>,
++   which are included above.  */
++# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
++
++#  if !GNULIB_defined_rpl_mkdir
++static int
++rpl_mkdir (char const *name, mode_t mode)
++{
++  return _mkdir (name);
++}
++#   define GNULIB_defined_rpl_mkdir 1
++#  endif
++
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   define mkdir rpl_mkdir
++#  endif
++_GL_CXXALIAS_RPL (mkdir, int, (char const *name, mode_t mode));
++# else
++_GL_CXXALIAS_SYS (mkdir, int, (char const *name, mode_t mode));
++# endif
++#endif
++_GL_CXXALIASWARN (mkdir);
++
++
++#if @GNULIB_MKDIRAT@
++# if !@HAVE_MKDIRAT@
++_GL_FUNCDECL_SYS (mkdirat, int, (int fd, char const *file, mode_t mode)
++                                _GL_ARG_NONNULL ((2)));
++# endif
++_GL_CXXALIAS_SYS (mkdirat, int, (int fd, char const *file, mode_t mode));
++_GL_CXXALIASWARN (mkdirat);
++#elif defined GNULIB_POSIXCHECK
++# undef mkdirat
++# if HAVE_RAW_DECL_MKDIRAT
++_GL_WARN_ON_USE (mkdirat, "mkdirat is not portable - "
++                 "use gnulib module openat for portability");
++# endif
++#endif
++
++
++#if @GNULIB_MKFIFO@
++# if @REPLACE_MKFIFO@
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef mkfifo
++#   define mkfifo rpl_mkfifo
++#  endif
++_GL_FUNCDECL_RPL (mkfifo, int, (char const *file, mode_t mode)
++                               _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (mkfifo, int, (char const *file, mode_t mode));
++# else
++#  if !@HAVE_MKFIFO@
++_GL_FUNCDECL_SYS (mkfifo, int, (char const *file, mode_t mode)
++                               _GL_ARG_NONNULL ((1)));
++#  endif
++_GL_CXXALIAS_SYS (mkfifo, int, (char const *file, mode_t mode));
++# endif
++_GL_CXXALIASWARN (mkfifo);
++#elif defined GNULIB_POSIXCHECK
++# undef mkfifo
++# if HAVE_RAW_DECL_MKFIFO
++_GL_WARN_ON_USE (mkfifo, "mkfifo is not portable - "
++                 "use gnulib module mkfifo for portability");
++# endif
++#endif
++
++
++#if @GNULIB_MKFIFOAT@
++# if !@HAVE_MKFIFOAT@
++_GL_FUNCDECL_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode)
++                                 _GL_ARG_NONNULL ((2)));
++# endif
++_GL_CXXALIAS_SYS (mkfifoat, int, (int fd, char const *file, mode_t mode));
++_GL_CXXALIASWARN (mkfifoat);
++#elif defined GNULIB_POSIXCHECK
++# undef mkfifoat
++# if HAVE_RAW_DECL_MKFIFOAT
++_GL_WARN_ON_USE (mkfifoat, "mkfifoat is not portable - "
++                 "use gnulib module mkfifoat for portability");
++# endif
++#endif
++
++
++#if @GNULIB_MKNOD@
++# if @REPLACE_MKNOD@
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef mknod
++#   define mknod rpl_mknod
++#  endif
++_GL_FUNCDECL_RPL (mknod, int, (char const *file, mode_t mode, dev_t dev)
++                              _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (mknod, int, (char const *file, mode_t mode, dev_t dev));
++# else
++#  if !@HAVE_MKNOD@
++_GL_FUNCDECL_SYS (mknod, int, (char const *file, mode_t mode, dev_t dev)
++                              _GL_ARG_NONNULL ((1)));
++#  endif
++/* Need to cast, because on OSF/1 5.1, the third parameter is '...'.  */
++_GL_CXXALIAS_SYS_CAST (mknod, int, (char const *file, mode_t mode, dev_t dev));
++# endif
++_GL_CXXALIASWARN (mknod);
++#elif defined GNULIB_POSIXCHECK
++# undef mknod
++# if HAVE_RAW_DECL_MKNOD
++_GL_WARN_ON_USE (mknod, "mknod is not portable - "
++                 "use gnulib module mknod for portability");
++# endif
++#endif
++
++
++#if @GNULIB_MKNODAT@
++# if !@HAVE_MKNODAT@
++_GL_FUNCDECL_SYS (mknodat, int,
++                  (int fd, char const *file, mode_t mode, dev_t dev)
++                  _GL_ARG_NONNULL ((2)));
++# endif
++_GL_CXXALIAS_SYS (mknodat, int,
++                  (int fd, char const *file, mode_t mode, dev_t dev));
++_GL_CXXALIASWARN (mknodat);
++#elif defined GNULIB_POSIXCHECK
++# undef mknodat
++# if HAVE_RAW_DECL_MKNODAT
++_GL_WARN_ON_USE (mknodat, "mknodat is not portable - "
++                 "use gnulib module mkfifoat for portability");
++# endif
++#endif
++
++
++#if @GNULIB_STAT@
++# if @REPLACE_STAT@
++/* We can't use the object-like #define stat rpl_stat, because of
++   struct stat.  This means that rpl_stat will not be used if the user
++   does (stat)(a,b).  Oh well.  */
++#  if defined _AIX && defined stat && defined _LARGE_FILES
++    /* With _LARGE_FILES defined, AIX (only) defines stat to stat64,
++       so we have to replace stat64() instead of stat(). */
++#   undef stat64
++#   define stat64(name, st) rpl_stat (name, st)
++#  elif @WINDOWS_64_BIT_ST_SIZE@
++    /* Above, we define stat to _stati64.  */
++#   if defined __MINGW32__ && defined _stati64
++#    ifndef _USE_32BIT_TIME_T
++      /* The system headers define _stati64 to _stat64.  */
++#     undef _stat64
++#     define _stat64(name, st) rpl_stat (name, st)
++#    endif
++#   elif defined _MSC_VER && defined _stati64
++#    ifdef _USE_32BIT_TIME_T
++      /* The system headers define _stati64 to _stat32i64.  */
++#     undef _stat32i64
++#     define _stat32i64(name, st) rpl_stat (name, st)
++#    else
++      /* The system headers define _stati64 to _stat64.  */
++#     undef _stat64
++#     define _stat64(name, st) rpl_stat (name, st)
++#    endif
++#   else
++#    undef _stati64
++#    define _stati64(name, st) rpl_stat (name, st)
++#   endif
++#  elif defined __MINGW32__ && defined stat
++#   ifdef _USE_32BIT_TIME_T
++     /* The system headers define stat to _stat32i64.  */
++#    undef _stat32i64
++#    define _stat32i64(name, st) rpl_stat (name, st)
++#   else
++     /* The system headers define stat to _stat64.  */
++#    undef _stat64
++#    define _stat64(name, st) rpl_stat (name, st)
++#   endif
++#  elif defined _MSC_VER && defined stat
++#   ifdef _USE_32BIT_TIME_T
++     /* The system headers define stat to _stat32.  */
++#    undef _stat32
++#    define _stat32(name, st) rpl_stat (name, st)
++#   else
++     /* The system headers define stat to _stat64i32.  */
++#    undef _stat64i32
++#    define _stat64i32(name, st) rpl_stat (name, st)
++#   endif
++#  else /* !(_AIX ||__MINGW32__ ||  _MSC_VER) */
++#   undef stat
++#   define stat(name, st) rpl_stat (name, st)
++#  endif /* !_LARGE_FILES */
++_GL_EXTERN_C int stat (const char *name, struct stat *buf)
++                      _GL_ARG_NONNULL ((1, 2));
++# endif
++#elif defined GNULIB_POSIXCHECK
++# undef stat
++# if HAVE_RAW_DECL_STAT
++_GL_WARN_ON_USE (stat, "stat is unportable - "
++                 "use gnulib module stat for portability");
++# endif
++#endif
++
++
++#if @GNULIB_UTIMENSAT@
++/* Use the rpl_ prefix also on Solaris <= 9, because on Solaris 9 our utimensat
++   implementation relies on futimesat, which on Solaris 10 makes an invocation
++   to utimensat that is meant to invoke the libc's utimensat(), not gnulib's
++   utimensat().  */
++# if @REPLACE_UTIMENSAT@ || (!@HAVE_UTIMENSAT@ && defined __sun)
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef utimensat
++#   define utimensat rpl_utimensat
++#  endif
++_GL_FUNCDECL_RPL (utimensat, int, (int fd, char const *name,
++                                   struct timespec const times[2], int flag)
++                                  _GL_ARG_NONNULL ((2)));
++_GL_CXXALIAS_RPL (utimensat, int, (int fd, char const *name,
++                                   struct timespec const times[2], int flag));
++# else
++#  if !@HAVE_UTIMENSAT@
++_GL_FUNCDECL_SYS (utimensat, int, (int fd, char const *name,
++                                   struct timespec const times[2], int flag)
++                                  _GL_ARG_NONNULL ((2)));
++#  endif
++_GL_CXXALIAS_SYS (utimensat, int, (int fd, char const *name,
++                                   struct timespec const times[2], int flag));
++# endif
++# if @HAVE_UTIMENSAT@
++_GL_CXXALIASWARN (utimensat);
++# endif
++#elif defined GNULIB_POSIXCHECK
++# undef utimensat
++# if HAVE_RAW_DECL_UTIMENSAT
++_GL_WARN_ON_USE (utimensat, "utimensat is not portable - "
++                 "use gnulib module utimensat for portability");
++# endif
++#endif
++
++
++#endif /* _@GUARD_PREFIX@_SYS_STAT_H */
++#endif /* _@GUARD_PREFIX@_SYS_STAT_H */
++#endif
+diff --git a/grub-core/gnulib/sys_time.in.h b/grub-core/gnulib/sys_time.in.h
+new file mode 100644
+index 00000000000..30057ad49fd
+--- /dev/null
++++ b/grub-core/gnulib/sys_time.in.h
+@@ -0,0 +1,213 @@
++/* Provide a more complete sys/time.h.
++
++   Copyright (C) 2007-2014 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 3, 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, see <http://www.gnu.org/licenses/>.  */
++
++/* Written by Paul Eggert.  */
++
++#ifndef _@GUARD_PREFIX@_SYS_TIME_H
++
++#if __GNUC__ >= 3
++@PRAGMA_SYSTEM_HEADER@
++#endif
++@PRAGMA_COLUMNS@
++
++/* On Cygwin and on many BSDish systems, <sys/time.h> includes itself
++   recursively via <sys/select.h>.
++   Simply delegate to the system's header in this case; it is a no-op.
++   Without this extra ifdef, the C++ gettimeofday declaration below
++   would be a forward declaration in gnulib's nested <sys/time.h>.  */
++#if defined _CYGWIN_SYS_TIME_H || defined _SYS_TIME_H || defined _SYS_TIME_H_
++# @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@
++#else
++
++/* The include_next requires a split double-inclusion guard.  */
++#if @HAVE_SYS_TIME_H@
++# @INCLUDE_NEXT@ @NEXT_SYS_TIME_H@
++#endif
++
++#ifndef _@GUARD_PREFIX@_SYS_TIME_H
++#define _@GUARD_PREFIX@_SYS_TIME_H
++
++#if ! @HAVE_SYS_TIME_H@
++# include <time.h>
++#endif
++
++/* On native Windows with MSVC, get the 'struct timeval' type.
++   Also, on native Windows with a 64-bit time_t, where we are overriding the
++   'struct timeval' type, get all declarations of system functions whose
++   signature contains 'struct timeval'.  */
++#if (defined _MSC_VER || @REPLACE_STRUCT_TIMEVAL@) && @HAVE_WINSOCK2_H@ && !defined _GL_INCLUDING_WINSOCK2_H
++# define _GL_INCLUDING_WINSOCK2_H
++# include <winsock2.h>
++# undef _GL_INCLUDING_WINSOCK2_H
++#endif
++
++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
++
++/* The definition of _GL_ARG_NONNULL is copied here.  */
++
++/* The definition of _GL_WARN_ON_USE is copied here.  */
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#if !@HAVE_STRUCT_TIMEVAL@ || @REPLACE_STRUCT_TIMEVAL@
++
++# if @REPLACE_STRUCT_TIMEVAL@
++#  define timeval rpl_timeval
++# endif
++
++# if !GNULIB_defined_struct_timeval
++struct timeval
++{
++  time_t tv_sec;
++  long int tv_usec;
++};
++#  define GNULIB_defined_struct_timeval 1
++# endif
++
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#if @GNULIB_GETTIMEOFDAY@
++# if @REPLACE_GETTIMEOFDAY@
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef gettimeofday
++#   define gettimeofday rpl_gettimeofday
++#  endif
++_GL_FUNCDECL_RPL (gettimeofday, int,
++                  (struct timeval *restrict, void *restrict)
++                  _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (gettimeofday, int,
++                  (struct timeval *restrict, void *restrict));
++# else
++#  if !@HAVE_GETTIMEOFDAY@
++_GL_FUNCDECL_SYS (gettimeofday, int,
++                  (struct timeval *restrict, void *restrict)
++                  _GL_ARG_NONNULL ((1)));
++#  endif
++/* Need to cast, because on glibc systems, by default, the second argument is
++                                                  struct timezone *.  */
++_GL_CXXALIAS_SYS_CAST (gettimeofday, int,
++                       (struct timeval *restrict, void *restrict));
++# endif
++_GL_CXXALIASWARN (gettimeofday);
++#elif defined GNULIB_POSIXCHECK
++# undef gettimeofday
++# if HAVE_RAW_DECL_GETTIMEOFDAY
++_GL_WARN_ON_USE (gettimeofday, "gettimeofday is unportable - "
++                 "use gnulib module gettimeofday for portability");
++# endif
++#endif
++
++/* Hide some function declarations from <winsock2.h>.  */
++
++#if defined _MSC_VER && @HAVE_WINSOCK2_H@
++# if !defined _@GUARD_PREFIX@_UNISTD_H
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef close
++#   define close close_used_without_including_unistd_h
++#  else
++     _GL_WARN_ON_USE (close,
++                      "close() used without including <unistd.h>");
++#  endif
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef gethostname
++#   define gethostname gethostname_used_without_including_unistd_h
++#  else
++     _GL_WARN_ON_USE (gethostname,
++                      "gethostname() used without including <unistd.h>");
++#  endif
++# endif
++# if !defined _@GUARD_PREFIX@_SYS_SOCKET_H
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef socket
++#   define socket              socket_used_without_including_sys_socket_h
++#   undef connect
++#   define connect             connect_used_without_including_sys_socket_h
++#   undef accept
++#   define accept              accept_used_without_including_sys_socket_h
++#   undef bind
++#   define bind                bind_used_without_including_sys_socket_h
++#   undef getpeername
++#   define getpeername         getpeername_used_without_including_sys_socket_h
++#   undef getsockname
++#   define getsockname         getsockname_used_without_including_sys_socket_h
++#   undef getsockopt
++#   define getsockopt          getsockopt_used_without_including_sys_socket_h
++#   undef listen
++#   define listen              listen_used_without_including_sys_socket_h
++#   undef recv
++#   define recv                recv_used_without_including_sys_socket_h
++#   undef send
++#   define send                send_used_without_including_sys_socket_h
++#   undef recvfrom
++#   define recvfrom            recvfrom_used_without_including_sys_socket_h
++#   undef sendto
++#   define sendto              sendto_used_without_including_sys_socket_h
++#   undef setsockopt
++#   define setsockopt          setsockopt_used_without_including_sys_socket_h
++#   undef shutdown
++#   define shutdown            shutdown_used_without_including_sys_socket_h
++#  else
++     _GL_WARN_ON_USE (socket,
++                      "socket() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (connect,
++                      "connect() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (accept,
++                      "accept() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (bind,
++                      "bind() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (getpeername,
++                      "getpeername() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (getsockname,
++                      "getsockname() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (getsockopt,
++                      "getsockopt() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (listen,
++                      "listen() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (recv,
++                      "recv() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (send,
++                      "send() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (recvfrom,
++                      "recvfrom() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (sendto,
++                      "sendto() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (setsockopt,
++                      "setsockopt() used without including <sys/socket.h>");
++     _GL_WARN_ON_USE (shutdown,
++                      "shutdown() used without including <sys/socket.h>");
++#  endif
++# endif
++# if !defined _@GUARD_PREFIX@_SYS_SELECT_H
++#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#   undef select
++#   define select select_used_without_including_sys_select_h
++#  else
++     _GL_WARN_ON_USE (select,
++                      "select() used without including <sys/select.h>");
++#  endif
++# endif
++#endif
++
++#endif /* _@GUARD_PREFIX@_SYS_TIME_H */
++#endif /* _CYGWIN_SYS_TIME_H */
++#endif /* _@GUARD_PREFIX@_SYS_TIME_H */
+diff --git a/grub-core/gnulib/sys_types.in.h b/grub-core/gnulib/sys_types.in.h
+index d7da35623b1..9520c09030c 100644
+--- a/grub-core/gnulib/sys_types.in.h
++++ b/grub-core/gnulib/sys_types.in.h
+@@ -23,7 +23,9 @@
+ #ifndef _@GUARD_PREFIX@_SYS_TYPES_H
+ 
+ /* The include_next requires a split double-inclusion guard.  */
++# define _GL_INCLUDING_SYS_TYPES_H
+ #@INCLUDE_NEXT@ @NEXT_SYS_TYPES_H@
++# undef _GL_INCLUDING_SYS_TYPES_H
+ 
+ #ifndef _@GUARD_PREFIX@_SYS_TYPES_H
+ #define _@GUARD_PREFIX@_SYS_TYPES_H
+diff --git a/grub-core/gnulib/time.h b/grub-core/gnulib/time.h
+new file mode 100644
+index 00000000000..b9203d5569a
+--- /dev/null
++++ b/grub-core/gnulib/time.h
+@@ -0,0 +1,586 @@
++/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
++/* A more-standard <time.h>.
++
++   Copyright (C) 2007-2014 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 3, 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, see <http://www.gnu.org/licenses/>.  */
++
++#if __GNUC__ >= 3
++#pragma GCC system_header
++#endif
++
++
++/* Don't get in the way of glibc when it includes time.h merely to
++   declare a few standard symbols, rather than to declare all the
++   symbols.  Also, Solaris 8 <time.h> eventually includes itself
++   recursively; if that is happening, just include the system <time.h>
++   without adding our own declarations.  */
++#if (defined __need_time_t || defined __need_clock_t \
++     || defined __need_timespec \
++     || defined _GL_TIME_H)
++
++# include_next <time.h>
++
++#else
++
++# define _GL_TIME_H
++
++# include_next <time.h>
++
++/* NetBSD 5.0 mis-defines NULL.  */
++# include <stddef.h>
++
++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
++#ifndef _GL_CXXDEFS_H
++#define _GL_CXXDEFS_H
++
++/* The three most frequent use cases of these macros are:
++
++   * For providing a substitute for a function that is missing on some
++     platforms, but is declared and works fine on the platforms on which
++     it exists:
++
++       #if @GNULIB_FOO@
++       # if !@HAVE_FOO@
++       _GL_FUNCDECL_SYS (foo, ...);
++       # endif
++       _GL_CXXALIAS_SYS (foo, ...);
++       _GL_CXXALIASWARN (foo);
++       #elif defined GNULIB_POSIXCHECK
++       ...
++       #endif
++
++   * For providing a replacement for a function that exists on all platforms,
++     but is broken/insufficient and needs to be replaced on some platforms:
++
++       #if @GNULIB_FOO@
++       # if @REPLACE_FOO@
++       #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++       #   undef foo
++       #   define foo rpl_foo
++       #  endif
++       _GL_FUNCDECL_RPL (foo, ...);
++       _GL_CXXALIAS_RPL (foo, ...);
++       # else
++       _GL_CXXALIAS_SYS (foo, ...);
++       # endif
++       _GL_CXXALIASWARN (foo);
++       #elif defined GNULIB_POSIXCHECK
++       ...
++       #endif
++
++   * For providing a replacement for a function that exists on some platforms
++     but is broken/insufficient and needs to be replaced on some of them and
++     is additionally either missing or undeclared on some other platforms:
++
++       #if @GNULIB_FOO@
++       # if @REPLACE_FOO@
++       #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++       #   undef foo
++       #   define foo rpl_foo
++       #  endif
++       _GL_FUNCDECL_RPL (foo, ...);
++       _GL_CXXALIAS_RPL (foo, ...);
++       # else
++       #  if !@HAVE_FOO@   or   if !@HAVE_DECL_FOO@
++       _GL_FUNCDECL_SYS (foo, ...);
++       #  endif
++       _GL_CXXALIAS_SYS (foo, ...);
++       # endif
++       _GL_CXXALIASWARN (foo);
++       #elif defined GNULIB_POSIXCHECK
++       ...
++       #endif
++*/
++
++/* _GL_EXTERN_C declaration;
++   performs the declaration with C linkage.  */
++#if defined __cplusplus
++# define _GL_EXTERN_C extern "C"
++#else
++# define _GL_EXTERN_C extern
++#endif
++
++/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes);
++   declares a replacement function, named rpl_func, with the given prototype,
++   consisting of return type, parameters, and attributes.
++   Example:
++     _GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...)
++                                  _GL_ARG_NONNULL ((1)));
++ */
++#define _GL_FUNCDECL_RPL(func,rettype,parameters_and_attributes) \
++  _GL_FUNCDECL_RPL_1 (rpl_##func, rettype, parameters_and_attributes)
++#define _GL_FUNCDECL_RPL_1(rpl_func,rettype,parameters_and_attributes) \
++  _GL_EXTERN_C rettype rpl_func parameters_and_attributes
++
++/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes);
++   declares the system function, named func, with the given prototype,
++   consisting of return type, parameters, and attributes.
++   Example:
++     _GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...)
++                                  _GL_ARG_NONNULL ((1)));
++ */
++#define _GL_FUNCDECL_SYS(func,rettype,parameters_and_attributes) \
++  _GL_EXTERN_C rettype func parameters_and_attributes
++
++/* _GL_CXXALIAS_RPL (func, rettype, parameters);
++   declares a C++ alias called GNULIB_NAMESPACE::func
++   that redirects to rpl_func, if GNULIB_NAMESPACE is defined.
++   Example:
++     _GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
++ */
++#define _GL_CXXALIAS_RPL(func,rettype,parameters) \
++  _GL_CXXALIAS_RPL_1 (func, rpl_##func, rettype, parameters)
++#if defined __cplusplus && defined GNULIB_NAMESPACE
++# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
++    namespace GNULIB_NAMESPACE                                \
++    {                                                         \
++      rettype (*const func) parameters = ::rpl_func;          \
++    }                                                         \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#else
++# define _GL_CXXALIAS_RPL_1(func,rpl_func,rettype,parameters) \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#endif
++
++/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters);
++   is like  _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters);
++   except that the C function rpl_func may have a slightly different
++   declaration.  A cast is used to silence the "invalid conversion" error
++   that would otherwise occur.  */
++#if defined __cplusplus && defined GNULIB_NAMESPACE
++# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
++    namespace GNULIB_NAMESPACE                                     \
++    {                                                              \
++      rettype (*const func) parameters =                           \
++        reinterpret_cast<rettype(*)parameters>(::rpl_func);        \
++    }                                                              \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#else
++# define _GL_CXXALIAS_RPL_CAST_1(func,rpl_func,rettype,parameters) \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#endif
++
++/* _GL_CXXALIAS_SYS (func, rettype, parameters);
++   declares a C++ alias called GNULIB_NAMESPACE::func
++   that redirects to the system provided function func, if GNULIB_NAMESPACE
++   is defined.
++   Example:
++     _GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
++ */
++#if defined __cplusplus && defined GNULIB_NAMESPACE
++  /* If we were to write
++       rettype (*const func) parameters = ::func;
++     like above in _GL_CXXALIAS_RPL_1, the compiler could optimize calls
++     better (remove an indirection through a 'static' pointer variable),
++     but then the _GL_CXXALIASWARN macro below would cause a warning not only
++     for uses of ::func but also for uses of GNULIB_NAMESPACE::func.  */
++# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
++    namespace GNULIB_NAMESPACE                     \
++    {                                              \
++      static rettype (*func) parameters = ::func;  \
++    }                                              \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#else
++# define _GL_CXXALIAS_SYS(func,rettype,parameters) \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#endif
++
++/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters);
++   is like  _GL_CXXALIAS_SYS (func, rettype, parameters);
++   except that the C function func may have a slightly different declaration.
++   A cast is used to silence the "invalid conversion" error that would
++   otherwise occur.  */
++#if defined __cplusplus && defined GNULIB_NAMESPACE
++# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
++    namespace GNULIB_NAMESPACE                          \
++    {                                                   \
++      static rettype (*func) parameters =               \
++        reinterpret_cast<rettype(*)parameters>(::func); \
++    }                                                   \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#else
++# define _GL_CXXALIAS_SYS_CAST(func,rettype,parameters) \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#endif
++
++/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2);
++   is like  _GL_CXXALIAS_SYS (func, rettype, parameters);
++   except that the C function is picked among a set of overloaded functions,
++   namely the one with rettype2 and parameters2.  Two consecutive casts
++   are used to silence the "cannot find a match" and "invalid conversion"
++   errors that would otherwise occur.  */
++#if defined __cplusplus && defined GNULIB_NAMESPACE
++  /* The outer cast must be a reinterpret_cast.
++     The inner cast: When the function is defined as a set of overloaded
++     functions, it works as a static_cast<>, choosing the designated variant.
++     When the function is defined as a single variant, it works as a
++     reinterpret_cast<>. The parenthesized cast syntax works both ways.  */
++# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
++    namespace GNULIB_NAMESPACE                                                \
++    {                                                                         \
++      static rettype (*func) parameters =                                     \
++        reinterpret_cast<rettype(*)parameters>(                               \
++          (rettype2(*)parameters2)(::func));                                  \
++    }                                                                         \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#else
++# define _GL_CXXALIAS_SYS_CAST2(func,rettype,parameters,rettype2,parameters2) \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#endif
++
++/* _GL_CXXALIASWARN (func);
++   causes a warning to be emitted when ::func is used but not when
++   GNULIB_NAMESPACE::func is used.  func must be defined without overloaded
++   variants.  */
++#if defined __cplusplus && defined GNULIB_NAMESPACE
++# define _GL_CXXALIASWARN(func) \
++   _GL_CXXALIASWARN_1 (func, GNULIB_NAMESPACE)
++# define _GL_CXXALIASWARN_1(func,namespace) \
++   _GL_CXXALIASWARN_2 (func, namespace)
++/* To work around GCC bug <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,
++   we enable the warning only when not optimizing.  */
++# if !__OPTIMIZE__
++#  define _GL_CXXALIASWARN_2(func,namespace) \
++    _GL_WARN_ON_USE (func, \
++                     "The symbol ::" #func " refers to the system function. " \
++                     "Use " #namespace "::" #func " instead.")
++# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
++#  define _GL_CXXALIASWARN_2(func,namespace) \
++     extern __typeof__ (func) func
++# else
++#  define _GL_CXXALIASWARN_2(func,namespace) \
++     _GL_EXTERN_C int _gl_cxxalias_dummy
++# endif
++#else
++# define _GL_CXXALIASWARN(func) \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#endif
++
++/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes);
++   causes a warning to be emitted when the given overloaded variant of ::func
++   is used but not when GNULIB_NAMESPACE::func is used.  */
++#if defined __cplusplus && defined GNULIB_NAMESPACE
++# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
++   _GL_CXXALIASWARN1_1 (func, rettype, parameters_and_attributes, \
++                        GNULIB_NAMESPACE)
++# define _GL_CXXALIASWARN1_1(func,rettype,parameters_and_attributes,namespace) \
++   _GL_CXXALIASWARN1_2 (func, rettype, parameters_and_attributes, namespace)
++/* To work around GCC bug <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,
++   we enable the warning only when not optimizing.  */
++# if !__OPTIMIZE__
++#  define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
++    _GL_WARN_ON_USE_CXX (func, rettype, parameters_and_attributes, \
++                         "The symbol ::" #func " refers to the system function. " \
++                         "Use " #namespace "::" #func " instead.")
++# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
++#  define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
++     extern __typeof__ (func) func
++# else
++#  define _GL_CXXALIASWARN1_2(func,rettype,parameters_and_attributes,namespace) \
++     _GL_EXTERN_C int _gl_cxxalias_dummy
++# endif
++#else
++# define _GL_CXXALIASWARN1(func,rettype,parameters_and_attributes) \
++    _GL_EXTERN_C int _gl_cxxalias_dummy
++#endif
++
++#endif /* _GL_CXXDEFS_H */
++
++/* The definition of _GL_ARG_NONNULL is copied here.  */
++/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools
++   that the values passed as arguments n, ..., m must be non-NULL pointers.
++   n = 1 stands for the first argument, n = 2 for the second argument etc.  */
++#ifndef _GL_ARG_NONNULL
++# if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ > 3
++#  define _GL_ARG_NONNULL(params) __attribute__ ((__nonnull__ params))
++# else
++#  define _GL_ARG_NONNULL(params)
++# endif
++#endif
++
++/* The definition of _GL_WARN_ON_USE is copied here.  */
++#ifndef _GL_WARN_ON_USE
++
++# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)
++/* A compiler attribute is available in gcc versions 4.3.0 and later.  */
++#  define _GL_WARN_ON_USE(function, message) \
++extern __typeof__ (function) function __attribute__ ((__warning__ (message)))
++# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
++/* Verify the existence of the function.  */
++#  define _GL_WARN_ON_USE(function, message) \
++extern __typeof__ (function) function
++# else /* Unsupported.  */
++#  define _GL_WARN_ON_USE(function, message) \
++_GL_WARN_EXTERN_C int _gl_warn_on_use
++# endif
++#endif
++
++/* _GL_WARN_ON_USE_CXX (function, rettype, parameters_and_attributes, "string")
++   is like _GL_WARN_ON_USE (function, "string"), except that the function is
++   declared with the given prototype, consisting of return type, parameters,
++   and attributes.
++   This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does
++   not work in this case.  */
++#ifndef _GL_WARN_ON_USE_CXX
++# if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)
++#  define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \
++extern rettype function parameters_and_attributes \
++     __attribute__ ((__warning__ (msg)))
++# elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
++/* Verify the existence of the function.  */
++#  define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \
++extern rettype function parameters_and_attributes
++# else /* Unsupported.  */
++#  define _GL_WARN_ON_USE_CXX(function,rettype,parameters_and_attributes,msg) \
++_GL_WARN_EXTERN_C int _gl_warn_on_use
++# endif
++#endif
++
++/* _GL_WARN_EXTERN_C declaration;
++   performs the declaration with C linkage.  */
++#ifndef _GL_WARN_EXTERN_C
++# if defined __cplusplus
++#  define _GL_WARN_EXTERN_C extern "C"
++# else
++#  define _GL_WARN_EXTERN_C extern
++# endif
++#endif
++
++/* Some systems don't define struct timespec (e.g., AIX 4.1, Ultrix 4.3).
++   Or they define it with the wrong member names or define it in <sys/time.h>
++   (e.g., FreeBSD circa 1997).  Stock Mingw prior to 3.0 does not define it,
++   but the pthreads-win32 library defines it in <pthread.h>.  */
++# if ! 1
++#  if 0
++#   include <sys/time.h>
++#  elif 0
++#   include <pthread.h>
++#  else
++
++#   ifdef __cplusplus
++extern "C" {
++#   endif
++
++#   if !GNULIB_defined_struct_timespec
++#    undef timespec
++#    define timespec rpl_timespec
++struct timespec
++{
++  time_t tv_sec;
++  long int tv_nsec;
++};
++#    define GNULIB_defined_struct_timespec 1
++#   endif
++
++#   ifdef __cplusplus
++}
++#   endif
++
++#  endif
++# endif
++
++# if !GNULIB_defined_struct_time_t_must_be_integral
++/* Per http://austingroupbugs.net/view.php?id=327, POSIX requires
++   time_t to be an integer type, even though C99 permits floating
++   point.  We don't know of any implementation that uses floating
++   point, and it is much easier to write code that doesn't have to
++   worry about that corner case, so we force the issue.  */
++struct __time_t_must_be_integral {
++  unsigned int __floating_time_t_unsupported : (time_t) 1;
++};
++#  define GNULIB_defined_struct_time_t_must_be_integral 1
++# endif
++
++/* Sleep for at least RQTP seconds unless interrupted,  If interrupted,
++   return -1 and store the remaining time into RMTP.  See
++   <http://www.opengroup.org/susv3xsh/nanosleep.html>.  */
++# if 0
++#  if GNULIB_PORTCHECK
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    define nanosleep rpl_nanosleep
++#   endif
++_GL_FUNCDECL_RPL (nanosleep, int,
++                  (struct timespec const *__rqtp, struct timespec *__rmtp)
++                  _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (nanosleep, int,
++                  (struct timespec const *__rqtp, struct timespec *__rmtp));
++#  else
++#   if ! 1
++_GL_FUNCDECL_SYS (nanosleep, int,
++                  (struct timespec const *__rqtp, struct timespec *__rmtp)
++                  _GL_ARG_NONNULL ((1)));
++#   endif
++_GL_CXXALIAS_SYS (nanosleep, int,
++                  (struct timespec const *__rqtp, struct timespec *__rmtp));
++#  endif
++_GL_CXXALIASWARN (nanosleep);
++# endif
++
++/* Return the 'time_t' representation of TP and normalize TP.  */
++# if 0
++#  if GNULIB_PORTCHECK
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    define mktime rpl_mktime
++#   endif
++_GL_FUNCDECL_RPL (mktime, time_t, (struct tm *__tp) _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (mktime, time_t, (struct tm *__tp));
++#  else
++_GL_CXXALIAS_SYS (mktime, time_t, (struct tm *__tp));
++#  endif
++_GL_CXXALIASWARN (mktime);
++# endif
++
++/* Convert TIMER to RESULT, assuming local time and UTC respectively.  See
++   <http://www.opengroup.org/susv3xsh/localtime_r.html> and
++   <http://www.opengroup.org/susv3xsh/gmtime_r.html>.  */
++# if 0
++#  if GNULIB_PORTCHECK
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    undef localtime_r
++#    define localtime_r rpl_localtime_r
++#   endif
++_GL_FUNCDECL_RPL (localtime_r, struct tm *, (time_t const *restrict __timer,
++                                             struct tm *restrict __result)
++                                            _GL_ARG_NONNULL ((1, 2)));
++_GL_CXXALIAS_RPL (localtime_r, struct tm *, (time_t const *restrict __timer,
++                                             struct tm *restrict __result));
++#  else
++#   if ! 1
++_GL_FUNCDECL_SYS (localtime_r, struct tm *, (time_t const *restrict __timer,
++                                             struct tm *restrict __result)
++                                            _GL_ARG_NONNULL ((1, 2)));
++#   endif
++_GL_CXXALIAS_SYS (localtime_r, struct tm *, (time_t const *restrict __timer,
++                                             struct tm *restrict __result));
++#  endif
++#  if 1
++_GL_CXXALIASWARN (localtime_r);
++#  endif
++#  if GNULIB_PORTCHECK
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    undef gmtime_r
++#    define gmtime_r rpl_gmtime_r
++#   endif
++_GL_FUNCDECL_RPL (gmtime_r, struct tm *, (time_t const *restrict __timer,
++                                          struct tm *restrict __result)
++                                         _GL_ARG_NONNULL ((1, 2)));
++_GL_CXXALIAS_RPL (gmtime_r, struct tm *, (time_t const *restrict __timer,
++                                          struct tm *restrict __result));
++#  else
++#   if ! 1
++_GL_FUNCDECL_SYS (gmtime_r, struct tm *, (time_t const *restrict __timer,
++                                          struct tm *restrict __result)
++                                         _GL_ARG_NONNULL ((1, 2)));
++#   endif
++_GL_CXXALIAS_SYS (gmtime_r, struct tm *, (time_t const *restrict __timer,
++                                          struct tm *restrict __result));
++#  endif
++#  if 1
++_GL_CXXALIASWARN (gmtime_r);
++#  endif
++# endif
++
++/* Convert TIMER to RESULT, assuming local time and UTC respectively.  See
++   <http://www.opengroup.org/susv3xsh/localtime.html> and
++   <http://www.opengroup.org/susv3xsh/gmtime.html>.  */
++# if 1
++#  if 0
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    undef localtime
++#    define localtime rpl_localtime
++#   endif
++_GL_FUNCDECL_RPL (localtime, struct tm *, (time_t const *__timer)
++		                          _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (localtime, struct tm *, (time_t const *__timer));
++#  else
++_GL_CXXALIAS_SYS (localtime, struct tm *, (time_t const *__timer));
++#  endif
++_GL_CXXALIASWARN (localtime);
++# endif
++
++# if 1
++#  if 0
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    undef gmtime
++#    define gmtime rpl_gmtime
++#   endif
++_GL_FUNCDECL_RPL (gmtime, struct tm *, (time_t const *__timer)
++                                       _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (gmtime, struct tm *, (time_t const *__timer));
++#  else
++_GL_CXXALIAS_SYS (gmtime, struct tm *, (time_t const *__timer));
++#  endif
++_GL_CXXALIASWARN (gmtime);
++# endif
++
++/* Parse BUF as a time stamp, assuming FORMAT specifies its layout, and store
++   the resulting broken-down time into TM.  See
++   <http://www.opengroup.org/susv3xsh/strptime.html>.  */
++# if 0
++#  if ! 1
++_GL_FUNCDECL_SYS (strptime, char *, (char const *restrict __buf,
++                                     char const *restrict __format,
++                                     struct tm *restrict __tm)
++                                    _GL_ARG_NONNULL ((1, 2, 3)));
++#  endif
++_GL_CXXALIAS_SYS (strptime, char *, (char const *restrict __buf,
++                                     char const *restrict __format,
++                                     struct tm *restrict __tm));
++_GL_CXXALIASWARN (strptime);
++# endif
++
++/* Convert TM to a time_t value, assuming UTC.  */
++# if 0
++#  if GNULIB_PORTCHECK
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    undef timegm
++#    define timegm rpl_timegm
++#   endif
++_GL_FUNCDECL_RPL (timegm, time_t, (struct tm *__tm) _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (timegm, time_t, (struct tm *__tm));
++#  else
++#   if ! 1
++_GL_FUNCDECL_SYS (timegm, time_t, (struct tm *__tm) _GL_ARG_NONNULL ((1)));
++#   endif
++_GL_CXXALIAS_SYS (timegm, time_t, (struct tm *__tm));
++#  endif
++_GL_CXXALIASWARN (timegm);
++# endif
++
++/* Encourage applications to avoid unsafe functions that can overrun
++   buffers when given outlandish struct tm values.  Portable
++   applications should use strftime (or even sprintf) instead.  */
++# if defined GNULIB_POSIXCHECK
++#  undef asctime
++_GL_WARN_ON_USE (asctime, "asctime can overrun buffers in some cases - "
++                 "better use strftime (or even sprintf) instead");
++# endif
++# if defined GNULIB_POSIXCHECK
++#  undef asctime_r
++_GL_WARN_ON_USE (asctime, "asctime_r can overrun buffers in some cases - "
++                 "better use strftime (or even sprintf) instead");
++# endif
++# if defined GNULIB_POSIXCHECK
++#  undef ctime
++_GL_WARN_ON_USE (asctime, "ctime can overrun buffers in some cases - "
++                 "better use strftime (or even sprintf) instead");
++# endif
++# if defined GNULIB_POSIXCHECK
++#  undef ctime_r
++_GL_WARN_ON_USE (asctime, "ctime_r can overrun buffers in some cases - "
++                 "better use strftime (or even sprintf) instead");
++# endif
++
++#endif
+diff --git a/grub-core/gnulib/time.in.h b/grub-core/gnulib/time.in.h
+new file mode 100644
+index 00000000000..81abdf46e0b
+--- /dev/null
++++ b/grub-core/gnulib/time.in.h
+@@ -0,0 +1,274 @@
++/* A more-standard <time.h>.
++
++   Copyright (C) 2007-2014 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 3, 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, see <http://www.gnu.org/licenses/>.  */
++
++#if __GNUC__ >= 3
++@PRAGMA_SYSTEM_HEADER@
++#endif
++@PRAGMA_COLUMNS@
++
++/* Don't get in the way of glibc when it includes time.h merely to
++   declare a few standard symbols, rather than to declare all the
++   symbols.  Also, Solaris 8 <time.h> eventually includes itself
++   recursively; if that is happening, just include the system <time.h>
++   without adding our own declarations.  */
++#if (defined __need_time_t || defined __need_clock_t \
++     || defined __need_timespec \
++     || defined _@GUARD_PREFIX@_TIME_H)
++
++# @INCLUDE_NEXT@ @NEXT_TIME_H@
++
++#else
++
++# define _@GUARD_PREFIX@_TIME_H
++
++# @INCLUDE_NEXT@ @NEXT_TIME_H@
++
++/* NetBSD 5.0 mis-defines NULL.  */
++# include <stddef.h>
++
++/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
++
++/* The definition of _GL_ARG_NONNULL is copied here.  */
++
++/* The definition of _GL_WARN_ON_USE is copied here.  */
++
++/* Some systems don't define struct timespec (e.g., AIX 4.1, Ultrix 4.3).
++   Or they define it with the wrong member names or define it in <sys/time.h>
++   (e.g., FreeBSD circa 1997).  Stock Mingw prior to 3.0 does not define it,
++   but the pthreads-win32 library defines it in <pthread.h>.  */
++# if ! @TIME_H_DEFINES_STRUCT_TIMESPEC@
++#  if @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@
++#   include <sys/time.h>
++#  elif @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@
++#   include <pthread.h>
++#  else
++
++#   ifdef __cplusplus
++extern "C" {
++#   endif
++
++#   if !GNULIB_defined_struct_timespec
++#    undef timespec
++#    define timespec rpl_timespec
++struct timespec
++{
++  time_t tv_sec;
++  long int tv_nsec;
++};
++#    define GNULIB_defined_struct_timespec 1
++#   endif
++
++#   ifdef __cplusplus
++}
++#   endif
++
++#  endif
++# endif
++
++# if !GNULIB_defined_struct_time_t_must_be_integral
++/* Per http://austingroupbugs.net/view.php?id=327, POSIX requires
++   time_t to be an integer type, even though C99 permits floating
++   point.  We don't know of any implementation that uses floating
++   point, and it is much easier to write code that doesn't have to
++   worry about that corner case, so we force the issue.  */
++struct __time_t_must_be_integral {
++  unsigned int __floating_time_t_unsupported : (time_t) 1;
++};
++#  define GNULIB_defined_struct_time_t_must_be_integral 1
++# endif
++
++/* Sleep for at least RQTP seconds unless interrupted,  If interrupted,
++   return -1 and store the remaining time into RMTP.  See
++   <http://www.opengroup.org/susv3xsh/nanosleep.html>.  */
++# if @GNULIB_NANOSLEEP@
++#  if @REPLACE_NANOSLEEP@
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    define nanosleep rpl_nanosleep
++#   endif
++_GL_FUNCDECL_RPL (nanosleep, int,
++                  (struct timespec const *__rqtp, struct timespec *__rmtp)
++                  _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (nanosleep, int,
++                  (struct timespec const *__rqtp, struct timespec *__rmtp));
++#  else
++#   if ! @HAVE_NANOSLEEP@
++_GL_FUNCDECL_SYS (nanosleep, int,
++                  (struct timespec const *__rqtp, struct timespec *__rmtp)
++                  _GL_ARG_NONNULL ((1)));
++#   endif
++_GL_CXXALIAS_SYS (nanosleep, int,
++                  (struct timespec const *__rqtp, struct timespec *__rmtp));
++#  endif
++_GL_CXXALIASWARN (nanosleep);
++# endif
++
++/* Return the 'time_t' representation of TP and normalize TP.  */
++# if @GNULIB_MKTIME@
++#  if @REPLACE_MKTIME@
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    define mktime rpl_mktime
++#   endif
++_GL_FUNCDECL_RPL (mktime, time_t, (struct tm *__tp) _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (mktime, time_t, (struct tm *__tp));
++#  else
++_GL_CXXALIAS_SYS (mktime, time_t, (struct tm *__tp));
++#  endif
++_GL_CXXALIASWARN (mktime);
++# endif
++
++/* Convert TIMER to RESULT, assuming local time and UTC respectively.  See
++   <http://www.opengroup.org/susv3xsh/localtime_r.html> and
++   <http://www.opengroup.org/susv3xsh/gmtime_r.html>.  */
++# if @GNULIB_TIME_R@
++#  if @REPLACE_LOCALTIME_R@
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    undef localtime_r
++#    define localtime_r rpl_localtime_r
++#   endif
++_GL_FUNCDECL_RPL (localtime_r, struct tm *, (time_t const *restrict __timer,
++                                             struct tm *restrict __result)
++                                            _GL_ARG_NONNULL ((1, 2)));
++_GL_CXXALIAS_RPL (localtime_r, struct tm *, (time_t const *restrict __timer,
++                                             struct tm *restrict __result));
++#  else
++#   if ! @HAVE_DECL_LOCALTIME_R@
++_GL_FUNCDECL_SYS (localtime_r, struct tm *, (time_t const *restrict __timer,
++                                             struct tm *restrict __result)
++                                            _GL_ARG_NONNULL ((1, 2)));
++#   endif
++_GL_CXXALIAS_SYS (localtime_r, struct tm *, (time_t const *restrict __timer,
++                                             struct tm *restrict __result));
++#  endif
++#  if @HAVE_DECL_LOCALTIME_R@
++_GL_CXXALIASWARN (localtime_r);
++#  endif
++#  if @REPLACE_LOCALTIME_R@
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    undef gmtime_r
++#    define gmtime_r rpl_gmtime_r
++#   endif
++_GL_FUNCDECL_RPL (gmtime_r, struct tm *, (time_t const *restrict __timer,
++                                          struct tm *restrict __result)
++                                         _GL_ARG_NONNULL ((1, 2)));
++_GL_CXXALIAS_RPL (gmtime_r, struct tm *, (time_t const *restrict __timer,
++                                          struct tm *restrict __result));
++#  else
++#   if ! @HAVE_DECL_LOCALTIME_R@
++_GL_FUNCDECL_SYS (gmtime_r, struct tm *, (time_t const *restrict __timer,
++                                          struct tm *restrict __result)
++                                         _GL_ARG_NONNULL ((1, 2)));
++#   endif
++_GL_CXXALIAS_SYS (gmtime_r, struct tm *, (time_t const *restrict __timer,
++                                          struct tm *restrict __result));
++#  endif
++#  if @HAVE_DECL_LOCALTIME_R@
++_GL_CXXALIASWARN (gmtime_r);
++#  endif
++# endif
++
++/* Convert TIMER to RESULT, assuming local time and UTC respectively.  See
++   <http://www.opengroup.org/susv3xsh/localtime.html> and
++   <http://www.opengroup.org/susv3xsh/gmtime.html>.  */
++# if @GNULIB_GETTIMEOFDAY@
++#  if @REPLACE_LOCALTIME@
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    undef localtime
++#    define localtime rpl_localtime
++#   endif
++_GL_FUNCDECL_RPL (localtime, struct tm *, (time_t const *__timer)
++		                          _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (localtime, struct tm *, (time_t const *__timer));
++#  else
++_GL_CXXALIAS_SYS (localtime, struct tm *, (time_t const *__timer));
++#  endif
++_GL_CXXALIASWARN (localtime);
++# endif
++
++# if @GNULIB_GETTIMEOFDAY@
++#  if @REPLACE_GMTIME@
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    undef gmtime
++#    define gmtime rpl_gmtime
++#   endif
++_GL_FUNCDECL_RPL (gmtime, struct tm *, (time_t const *__timer)
++                                       _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (gmtime, struct tm *, (time_t const *__timer));
++#  else
++_GL_CXXALIAS_SYS (gmtime, struct tm *, (time_t const *__timer));
++#  endif
++_GL_CXXALIASWARN (gmtime);
++# endif
++
++/* Parse BUF as a time stamp, assuming FORMAT specifies its layout, and store
++   the resulting broken-down time into TM.  See
++   <http://www.opengroup.org/susv3xsh/strptime.html>.  */
++# if @GNULIB_STRPTIME@
++#  if ! @HAVE_STRPTIME@
++_GL_FUNCDECL_SYS (strptime, char *, (char const *restrict __buf,
++                                     char const *restrict __format,
++                                     struct tm *restrict __tm)
++                                    _GL_ARG_NONNULL ((1, 2, 3)));
++#  endif
++_GL_CXXALIAS_SYS (strptime, char *, (char const *restrict __buf,
++                                     char const *restrict __format,
++                                     struct tm *restrict __tm));
++_GL_CXXALIASWARN (strptime);
++# endif
++
++/* Convert TM to a time_t value, assuming UTC.  */
++# if @GNULIB_TIMEGM@
++#  if @REPLACE_TIMEGM@
++#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
++#    undef timegm
++#    define timegm rpl_timegm
++#   endif
++_GL_FUNCDECL_RPL (timegm, time_t, (struct tm *__tm) _GL_ARG_NONNULL ((1)));
++_GL_CXXALIAS_RPL (timegm, time_t, (struct tm *__tm));
++#  else
++#   if ! @HAVE_TIMEGM@
++_GL_FUNCDECL_SYS (timegm, time_t, (struct tm *__tm) _GL_ARG_NONNULL ((1)));
++#   endif
++_GL_CXXALIAS_SYS (timegm, time_t, (struct tm *__tm));
++#  endif
++_GL_CXXALIASWARN (timegm);
++# endif
++
++/* Encourage applications to avoid unsafe functions that can overrun
++   buffers when given outlandish struct tm values.  Portable
++   applications should use strftime (or even sprintf) instead.  */
++# if defined GNULIB_POSIXCHECK
++#  undef asctime
++_GL_WARN_ON_USE (asctime, "asctime can overrun buffers in some cases - "
++                 "better use strftime (or even sprintf) instead");
++# endif
++# if defined GNULIB_POSIXCHECK
++#  undef asctime_r
++_GL_WARN_ON_USE (asctime, "asctime_r can overrun buffers in some cases - "
++                 "better use strftime (or even sprintf) instead");
++# endif
++# if defined GNULIB_POSIXCHECK
++#  undef ctime
++_GL_WARN_ON_USE (asctime, "ctime can overrun buffers in some cases - "
++                 "better use strftime (or even sprintf) instead");
++# endif
++# if defined GNULIB_POSIXCHECK
++#  undef ctime_r
++_GL_WARN_ON_USE (asctime, "ctime_r can overrun buffers in some cases - "
++                 "better use strftime (or even sprintf) instead");
++# endif
++
++#endif
+diff --git a/include/grub/osdep/hostfile_aros.h b/include/grub/osdep/hostfile_aros.h
+index a059c0fa40a..161fbb7bdfd 100644
+--- a/include/grub/osdep/hostfile_aros.h
++++ b/include/grub/osdep/hostfile_aros.h
+@@ -68,6 +68,12 @@ grub_util_rename (const char *from, const char *to)
+   return rename (from, to);
+ }
+ 
++static inline ssize_t
++grub_util_readlink (const char *name, char *buf, size_t bufsize)
++{
++  return readlink(name, buf, bufsize);
++}
++
+ #define grub_util_mkdir(a) mkdir ((a), 0755)
+ 
+ struct grub_util_fd
+diff --git a/include/grub/osdep/hostfile_unix.h b/include/grub/osdep/hostfile_unix.h
+index 9ffe46fa3ca..17cd3aa8b30 100644
+--- a/include/grub/osdep/hostfile_unix.h
++++ b/include/grub/osdep/hostfile_unix.h
+@@ -71,6 +71,12 @@ grub_util_rename (const char *from, const char *to)
+   return rename (from, to);
+ }
+ 
++static inline ssize_t
++grub_util_readlink (const char *name, char *buf, size_t bufsize)
++{
++  return readlink(name, buf, bufsize);
++}
++
+ #define grub_util_mkdir(a) mkdir ((a), 0755)
+ 
+ #if defined (__NetBSD__)
+diff --git a/include/grub/osdep/hostfile_windows.h b/include/grub/osdep/hostfile_windows.h
+index bf6451b6db4..8c92d0591bb 100644
+--- a/include/grub/osdep/hostfile_windows.h
++++ b/include/grub/osdep/hostfile_windows.h
+@@ -41,6 +41,8 @@ typedef struct grub_util_fd_dir *grub_util_fd_dir_t;
+ 
+ int
+ grub_util_rename (const char *from, const char *to);
++ssize_t
++grub_util_readlink (const char *name, char *buf, size_t bufsize);
+ int
+ grub_util_unlink (const char *name);
+ void
+diff --git a/grub-core/gnulib/Makefile.am b/grub-core/gnulib/Makefile.am
+index 3444397fe37..b7c5e60e1c3 100644
+--- a/grub-core/gnulib/Makefile.am
++++ b/grub-core/gnulib/Makefile.am
+@@ -21,7 +21,7 @@
+ # the same distribution terms as the rest of that program.
+ #
+ # Generated by gnulib-tool.
+-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=grub-core/gnulib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files argp error fnmatch getdelim getline gettext progname regex
++# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=grub-core/gnulib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files argp error fnmatch getdelim getline gettext progname readlink regex
+ 
+ AUTOMAKE_OPTIONS = 1.5 gnits subdir-objects
+ 
+@@ -326,6 +326,15 @@ libgnu_a_SOURCES += gettext.h
+ 
+ ## end   gnulib module gettext-h
+ 
++## begin gnulib module gettimeofday
++
++
++EXTRA_DIST += gettimeofday.c
++
++EXTRA_libgnu_a_SOURCES += gettimeofday.c
++
++## end   gnulib module gettimeofday
++
+ ## begin gnulib module havelib
+ 
+ 
+@@ -596,6 +605,13 @@ EXTRA_libgnu_a_SOURCES += nl_langinfo.c
+ 
+ ## end   gnulib module nl_langinfo
+ 
++## begin gnulib module pathmax
++
++
++EXTRA_DIST += pathmax.h
++
++## end   gnulib module pathmax
++
+ ## begin gnulib module progname
+ 
+ libgnu_a_SOURCES += progname.h progname.c
+@@ -611,6 +627,15 @@ EXTRA_libgnu_a_SOURCES += rawmemchr.c
+ 
+ ## end   gnulib module rawmemchr
+ 
++## begin gnulib module readlink
++
++
++EXTRA_DIST += readlink.c
++
++EXTRA_libgnu_a_SOURCES += readlink.c
++
++## end   gnulib module readlink
++
+ ## begin gnulib module realloc-posix
+ 
+ 
+@@ -725,6 +750,15 @@ EXTRA_DIST += $(top_srcdir)/build-aux/snippet/warn-on-use.h
+ 
+ ## end   gnulib module snippet/warn-on-use
+ 
++## begin gnulib module stat
++
++
++EXTRA_DIST += stat.c
++
++EXTRA_libgnu_a_SOURCES += stat.c
++
++## end   gnulib module stat
++
+ ## begin gnulib module stdalign
+ 
+ BUILT_SOURCES += $(STDALIGN_H)
+@@ -1280,6 +1314,102 @@ libgnu_a_SOURCES += strnlen1.h strnlen1.c
+ 
+ ## end   gnulib module strnlen1
+ 
++## begin gnulib module sys_stat
++
++BUILT_SOURCES += sys/stat.h
++
++# We need the following in order to create <sys/stat.h> when the system
++# has one that is incomplete.
++sys/stat.h: sys_stat.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
++	$(AM_V_at)$(MKDIR_P) sys
++	$(AM_V_GEN)rm -f $@-t $@ && \
++	{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
++	  sed -e 's|@''GUARD_PREFIX''@|GL|g' \
++	      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
++	      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
++	      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
++	      -e 's|@''NEXT_SYS_STAT_H''@|$(NEXT_SYS_STAT_H)|g' \
++	      -e 's|@''WINDOWS_64_BIT_ST_SIZE''@|$(WINDOWS_64_BIT_ST_SIZE)|g' \
++	      -e 's/@''GNULIB_FCHMODAT''@/$(GNULIB_FCHMODAT)/g' \
++	      -e 's/@''GNULIB_FSTAT''@/$(GNULIB_FSTAT)/g' \
++	      -e 's/@''GNULIB_FSTATAT''@/$(GNULIB_FSTATAT)/g' \
++	      -e 's/@''GNULIB_FUTIMENS''@/$(GNULIB_FUTIMENS)/g' \
++	      -e 's/@''GNULIB_LCHMOD''@/$(GNULIB_LCHMOD)/g' \
++	      -e 's/@''GNULIB_LSTAT''@/$(GNULIB_LSTAT)/g' \
++	      -e 's/@''GNULIB_MKDIRAT''@/$(GNULIB_MKDIRAT)/g' \
++	      -e 's/@''GNULIB_MKFIFO''@/$(GNULIB_MKFIFO)/g' \
++	      -e 's/@''GNULIB_MKFIFOAT''@/$(GNULIB_MKFIFOAT)/g' \
++	      -e 's/@''GNULIB_MKNOD''@/$(GNULIB_MKNOD)/g' \
++	      -e 's/@''GNULIB_MKNODAT''@/$(GNULIB_MKNODAT)/g' \
++	      -e 's/@''GNULIB_STAT''@/$(GNULIB_STAT)/g' \
++	      -e 's/@''GNULIB_UTIMENSAT''@/$(GNULIB_UTIMENSAT)/g' \
++	      -e 's|@''HAVE_FCHMODAT''@|$(HAVE_FCHMODAT)|g' \
++	      -e 's|@''HAVE_FSTATAT''@|$(HAVE_FSTATAT)|g' \
++	      -e 's|@''HAVE_FUTIMENS''@|$(HAVE_FUTIMENS)|g' \
++	      -e 's|@''HAVE_LCHMOD''@|$(HAVE_LCHMOD)|g' \
++	      -e 's|@''HAVE_LSTAT''@|$(HAVE_LSTAT)|g' \
++	      -e 's|@''HAVE_MKDIRAT''@|$(HAVE_MKDIRAT)|g' \
++	      -e 's|@''HAVE_MKFIFO''@|$(HAVE_MKFIFO)|g' \
++	      -e 's|@''HAVE_MKFIFOAT''@|$(HAVE_MKFIFOAT)|g' \
++	      -e 's|@''HAVE_MKNOD''@|$(HAVE_MKNOD)|g' \
++	      -e 's|@''HAVE_MKNODAT''@|$(HAVE_MKNODAT)|g' \
++	      -e 's|@''HAVE_UTIMENSAT''@|$(HAVE_UTIMENSAT)|g' \
++	      -e 's|@''REPLACE_FSTAT''@|$(REPLACE_FSTAT)|g' \
++	      -e 's|@''REPLACE_FSTATAT''@|$(REPLACE_FSTATAT)|g' \
++	      -e 's|@''REPLACE_FUTIMENS''@|$(REPLACE_FUTIMENS)|g' \
++	      -e 's|@''REPLACE_LSTAT''@|$(REPLACE_LSTAT)|g' \
++	      -e 's|@''REPLACE_MKDIR''@|$(REPLACE_MKDIR)|g' \
++	      -e 's|@''REPLACE_MKFIFO''@|$(REPLACE_MKFIFO)|g' \
++	      -e 's|@''REPLACE_MKNOD''@|$(REPLACE_MKNOD)|g' \
++	      -e 's|@''REPLACE_STAT''@|$(REPLACE_STAT)|g' \
++	      -e 's|@''REPLACE_UTIMENSAT''@|$(REPLACE_UTIMENSAT)|g' \
++	      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
++	      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
++	      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
++	      < $(srcdir)/sys_stat.in.h; \
++	} > $@-t && \
++	mv $@-t $@
++MOSTLYCLEANFILES += sys/stat.h sys/stat.h-t
++MOSTLYCLEANDIRS += sys
++
++EXTRA_DIST += sys_stat.in.h
++
++## end   gnulib module sys_stat
++
++## begin gnulib module sys_time
++
++BUILT_SOURCES += sys/time.h
++
++# We need the following in order to create <sys/time.h> when the system
++# doesn't have one that works with the given compiler.
++sys/time.h: sys_time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
++	$(AM_V_at)$(MKDIR_P) sys
++	$(AM_V_GEN)rm -f $@-t $@ && \
++	{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
++	  sed -e 's|@''GUARD_PREFIX''@|GL|g' \
++	      -e 's/@''HAVE_SYS_TIME_H''@/$(HAVE_SYS_TIME_H)/g' \
++	      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
++	      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
++	      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
++	      -e 's|@''NEXT_SYS_TIME_H''@|$(NEXT_SYS_TIME_H)|g' \
++	      -e 's/@''GNULIB_GETTIMEOFDAY''@/$(GNULIB_GETTIMEOFDAY)/g' \
++	      -e 's|@''HAVE_WINSOCK2_H''@|$(HAVE_WINSOCK2_H)|g' \
++	      -e 's/@''HAVE_GETTIMEOFDAY''@/$(HAVE_GETTIMEOFDAY)/g' \
++	      -e 's/@''HAVE_STRUCT_TIMEVAL''@/$(HAVE_STRUCT_TIMEVAL)/g' \
++	      -e 's/@''REPLACE_GETTIMEOFDAY''@/$(REPLACE_GETTIMEOFDAY)/g' \
++	      -e 's/@''REPLACE_STRUCT_TIMEVAL''@/$(REPLACE_STRUCT_TIMEVAL)/g' \
++	      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
++	      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
++	      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
++	      < $(srcdir)/sys_time.in.h; \
++	} > $@-t && \
++	mv $@-t $@
++MOSTLYCLEANFILES += sys/time.h sys/time.h-t
++
++EXTRA_DIST += sys_time.in.h
++
++## end   gnulib module sys_time
++
+ ## begin gnulib module sys_types
+ 
+ BUILT_SOURCES += sys/types.h
+@@ -1334,6 +1464,51 @@ EXTRA_DIST += sysexits.in.h
+ 
+ ## end   gnulib module sysexits
+ 
++## begin gnulib module time
++
++BUILT_SOURCES += time.h
++
++# We need the following in order to create <time.h> when the system
++# doesn't have one that works with the given compiler.
++time.h: time.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H)
++	$(AM_V_GEN)rm -f $@-t $@ && \
++	{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */' && \
++	  sed -e 's|@''GUARD_PREFIX''@|GL|g' \
++	      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
++	      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
++	      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
++	      -e 's|@''NEXT_TIME_H''@|$(NEXT_TIME_H)|g' \
++	      -e 's/@''GNULIB_GETTIMEOFDAY''@/$(GNULIB_GETTIMEOFDAY)/g' \
++	      -e 's/@''GNULIB_MKTIME''@/$(GNULIB_MKTIME)/g' \
++	      -e 's/@''GNULIB_NANOSLEEP''@/$(GNULIB_NANOSLEEP)/g' \
++	      -e 's/@''GNULIB_STRPTIME''@/$(GNULIB_STRPTIME)/g' \
++	      -e 's/@''GNULIB_TIMEGM''@/$(GNULIB_TIMEGM)/g' \
++	      -e 's/@''GNULIB_TIME_R''@/$(GNULIB_TIME_R)/g' \
++	      -e 's|@''HAVE_DECL_LOCALTIME_R''@|$(HAVE_DECL_LOCALTIME_R)|g' \
++	      -e 's|@''HAVE_NANOSLEEP''@|$(HAVE_NANOSLEEP)|g' \
++	      -e 's|@''HAVE_STRPTIME''@|$(HAVE_STRPTIME)|g' \
++	      -e 's|@''HAVE_TIMEGM''@|$(HAVE_TIMEGM)|g' \
++	      -e 's|@''REPLACE_GMTIME''@|$(REPLACE_GMTIME)|g' \
++	      -e 's|@''REPLACE_LOCALTIME''@|$(REPLACE_LOCALTIME)|g' \
++	      -e 's|@''REPLACE_LOCALTIME_R''@|$(REPLACE_LOCALTIME_R)|g' \
++	      -e 's|@''REPLACE_MKTIME''@|$(REPLACE_MKTIME)|g' \
++	      -e 's|@''REPLACE_NANOSLEEP''@|$(REPLACE_NANOSLEEP)|g' \
++	      -e 's|@''REPLACE_TIMEGM''@|$(REPLACE_TIMEGM)|g' \
++	      -e 's|@''PTHREAD_H_DEFINES_STRUCT_TIMESPEC''@|$(PTHREAD_H_DEFINES_STRUCT_TIMESPEC)|g' \
++	      -e 's|@''SYS_TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(SYS_TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \
++	      -e 's|@''TIME_H_DEFINES_STRUCT_TIMESPEC''@|$(TIME_H_DEFINES_STRUCT_TIMESPEC)|g' \
++	      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
++	      -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \
++	      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
++	      < $(srcdir)/time.in.h; \
++	} > $@-t && \
++	mv $@-t $@
++MOSTLYCLEANFILES += time.h time.h-t
++
++EXTRA_DIST += time.in.h
++
++## end   gnulib module time
++
+ ## begin gnulib module unistd
+ 
+ BUILT_SOURCES += unistd.h
+diff --git a/m4/gettimeofday.m4 b/m4/gettimeofday.m4
+new file mode 100644
+index 00000000000..1c2d66ee261
+--- /dev/null
++++ b/m4/gettimeofday.m4
+@@ -0,0 +1,138 @@
++# serial 21
++
++# Copyright (C) 2001-2003, 2005, 2007, 2009-2014 Free Software Foundation, Inc.
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++dnl From Jim Meyering.
++
++AC_DEFUN([gl_FUNC_GETTIMEOFDAY],
++[
++  AC_REQUIRE([AC_C_RESTRICT])
++  AC_REQUIRE([gl_HEADER_SYS_TIME_H])
++  AC_REQUIRE([gl_HEADER_SYS_TIME_H_DEFAULTS])
++  AC_CHECK_FUNCS_ONCE([gettimeofday])
++
++  gl_gettimeofday_timezone=void
++  if test $ac_cv_func_gettimeofday != yes; then
++    HAVE_GETTIMEOFDAY=0
++  else
++    gl_FUNC_GETTIMEOFDAY_CLOBBER
++    AC_CACHE_CHECK([for gettimeofday with POSIX signature],
++      [gl_cv_func_gettimeofday_posix_signature],
++      [AC_COMPILE_IFELSE(
++         [AC_LANG_PROGRAM(
++            [[#include <sys/time.h>
++              struct timeval c;
++              int gettimeofday (struct timeval *restrict, void *restrict);
++            ]],
++            [[/* glibc uses struct timezone * rather than the POSIX void *
++                 if _GNU_SOURCE is defined.  However, since the only portable
++                 use of gettimeofday uses NULL as the second parameter, and
++                 since the glibc definition is actually more typesafe, it is
++                 not worth wrapping this to get a compliant signature.  */
++              int (*f) (struct timeval *restrict, void *restrict)
++                = gettimeofday;
++              int x = f (&c, 0);
++              return !(x | c.tv_sec | c.tv_usec);
++            ]])],
++          [gl_cv_func_gettimeofday_posix_signature=yes],
++          [AC_COMPILE_IFELSE(
++            [AC_LANG_PROGRAM(
++              [[#include <sys/time.h>
++int gettimeofday (struct timeval *restrict, struct timezone *restrict);
++              ]])],
++            [gl_cv_func_gettimeofday_posix_signature=almost],
++            [gl_cv_func_gettimeofday_posix_signature=no])])])
++    if test $gl_cv_func_gettimeofday_posix_signature = almost; then
++      gl_gettimeofday_timezone='struct timezone'
++    elif test $gl_cv_func_gettimeofday_posix_signature != yes; then
++      REPLACE_GETTIMEOFDAY=1
++    fi
++    dnl If we override 'struct timeval', we also have to override gettimeofday.
++    if test $REPLACE_STRUCT_TIMEVAL = 1; then
++      REPLACE_GETTIMEOFDAY=1
++    fi
++    m4_ifdef([gl_FUNC_TZSET_CLOBBER], [
++      gl_FUNC_TZSET_CLOBBER
++      case "$gl_cv_func_tzset_clobber" in
++        *yes)
++          REPLACE_GETTIMEOFDAY=1
++          gl_GETTIMEOFDAY_REPLACE_LOCALTIME
++          AC_DEFINE([tzset], [rpl_tzset],
++            [Define to rpl_tzset if the wrapper function should be used.])
++          AC_DEFINE([TZSET_CLOBBERS_LOCALTIME], [1],
++            [Define if tzset clobbers localtime's static buffer.])
++          ;;
++      esac
++    ])
++  fi
++  AC_DEFINE_UNQUOTED([GETTIMEOFDAY_TIMEZONE], [$gl_gettimeofday_timezone],
++    [Define this to 'void' or 'struct timezone' to match the system's
++     declaration of the second argument to gettimeofday.])
++])
++
++
++dnl See if gettimeofday clobbers the static buffer that localtime uses
++dnl for its return value.  The gettimeofday function from Mac OS X 10.0.4
++dnl (i.e., Darwin 1.3.7) has this problem.
++dnl
++dnl If it does, then arrange to use gettimeofday and localtime only via
++dnl the wrapper functions that work around the problem.
++
++AC_DEFUN([gl_FUNC_GETTIMEOFDAY_CLOBBER],
++[
++ AC_REQUIRE([gl_HEADER_SYS_TIME_H])
++ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
++
++ AC_CACHE_CHECK([whether gettimeofday clobbers localtime buffer],
++  [gl_cv_func_gettimeofday_clobber],
++  [AC_RUN_IFELSE(
++     [AC_LANG_PROGRAM(
++        [[#include <string.h>
++          #include <sys/time.h>
++          #include <time.h>
++          #include <stdlib.h>
++        ]],
++        [[
++          time_t t = 0;
++          struct tm *lt;
++          struct tm saved_lt;
++          struct timeval tv;
++          lt = localtime (&t);
++          saved_lt = *lt;
++          gettimeofday (&tv, NULL);
++          return memcmp (lt, &saved_lt, sizeof (struct tm)) != 0;
++        ]])],
++     [gl_cv_func_gettimeofday_clobber=no],
++     [gl_cv_func_gettimeofday_clobber=yes],
++     [# When cross-compiling:
++      case "$host_os" in
++                # Guess all is fine on glibc systems.
++        *-gnu*) gl_cv_func_gettimeofday_clobber="guessing no" ;;
++                # If we don't know, assume the worst.
++        *)      gl_cv_func_gettimeofday_clobber="guessing yes" ;;
++      esac
++     ])])
++
++ case "$gl_cv_func_gettimeofday_clobber" in
++   *yes)
++     REPLACE_GETTIMEOFDAY=1
++     gl_GETTIMEOFDAY_REPLACE_LOCALTIME
++     AC_DEFINE([GETTIMEOFDAY_CLOBBERS_LOCALTIME], [1],
++       [Define if gettimeofday clobbers the localtime buffer.])
++     ;;
++ esac
++])
++
++AC_DEFUN([gl_GETTIMEOFDAY_REPLACE_LOCALTIME], [
++  REPLACE_GMTIME=1
++  REPLACE_LOCALTIME=1
++])
++
++# Prerequisites of lib/gettimeofday.c.
++AC_DEFUN([gl_PREREQ_GETTIMEOFDAY], [
++  AC_CHECK_HEADERS([sys/timeb.h])
++  AC_CHECK_FUNCS([_ftime])
++])
+diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4
+index 408918440b6..ef2ec5bcce0 100644
+--- a/m4/gnulib-cache.m4
++++ b/m4/gnulib-cache.m4
+@@ -27,7 +27,7 @@
+ 
+ 
+ # Specification in the form of a command-line invocation:
+-#   gnulib-tool --import --dir=. --lib=libgnu --source-base=grub-core/gnulib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files argp error fnmatch getdelim getline gettext progname regex
++#   gnulib-tool --import --dir=. --lib=libgnu --source-base=grub-core/gnulib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --no-conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files argp error fnmatch getdelim getline gettext progname readlink regex
+ 
+ # Specification in the form of a few gnulib-tool.m4 macro invocations:
+ gl_LOCAL_DIR([])
+@@ -39,6 +39,7 @@ gl_MODULES([
+   getline
+   gettext
+   progname
++  readlink
+   regex
+ ])
+ gl_AVOID([])
+diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
+index 7a19f60d85e..66fd0eda901 100644
+--- a/m4/gnulib-comp.m4
++++ b/m4/gnulib-comp.m4
+@@ -60,10 +60,13 @@ AC_DEFUN([gl_EARLY],
+   # Code from module getopt-posix:
+   # Code from module gettext:
+   # Code from module gettext-h:
++  # Code from module gettimeofday:
+   # Code from module havelib:
+   # Code from module include_next:
+   # Code from module intprops:
+   # Code from module langinfo:
++  # Code from module largefile:
++  AC_REQUIRE([AC_SYS_LARGEFILE])
+   # Code from module localcharset:
+   # Code from module locale:
+   # Code from module localeconv:
+@@ -81,8 +84,10 @@ AC_DEFUN([gl_EARLY],
+   # Code from module multiarch:
+   # Code from module nl_langinfo:
+   # Code from module nocrash:
++  # Code from module pathmax:
+   # Code from module progname:
+   # Code from module rawmemchr:
++  # Code from module readlink:
+   # Code from module realloc-posix:
+   # Code from module regex:
+   # Code from module size_max:
+@@ -92,6 +97,7 @@ AC_DEFUN([gl_EARLY],
+   # Code from module snippet/c++defs:
+   # Code from module snippet/warn-on-use:
+   # Code from module ssize_t:
++  # Code from module stat:
+   # Code from module stdalign:
+   # Code from module stdbool:
+   # Code from module stddef:
+@@ -108,8 +114,11 @@ AC_DEFUN([gl_EARLY],
+   # Code from module strndup:
+   # Code from module strnlen:
+   # Code from module strnlen1:
++  # Code from module sys_stat:
++  # Code from module sys_time:
+   # Code from module sys_types:
+   # Code from module sysexits:
++  # Code from module time:
+   # Code from module unistd:
+   # Code from module unitypes:
+   # Code from module uniwidth/base:
+@@ -211,7 +220,14 @@ AC_DEFUN([gl_INIT],
+   AM_GNU_GETTEXT_VERSION([0.18.1])
+   AC_SUBST([LIBINTL])
+   AC_SUBST([LTLIBINTL])
++  gl_FUNC_GETTIMEOFDAY
++  if test $HAVE_GETTIMEOFDAY = 0 || test $REPLACE_GETTIMEOFDAY = 1; then
++    AC_LIBOBJ([gettimeofday])
++    gl_PREREQ_GETTIMEOFDAY
++  fi
++  gl_SYS_TIME_MODULE_INDICATOR([gettimeofday])
+   gl_LANGINFO_H
++  AC_REQUIRE([gl_LARGEFILE])
+   gl_LOCALCHARSET
+   LOCALCHARSET_TESTS_ENVIRONMENT="CHARSETALIASDIR=\"\$(abs_top_builddir)/$gl_source_base\""
+   AC_SUBST([LOCALCHARSET_TESTS_ENVIRONMENT])
+@@ -284,6 +300,7 @@ AC_DEFUN([gl_INIT],
+     AC_LIBOBJ([nl_langinfo])
+   fi
+   gl_LANGINFO_MODULE_INDICATOR([nl_langinfo])
++  gl_PATHMAX
+   AC_CHECK_DECLS([program_invocation_name], [], [], [#include <errno.h>])
+   AC_CHECK_DECLS([program_invocation_short_name], [], [], [#include <errno.h>])
+   gl_FUNC_RAWMEMCHR
+@@ -292,6 +309,12 @@ AC_DEFUN([gl_INIT],
+     gl_PREREQ_RAWMEMCHR
+   fi
+   gl_STRING_MODULE_INDICATOR([rawmemchr])
++  gl_FUNC_READLINK
++  if test $HAVE_READLINK = 0 || test $REPLACE_READLINK = 1; then
++    AC_LIBOBJ([readlink])
++    gl_PREREQ_READLINK
++  fi
++  gl_UNISTD_MODULE_INDICATOR([readlink])
+   gl_FUNC_REALLOC_POSIX
+   if test $REPLACE_REALLOC = 1; then
+     AC_LIBOBJ([realloc])
+@@ -309,6 +332,12 @@ AC_DEFUN([gl_INIT],
+   fi
+   gl_UNISTD_MODULE_INDICATOR([sleep])
+   gt_TYPE_SSIZE_T
++  gl_FUNC_STAT
++  if test $REPLACE_STAT = 1; then
++    AC_LIBOBJ([stat])
++    gl_PREREQ_STAT
++  fi
++  gl_SYS_STAT_MODULE_INDICATOR([stat])
+   gl_STDALIGN_H
+   AM_STDBOOL_H
+   gl_STDDEF_H
+@@ -355,9 +384,14 @@ AC_DEFUN([gl_INIT],
+     gl_PREREQ_STRNLEN
+   fi
+   gl_STRING_MODULE_INDICATOR([strnlen])
++  gl_HEADER_SYS_STAT_H
++  AC_PROG_MKDIR_P
++  gl_HEADER_SYS_TIME_H
++  AC_PROG_MKDIR_P
+   gl_SYS_TYPES_H
+   AC_PROG_MKDIR_P
+   gl_SYSEXITS
++  gl_HEADER_TIME_H
+   gl_UNISTD_H
+   gl_LIBUNISTRING_LIBHEADER([0.9], [unitypes.h])
+   gl_LIBUNISTRING_LIBHEADER([0.9], [uniwidth.h])
+@@ -562,6 +596,7 @@ AC_DEFUN([gl_FILE_LIST], [
+   lib/getopt1.c
+   lib/getopt_int.h
+   lib/gettext.h
++  lib/gettimeofday.c
+   lib/intprops.h
+   lib/itold.c
+   lib/langinfo.in.h
+@@ -587,6 +622,7 @@ AC_DEFUN([gl_FILE_LIST], [
+   lib/msvc-nothrow.c
+   lib/msvc-nothrow.h
+   lib/nl_langinfo.c
++  lib/pathmax.h
+   lib/printf-args.c
+   lib/printf-args.h
+   lib/printf-parse.c
+@@ -595,6 +631,7 @@ AC_DEFUN([gl_FILE_LIST], [
+   lib/progname.h
+   lib/rawmemchr.c
+   lib/rawmemchr.valgrind
++  lib/readlink.c
+   lib/realloc.c
+   lib/ref-add.sin
+   lib/ref-del.sin
+@@ -606,6 +643,7 @@ AC_DEFUN([gl_FILE_LIST], [
+   lib/regexec.c
+   lib/size_max.h
+   lib/sleep.c
++  lib/stat.c
+   lib/stdalign.in.h
+   lib/stdbool.in.h
+   lib/stddef.in.h
+@@ -627,8 +665,11 @@ AC_DEFUN([gl_FILE_LIST], [
+   lib/strnlen.c
+   lib/strnlen1.c
+   lib/strnlen1.h
++  lib/sys_stat.in.h
++  lib/sys_time.in.h
+   lib/sys_types.in.h
+   lib/sysexits.in.h
++  lib/time.in.h
+   lib/unistd.c
+   lib/unistd.in.h
+   lib/unitypes.in.h
+@@ -667,6 +708,7 @@ AC_DEFUN([gl_FILE_LIST], [
+   m4/getline.m4
+   m4/getopt.m4
+   m4/gettext.m4
++  m4/gettimeofday.m4
+   m4/glibc2.m4
+   m4/glibc21.m4
+   m4/gnulib-common.m4
+@@ -681,6 +723,7 @@ AC_DEFUN([gl_FILE_LIST], [
+   m4/inttypes-pri.m4
+   m4/inttypes_h.m4
+   m4/langinfo_h.m4
++  m4/largefile.m4
+   m4/lcmessage.m4
+   m4/lib-ld.m4
+   m4/lib-link.m4
+@@ -712,16 +755,19 @@ AC_DEFUN([gl_FILE_LIST], [
+   m4/nls.m4
+   m4/nocrash.m4
+   m4/off_t.m4
++  m4/pathmax.m4
+   m4/po.m4
+   m4/printf-posix.m4
+   m4/printf.m4
+   m4/progtest.m4
+   m4/rawmemchr.m4
++  m4/readlink.m4
+   m4/realloc.m4
+   m4/regex.m4
+   m4/size_max.m4
+   m4/sleep.m4
+   m4/ssize_t.m4
++  m4/stat.m4
+   m4/stdalign.m4
+   m4/stdbool.m4
+   m4/stddef_h.m4
+@@ -737,9 +783,12 @@ AC_DEFUN([gl_FILE_LIST], [
+   m4/strndup.m4
+   m4/strnlen.m4
+   m4/sys_socket_h.m4
++  m4/sys_stat_h.m4
++  m4/sys_time_h.m4
+   m4/sys_types_h.m4
+   m4/sysexits.m4
+   m4/threadlib.m4
++  m4/time_h.m4
+   m4/uintmax_t.m4
+   m4/unistd_h.m4
+   m4/vasnprintf.m4
+diff --git a/m4/largefile.m4 b/m4/largefile.m4
+new file mode 100644
+index 00000000000..a1b564ad9af
+--- /dev/null
++++ b/m4/largefile.m4
+@@ -0,0 +1,146 @@
++# Enable large files on systems where this is not the default.
++
++# Copyright 1992-1996, 1998-2014 Free Software Foundation, Inc.
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# The following implementation works around a problem in autoconf <= 2.69;
++# AC_SYS_LARGEFILE does not configure for large inodes on Mac OS X 10.5,
++# or configures them incorrectly in some cases.
++m4_version_prereq([2.70], [] ,[
++
++# _AC_SYS_LARGEFILE_TEST_INCLUDES
++# -------------------------------
++m4_define([_AC_SYS_LARGEFILE_TEST_INCLUDES],
++[@%:@include <sys/types.h>
++ /* Check that off_t can represent 2**63 - 1 correctly.
++    We can't simply define LARGE_OFF_T to be 9223372036854775807,
++    since some C++ compilers masquerading as C compilers
++    incorrectly reject 9223372036854775807.  */
++@%:@define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
++  int off_t_is_large[[(LARGE_OFF_T % 2147483629 == 721
++                       && LARGE_OFF_T % 2147483647 == 1)
++                      ? 1 : -1]];[]dnl
++])
++
++
++# _AC_SYS_LARGEFILE_MACRO_VALUE(C-MACRO, VALUE,
++#                               CACHE-VAR,
++#                               DESCRIPTION,
++#                               PROLOGUE, [FUNCTION-BODY])
++# --------------------------------------------------------
++m4_define([_AC_SYS_LARGEFILE_MACRO_VALUE],
++[AC_CACHE_CHECK([for $1 value needed for large files], [$3],
++[while :; do
++  m4_ifval([$6], [AC_LINK_IFELSE], [AC_COMPILE_IFELSE])(
++    [AC_LANG_PROGRAM([$5], [$6])],
++    [$3=no; break])
++  m4_ifval([$6], [AC_LINK_IFELSE], [AC_COMPILE_IFELSE])(
++    [AC_LANG_PROGRAM([@%:@define $1 $2
++$5], [$6])],
++    [$3=$2; break])
++  $3=unknown
++  break
++done])
++case $$3 in #(
++  no | unknown) ;;
++  *) AC_DEFINE_UNQUOTED([$1], [$$3], [$4]);;
++esac
++rm -rf conftest*[]dnl
++])# _AC_SYS_LARGEFILE_MACRO_VALUE
++
++
++# AC_SYS_LARGEFILE
++# ----------------
++# By default, many hosts won't let programs access large files;
++# one must use special compiler options to get large-file access to work.
++# For more details about this brain damage please see:
++# http://www.unix-systems.org/version2/whatsnew/lfs20mar.html
++AC_DEFUN([AC_SYS_LARGEFILE],
++[AC_ARG_ENABLE(largefile,
++               [  --disable-largefile     omit support for large files])
++if test "$enable_largefile" != no; then
++
++  AC_CACHE_CHECK([for special C compiler options needed for large files],
++    ac_cv_sys_largefile_CC,
++    [ac_cv_sys_largefile_CC=no
++     if test "$GCC" != yes; then
++       ac_save_CC=$CC
++       while :; do
++         # IRIX 6.2 and later do not support large files by default,
++         # so use the C compiler's -n32 option if that helps.
++         AC_LANG_CONFTEST([AC_LANG_PROGRAM([_AC_SYS_LARGEFILE_TEST_INCLUDES])])
++         AC_COMPILE_IFELSE([], [break])
++         CC="$CC -n32"
++         AC_COMPILE_IFELSE([], [ac_cv_sys_largefile_CC=' -n32'; break])
++         break
++       done
++       CC=$ac_save_CC
++       rm -f conftest.$ac_ext
++    fi])
++  if test "$ac_cv_sys_largefile_CC" != no; then
++    CC=$CC$ac_cv_sys_largefile_CC
++  fi
++
++  _AC_SYS_LARGEFILE_MACRO_VALUE(_FILE_OFFSET_BITS, 64,
++    ac_cv_sys_file_offset_bits,
++    [Number of bits in a file offset, on hosts where this is settable.],
++    [_AC_SYS_LARGEFILE_TEST_INCLUDES])
++  if test $ac_cv_sys_file_offset_bits = unknown; then
++    _AC_SYS_LARGEFILE_MACRO_VALUE(_LARGE_FILES, 1,
++      ac_cv_sys_large_files,
++      [Define for large files, on AIX-style hosts.],
++      [_AC_SYS_LARGEFILE_TEST_INCLUDES])
++  fi
++
++  AC_DEFINE([_DARWIN_USE_64_BIT_INODE], [1],
++    [Enable large inode numbers on Mac OS X 10.5.])
++fi
++])# AC_SYS_LARGEFILE
++])# m4_version_prereq 2.70
++
++# Enable large files on systems where this is implemented by Gnulib, not by the
++# system headers.
++# Set the variables WINDOWS_64_BIT_OFF_T, WINDOWS_64_BIT_ST_SIZE if Gnulib
++# overrides ensure that off_t or 'struct size.st_size' are 64-bit, respectively.
++AC_DEFUN([gl_LARGEFILE],
++[
++  AC_REQUIRE([AC_CANONICAL_HOST])
++  case "$host_os" in
++    mingw*)
++      dnl Native Windows.
++      dnl mingw64 defines off_t to a 64-bit type already, if
++      dnl _FILE_OFFSET_BITS=64, which is ensured by AC_SYS_LARGEFILE.
++      AC_CACHE_CHECK([for 64-bit off_t], [gl_cv_type_off_t_64],
++        [AC_COMPILE_IFELSE(
++           [AC_LANG_PROGRAM(
++              [[#include <sys/types.h>
++                int verify_off_t_size[sizeof (off_t) >= 8 ? 1 : -1];
++              ]],
++              [[]])],
++           [gl_cv_type_off_t_64=yes], [gl_cv_type_off_t_64=no])
++        ])
++      if test $gl_cv_type_off_t_64 = no; then
++        WINDOWS_64_BIT_OFF_T=1
++      else
++        WINDOWS_64_BIT_OFF_T=0
++      fi
++      dnl But all native Windows platforms (including mingw64) have a 32-bit
++      dnl st_size member in 'struct stat'.
++      WINDOWS_64_BIT_ST_SIZE=1
++      ;;
++    *)
++      dnl Nothing to do on gnulib's side.
++      dnl A 64-bit off_t is
++      dnl   - already the default on Mac OS X, FreeBSD, NetBSD, OpenBSD, IRIX,
++      dnl     OSF/1, Cygwin,
++      dnl   - enabled by _FILE_OFFSET_BITS=64 (ensured by AC_SYS_LARGEFILE) on
++      dnl     glibc, HP-UX, Solaris,
++      dnl   - enabled by _LARGE_FILES=1 (ensured by AC_SYS_LARGEFILE) on AIX,
++      dnl   - impossible to achieve on Minix 3.1.8.
++      WINDOWS_64_BIT_OFF_T=0
++      WINDOWS_64_BIT_ST_SIZE=0
++      ;;
++  esac
++])
+diff --git a/m4/pathmax.m4 b/m4/pathmax.m4
+new file mode 100644
+index 00000000000..114f91f04b5
+--- /dev/null
++++ b/m4/pathmax.m4
+@@ -0,0 +1,42 @@
++# pathmax.m4 serial 10
++dnl Copyright (C) 2002-2003, 2005-2006, 2009-2014 Free Software Foundation,
++dnl Inc.
++dnl This file is free software; the Free Software Foundation
++dnl gives unlimited permission to copy and/or distribute it,
++dnl with or without modifications, as long as this notice is preserved.
++
++AC_DEFUN([gl_PATHMAX],
++[
++  dnl Prerequisites of lib/pathmax.h.
++  AC_CHECK_HEADERS_ONCE([sys/param.h])
++])
++
++# Expands to a piece of C program that defines PATH_MAX in the same way as
++# "pathmax.h" will do.
++AC_DEFUN([gl_PATHMAX_SNIPPET], [[
++/* Arrange to define PATH_MAX, like "pathmax.h" does. */
++#if HAVE_UNISTD_H
++# include <unistd.h>
++#endif
++#include <limits.h>
++#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
++# include <sys/param.h>
++#endif
++#if !defined PATH_MAX && defined MAXPATHLEN
++# define PATH_MAX MAXPATHLEN
++#endif
++#ifdef __hpux
++# undef PATH_MAX
++# define PATH_MAX 1024
++#endif
++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
++# undef PATH_MAX
++# define PATH_MAX 260
++#endif
++]])
++
++# Prerequisites of gl_PATHMAX_SNIPPET.
++AC_DEFUN([gl_PATHMAX_SNIPPET_PREREQ],
++[
++  AC_CHECK_HEADERS_ONCE([unistd.h sys/param.h])
++])
+diff --git a/m4/readlink.m4 b/m4/readlink.m4
+new file mode 100644
+index 00000000000..f9ce868c2e4
+--- /dev/null
++++ b/m4/readlink.m4
+@@ -0,0 +1,71 @@
++# readlink.m4 serial 12
++dnl Copyright (C) 2003, 2007, 2009-2014 Free Software Foundation, Inc.
++dnl This file is free software; the Free Software Foundation
++dnl gives unlimited permission to copy and/or distribute it,
++dnl with or without modifications, as long as this notice is preserved.
++
++AC_DEFUN([gl_FUNC_READLINK],
++[
++  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
++  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
++  AC_CHECK_FUNCS_ONCE([readlink])
++  if test $ac_cv_func_readlink = no; then
++    HAVE_READLINK=0
++  else
++    AC_CACHE_CHECK([whether readlink signature is correct],
++      [gl_cv_decl_readlink_works],
++      [AC_COMPILE_IFELSE(
++         [AC_LANG_PROGRAM(
++           [[#include <unistd.h>
++      /* Cause compilation failure if original declaration has wrong type.  */
++      ssize_t readlink (const char *, char *, size_t);]])],
++         [gl_cv_decl_readlink_works=yes], [gl_cv_decl_readlink_works=no])])
++    dnl Solaris 9 ignores trailing slash.
++    dnl FreeBSD 7.2 dereferences only one level of links with trailing slash.
++    AC_CACHE_CHECK([whether readlink handles trailing slash correctly],
++      [gl_cv_func_readlink_works],
++      [# We have readlink, so assume ln -s works.
++       ln -s conftest.no-such conftest.link
++       ln -s conftest.link conftest.lnk2
++       AC_RUN_IFELSE(
++         [AC_LANG_PROGRAM(
++           [[#include <unistd.h>
++]], [[char buf[20];
++      return readlink ("conftest.lnk2/", buf, sizeof buf) != -1;]])],
++         [gl_cv_func_readlink_works=yes], [gl_cv_func_readlink_works=no],
++         [case "$host_os" in
++                    # Guess yes on glibc systems.
++            *-gnu*) gl_cv_func_readlink_works="guessing yes" ;;
++                    # If we don't know, assume the worst.
++            *)      gl_cv_func_readlink_works="guessing no" ;;
++          esac
++         ])
++      rm -f conftest.link conftest.lnk2])
++    case "$gl_cv_func_readlink_works" in
++      *yes)
++        if test "$gl_cv_decl_readlink_works" != yes; then
++          REPLACE_READLINK=1
++        fi
++        ;;
++      *)
++        AC_DEFINE([READLINK_TRAILING_SLASH_BUG], [1], [Define to 1 if readlink
++          fails to recognize a trailing slash.])
++        REPLACE_READLINK=1
++        ;;
++    esac
++  fi
++])
++
++# Like gl_FUNC_READLINK, except prepare for separate compilation
++# (no REPLACE_READLINK, no AC_LIBOBJ).
++AC_DEFUN([gl_FUNC_READLINK_SEPARATE],
++[
++  AC_CHECK_FUNCS_ONCE([readlink])
++  gl_PREREQ_READLINK
++])
++
++# Prerequisites of lib/readlink.c.
++AC_DEFUN([gl_PREREQ_READLINK],
++[
++  :
++])
+diff --git a/m4/stat.m4 b/m4/stat.m4
+new file mode 100644
+index 00000000000..1ae327b3684
+--- /dev/null
++++ b/m4/stat.m4
+@@ -0,0 +1,71 @@
++# serial 11
++
++# Copyright (C) 2009-2014 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++AC_DEFUN([gl_FUNC_STAT],
++[
++  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
++  AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
++  AC_CHECK_FUNCS_ONCE([lstat])
++  dnl mingw is the only known platform where stat(".") and stat("./") differ
++  AC_CACHE_CHECK([whether stat handles trailing slashes on directories],
++      [gl_cv_func_stat_dir_slash],
++      [AC_RUN_IFELSE(
++         [AC_LANG_PROGRAM(
++           [[#include <sys/stat.h>
++]], [[struct stat st; return stat (".", &st) != stat ("./", &st);]])],
++         [gl_cv_func_stat_dir_slash=yes], [gl_cv_func_stat_dir_slash=no],
++         [case $host_os in
++            mingw*) gl_cv_func_stat_dir_slash="guessing no";;
++            *) gl_cv_func_stat_dir_slash="guessing yes";;
++          esac])])
++  dnl AIX 7.1, Solaris 9, mingw64 mistakenly succeed on stat("file/").
++  dnl (For mingw, this is due to a broken stat() override in libmingwex.a.)
++  dnl FreeBSD 7.2 mistakenly succeeds on stat("link-to-file/").
++  AC_CACHE_CHECK([whether stat handles trailing slashes on files],
++      [gl_cv_func_stat_file_slash],
++      [touch conftest.tmp
++       # Assume that if we have lstat, we can also check symlinks.
++       if test $ac_cv_func_lstat = yes; then
++         ln -s conftest.tmp conftest.lnk
++       fi
++       AC_RUN_IFELSE(
++         [AC_LANG_PROGRAM(
++           [[#include <sys/stat.h>
++]], [[int result = 0;
++      struct stat st;
++      if (!stat ("conftest.tmp/", &st))
++        result |= 1;
++#if HAVE_LSTAT
++      if (!stat ("conftest.lnk/", &st))
++        result |= 2;
++#endif
++      return result;
++           ]])],
++         [gl_cv_func_stat_file_slash=yes], [gl_cv_func_stat_file_slash=no],
++         [case "$host_os" in
++                    # Guess yes on glibc systems.
++            *-gnu*) gl_cv_func_stat_file_slash="guessing yes" ;;
++                    # If we don't know, assume the worst.
++            *)      gl_cv_func_stat_file_slash="guessing no" ;;
++          esac
++         ])
++       rm -f conftest.tmp conftest.lnk])
++  case $gl_cv_func_stat_dir_slash in
++    *no) REPLACE_STAT=1
++      AC_DEFINE([REPLACE_FUNC_STAT_DIR], [1], [Define to 1 if stat needs
++        help when passed a directory name with a trailing slash]);;
++  esac
++  case $gl_cv_func_stat_file_slash in
++    *no) REPLACE_STAT=1
++      AC_DEFINE([REPLACE_FUNC_STAT_FILE], [1], [Define to 1 if stat needs
++        help when passed a file name with a trailing slash]);;
++  esac
++])
++
++# Prerequisites of lib/stat.c.
++AC_DEFUN([gl_PREREQ_STAT], [:])
+diff --git a/m4/sys_stat_h.m4 b/m4/sys_stat_h.m4
+new file mode 100644
+index 00000000000..eaa7642ba31
+--- /dev/null
++++ b/m4/sys_stat_h.m4
+@@ -0,0 +1,96 @@
++# sys_stat_h.m4 serial 28   -*- Autoconf -*-
++dnl Copyright (C) 2006-2014 Free Software Foundation, Inc.
++dnl This file is free software; the Free Software Foundation
++dnl gives unlimited permission to copy and/or distribute it,
++dnl with or without modifications, as long as this notice is preserved.
++
++dnl From Eric Blake.
++dnl Provide a GNU-like <sys/stat.h>.
++
++AC_DEFUN([gl_HEADER_SYS_STAT_H],
++[
++  AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
++
++  dnl Check for broken stat macros.
++  AC_REQUIRE([AC_HEADER_STAT])
++
++  gl_CHECK_NEXT_HEADERS([sys/stat.h])
++
++  dnl Ensure the type mode_t gets defined.
++  AC_REQUIRE([AC_TYPE_MODE_T])
++
++  dnl Whether to override 'struct stat'.
++  m4_ifdef([gl_LARGEFILE], [
++    AC_REQUIRE([gl_LARGEFILE])
++  ], [
++    WINDOWS_64_BIT_ST_SIZE=0
++  ])
++  AC_SUBST([WINDOWS_64_BIT_ST_SIZE])
++  if test $WINDOWS_64_BIT_ST_SIZE = 1; then
++    AC_DEFINE([_GL_WINDOWS_64_BIT_ST_SIZE], [1],
++      [Define to 1 if Gnulib overrides 'struct stat' on Windows so that
++       struct stat.st_size becomes 64-bit.])
++  fi
++
++  dnl Define types that are supposed to be defined in <sys/types.h> or
++  dnl <sys/stat.h>.
++  AC_CHECK_TYPE([nlink_t], [],
++    [AC_DEFINE([nlink_t], [int],
++       [Define to the type of st_nlink in struct stat, or a supertype.])],
++    [#include <sys/types.h>
++     #include <sys/stat.h>])
++
++  dnl Check for declarations of anything we want to poison if the
++  dnl corresponding gnulib module is not in use.
++  gl_WARN_ON_USE_PREPARE([[#include <sys/stat.h>
++    ]], [fchmodat fstat fstatat futimens lchmod lstat mkdirat mkfifo mkfifoat
++    mknod mknodat stat utimensat])
++]) # gl_HEADER_SYS_STAT_H
++
++AC_DEFUN([gl_SYS_STAT_MODULE_INDICATOR],
++[
++  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
++  AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
++  gl_MODULE_INDICATOR_SET_VARIABLE([$1])
++  dnl Define it also as a C macro, for the benefit of the unit tests.
++  gl_MODULE_INDICATOR_FOR_TESTS([$1])
++])
++
++AC_DEFUN([gl_SYS_STAT_H_DEFAULTS],
++[
++  AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) dnl for REPLACE_FCHDIR
++  GNULIB_FCHMODAT=0;    AC_SUBST([GNULIB_FCHMODAT])
++  GNULIB_FSTAT=0;       AC_SUBST([GNULIB_FSTAT])
++  GNULIB_FSTATAT=0;     AC_SUBST([GNULIB_FSTATAT])
++  GNULIB_FUTIMENS=0;    AC_SUBST([GNULIB_FUTIMENS])
++  GNULIB_LCHMOD=0;      AC_SUBST([GNULIB_LCHMOD])
++  GNULIB_LSTAT=0;       AC_SUBST([GNULIB_LSTAT])
++  GNULIB_MKDIRAT=0;     AC_SUBST([GNULIB_MKDIRAT])
++  GNULIB_MKFIFO=0;      AC_SUBST([GNULIB_MKFIFO])
++  GNULIB_MKFIFOAT=0;    AC_SUBST([GNULIB_MKFIFOAT])
++  GNULIB_MKNOD=0;       AC_SUBST([GNULIB_MKNOD])
++  GNULIB_MKNODAT=0;     AC_SUBST([GNULIB_MKNODAT])
++  GNULIB_STAT=0;        AC_SUBST([GNULIB_STAT])
++  GNULIB_UTIMENSAT=0;   AC_SUBST([GNULIB_UTIMENSAT])
++  dnl Assume proper GNU behavior unless another module says otherwise.
++  HAVE_FCHMODAT=1;      AC_SUBST([HAVE_FCHMODAT])
++  HAVE_FSTATAT=1;       AC_SUBST([HAVE_FSTATAT])
++  HAVE_FUTIMENS=1;      AC_SUBST([HAVE_FUTIMENS])
++  HAVE_LCHMOD=1;        AC_SUBST([HAVE_LCHMOD])
++  HAVE_LSTAT=1;         AC_SUBST([HAVE_LSTAT])
++  HAVE_MKDIRAT=1;       AC_SUBST([HAVE_MKDIRAT])
++  HAVE_MKFIFO=1;        AC_SUBST([HAVE_MKFIFO])
++  HAVE_MKFIFOAT=1;      AC_SUBST([HAVE_MKFIFOAT])
++  HAVE_MKNOD=1;         AC_SUBST([HAVE_MKNOD])
++  HAVE_MKNODAT=1;       AC_SUBST([HAVE_MKNODAT])
++  HAVE_UTIMENSAT=1;     AC_SUBST([HAVE_UTIMENSAT])
++  REPLACE_FSTAT=0;      AC_SUBST([REPLACE_FSTAT])
++  REPLACE_FSTATAT=0;    AC_SUBST([REPLACE_FSTATAT])
++  REPLACE_FUTIMENS=0;   AC_SUBST([REPLACE_FUTIMENS])
++  REPLACE_LSTAT=0;      AC_SUBST([REPLACE_LSTAT])
++  REPLACE_MKDIR=0;      AC_SUBST([REPLACE_MKDIR])
++  REPLACE_MKFIFO=0;     AC_SUBST([REPLACE_MKFIFO])
++  REPLACE_MKNOD=0;      AC_SUBST([REPLACE_MKNOD])
++  REPLACE_STAT=0;       AC_SUBST([REPLACE_STAT])
++  REPLACE_UTIMENSAT=0;  AC_SUBST([REPLACE_UTIMENSAT])
++])
+diff --git a/m4/sys_time_h.m4 b/m4/sys_time_h.m4
+new file mode 100644
+index 00000000000..5c79300f8ec
+--- /dev/null
++++ b/m4/sys_time_h.m4
+@@ -0,0 +1,110 @@
++# Configure a replacement for <sys/time.h>.
++# serial 8
++
++# Copyright (C) 2007, 2009-2014 Free Software Foundation, Inc.
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# Written by Paul Eggert and Martin Lambers.
++
++AC_DEFUN([gl_HEADER_SYS_TIME_H],
++[
++  dnl Use AC_REQUIRE here, so that the REPLACE_GETTIMEOFDAY=0 statement
++  dnl below is expanded once only, before all REPLACE_GETTIMEOFDAY=1
++  dnl statements that occur in other macros.
++  AC_REQUIRE([gl_HEADER_SYS_TIME_H_BODY])
++])
++
++AC_DEFUN([gl_HEADER_SYS_TIME_H_BODY],
++[
++  AC_REQUIRE([AC_C_RESTRICT])
++  AC_REQUIRE([gl_HEADER_SYS_TIME_H_DEFAULTS])
++  AC_CHECK_HEADERS_ONCE([sys/time.h])
++  gl_CHECK_NEXT_HEADERS([sys/time.h])
++
++  if test $ac_cv_header_sys_time_h != yes; then
++    HAVE_SYS_TIME_H=0
++  fi
++
++  dnl On native Windows with MSVC, 'struct timeval' is defined in <winsock2.h>
++  dnl only. So include that header in the list.
++  gl_PREREQ_SYS_H_WINSOCK2
++  AC_CACHE_CHECK([for struct timeval], [gl_cv_sys_struct_timeval],
++    [AC_COMPILE_IFELSE(
++       [AC_LANG_PROGRAM(
++          [[#if HAVE_SYS_TIME_H
++             #include <sys/time.h>
++            #endif
++            #include <time.h>
++            #if HAVE_WINSOCK2_H
++            # include <winsock2.h>
++            #endif
++          ]],
++          [[static struct timeval x; x.tv_sec = x.tv_usec;]])],
++       [gl_cv_sys_struct_timeval=yes],
++       [gl_cv_sys_struct_timeval=no])
++    ])
++  if test $gl_cv_sys_struct_timeval != yes; then
++    HAVE_STRUCT_TIMEVAL=0
++  else
++    dnl On native Windows with a 64-bit 'time_t', 'struct timeval' is defined
++    dnl (in <sys/time.h> and <winsock2.h> for mingw64, in <winsock2.h> only
++    dnl for MSVC) with a tv_sec field of type 'long' (32-bit!), which is
++    dnl smaller than the 'time_t' type mandated by POSIX.
++    dnl On OpenBSD 5.1 amd64, tv_sec is 64 bits and time_t 32 bits, but
++    dnl that is good enough.
++    AC_CACHE_CHECK([for wide-enough struct timeval.tv_sec member],
++      [gl_cv_sys_struct_timeval_tv_sec],
++      [AC_COMPILE_IFELSE(
++         [AC_LANG_PROGRAM(
++            [[#if HAVE_SYS_TIME_H
++               #include <sys/time.h>
++              #endif
++              #include <time.h>
++              #if HAVE_WINSOCK2_H
++              # include <winsock2.h>
++              #endif
++            ]],
++            [[static struct timeval x;
++              typedef int verify_tv_sec_type[
++                sizeof (time_t) <= sizeof x.tv_sec ? 1 : -1
++              ];
++            ]])],
++         [gl_cv_sys_struct_timeval_tv_sec=yes],
++         [gl_cv_sys_struct_timeval_tv_sec=no])
++      ])
++    if test $gl_cv_sys_struct_timeval_tv_sec != yes; then
++      REPLACE_STRUCT_TIMEVAL=1
++    fi
++  fi
++
++  dnl Check for declarations of anything we want to poison if the
++  dnl corresponding gnulib module is not in use.
++  gl_WARN_ON_USE_PREPARE([[
++#if HAVE_SYS_TIME_H
++# include <sys/time.h>
++#endif
++#include <time.h>
++    ]], [gettimeofday])
++])
++
++AC_DEFUN([gl_SYS_TIME_MODULE_INDICATOR],
++[
++  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
++  AC_REQUIRE([gl_HEADER_SYS_TIME_H_DEFAULTS])
++  gl_MODULE_INDICATOR_SET_VARIABLE([$1])
++  dnl Define it also as a C macro, for the benefit of the unit tests.
++  gl_MODULE_INDICATOR_FOR_TESTS([$1])
++])
++
++AC_DEFUN([gl_HEADER_SYS_TIME_H_DEFAULTS],
++[
++  GNULIB_GETTIMEOFDAY=0;     AC_SUBST([GNULIB_GETTIMEOFDAY])
++  dnl Assume POSIX behavior unless another module says otherwise.
++  HAVE_GETTIMEOFDAY=1;       AC_SUBST([HAVE_GETTIMEOFDAY])
++  HAVE_STRUCT_TIMEVAL=1;     AC_SUBST([HAVE_STRUCT_TIMEVAL])
++  HAVE_SYS_TIME_H=1;         AC_SUBST([HAVE_SYS_TIME_H])
++  REPLACE_GETTIMEOFDAY=0;    AC_SUBST([REPLACE_GETTIMEOFDAY])
++  REPLACE_STRUCT_TIMEVAL=0;  AC_SUBST([REPLACE_STRUCT_TIMEVAL])
++])
+diff --git a/m4/time_h.m4 b/m4/time_h.m4
+new file mode 100644
+index 00000000000..9852778f9a5
+--- /dev/null
++++ b/m4/time_h.m4
+@@ -0,0 +1,118 @@
++# Configure a more-standard replacement for <time.h>.
++
++# Copyright (C) 2000-2001, 2003-2007, 2009-2014 Free Software Foundation, Inc.
++
++# serial 8
++
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# Written by Paul Eggert and Jim Meyering.
++
++AC_DEFUN([gl_HEADER_TIME_H],
++[
++  dnl Use AC_REQUIRE here, so that the default behavior below is expanded
++  dnl once only, before all statements that occur in other macros.
++  AC_REQUIRE([gl_HEADER_TIME_H_BODY])
++])
++
++AC_DEFUN([gl_HEADER_TIME_H_BODY],
++[
++  AC_REQUIRE([AC_C_RESTRICT])
++  AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
++  gl_NEXT_HEADERS([time.h])
++  AC_REQUIRE([gl_CHECK_TYPE_STRUCT_TIMESPEC])
++])
++
++dnl Check whether 'struct timespec' is declared
++dnl in time.h, sys/time.h, or pthread.h.
++
++AC_DEFUN([gl_CHECK_TYPE_STRUCT_TIMESPEC],
++[
++  AC_CHECK_HEADERS_ONCE([sys/time.h])
++  AC_CACHE_CHECK([for struct timespec in <time.h>],
++    [gl_cv_sys_struct_timespec_in_time_h],
++    [AC_COMPILE_IFELSE(
++       [AC_LANG_PROGRAM(
++          [[#include <time.h>
++          ]],
++          [[static struct timespec x; x.tv_sec = x.tv_nsec;]])],
++       [gl_cv_sys_struct_timespec_in_time_h=yes],
++       [gl_cv_sys_struct_timespec_in_time_h=no])])
++
++  TIME_H_DEFINES_STRUCT_TIMESPEC=0
++  SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=0
++  PTHREAD_H_DEFINES_STRUCT_TIMESPEC=0
++  if test $gl_cv_sys_struct_timespec_in_time_h = yes; then
++    TIME_H_DEFINES_STRUCT_TIMESPEC=1
++  else
++    AC_CACHE_CHECK([for struct timespec in <sys/time.h>],
++      [gl_cv_sys_struct_timespec_in_sys_time_h],
++      [AC_COMPILE_IFELSE(
++         [AC_LANG_PROGRAM(
++            [[#include <sys/time.h>
++            ]],
++            [[static struct timespec x; x.tv_sec = x.tv_nsec;]])],
++         [gl_cv_sys_struct_timespec_in_sys_time_h=yes],
++         [gl_cv_sys_struct_timespec_in_sys_time_h=no])])
++    if test $gl_cv_sys_struct_timespec_in_sys_time_h = yes; then
++      SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=1
++    else
++      AC_CACHE_CHECK([for struct timespec in <pthread.h>],
++        [gl_cv_sys_struct_timespec_in_pthread_h],
++        [AC_COMPILE_IFELSE(
++           [AC_LANG_PROGRAM(
++              [[#include <pthread.h>
++              ]],
++              [[static struct timespec x; x.tv_sec = x.tv_nsec;]])],
++           [gl_cv_sys_struct_timespec_in_pthread_h=yes],
++           [gl_cv_sys_struct_timespec_in_pthread_h=no])])
++      if test $gl_cv_sys_struct_timespec_in_pthread_h = yes; then
++        PTHREAD_H_DEFINES_STRUCT_TIMESPEC=1
++      fi
++    fi
++  fi
++  AC_SUBST([TIME_H_DEFINES_STRUCT_TIMESPEC])
++  AC_SUBST([SYS_TIME_H_DEFINES_STRUCT_TIMESPEC])
++  AC_SUBST([PTHREAD_H_DEFINES_STRUCT_TIMESPEC])
++])
++
++AC_DEFUN([gl_TIME_MODULE_INDICATOR],
++[
++  dnl Use AC_REQUIRE here, so that the default settings are expanded once only.
++  AC_REQUIRE([gl_HEADER_TIME_H_DEFAULTS])
++  gl_MODULE_INDICATOR_SET_VARIABLE([$1])
++  dnl Define it also as a C macro, for the benefit of the unit tests.
++  gl_MODULE_INDICATOR_FOR_TESTS([$1])
++])
++
++AC_DEFUN([gl_HEADER_TIME_H_DEFAULTS],
++[
++  GNULIB_MKTIME=0;                       AC_SUBST([GNULIB_MKTIME])
++  GNULIB_NANOSLEEP=0;                    AC_SUBST([GNULIB_NANOSLEEP])
++  GNULIB_STRPTIME=0;                     AC_SUBST([GNULIB_STRPTIME])
++  GNULIB_TIMEGM=0;                       AC_SUBST([GNULIB_TIMEGM])
++  GNULIB_TIME_R=0;                       AC_SUBST([GNULIB_TIME_R])
++  dnl Assume proper GNU behavior unless another module says otherwise.
++  HAVE_DECL_LOCALTIME_R=1;               AC_SUBST([HAVE_DECL_LOCALTIME_R])
++  HAVE_NANOSLEEP=1;                      AC_SUBST([HAVE_NANOSLEEP])
++  HAVE_STRPTIME=1;                       AC_SUBST([HAVE_STRPTIME])
++  HAVE_TIMEGM=1;                         AC_SUBST([HAVE_TIMEGM])
++  dnl If another module says to replace or to not replace, do that.
++  dnl Otherwise, replace only if someone compiles with -DGNULIB_PORTCHECK;
++  dnl this lets maintainers check for portability.
++  REPLACE_LOCALTIME_R=GNULIB_PORTCHECK;  AC_SUBST([REPLACE_LOCALTIME_R])
++  REPLACE_MKTIME=GNULIB_PORTCHECK;       AC_SUBST([REPLACE_MKTIME])
++  REPLACE_NANOSLEEP=GNULIB_PORTCHECK;    AC_SUBST([REPLACE_NANOSLEEP])
++  REPLACE_TIMEGM=GNULIB_PORTCHECK;       AC_SUBST([REPLACE_TIMEGM])
++
++  dnl Hack so that the time module doesn't depend on the sys_time module.
++  dnl First, default GNULIB_GETTIMEOFDAY to 0 if sys_time is absent.
++  : ${GNULIB_GETTIMEOFDAY=0};            AC_SUBST([GNULIB_GETTIMEOFDAY])
++  dnl Second, it's OK to not use GNULIB_PORTCHECK for REPLACE_GMTIME
++  dnl and REPLACE_LOCALTIME, as portability to Solaris 2.6 and earlier
++  dnl is no longer a big deal.
++  REPLACE_GMTIME=0;                      AC_SUBST([REPLACE_GMTIME])
++  REPLACE_LOCALTIME=0;                   AC_SUBST([REPLACE_LOCALTIME])
++])
diff --git a/SOURCES/0055-Make-editenv-chase-symlinks-including-those-across-d.patch b/SOURCES/0055-Make-editenv-chase-symlinks-including-those-across-d.patch
new file mode 100644
index 0000000..73e316e
--- /dev/null
+++ b/SOURCES/0055-Make-editenv-chase-symlinks-including-those-across-d.patch
@@ -0,0 +1,102 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 3 Sep 2014 10:38:00 -0400
+Subject: [PATCH] Make editenv chase symlinks including those across devices.
+
+This lets us make /boot/grub2/grubenv a symlink to
+/boot/efi/EFI/fedora/grubenv even though they're different mount points,
+which allows /usr/bin/grub2-editenv to be the same across platforms
+(i.e. UEFI vs BIOS).
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+Reviewed-by: Adam Jackson <ajax@redhat.com>
+---
+ Makefile.util.def |  9 +++++++++
+ util/editenv.c    | 46 ++++++++++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 53 insertions(+), 2 deletions(-)
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index c7b775bce73..d08713b5500 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -231,8 +231,17 @@ program = {
+ 
+   common = util/grub-editenv.c;
+   common = util/editenv.c;
++  common = util/grub-install-common.c;
+   common = grub-core/osdep/init.c;
++  common = grub-core/osdep/compress.c;
++  extra_dist = grub-core/osdep/unix/compress.c;
++  extra_dist = grub-core/osdep/basic/compress.c;
++  common = util/mkimage.c;
++  common = grub-core/osdep/config.c;
++  common = util/config.c;
++  common = util/resolve.c;
+ 
++  ldadd = '$(LIBLZMA)';
+   ldadd = libgrubmods.a;
+   ldadd = libgrubgcry.a;
+   ldadd = libgrubkern.a;
+diff --git a/util/editenv.c b/util/editenv.c
+index c6f8d2298c3..d8d1dad6ab9 100644
+--- a/util/editenv.c
++++ b/util/editenv.c
+@@ -37,6 +37,7 @@ grub_util_create_envblk_file (const char *name)
+   FILE *fp;
+   char *buf;
+   char *namenew;
++  char *rename_target = xstrdup(name);
+ 
+   buf = xmalloc (DEFAULT_ENVBLK_SIZE);
+ 
+@@ -59,7 +60,48 @@ grub_util_create_envblk_file (const char *name)
+   free (buf);
+   fclose (fp);
+ 
+-  if (grub_util_rename (namenew, name) < 0)
+-    grub_util_error (_("cannot rename the file %s to %s"), namenew, name);
++  ssize_t size = 1;
++  while (1)
++    {
++      char *linkbuf;
++      ssize_t retsize;
++
++      linkbuf = xmalloc(size+1);
++      retsize = grub_util_readlink (rename_target, linkbuf, size);
++      if (retsize < 0 && (errno == ENOENT || errno == EINVAL))
++	{
++	  free (linkbuf);
++	  break;
++	}
++      else if (retsize < 0)
++	{
++	  grub_util_error (_("cannot rename the file %s to %s: %m"), namenew, name);
++	  free (linkbuf);
++	  free (namenew);
++	  return;
++	}
++      else if (retsize == size)
++	{
++	  free(linkbuf);
++	  size += 128;
++	  continue;
++	}
++
++      free (rename_target);
++      linkbuf[retsize] = '\0';
++      rename_target = linkbuf;
++    }
++
++  int rc = grub_util_rename (namenew, rename_target);
++  if (rc < 0 && errno == EXDEV)
++    {
++      rc = grub_install_copy_file (namenew, rename_target, 1);
++      grub_util_unlink (namenew);
++    }
++
++  if (rc < 0)
++    grub_util_error (_("cannot rename the file %s to %s: %m"), namenew, name);
++
+   free (namenew);
++  free (rename_target);
+ }
diff --git a/SOURCES/0056-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch b/SOURCES/0056-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch
new file mode 100644
index 0000000..81e0e52
--- /dev/null
+++ b/SOURCES/0056-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 4 Sep 2014 14:23:23 -0400
+Subject: [PATCH] Generate OS and CLASS in 10_linux from /etc/os-release
+
+This makes us use pretty names in the titles we generate in
+grub2-mkconfig when GRUB_DISTRIBUTOR isn't set.
+
+Resolves: rhbz#996794
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/10_linux.in | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index b744438e04a..43d98476b88 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -29,7 +29,8 @@ export TEXTDOMAINDIR="@localedir@"
+ CLASS="--class gnu-linux --class gnu --class os --unrestricted"
+ 
+ if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
+-  OS="$(sed 's, release .*$,,g' /etc/system-release)"
++  OS="$(eval $(grep PRETTY_NAME /etc/os-release) ; echo ${PRETTY_NAME})"
++  CLASS="--class $(eval $(grep '^ID_LIKE=\|^ID=' /etc/os-release) ; [ -n "${ID_LIKE}" ] && echo ${ID_LIKE} || echo ${ID}) ${CLASS}"
+ else
+   OS="${GRUB_DISTRIBUTOR}"
+   CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
diff --git a/SOURCES/0057-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch b/SOURCES/0057-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch
new file mode 100644
index 0000000..fc29633
--- /dev/null
+++ b/SOURCES/0057-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch
@@ -0,0 +1,30 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 4 Sep 2014 15:52:08 -0400
+Subject: [PATCH] Minimize the sort ordering for .debug and -rescue- kernels.
+
+Resolves: rhbz#1065360
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-mkconfig_lib.in | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index 1001a12232b..1a4a57898f9 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -249,6 +249,14 @@ version_test_gt ()
+     *.old:*.old) ;;
+     *.old:*) version_test_gt_a="`echo "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;;
+     *:*.old) version_test_gt_b="`echo "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;;
++    *-rescue*:*-rescue*) ;;
++    *?debug:*?debug) ;;
++    *-rescue*:*?debug) return 1 ;;
++    *?debug:*-rescue*) return 0 ;;
++    *-rescue*:*) return 1 ;;
++    *:*-rescue*) return 0 ;;
++    *?debug:*) return 1 ;;
++    *:*?debug) return 0 ;;
+   esac
+   version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b"
+   return "$?"
diff --git a/SOURCES/0058-Try-prefix-if-fw_path-doesn-t-work.patch b/SOURCES/0058-Try-prefix-if-fw_path-doesn-t-work.patch
new file mode 100644
index 0000000..1ded908
--- /dev/null
+++ b/SOURCES/0058-Try-prefix-if-fw_path-doesn-t-work.patch
@@ -0,0 +1,208 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 3 Oct 2014 11:08:03 -0400
+Subject: [PATCH] Try $prefix if $fw_path doesn't work.
+
+Related: rhbz#1148652
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/ieee1275/init.c |  28 +++++-----
+ grub-core/net/net.c            |   2 +-
+ grub-core/normal/main.c        | 120 ++++++++++++++++++++---------------------
+ 3 files changed, 75 insertions(+), 75 deletions(-)
+
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index f5423ce27d9..e01bc6eab19 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -124,23 +124,25 @@ grub_machine_get_bootlocation (char **device, char **path)
+       grub_free (canon);
+     }
+   else
+-    *device = grub_ieee1275_encode_devname (bootpath);
+-  grub_free (type);
+-
+-  filename = grub_ieee1275_get_filename (bootpath);
+-  if (filename)
+     {
+-      char *lastslash = grub_strrchr (filename, '\\');
+-
+-      /* Truncate at last directory.  */
+-      if (lastslash)
++      filename = grub_ieee1275_get_filename (bootpath);
++      if (filename)
+         {
+-	  *lastslash = '\0';
+-	  grub_translate_ieee1275_path (filename);
++          char *lastslash = grub_strrchr (filename, '\\');
+ 
+-	  *path = filename;
+-	}
++          /* Truncate at last directory.  */
++          if (lastslash)
++            {
++              *lastslash = '\0';
++              grub_translate_ieee1275_path (filename);
++
++              *path = filename;
++            }
++        }
++      *device = grub_ieee1275_encode_devname (bootpath);
+     }
++
++  grub_free (type);
+   grub_free (bootpath);
+ }
+ 
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 0769bf850d3..16d2ce06d5a 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -1850,7 +1850,7 @@ grub_net_search_configfile (char *config)
+   /* Remove the remaining minus sign at the end. */
+   config[config_len] = '\0';
+ 
+-  return GRUB_ERR_NONE;
++  return GRUB_ERR_FILE_NOT_FOUND;
+ }
+ 
+ static struct grub_preboot *fini_hnd;
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 7d9c4f09b9b..b69f9e738fa 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -331,74 +331,72 @@ grub_enter_normal_mode (const char *config)
+   grub_boot_time ("Exiting normal mode");
+ }
+ 
++static grub_err_t
++grub_try_normal (const char *variable)
++{
++    char *config;
++    const char *prefix;
++    grub_err_t err = GRUB_ERR_FILE_NOT_FOUND;
++
++    prefix = grub_env_get (variable);
++    if (!prefix)
++      return GRUB_ERR_FILE_NOT_FOUND;
++
++    if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0)
++      {
++	grub_size_t config_len;
++	config_len = grub_strlen (prefix) +
++	  sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
++	config = grub_malloc (config_len);
++
++	if (! config)
++	  return GRUB_ERR_FILE_NOT_FOUND;
++
++	grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
++	err = grub_net_search_configfile (config);
++      }
++
++    if (err != GRUB_ERR_NONE)
++      {
++	config = grub_xasprintf ("%s/grub.cfg", prefix);
++	if (config)
++	  {
++	    grub_file_t file;
++	    file = grub_file_open (config);
++	    if (file)
++	      {
++		grub_file_close (file);
++		err = GRUB_ERR_NONE;
++	      }
++	  }
++      }
++
++    if (err == GRUB_ERR_NONE)
++      grub_enter_normal_mode (config);
++
++    grub_errno = 0;
++    grub_free (config);
++    return err;
++}
++
+ /* Enter normal mode from rescue mode.  */
+ static grub_err_t
+ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+ 		 int argc, char *argv[])
+ {
+-  if (argc == 0)
+-    {
+-      /* Guess the config filename. It is necessary to make CONFIG static,
+-	 so that it won't get broken by longjmp.  */
+-      char *config;
+-      const char *prefix;
+-
+-      prefix = grub_env_get ("fw_path");
+-      if (! prefix)
+-	      prefix = grub_env_get ("prefix");
+-
+-      if (prefix)
+-	{
+-	  if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0)
+-	    {
+-	      grub_size_t config_len;
+-	      config_len = grub_strlen (prefix) +
+-		sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
+-	      config = grub_malloc (config_len);
+-
+-	      if (! config)
+-		goto quit;
+-
+-	      grub_snprintf (config, config_len, "%s/grub.cfg", prefix);
+-
+-	      grub_net_search_configfile (config);
+-
+-	      grub_enter_normal_mode (config);
+-	      grub_free (config);
+-	      config = NULL;
+-	    }
+-
+-	  if (!config)
+-	    {
+-	      config = grub_xasprintf ("%s/grub.cfg", prefix);
+-	      if (config)
+-		{
+-		  grub_file_t file;
+-
+-		  file = grub_file_open (config);
+-		  if (file)
+-		    {
+-		      grub_file_close (file);
+-		      grub_enter_normal_mode (config);
+-		    }
+-		  else
+-		    {
+-		      /*  Ignore all errors.  */
+-		      grub_errno = 0;
+-		    }
+-		  grub_free (config);
+-		}
+-	    }
+-	}
+-      else
+-	{
+-	  grub_enter_normal_mode (0);
+-	}
+-    }
+-  else
++  if (argc)
+     grub_enter_normal_mode (argv[0]);
++  else
++    {
++      /* Guess the config filename. */
++      grub_err_t err;
++      err = grub_try_normal ("fw_path");
++      if (err == GRUB_ERR_FILE_NOT_FOUND)
++        err = grub_try_normal ("prefix");
++      if (err == GRUB_ERR_FILE_NOT_FOUND)
++        grub_enter_normal_mode (0);
++    }
+ 
+-quit:
+   return 0;
+ }
+ 
diff --git a/SOURCES/0059-Update-info-with-grub.cfg-netboot-selection-order-11.patch b/SOURCES/0059-Update-info-with-grub.cfg-netboot-selection-order-11.patch
new file mode 100644
index 0000000..26de3f4
--- /dev/null
+++ b/SOURCES/0059-Update-info-with-grub.cfg-netboot-selection-order-11.patch
@@ -0,0 +1,66 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Mon, 16 Mar 2015 16:34:51 -0400
+Subject: [PATCH] Update info with grub.cfg netboot selection order (#1148650)
+
+Added documentation to the grub info page that specifies the order
+netboot clients will use to select a grub configuration file.
+
+Resolves rhbz#1148650
+---
+ docs/grub.texi | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 2fd32608c01..a7155c22ffe 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -2493,6 +2493,48 @@ grub-mknetdir --net-directory=/srv/tftp --subdir=/boot/grub -d /usr/lib/grub/i38
+ Then follow instructions printed out by grub-mknetdir on configuring your DHCP
+ server.
+ 
++The grub.cfg file is placed in the same directory as the path output by
++grub-mknetdir hereafter referred to as FWPATH. GRUB will search for its 
++configuration files in order using the following rules where the appended
++value corresponds to a value on the client machine.
++
++@example
++@group
++@samp{(FWPATH)}/grub.cfg-@samp{(UUID OF NIC)}
++@samp{(FWPATH)}/grub.cfg-@samp{(MAC ADDRESS OF NIC)}
++@samp{(FWPATH)}/grub.cfg-@samp{(IPv4 OR IPv6 ADDRESS)}
++@samp{(FWPATH)}/grub.cfg
++@end group
++@end example
++
++The client will only attempt to look up an IPv6 address config once, however,
++it will try the IPv4 multiple times. The concrete example below shows what
++would happen under the IPv4 case.
++
++@example
++@group
++UUID: 7726a678-7fc0-4853-a4f6-c85ac36a120a
++MAC:  52:54:00:ec:33:81
++IPV4: 10.0.0.130 (0A000082)
++@end group
++@end example
++
++@example
++@group
++@samp{(FWPATH)}/grub.cfg-7726a678-7fc0-4853-a4f6-c85ac36a120a
++@samp{(FWPATH)}/grub.cfg-52-54-00-ec-33-81
++@samp{(FWPATH)}/grub.cfg-0A000082
++@samp{(FWPATH)}/grub.cfg-0A00008
++@samp{(FWPATH)}/grub.cfg-0A0000
++@samp{(FWPATH)}/grub.cfg-0A000
++@samp{(FWPATH)}/grub.cfg-0A00
++@samp{(FWPATH)}/grub.cfg-0A0
++@samp{(FWPATH)}/grub.cfg-0A
++@samp{(FWPATH)}/grub.cfg-0
++@samp{(FWPATH)}/grub.cfg
++@end group
++@end example
++
+ After GRUB has started, files on the TFTP server will be accessible via the
+ @samp{(tftp)} device.
+ 
diff --git a/SOURCES/0060-Use-Distribution-Package-Sort-for-grub2-mkconfig-112.patch b/SOURCES/0060-Use-Distribution-Package-Sort-for-grub2-mkconfig-112.patch
new file mode 100644
index 0000000..d686cf3
--- /dev/null
+++ b/SOURCES/0060-Use-Distribution-Package-Sort-for-grub2-mkconfig-112.patch
@@ -0,0 +1,447 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Mon, 16 Mar 2015 14:14:19 -0400
+Subject: [PATCH] Use Distribution Package Sort for grub2-mkconfig (#1124074)
+
+Users reported that newly installed kernels on their systems installed
+with grub-mkconfig would not appear on the grub boot list in order
+starting with the most recent. Added an option for rpm-based systems to
+use the rpm-sort library to sort kernels instead.
+
+Resolves rhbz#1124074
+---
+ configure.ac              |  29 +++++
+ Makefile.util.def         |  16 +++
+ util/grub-rpm-sort.c      | 281 ++++++++++++++++++++++++++++++++++++++++++++++
+ .gitignore                |   2 +
+ util/grub-mkconfig_lib.in |   8 +-
+ util/grub-rpm-sort.8      |  12 ++
+ 6 files changed, 347 insertions(+), 1 deletion(-)
+ create mode 100644 util/grub-rpm-sort.c
+ create mode 100644 util/grub-rpm-sort.8
+
+diff --git a/configure.ac b/configure.ac
+index d5db2803ec4..056df1cbaf9 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -65,6 +65,7 @@ grub_TRANSFORM([grub-mkrelpath])
+ grub_TRANSFORM([grub-mkrescue])
+ grub_TRANSFORM([grub-probe])
+ grub_TRANSFORM([grub-reboot])
++grub_TRANSFORM([grub-rpm-sort])
+ grub_TRANSFORM([grub-script-check])
+ grub_TRANSFORM([grub-set-default])
+ grub_TRANSFORM([grub-sparc64-setup])
+@@ -88,6 +89,7 @@ grub_TRANSFORM([grub-mkrescue.1])
+ grub_TRANSFORM([grub-mkstandalone.3])
+ grub_TRANSFORM([grub-ofpathname.3])
+ grub_TRANSFORM([grub-probe.3])
++grub_TRANSFORM([grub-rpm-sort.8])
+ grub_TRANSFORM([grub-reboot.3])
+ grub_TRANSFORM([grub-render-label.3])
+ grub_TRANSFORM([grub-script-check.3])
+@@ -1790,6 +1792,33 @@ fi
+ 
+ AC_SUBST([LIBDEVMAPPER])
+ 
++AC_ARG_ENABLE([rpm-sort],
++              [AS_HELP_STRING([--enable-rpm-sort],
++                              [enable native rpm sorting of kernels in grub (default=guessed)])])
++if test x"$enable_rpm-sort" = xno ; then
++  rpm_sort_excuse="explicitly disabled"
++fi
++
++if test x"$rpm_sort_excuse" = x ; then
++  # Check for rpmlib header.
++  AC_CHECK_HEADER([rpm/rpmlib.h], [],
++               [rpm_sort_excuse="need rpm/rpmlib header"])
++fi
++
++if test x"$rpm_sort_excuse" = x ; then
++  # Check for rpm library.
++  AC_CHECK_LIB([rpm], [rpmvercmp], [],
++               [rpm_sort_excuse="rpmlib missing rpmvercmp"])
++fi
++
++if test x"$rpm_sort_excuse" = x ; then
++   LIBRPM="-lrpm";
++   AC_DEFINE([HAVE_RPM], [1],
++             [Define to 1 if you have the rpm library.])
++fi
++
++AC_SUBST([LIBRPM])
++
+ LIBGEOM=
+ if test x$host_kernel = xkfreebsd; then
+   AC_CHECK_LIB([geom], [geom_gettree], [],
+diff --git a/Makefile.util.def b/Makefile.util.def
+index d08713b5500..406d96861b6 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -685,6 +685,22 @@ program = {
+   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
+ };
+ 
++program = {
++  name = grub-rpm-sort;
++  mansection = 8;
++  installdir = sbin;
++
++  common = grub-core/kern/emu/misc.c;
++  common = grub-core/kern/emu/argp_common.c;
++  common = grub-core/osdep/init.c;
++  common = util/misc.c;
++  common = util/grub-rpm-sort.c;
++
++  ldadd = grub-core/gnulib/libgnu.a;
++  ldadd = libgrubkern.a;
++  ldadd = '$(LIBDEVMAPPER) $(LIBRPM)';
++};
++
+ script = {
+   name = grub-mkconfig;
+   common = util/grub-mkconfig.in;
+diff --git a/util/grub-rpm-sort.c b/util/grub-rpm-sort.c
+new file mode 100644
+index 00000000000..f33bd1ed568
+--- /dev/null
++++ b/util/grub-rpm-sort.c
+@@ -0,0 +1,281 @@
++#include <config.h>
++#include <grub/types.h>
++#include <grub/util/misc.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include <assert.h>
++#include <argp.h>
++#include <rpm/rpmlib.h>
++
++static size_t
++read_file (const char *input, char **ret)
++{
++  FILE *in;
++  size_t s;
++  size_t sz = 2048;
++  size_t offset = 0;
++  char *text;
++
++  if (!strcmp(input, "-"))
++    in = stdin;
++  else
++    in = grub_util_fopen(input, "r");
++
++  text = xmalloc (sz);
++
++  if (!in)
++    grub_util_error (_("cannot open `%s': %s"), input, strerror (errno));
++
++  while ((s = fread (text + offset, 1, sz - offset, in)) != 0)
++    {
++      offset += s;
++      if (sz - offset == 0)
++	{
++	  sz += 2048;
++	  text = xrealloc (text, sz);
++	}
++    }
++
++  text[offset] = '\0';
++  *ret = text;
++
++  if (in != stdin)
++    fclose(in);
++
++  return offset + 1;
++}
++
++/* returns name/version/release */
++/* NULL string pointer returned if nothing found */
++static void
++split_package_string (char *package_string, char **name,
++                     char **version, char **release)
++{
++  char *package_version, *package_release;
++
++  /* Release */
++  package_release = strrchr (package_string, '-');
++
++  if (package_release != NULL)
++      *package_release++ = '\0';
++
++  *release = package_release;
++
++  /* Version */
++  package_version = strrchr(package_string, '-');
++
++  if (package_version != NULL)
++      *package_version++ = '\0';
++
++  *version = package_version;
++  /* Name */
++  *name = package_string;
++
++  /* Bubble up non-null values from release to name */
++  if (*name == NULL)
++    {
++      *name = (*version == NULL ? *release : *version);
++      *version = *release;
++      *release = NULL;
++    }
++  if (*version == NULL)
++    {
++      *version = *release;
++      *release = NULL;
++    }
++}
++
++/*
++ * package name-version-release comparator for qsort
++ * expects p, q which are pointers to character strings (char *)
++ * which will not be altered in this function
++ */
++static int
++package_version_compare (const void *p, const void *q)
++{
++  char *local_p, *local_q;
++  char *lhs_name, *lhs_version, *lhs_release;
++  char *rhs_name, *rhs_version, *rhs_release;
++  int vercmpflag = 0;
++
++  local_p = alloca (strlen (*(char * const *)p) + 1);
++  local_q = alloca (strlen (*(char * const *)q) + 1);
++
++  /* make sure these allocated */
++  assert (local_p);
++  assert (local_q);
++
++  strcpy (local_p, *(char * const *)p);
++  strcpy (local_q, *(char * const *)q);
++
++  split_package_string (local_p, &lhs_name, &lhs_version, &lhs_release);
++  split_package_string (local_q, &rhs_name, &rhs_version, &rhs_release);
++
++  /* Check Name and return if unequal */
++  vercmpflag = rpmvercmp ((lhs_name == NULL ? "" : lhs_name),
++                          (rhs_name == NULL ? "" : rhs_name));
++  if (vercmpflag != 0)
++    return vercmpflag;
++
++  /* Check version and return if unequal */
++  vercmpflag = rpmvercmp ((lhs_version == NULL ? "" : lhs_version),
++                          (rhs_version == NULL ? "" : rhs_version));
++  if (vercmpflag != 0)
++    return vercmpflag;
++
++  /* Check release and return the version compare value */
++  vercmpflag = rpmvercmp ((lhs_release == NULL ? "" : lhs_release),
++                          (rhs_release == NULL ? "" : rhs_release));
++
++  return vercmpflag;
++}
++
++static void
++add_input (const char *filename, char ***package_names, size_t *n_package_names)
++{
++  char *orig_input_buffer = NULL;
++  char *input_buffer;
++  char *position_of_newline;
++  char **names = *package_names;
++  char **new_names = NULL;
++  size_t n_names = *n_package_names;
++
++  if (!*package_names)
++    new_names = names = xmalloc (sizeof (char *) * 2);
++
++  if (read_file (filename, &orig_input_buffer) < 2)
++    {
++      if (new_names)
++	free (new_names);
++      if (orig_input_buffer)
++	free (orig_input_buffer);
++      return;
++    }
++
++  input_buffer = orig_input_buffer;
++  while (input_buffer && *input_buffer &&
++	 (position_of_newline = strchrnul (input_buffer, '\n')))
++    {
++      size_t sz = position_of_newline - input_buffer;
++      char *new;
++
++      if (sz == 0)
++	{
++	  input_buffer = position_of_newline + 1;
++	  continue;
++	}
++
++      new = xmalloc (sz+1);
++      strncpy (new, input_buffer, sz);
++      new[sz] = '\0';
++
++      names = xrealloc (names, sizeof (char *) * (n_names + 1));
++      names[n_names] = new;
++      n_names++;
++
++      /* move buffer ahead to next line */
++      input_buffer = position_of_newline + 1;
++      if (*position_of_newline == '\0')
++	input_buffer = NULL;
++    }
++
++  free (orig_input_buffer);
++
++  *package_names = names;
++  *n_package_names = n_names;
++}
++
++static char *
++help_filter (int key, const char *text, void *input __attribute__ ((unused)))
++{
++  return (char *)text;
++}
++
++static struct argp_option options[] = {
++  { 0, }
++};
++
++struct arguments
++{
++  size_t ninputs;
++  size_t input_max;
++  char **inputs;
++};
++
++static error_t
++argp_parser (int key, char *arg, struct argp_state *state)
++{
++  struct arguments *arguments = state->input;
++  switch (key)
++    {
++    case ARGP_KEY_ARG:
++      assert (arguments->ninputs < arguments->input_max);
++      arguments->inputs[arguments->ninputs++] = xstrdup (arg);
++      break;
++    default:
++      return ARGP_ERR_UNKNOWN;
++    }
++  return 0;
++}
++
++static struct argp argp = {
++  options, argp_parser, N_("[INPUT_FILES]"),
++  N_("Sort a list of strings in RPM version sort order."),
++  NULL, help_filter, NULL
++};
++
++int
++main (int argc, char *argv[])
++{
++  struct arguments arguments;
++  char **package_names = NULL;
++  size_t n_package_names = 0;
++  int i;
++
++  grub_util_host_init (&argc, &argv);
++
++  memset (&arguments, 0, sizeof (struct arguments));
++  arguments.input_max = argc+1;
++  arguments.inputs = xmalloc ((arguments.input_max + 1)
++			      * sizeof (arguments.inputs[0]));
++  memset (arguments.inputs, 0, (arguments.input_max + 1)
++	  * sizeof (arguments.inputs[0]));
++
++  /* Parse our arguments */
++  if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0)
++    grub_util_error ("%s", _("Error in parsing command line arguments\n"));
++
++  /* If there's no inputs in argv, add one for stdin */
++  if (!arguments.ninputs)
++    {
++      arguments.ninputs = 1;
++      arguments.inputs[0] = xmalloc (2);
++      strcpy(arguments.inputs[0], "-");
++    }
++
++  for (i = 0; i < arguments.ninputs; i++)
++    add_input(arguments.inputs[i], &package_names, &n_package_names);
++
++  if (package_names == NULL || n_package_names < 1)
++    grub_util_error ("%s", _("Invalid input\n"));
++
++  qsort (package_names, n_package_names, sizeof (char *),
++	 package_version_compare);
++
++  /* send sorted list to stdout */
++  for (i = 0; i < n_package_names; i++)
++    {
++      fprintf (stdout, "%s\n", package_names[i]);
++      free (package_names[i]);
++    }
++
++  free (package_names);
++  for (i = 0; i < arguments.ninputs; i++)
++    free (arguments.inputs[i]);
++
++  free (arguments.inputs);
++
++  return 0;
++}
+diff --git a/.gitignore b/.gitignore
+index 43f04d47277..fa2e5b609b1 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -105,6 +105,8 @@ grub-*.tar.*
+ /grub*-reboot.8
+ /grub*-render-label
+ /grub*-render-label.1
++/grub*-rpm-sort
++/grub*-rpm-sort.8
+ /grub*-script-check
+ /grub*-script-check.1
+ /grub*-set-default
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index 1a4a57898f9..7fe3598435c 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -214,6 +214,12 @@ version_sort ()
+    esac
+ }
+ 
++if [ "x$RPMLIB" = x ]; then
++  kernel_sort=version_sort
++else
++  kernel_sort="${sbindir}/grub-rpm-sort"
++fi
++
+ version_test_numeric ()
+ {
+   version_test_numeric_a="$1"
+@@ -230,7 +236,7 @@ version_test_numeric ()
+     version_test_numeric_a="$version_test_numeric_b"
+     version_test_numeric_b="$version_test_numeric_c"
+   fi
+-  if (echo "$version_test_numeric_a" ; echo "$version_test_numeric_b") | version_sort | head -n 1 | grep -qx "$version_test_numeric_b" ; then
++  if (echo "$version_test_numeric_a" ; echo "$version_test_numeric_b") | "$kernel_sort" | head -n 1 | grep -qx "$version_test_numeric_b" ; then
+     return 0
+   else
+     return 1
+diff --git a/util/grub-rpm-sort.8 b/util/grub-rpm-sort.8
+new file mode 100644
+index 00000000000..8ce21488448
+--- /dev/null
++++ b/util/grub-rpm-sort.8
+@@ -0,0 +1,12 @@
++.TH GRUB-RPM-SORT 8 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-rpm-sort\fR \(em Sort input according to RPM version compare.
++
++.SH SYNOPSIS
++\fBgrub-rpm-sort\fR [OPTIONS].
++
++.SH DESCRIPTION
++You should not normally run this program directly.  Use grub-mkconfig instead.
++
++.SH SEE ALSO
++.BR "info grub"
diff --git a/SOURCES/0061-Handle-rssd-storage-devices.patch b/SOURCES/0061-Handle-rssd-storage-devices.patch
new file mode 100644
index 0000000..8f25692
--- /dev/null
+++ b/SOURCES/0061-Handle-rssd-storage-devices.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 30 Jun 2015 15:50:41 -0400
+Subject: [PATCH] Handle rssd storage devices.
+
+Resolves: rhbz#1087962
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/osdep/linux/getroot.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
+index 90d92d3ad5c..6d9f4e5faa2 100644
+--- a/grub-core/osdep/linux/getroot.c
++++ b/grub-core/osdep/linux/getroot.c
+@@ -921,6 +921,19 @@ grub_util_part_to_disk (const char *os_dev, struct stat *st,
+ 	  return path;
+ 	}
+ 
++      /* If this is an rssd device. */
++      if ((strncmp ("rssd", p, 4) == 0) && p[4] >= 'a' && p[4] <= 'z')
++	{
++	  char *pp = p + 4;
++	  while (*pp >= 'a' && *pp <= 'z')
++	    pp++;
++	  if (*pp)
++	    *is_part = 1;
++	  /* /dev/rssd[a-z]+[0-9]* */
++	  *pp = '\0';
++	  return path;
++	}
++
+       /* If this is a loop device */
+       if ((strncmp ("loop", p, 4) == 0) && p[4] >= '0' && p[4] <= '9')
+ 	{
diff --git a/SOURCES/0062-Make-grub2-mkconfig-construct-titles-that-look-like-.patch b/SOURCES/0062-Make-grub2-mkconfig-construct-titles-that-look-like-.patch
new file mode 100644
index 0000000..3bbaa1d
--- /dev/null
+++ b/SOURCES/0062-Make-grub2-mkconfig-construct-titles-that-look-like-.patch
@@ -0,0 +1,69 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 28 Apr 2015 11:15:03 -0400
+Subject: [PATCH] Make grub2-mkconfig construct titles that look like the ones
+ we want elsewhere.
+
+Resolves: rhbz#1215839
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/10_linux.in | 34 +++++++++++++++++++++++++++-------
+ 1 file changed, 27 insertions(+), 7 deletions(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 43d98476b88..a8a8e2cf325 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -78,6 +78,32 @@ case x"$GRUB_FS" in
+ 	;;
+ esac
+ 
++mktitle ()
++{
++  local title_type
++  local version
++  local OS_NAME
++  local OS_VERS
++
++  title_type=$1 && shift
++  version=$1 && shift
++
++  OS_NAME="$(eval $(grep ^NAME= /etc/os-release) ; echo ${NAME})"
++  OS_VERS="$(eval $(grep ^VERSION= /etc/os-release) ; echo ${VERSION})"
++
++  case $title_type in
++    recovery)
++      title=$(printf '%s (%s) %s (recovery mode)' \
++                     "${OS_NAME}" "${version}" "${OS_VERS}")
++      ;;
++    *)
++      title=$(printf '%s (%s) %s' \
++                     "${OS_NAME}" "${version}" "${OS_VERS}")
++      ;;
++  esac
++  echo -n ${title}
++}
++
+ title_correction_code=
+ 
+ linux_entry ()
+@@ -91,17 +117,11 @@ linux_entry ()
+       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+   fi
+   if [ x$type != xsimple ] ; then
+-      case $type in
+-	  recovery)
+-	      title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;;
+-	  *)
+-	      title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;;
+-      esac
++      title=$(mktitle "$type" "$version")
+       if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
+ 	  replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')"
+ 	  quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)"
+ 	  title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
+-	  grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")"
+       fi
+       echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+   else
diff --git a/SOURCES/0063-Add-friendly-grub2-password-config-tool-985962.patch b/SOURCES/0063-Add-friendly-grub2-password-config-tool-985962.patch
new file mode 100644
index 0000000..49ebfa7
--- /dev/null
+++ b/SOURCES/0063-Add-friendly-grub2-password-config-tool-985962.patch
@@ -0,0 +1,272 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Thu, 25 Jun 2015 11:13:11 -0400
+Subject: [PATCH] Add friendly grub2 password config tool (#985962)
+
+Provided a tool for users to reset the grub2 root user password
+without having to alter the grub.cfg. The hashed password now
+lives in a root-only-readable configuration file.
+
+Resolves: rhbz#985962
+---
+ configure.ac             |   1 +
+ Makefile.util.def        |  13 +++++
+ .gitignore               |   2 +
+ util/grub-mkconfig.in    |   2 +
+ util/grub-setpassword.8  |  28 +++++++++++
+ util/grub-setpassword.in | 123 +++++++++++++++++++++++++++++++++++++++++++++++
+ util/grub.d/01_users.in  |  11 +++++
+ 7 files changed, 180 insertions(+)
+ create mode 100644 util/grub-setpassword.8
+ create mode 100644 util/grub-setpassword.in
+ create mode 100644 util/grub.d/01_users.in
+
+diff --git a/configure.ac b/configure.ac
+index 056df1cbaf9..679f634ce4c 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -65,6 +65,7 @@ grub_TRANSFORM([grub-mkrelpath])
+ grub_TRANSFORM([grub-mkrescue])
+ grub_TRANSFORM([grub-probe])
+ grub_TRANSFORM([grub-reboot])
++grub_TRANSFORM([grub-setpassword])
+ grub_TRANSFORM([grub-rpm-sort])
+ grub_TRANSFORM([grub-script-check])
+ grub_TRANSFORM([grub-set-default])
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 406d96861b6..fd91045bd6d 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -440,6 +440,12 @@ script = {
+   installdir = grubconf;
+ };
+ 
++script = {
++  name = '01_users';
++  common = util/grub.d/01_users.in;
++  installdir = grubconf;
++};
++
+ script = {
+   name = '10_windows';
+   common = util/grub.d/10_windows.in;
+@@ -722,6 +728,13 @@ script = {
+   installdir = sbin;
+ };
+ 
++script = {
++  name = grub-setpassword;
++  common = util/grub-setpassword.in;
++  mansection = 8;
++  installdir = sbin;
++};
++
+ script = {
+   name = grub-mkconfig_lib;
+   common = util/grub-mkconfig_lib.in;
+diff --git a/.gitignore b/.gitignore
+index fa2e5b609b1..5066689bc0a 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -111,6 +111,8 @@ grub-*.tar.*
+ /grub*-script-check.1
+ /grub*-set-default
+ /grub*-set-default.8
++/grub*-setsetpassword
++/grub*-setsetpassword.8
+ /grub*-shell
+ /grub*-shell-tester
+ /grub*-sparc64-setup
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index f68d4925ee6..bdb9982aefb 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -282,6 +282,8 @@ for i in "${grub_mkconfig_dir}"/* ; do
+     *~) ;;
+     # emacsen autosave files. FIXME: support other editors
+     */\#*\#) ;;
++    # rpm config files of yore.
++    *.rpmsave|*.rpmnew|*.rpmorig) ;;
+     *)
+       if grub_file_is_not_garbage "$i" && test -x "$i" ; then
+         echo
+diff --git a/util/grub-setpassword.8 b/util/grub-setpassword.8
+new file mode 100644
+index 00000000000..49200a848b7
+--- /dev/null
++++ b/util/grub-setpassword.8
+@@ -0,0 +1,28 @@
++.TH GRUB-SETPASSWORD 3 "Thu Jun 25 2015"
++.SH NAME
++\fBgrub-setpassword\fR \(em Generate the user.cfg file containing the hashed grub bootloader password.
++
++.SH SYNOPSIS
++\fBgrub-setpassword\fR [OPTION]
++
++.SH DESCRIPTION
++\fBgrub-setpassword\fR outputs the user.cfg file which contains the hashed GRUB bootloader password. This utility only supports configurations where there is a single root user.
++
++The file has the format:
++GRUB2_PASSWORD=<\fIhashed password\fR>.
++
++.SH OPTIONS
++.TP
++-h, --help
++Display program usage and exit.
++.TP
++-v, --version
++Display the current version.
++.TP
++-o, --output[=\fIDIRECTORY PATH\fR]
++Choose the file path to which user.cfg will be written.
++
++.SH SEE ALSO
++.BR "info grub"
++
++.BR "info grub2-mkpasswd-pbkdf2"
+diff --git a/util/grub-setpassword.in b/util/grub-setpassword.in
+new file mode 100644
+index 00000000000..dd76f00fc0e
+--- /dev/null
++++ b/util/grub-setpassword.in
+@@ -0,0 +1,123 @@
++#!/bin/sh -e
++
++if [ -d /sys/firmware/efi/efivars/ ]; then
++    grubdir=`echo "/@bootdirname@/efi/EFI/redhat/" | sed 's,//*,/,g'`
++else
++    grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
++fi
++
++PACKAGE_VERSION="@PACKAGE_VERSION@"
++PACKAGE_NAME="@PACKAGE_NAME@"
++self=`basename $0`
++bindir="@bindir@"
++grub_mkpasswd="${bindir}/@grub_mkpasswd_pbkdf2@"
++
++# Usage: usage
++# Print the usage.
++usage () {
++    cat <<EOF
++Usage: $0 [OPTION] [SOURCE]
++Run GRUB script in a Qemu instance.
++
++  -h, --help              print this message and exit
++  -v, --version           print the version information and exit
++  -o, --output_path       choose a custom output path for user.cfg
++
++$0 prompts the user to set a password on the grub bootloader. The password
++is written to a file named user.cfg.
++
++Report bugs at https://bugzilla.redhat.com.
++EOF
++}
++
++argument () {
++    opt=$1
++    shift
++
++    if test $# -eq 0; then
++        gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2
++        exit 1
++    fi
++    echo $1
++}
++
++# Ensure that it's the root user running this script
++if [ "${EUID}" -ne 0 ]; then
++    echo "The grub bootloader password may only be set by root."
++    usage
++    exit 2
++fi
++
++# Check the arguments.
++while test $# -gt 0
++do
++    option=$1
++    shift
++
++    case "$option" in
++    -h | --help)
++	usage
++	exit 0 ;;
++    -v | --version)
++	echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}"
++	exit 0 ;;
++    -o | --output)
++        OUTPUT_PATH=`argument $option "$@"`; shift ;;
++    --output=*)
++        OUTPUT_PATH=`echo "$option" | sed 's/--output=//'` ;;
++    -o=*)
++        OUTPUT_PATH=`echo "$option" | sed 's/-o=//'` ;;
++    esac
++done
++
++# set user input or default path for user.cfg file
++if [ -z "${OUTPUT_PATH}" ]; then
++    OUTPUT_PATH="${grubdir}"
++fi
++
++if [ ! -d "${OUTPUT_PATH}" ]; then
++    echo "${OUTPUT_PATH} does not exist."
++    usage
++    exit 2;
++fi
++
++ttyopt=$(stty -g)
++fixtty() {
++      stty ${ttyopt}
++}
++
++trap fixtty EXIT
++stty -echo
++
++# prompt & confirm new grub2 root user password
++echo -n "Enter password: "
++read PASSWORD
++echo
++echo -n "Confirm password: "
++read PASSWORD_CONFIRM
++echo
++stty ${ttyopt}
++
++getpass() {
++    local P0
++    local P1
++    P0="$1" && shift
++    P1="$1" && shift
++
++    ( echo ${P0} ; echo ${P1} ) | \
++        ${grub_mkpasswd} | \
++        grep -v '[eE]nter password:' | \
++        sed -e "s/PBKDF2 hash of your password is //"
++}
++
++MYPASS="$(getpass "${PASSWORD}" "${PASSWORD_CONFIRM}")"
++if [ -z "${MYPASS}" ]; then
++      echo "${self}: error: empty password" 1>&2
++      exit 1
++fi
++
++# on the ESP, these will fail to set the permissions, but it's okay because
++# the directory is protected.
++install -m 0600 /dev/null "${grubdir}/user.cfg" 2>/dev/null || :
++chmod 0600 "${grubdir}/user.cfg" 2>/dev/null || :
++echo "GRUB2_PASSWORD=${MYPASS}" > "${grubdir}/user.cfg"
+diff --git a/util/grub.d/01_users.in b/util/grub.d/01_users.in
+new file mode 100644
+index 00000000000..db2f44bfb78
+--- /dev/null
++++ b/util/grub.d/01_users.in
+@@ -0,0 +1,11 @@
++#!/bin/sh -e
++cat << EOF
++if [ -f \${prefix}/user.cfg ]; then
++  source \${prefix}/user.cfg
++  if [ -n "\${GRUB2_PASSWORD}" ]; then
++    set superusers="root"
++    export superusers
++    password_pbkdf2 root \${GRUB2_PASSWORD}
++  fi
++fi
++EOF
diff --git a/SOURCES/0064-Try-to-make-sure-configure.ac-and-grub-rpm-sort-play.patch b/SOURCES/0064-Try-to-make-sure-configure.ac-and-grub-rpm-sort-play.patch
new file mode 100644
index 0000000..09061ce
--- /dev/null
+++ b/SOURCES/0064-Try-to-make-sure-configure.ac-and-grub-rpm-sort-play.patch
@@ -0,0 +1,57 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 3 Aug 2015 11:46:42 -0400
+Subject: [PATCH] Try to make sure configure.ac and grub-rpm-sort play nice.
+
+Apparently the test for whether to use grub-rpm-sort and also the
+renaming of it to grub2-rpm-sort on the runtime side weren't right.
+
+Related: rhbz#1124074
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ configure.ac              | 2 +-
+ util/grub-mkconfig_lib.in | 9 ++++++---
+ 2 files changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 679f634ce4c..71d1056969e 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1796,7 +1796,7 @@ AC_SUBST([LIBDEVMAPPER])
+ AC_ARG_ENABLE([rpm-sort],
+               [AS_HELP_STRING([--enable-rpm-sort],
+                               [enable native rpm sorting of kernels in grub (default=guessed)])])
+-if test x"$enable_rpm-sort" = xno ; then
++if test x"$enable_rpm_sort" = xno ; then
+   rpm_sort_excuse="explicitly disabled"
+ fi
+ 
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index 7fe3598435c..113a41f9409 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -33,6 +33,9 @@ fi
+ if test "x$grub_mkrelpath" = x; then
+   grub_mkrelpath="${bindir}/@grub_mkrelpath@"
+ fi
++if test "x$grub_rpm_sort" = x; then
++  grub_rpm_sort="${sbindir}/@grub_rpm_sort@"
++fi
+ 
+ if which gettext >/dev/null 2>/dev/null; then
+   :
+@@ -214,10 +217,10 @@ version_sort ()
+    esac
+ }
+ 
+-if [ "x$RPMLIB" = x ]; then
++if [ "x$grub_rpm_sort" != x -a -x "$grub_rpm_sort" ]; then
++  kernel_sort="$grub_rpm_sort"
++else
+   kernel_sort=version_sort
+-else
+-  kernel_sort="${sbindir}/grub-rpm-sort"
+ fi
+ 
+ version_test_numeric ()
diff --git a/SOURCES/0065-tcp-add-window-scaling-support.patch b/SOURCES/0065-tcp-add-window-scaling-support.patch
new file mode 100644
index 0000000..7d1996c
--- /dev/null
+++ b/SOURCES/0065-tcp-add-window-scaling-support.patch
@@ -0,0 +1,87 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Josef Bacik <jbacik@fb.com>
+Date: Wed, 12 Aug 2015 08:57:55 -0700
+Subject: [PATCH] tcp: add window scaling support
+
+Sometimes we have to provision boxes across regions, such as California to
+Sweden.  The http server has a 10 minute timeout, so if we can't get our 250mb
+image transferred fast enough our provisioning fails, which is not ideal.  So
+add tcp window scaling on open connections and set the window size to 1mb.  With
+this change we're able to get higher sustained transfers between regions and can
+transfer our image in well below 10 minutes.  Without this patch we'd time out
+every time halfway through the transfer.  Thanks,
+
+Signed-off-by: Josef Bacik <jbacik@fb.com>
+---
+ grub-core/net/tcp.c | 42 +++++++++++++++++++++++++++++-------------
+ 1 file changed, 29 insertions(+), 13 deletions(-)
+
+diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c
+index e8ad34b84d4..7d4b822626d 100644
+--- a/grub-core/net/tcp.c
++++ b/grub-core/net/tcp.c
+@@ -106,6 +106,18 @@ struct tcphdr
+   grub_uint16_t urgent;
+ } GRUB_PACKED;
+ 
++struct tcp_scale_opt {
++  grub_uint8_t kind;
++  grub_uint8_t length;
++  grub_uint8_t scale;
++} GRUB_PACKED;
++
++struct tcp_synhdr {
++  struct tcphdr tcphdr;
++  struct tcp_scale_opt scale_opt;
++  grub_uint8_t padding;
++};
++
+ struct tcp_pseudohdr
+ {
+   grub_uint32_t src;
+@@ -566,7 +578,7 @@ grub_net_tcp_open (char *server,
+   grub_net_tcp_socket_t socket;
+   static grub_uint16_t in_port = 21550;
+   struct grub_net_buff *nb;
+-  struct tcphdr *tcph;
++  struct tcp_synhdr *tcph;
+   int i;
+   grub_uint8_t *nbd;
+   grub_net_link_level_address_t ll_target_addr;
+@@ -635,20 +647,24 @@ grub_net_tcp_open (char *server,
+     }
+ 
+   tcph = (void *) nb->data;
++  grub_memset(tcph, 0, sizeof (*tcph));
+   socket->my_start_seq = grub_get_time_ms ();
+   socket->my_cur_seq = socket->my_start_seq + 1;
+-  socket->my_window = 8192;
+-  tcph->seqnr = grub_cpu_to_be32 (socket->my_start_seq);
+-  tcph->ack = grub_cpu_to_be32_compile_time (0);
+-  tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN);
+-  tcph->window = grub_cpu_to_be16 (socket->my_window);
+-  tcph->urgent = 0;
+-  tcph->src = grub_cpu_to_be16 (socket->in_port);
+-  tcph->dst = grub_cpu_to_be16 (socket->out_port);
+-  tcph->checksum = 0;
+-  tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
+-						   &socket->inf->address,
+-						   &socket->out_nla);
++  socket->my_window = 32768;
++  tcph->tcphdr.seqnr = grub_cpu_to_be32 (socket->my_start_seq);
++  tcph->tcphdr.ack = grub_cpu_to_be32_compile_time (0);
++  tcph->tcphdr.flags = grub_cpu_to_be16_compile_time ((6 << 12) | TCP_SYN);
++  tcph->tcphdr.window = grub_cpu_to_be16 (socket->my_window);
++  tcph->tcphdr.urgent = 0;
++  tcph->tcphdr.src = grub_cpu_to_be16 (socket->in_port);
++  tcph->tcphdr.dst = grub_cpu_to_be16 (socket->out_port);
++  tcph->tcphdr.checksum = 0;
++  tcph->scale_opt.kind = 3;
++  tcph->scale_opt.length = 3;
++  tcph->scale_opt.scale = 5;
++  tcph->tcphdr.checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
++							  &socket->inf->address,
++							  &socket->out_nla);
+ 
+   tcp_socket_register (socket);
+ 
diff --git a/SOURCES/0066-efinet-add-filter-for-the-first-exclusive-reopen-of-.patch b/SOURCES/0066-efinet-add-filter-for-the-first-exclusive-reopen-of-.patch
new file mode 100644
index 0000000..691d4dc
--- /dev/null
+++ b/SOURCES/0066-efinet-add-filter-for-the-first-exclusive-reopen-of-.patch
@@ -0,0 +1,59 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: RHEL Ninjas <example@example.com>
+Date: Fri, 25 Sep 2015 16:24:23 +0900
+Subject: [PATCH] efinet: add filter for the first exclusive reopen of SNP
+
+---
+ grub-core/net/drivers/efi/efinet.c | 39 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 5388f952ba9..d15a799f29a 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -383,6 +383,45 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 				    &pxe_mode->dhcp_ack,
+ 				    sizeof (pxe_mode->dhcp_ack),
+ 				    1, device, path);
++    net = grub_efi_open_protocol (card->efi_handle, &net_io_guid,
++				  GRUB_EFI_OPEN_PROTOCOL_BY_EXCLUSIVE);
++    if (net) {
++      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
++	  && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
++	continue;
++
++      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
++	continue;
++
++      if (net->mode->state == GRUB_EFI_NETWORK_STARTED
++	  && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
++	continue;
++
++      /* Enable hardware receive filters if driver declares support for it.
++	 We need unicast and broadcast and additionaly all nodes and
++	 solicited multicast for IPv6. Solicited multicast is per-IPv6
++	 address and we currently do not have API to do it so simply
++	 try to enable receive of all multicast packets or evertyhing in
++	 the worst case (i386 PXE driver always enables promiscuous too).
++
++	 This does trust firmware to do what it claims to do.
++       */
++      if (net->mode->receive_filter_mask)
++	{
++	  grub_uint32_t filters = GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST   |
++				  GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
++				  GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
++
++	  filters &= net->mode->receive_filter_mask;
++	  if (!(filters & GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST))
++	    filters |= (net->mode->receive_filter_mask &
++			GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS);
++
++	  efi_call_6 (net->receive_filters, net, filters, 0, 0, 0, NULL);
++	}
++
++      card->efi_net = net;
++    }
+     return;
+   }
+ }
diff --git a/SOURCES/0067-Fix-security-issue-when-reading-username-and-passwor.patch b/SOURCES/0067-Fix-security-issue-when-reading-username-and-passwor.patch
new file mode 100644
index 0000000..11bc434
--- /dev/null
+++ b/SOURCES/0067-Fix-security-issue-when-reading-username-and-passwor.patch
@@ -0,0 +1,44 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hector Marco-Gisbert <hecmargi@upv.es>
+Date: Fri, 13 Nov 2015 16:21:09 +0100
+Subject: [PATCH] Fix security issue when reading username and password
+
+  This patch fixes two integer underflows at:
+    * grub-core/lib/crypto.c
+    * grub-core/normal/auth.c
+
+Resolves: CVE-2015-8370
+
+Signed-off-by: Hector Marco-Gisbert <hecmargi@upv.es>
+Signed-off-by: Ismael Ripoll-Ripoll <iripoll@disca.upv.es>
+---
+ grub-core/lib/crypto.c  | 2 +-
+ grub-core/normal/auth.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c
+index ca334d5a40e..e6c78d16d39 100644
+--- a/grub-core/lib/crypto.c
++++ b/grub-core/lib/crypto.c
+@@ -468,7 +468,7 @@ grub_password_get (char buf[], unsigned buf_size)
+ 	  break;
+ 	}
+ 
+-      if (key == '\b')
++      if (key == '\b' && cur_len)
+ 	{
+ 	  if (cur_len)
+ 	    cur_len--;
+diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c
+index 6be678c0de1..c35ce972473 100644
+--- a/grub-core/normal/auth.c
++++ b/grub-core/normal/auth.c
+@@ -172,7 +172,7 @@ grub_username_get (char buf[], unsigned buf_size)
+ 	  break;
+ 	}
+ 
+-      if (key == GRUB_TERM_BACKSPACE)
++      if (key == GRUB_TERM_BACKSPACE && cur_len)
+ 	{
+ 	  if (cur_len)
+ 	    {
diff --git a/SOURCES/0068-Warn-if-grub-password-will-not-be-read-1290803.patch b/SOURCES/0068-Warn-if-grub-password-will-not-be-read-1290803.patch
new file mode 100644
index 0000000..de4a6ae
--- /dev/null
+++ b/SOURCES/0068-Warn-if-grub-password-will-not-be-read-1290803.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Mon, 22 Feb 2016 15:30:05 -0500
+Subject: [PATCH] Warn if grub password will not be read (#1290803)
+
+It is possible for a system to have never run grub-mkconfig and add the
+section that reads the user.cfg file which contains a user set GRUB
+password. Users in that scenario will now be warned that grub-mkconfig
+must be run prior to their newly set password taking effect.
+
+Resolves: rhbz#1290803
+---
+ util/grub-setpassword.in | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/util/grub-setpassword.in b/util/grub-setpassword.in
+index dd76f00fc0e..fb9d3a3b6f9 100644
+--- a/util/grub-setpassword.in
++++ b/util/grub-setpassword.in
+@@ -121,3 +121,8 @@ fi
+ install -m 0600 /dev/null "${grubdir}/user.cfg" 2>/dev/null || :
+ chmod 0600 "${grubdir}/user.cfg" 2>/dev/null || :
+ echo "GRUB2_PASSWORD=${MYPASS}" > "${grubdir}/user.cfg"
++
++if ! grep -q "^### BEGIN /etc/grub.d/01_users ###$" "${grubdir}/grub.cfg"; then
++    echo "WARNING: The current configuration lacks password support!"
++    echo "Update your configuration with @grub_mkconfig@ to support this feature."
++fi
diff --git a/SOURCES/0069-Clean-up-grub-setpassword-documentation-1290799.patch b/SOURCES/0069-Clean-up-grub-setpassword-documentation-1290799.patch
new file mode 100644
index 0000000..a405e88
--- /dev/null
+++ b/SOURCES/0069-Clean-up-grub-setpassword-documentation-1290799.patch
@@ -0,0 +1,55 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Tue, 26 Jan 2016 10:28:35 -0500
+Subject: [PATCH] Clean up grub-setpassword documentation (#1290799)
+
+The output for --help had some errors. Corrected those and polished the
+text to be a little easier to follow. Carried verbage over to man page
+to maintain internal consistency.
+
+Resolves: rhbz#1290799
+---
+ util/grub-setpassword.8  |  2 +-
+ util/grub-setpassword.in | 15 +++++++--------
+ 2 files changed, 8 insertions(+), 9 deletions(-)
+
+diff --git a/util/grub-setpassword.8 b/util/grub-setpassword.8
+index 49200a848b7..dc91dd6697b 100644
+--- a/util/grub-setpassword.8
++++ b/util/grub-setpassword.8
+@@ -19,7 +19,7 @@ Display program usage and exit.
+ -v, --version
+ Display the current version.
+ .TP
+--o, --output[=\fIDIRECTORY PATH\fR]
++-o, --output=<\fIDIRECTORY\fR>
+ Choose the file path to which user.cfg will be written.
+ 
+ .SH SEE ALSO
+diff --git a/util/grub-setpassword.in b/util/grub-setpassword.in
+index fb9d3a3b6f9..c8c0fa4199d 100644
+--- a/util/grub-setpassword.in
++++ b/util/grub-setpassword.in
+@@ -16,15 +16,14 @@ grub_mkpasswd="${bindir}/@grub_mkpasswd_pbkdf2@"
+ # Print the usage.
+ usage () {
+     cat <<EOF
+-Usage: $0 [OPTION] [SOURCE]
+-Run GRUB script in a Qemu instance.
+-
+-  -h, --help              print this message and exit
+-  -v, --version           print the version information and exit
+-  -o, --output_path       choose a custom output path for user.cfg
+-
++Usage: $0 [OPTION]
+ $0 prompts the user to set a password on the grub bootloader. The password
+-is written to a file named user.cfg.
++is written to a file named user.cfg which lives in the GRUB directory
++located by default at ${grubdir}.
++
++  -h, --help                     print this message and exit
++  -v, --version                  print the version information and exit
++  -o, --output_path <DIRECTORY>  put user.cfg in a user-selected directory
+ 
+ Report bugs at https://bugzilla.redhat.com.
+ EOF
diff --git a/SOURCES/0070-Fix-locale-issue-in-grub-setpassword-1294243.patch b/SOURCES/0070-Fix-locale-issue-in-grub-setpassword-1294243.patch
new file mode 100644
index 0000000..9b315cc
--- /dev/null
+++ b/SOURCES/0070-Fix-locale-issue-in-grub-setpassword-1294243.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Marshall <rmarshall@redhat.com>
+Date: Fri, 29 Jan 2016 16:56:11 -0500
+Subject: [PATCH] Fix locale issue in grub-setpassword (#1294243)
+
+A shell substitution was expecting non-translated output to grab the
+hashed password and put it in the user.cfg file. Modified code to force
+the generic C locale when this particular piece of code is run.
+
+Resolves: rhbz#1294243
+---
+ util/grub-setpassword.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util/grub-setpassword.in b/util/grub-setpassword.in
+index c8c0fa4199d..d7924af5192 100644
+--- a/util/grub-setpassword.in
++++ b/util/grub-setpassword.in
+@@ -104,7 +104,7 @@ getpass() {
+     P1="$1" && shift
+ 
+     ( echo ${P0} ; echo ${P1} ) | \
+-        ${grub_mkpasswd} | \
++        LC_ALL=C ${grub_mkpasswd} | \
+         grep -v '[eE]nter password:' | \
+         sed -e "s/PBKDF2 hash of your password is //"
+ }
diff --git a/SOURCES/0071-efiemu-Handle-persistent-RAM-and-unknown-possible-fu.patch b/SOURCES/0071-efiemu-Handle-persistent-RAM-and-unknown-possible-fu.patch
new file mode 100644
index 0000000..0891f8f
--- /dev/null
+++ b/SOURCES/0071-efiemu-Handle-persistent-RAM-and-unknown-possible-fu.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Robert Elliott <elliott@hpe.com>
+Date: Fri, 22 Jan 2016 13:32:30 +0100
+Subject: [PATCH] efiemu: Handle persistent RAM and unknown possible future
+ additions.
+
+(cherry picked from commit ae3b83a4d4df75a01198a2fed7542391e7c449e0)
+
+Resolves: rhbz#1288608
+---
+ grub-core/efiemu/mm.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/efiemu/mm.c b/grub-core/efiemu/mm.c
+index 52a032f7b2e..92e7df7e501 100644
+--- a/grub-core/efiemu/mm.c
++++ b/grub-core/efiemu/mm.c
+@@ -410,8 +410,8 @@ fill_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
+ 	return grub_efiemu_add_to_mmap (addr, size,
+ 					GRUB_EFI_ACPI_MEMORY_NVS);
+ 
+-      case GRUB_MEMORY_PERSISTENT:
+-      case GRUB_MEMORY_PERSISTENT_LEGACY:
++      case GRUB_MEMORY_PRAM:
++      case GRUB_MEMORY_PMEM:
+ 	return grub_efiemu_add_to_mmap (addr, size,
+ 					GRUB_EFI_PERSISTENT_MEMORY);
+       default:
diff --git a/SOURCES/0072-efiemu-Fix-compilation-failure.patch b/SOURCES/0072-efiemu-Fix-compilation-failure.patch
new file mode 100644
index 0000000..0c1c10f
--- /dev/null
+++ b/SOURCES/0072-efiemu-Fix-compilation-failure.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Vladimir Serbinenko <phcoder@gmail.com>
+Date: Fri, 22 Jan 2016 14:10:30 +0100
+Subject: [PATCH] efiemu: Fix compilation failure
+
+(cherry picked from commit b6a03dfd327489d53ee07c6d7d593b99c7b7cb62)
+
+Resolves: rhbz#1288608
+---
+ grub-core/efiemu/mm.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/efiemu/mm.c b/grub-core/efiemu/mm.c
+index 92e7df7e501..52a032f7b2e 100644
+--- a/grub-core/efiemu/mm.c
++++ b/grub-core/efiemu/mm.c
+@@ -410,8 +410,8 @@ fill_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
+ 	return grub_efiemu_add_to_mmap (addr, size,
+ 					GRUB_EFI_ACPI_MEMORY_NVS);
+ 
+-      case GRUB_MEMORY_PRAM:
+-      case GRUB_MEMORY_PMEM:
++      case GRUB_MEMORY_PERSISTENT:
++      case GRUB_MEMORY_PERSISTENT_LEGACY:
+ 	return grub_efiemu_add_to_mmap (addr, size,
+ 					GRUB_EFI_PERSISTENT_MEMORY);
+       default:
diff --git a/SOURCES/0073-Revert-reopen-SNP-protocol-for-exclusive-use-by-grub.patch b/SOURCES/0073-Revert-reopen-SNP-protocol-for-exclusive-use-by-grub.patch
new file mode 100644
index 0000000..9482299
--- /dev/null
+++ b/SOURCES/0073-Revert-reopen-SNP-protocol-for-exclusive-use-by-grub.patch
@@ -0,0 +1,65 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 7 Apr 2016 10:58:06 -0400
+Subject: [PATCH] Revert "reopen SNP protocol for exclusive use by grub"
+
+I *think* this should have been replaced by upstream's
+49426e9fd2e562c73a4f1206f32eff9e424a1a73, so I'm reverting for now.
+
+May resolve rhbz#1273974.
+
+This reverts commit 147daeab22db793978f952b6f0d832919a1b0081.
+---
+ grub-core/net/drivers/efi/efinet.c | 39 --------------------------------------
+ 1 file changed, 39 deletions(-)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index d15a799f29a..5388f952ba9 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -383,45 +383,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 				    &pxe_mode->dhcp_ack,
+ 				    sizeof (pxe_mode->dhcp_ack),
+ 				    1, device, path);
+-    net = grub_efi_open_protocol (card->efi_handle, &net_io_guid,
+-				  GRUB_EFI_OPEN_PROTOCOL_BY_EXCLUSIVE);
+-    if (net) {
+-      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
+-	  && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
+-	continue;
+-
+-      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
+-	continue;
+-
+-      if (net->mode->state == GRUB_EFI_NETWORK_STARTED
+-	  && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
+-	continue;
+-
+-      /* Enable hardware receive filters if driver declares support for it.
+-	 We need unicast and broadcast and additionaly all nodes and
+-	 solicited multicast for IPv6. Solicited multicast is per-IPv6
+-	 address and we currently do not have API to do it so simply
+-	 try to enable receive of all multicast packets or evertyhing in
+-	 the worst case (i386 PXE driver always enables promiscuous too).
+-
+-	 This does trust firmware to do what it claims to do.
+-       */
+-      if (net->mode->receive_filter_mask)
+-	{
+-	  grub_uint32_t filters = GRUB_EFI_SIMPLE_NETWORK_RECEIVE_UNICAST   |
+-				  GRUB_EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
+-				  GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+-
+-	  filters &= net->mode->receive_filter_mask;
+-	  if (!(filters & GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST))
+-	    filters |= (net->mode->receive_filter_mask &
+-			GRUB_EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS);
+-
+-	  efi_call_6 (net->receive_filters, net, filters, 0, 0, 0, NULL);
+-	}
+-
+-      card->efi_net = net;
+-    }
+     return;
+   }
+ }
diff --git a/SOURCES/0074-Add-a-url-parser.patch b/SOURCES/0074-Add-a-url-parser.patch
new file mode 100644
index 0000000..2697fd2
--- /dev/null
+++ b/SOURCES/0074-Add-a-url-parser.patch
@@ -0,0 +1,1021 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 14 Jun 2016 16:18:44 -0400
+Subject: [PATCH] Add a url parser.
+
+This patch adds a url parser that can parse http, https, tftp, and tftps
+urls, and is easily extensible to handle more types.
+
+It's a little ugly in terms of the arguments it takes.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/Makefile.core.def |   1 +
+ grub-core/kern/misc.c       |  13 +
+ grub-core/net/url.c         | 861 ++++++++++++++++++++++++++++++++++++++++++++
+ include/grub/misc.h         |  45 +++
+ include/grub/net/url.h      |  28 ++
+ 5 files changed, 948 insertions(+)
+ create mode 100644 grub-core/net/url.c
+ create mode 100644 include/grub/net/url.h
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index cd0902b46b8..991891a6e09 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2185,6 +2185,7 @@ module = {
+   common = net/ethernet.c;
+   common = net/arp.c;
+   common = net/netbuff.c;
++  common = net/url.c;
+ };
+ 
+ module = {
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 8344526be7f..f1fab700048 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -296,6 +296,19 @@ grub_strrchr (const char *s, int c)
+   return p;
+ }
+ 
++char *
++grub_strchrnul (const char *s, int c)
++{
++  do
++    {
++      if (*s == c)
++	break;
++    }
++  while (*s++);
++
++  return (char *) s;
++}
++
+ int
+ grub_strword (const char *haystack, const char *needle)
+ {
+diff --git a/grub-core/net/url.c b/grub-core/net/url.c
+new file mode 100644
+index 00000000000..146858284cd
+--- /dev/null
++++ b/grub-core/net/url.c
+@@ -0,0 +1,861 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2016  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifdef URL_TEST
++
++#define _GNU_SOURCE 1
++
++#include <errno.h>
++#include <limits.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/types.h>
++#include <unistd.h>
++
++#define N_(x) x
++
++#define grub_malloc(x) malloc(x)
++#define grub_free(x) ({if (x) free(x);})
++#define grub_error(a, fmt, args...) printf(fmt "\n", ## args)
++#define grub_dprintf(a, fmt, args...) printf(a ": " fmt, ## args)
++#define grub_strlen(x) strlen(x)
++#define grub_strdup(x) strdup(x)
++#define grub_strstr(x,y) strstr(x,y)
++#define grub_memcpy(x,y,z) memcpy(x,y,z)
++#define grub_strcmp(x,y) strcmp(x,y)
++#define grub_strncmp(x,y,z) strncmp(x,y,z)
++#define grub_strcasecmp(x,y) strcasecmp(x,y)
++#define grub_strchrnul(x,y) strchrnul(x,y)
++#define grub_strchr(x,y) strchr(x,y)
++#define grub_strndup(x,y) strndup(x,y)
++#define grub_strtoul(x,y,z) strtoul(x,y,z)
++#define grub_memmove(x,y,z) memmove(x,y,z)
++#define grub_size_t size_t
++#define grub_errno errno
++
++#else
++#include <grub/types.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/net/url.h>
++#endif
++
++static char *
++translate_slashes(char *str)
++{
++  int i, j;
++  if (str == NULL)
++    return str;
++
++  for (i = 0, j = 0; str[i] != '\0'; i++, j++)
++    {
++      if (str[i] == '\\')
++	{
++	  str[j] = '/';
++	  if (str[i+1] == '\\')
++	    i++;
++	}
++    }
++
++  return str;
++}
++
++static inline int
++hex2int (char c)
++{
++  if (c >= '0' && c <= '9')
++    return c - '0';
++  c |= 0x20;
++  if (c >= 'a' && c <= 'f')
++    return c - 'a' + 10;
++  return -1;
++}
++
++static int
++url_unescape (char *buf, grub_size_t len)
++{
++  int c, rc;
++  unsigned int i;
++
++
++  if (len < 3)
++    {
++      for (i = 0; i < len; i++)
++	if (buf[i] == '%')
++	  return -1;
++      return 0;
++    }
++
++  for (i = 0; len > 2 && i < len - 2; i++)
++    {
++      if (buf[i] == '%')
++	{
++	  unsigned int j;
++	  for (j = i+1; j < i+3; j++)
++	    {
++	      if (!(buf[j] >= '0' && buf[j] <= '9') &&
++		  !(buf[j] >= 'a' && buf[j] <= 'f') &&
++		  !(buf[j] >= 'A' && buf[j] <= 'F'))
++		return -1;
++	    }
++	  i += 2;
++	}
++    }
++  if (i == len - 2)
++    {
++      if (buf[i+1] == '%' || buf[i+2] == '%')
++	return -1;
++    }
++  for (i = 0; i < len - 2; i++)
++    {
++      if (buf[i] == '%')
++	{
++	  rc = hex2int (buf[i+1]);
++	  if (rc < 0)
++	    return -1;
++	  c = (rc & 0xf) << 4;
++	  rc = hex2int (buf[i+2]);
++	  if (rc < 0)
++	    return -1;
++	  c |= (rc & 0xf);
++
++	  buf[i] = c;
++	  grub_memmove (buf+i+1, buf+i+3, len-(i+2));
++	  len -= 2;
++	}
++    }
++  return 0;
++}
++
++static int
++extract_http_url_info (char *url, int ssl,
++		       char **userinfo, char **host, int *port,
++		       char **file)
++{
++  char *colon, *slash, *query, *at = NULL, *separator, *auth_end;
++
++  char *userinfo_off = NULL;
++  char *userinfo_end;
++  char *host_off = NULL;
++  char *host_end;
++  char *port_off = NULL;
++  char *port_end;
++  char *file_off = NULL;
++
++  grub_size_t l;
++  int c;
++
++  if (!url || !userinfo || !host || !port || !file)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid argument");
++
++  *userinfo = *host = *file = NULL;
++  *port = -1;
++
++  userinfo_off = url;
++
++  slash = grub_strchrnul (userinfo_off, '/');
++  query = grub_strchrnul (userinfo_off, '?');
++  auth_end = slash < query ? slash : query;
++  /* auth_end here is one /past/ the last character in the auth section, i.e.
++   * it's the : or / or NUL */
++
++  separator = grub_strchrnul (userinfo_off, '@');
++  if (separator > auth_end)
++    {
++      host_off = userinfo_off;
++      userinfo_off = NULL;
++      userinfo_end = NULL;
++    }
++  else
++    {
++      at = separator;
++      *separator = '\0';
++      userinfo_end = separator;
++      host_off = separator + 1;
++    }
++
++  if (*host_off == '[')
++    {
++      separator = grub_strchrnul (host_off, ']');
++      if (separator >= auth_end)
++	goto fail;
++
++      separator += 1;
++      host_end = separator;
++    }
++  else
++    {
++      host_end = separator = colon = grub_strchrnul (host_off, ':');
++
++      if (colon > auth_end)
++	{
++	  separator = NULL;
++	  host_end = auth_end;
++	}
++    }
++
++  if (separator && separator < auth_end)
++    {
++      if (*separator == ':')
++	{
++	  port_off = separator + 1;
++	  port_end = auth_end;
++
++	  if (auth_end - port_end > 0)
++	    goto fail;
++	  if (port_end - port_off < 1)
++	    goto fail;
++	}
++      else
++	goto fail;
++    }
++
++  file_off = auth_end;
++  if (port_off)
++    {
++      unsigned long portul;
++
++      separator = NULL;
++      c = *port_end;
++      *port_end = '\0';
++
++      portul = grub_strtoul (port_off, &separator, 10);
++      *port_end = c;
++#ifdef URL_TEST
++      if (portul == ULONG_MAX && errno == ERANGE)
++	goto fail;
++#else
++      if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
++	goto fail;
++#endif
++      if (portul & ~0xfffful)
++	goto fail;
++      if (separator != port_end)
++	goto fail;
++
++      *port = portul & 0xfffful;
++    }
++  else if (ssl)
++    *port = 443;
++  else
++    *port = 80;
++
++  if (userinfo_off && *userinfo_off)
++    {
++      l = userinfo_end - userinfo_off + 1;
++
++      *userinfo = grub_strndup (userinfo_off, l);
++      if (!*userinfo)
++	goto fail;
++      (*userinfo)[l-1]= '\0';
++    }
++
++  l = host_end - host_off;
++
++  if (host_end == NULL)
++    goto fail;
++  else
++    c = *host_end;
++
++  *host_end = '\0';
++  *host = grub_strndup (host_off, l);
++  *host_end = c;
++  if (!*host)
++    goto fail;
++  (*host)[l] = '\0';
++
++  *file = grub_strdup (file_off);
++  if (!*file)
++    goto fail;
++
++  if (at)
++    *at = '@';
++  return 0;
++fail:
++  if (at)
++    *at = '@';
++  grub_free (*userinfo);
++  grub_free (*host);
++  grub_free (*file);
++
++  return -1;
++}
++
++static int
++extract_tftp_url_info (char *url, int ssl, char **host, char **file, int *port)
++{
++  char *slash, *semi;
++
++  char *host_off = url;
++  char *host_end;
++  char *file_off;
++
++  int c;
++
++  if (!url || !host || !file || !port)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid argument");
++
++  if (ssl)
++    *port = 3713;
++  else
++    *port = 69;
++
++  slash = grub_strchr (url, '/');
++  if (!slash)
++    return -1;
++
++  host_end = file_off = slash;
++
++  semi = grub_strchrnul (slash, ';');
++  if (!grub_strncmp (semi, ";mode=", 6) && grub_strcmp (semi+6, "octet"))
++    {
++      grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++		  N_("TFTP mode `%s' is not implemented."), semi+6);
++      return -1;
++    }
++
++  /*
++   * Maybe somebody added a new method, I dunno.  Anyway, semi is a reserved
++   * character, so if it's there, it's the start of the mode block or it's
++   * invalid.  So set it to \0 unconditionally, not just for ;mode=octet
++   */
++  *semi = '\0';
++
++  c = *host_end;
++  *host_end = '\0';
++  *host = grub_strdup (host_off);
++  *host_end = c;
++
++  *file = grub_strdup (file_off);
++
++  if (!*file || !*host)
++    {
++      grub_free (*file);
++      grub_free (*host);
++      return -1;
++    }
++
++  return 0;
++}
++
++int
++extract_url_info (const char *urlbuf, grub_size_t buflen,
++		  char **scheme, char **userinfo,
++		  char **host, int *port, char **file)
++{
++  char *url;
++  char *colon;
++
++  char *scheme_off;
++  char *specific_off;
++
++  int rc;
++  int c;
++
++  int https;
++
++  if (!urlbuf || !buflen || !scheme || !userinfo || !host || !port || !file)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid argument");
++
++  *scheme = *userinfo = *host = *file = NULL;
++  *port = -1;
++
++  /* make sure we have our own coherent grub_string. */
++  url = grub_malloc (buflen + 1);
++  if (!url)
++    return -1;
++
++  grub_memcpy (url, urlbuf, buflen);
++  url[buflen] = '\0';
++
++  grub_dprintf ("net", "dhcpv6 boot-file-url: `%s'\n", url);
++
++  /* get rid of any backslashes */
++  url = translate_slashes (url);
++
++  /* find the constituent parts */
++  colon = grub_strstr (url, "://");
++  if (!colon)
++    goto fail;
++
++  scheme_off = url;
++  c = *colon;
++  *colon = '\0';
++  specific_off = colon + 3;
++
++  https = !grub_strcasecmp (scheme_off, "https");
++
++  rc = 0;
++  if (!grub_strcasecmp (scheme_off, "tftp"))
++    {
++      rc = extract_tftp_url_info (specific_off, 0, host, file, port);
++    }
++#ifdef URL_TEST
++  else if (!grub_strcasecmp (scheme_off, "http") || https)
++#else
++  else if (!grub_strcasecmp (scheme_off, "http"))
++#endif
++    {
++      rc = extract_http_url_info (specific_off,
++				  https, userinfo, host, port, file);
++    }
++#ifdef URL_TEST
++  else if (!grub_strcasecmp (scheme_off, "iscsi"))
++    {
++      grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++		  N_("Unimplemented URL scheme `%s'"), scheme_off);
++      *colon = c;
++      goto fail;
++    }
++  else if (!grub_strcasecmp (scheme_off, "tftps"))
++    {
++      rc = extract_tftp_url_info (specific_off, 1, host, file, port);
++    }
++#endif
++  else
++    {
++      grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++		  N_("Unimplemented URL scheme `%s'"), scheme_off);
++      *colon = c;
++      goto fail;
++    }
++
++  if (rc < 0)
++    {
++      *colon = c;
++      goto fail;
++    }
++
++  *scheme = grub_strdup (scheme_off);
++  *colon = c;
++  if (!*scheme)
++    goto fail;
++
++  if (*userinfo)
++    {
++      rc = url_unescape (*userinfo, grub_strlen (*userinfo));
++      if (rc < 0)
++	goto fail;
++    }
++
++  if (*host)
++    {
++      rc = url_unescape (*host, grub_strlen (*host));
++      if (rc < 0)
++	goto fail;
++    }
++
++  if (*file)
++    {
++      rc = url_unescape (*file, grub_strlen (*file));
++      if (rc < 0)
++	goto fail;
++    }
++
++  grub_free (url);
++  return 0;
++fail:
++  grub_free (*scheme);
++  grub_free (*userinfo);
++  grub_free (*host);
++  grub_free (*file);
++
++  if (!grub_errno)
++    grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("Invalid boot-file-url `%s'"),
++		url);
++  grub_free (url);
++  return -1;
++}
++
++#ifdef URL_TEST
++
++struct test {
++    char *url;
++    int rc;
++    char *scheme;
++    char *userinfo;
++    char *host;
++    int port;
++    char *file;
++} tests[] = {
++  {.url = "http://foo.example.com/",
++   .rc = 0,
++   .scheme = "http",
++   .host = "foo.example.com",
++   .port = 80,
++   .file = "/",
++  },
++  {.url = "http://foo.example.com/?foobar",
++   .rc = 0,
++   .scheme = "http",
++   .host = "foo.example.com",
++   .port = 80,
++   .file = "/?foobar",
++  },
++  {.url = "http://[foo.example.com/",
++   .rc = -1,
++  },
++  {.url = "http://[foo.example.com/?foobar",
++   .rc = -1,
++  },
++  {.url = "http://foo.example.com:/",
++   .rc = -1,
++  },
++  {.url = "http://foo.example.com:81/",
++   .rc = 0,
++   .scheme = "http",
++   .host = "foo.example.com",
++   .port = 81,
++   .file = "/",
++  },
++  {.url = "http://foo.example.com:81/?foobar",
++   .rc = 0,
++   .scheme = "http",
++   .host = "foo.example.com",
++   .port = 81,
++   .file = "/?foobar",
++  },
++  {.url = "http://[1234::1]/",
++   .rc = 0,
++   .scheme = "http",
++   .host = "[1234::1]",
++   .port = 80,
++   .file = "/",
++  },
++  {.url = "http://[1234::1]/?foobar",
++   .rc = 0,
++   .scheme = "http",
++   .host = "[1234::1]",
++   .port = 80,
++   .file = "/?foobar",
++  },
++  {.url = "http://[1234::1]:81/",
++   .rc = 0,
++   .scheme = "http",
++   .host = "[1234::1]",
++   .port = 81,
++   .file = "/",
++  },
++  {.url = "http://[1234::1]:81/?foobar",
++   .rc = 0,
++   .scheme = "http",
++   .host = "[1234::1]",
++   .port = 81,
++   .file = "/?foobar",
++  },
++  {.url = "http://foo@foo.example.com/",
++   .rc = 0,
++   .scheme = "http",
++   .userinfo = "foo",
++   .host = "foo.example.com",
++   .port = 80,
++   .file = "/",
++  },
++  {.url = "http://foo@foo.example.com/?foobar",
++   .rc = 0,
++   .scheme = "http",
++   .userinfo = "foo",
++   .host = "foo.example.com",
++   .port = 80,
++   .file = "/?foobar",
++  },
++  {.url = "http://foo@[foo.example.com/",
++   .rc = -1,
++  },
++  {.url = "http://foo@[foo.example.com/?foobar",
++   .rc = -1,
++  },
++  {.url = "http://foo@foo.example.com:81/",
++   .rc = 0,
++   .scheme = "http",
++   .userinfo = "foo",
++   .host = "foo.example.com",
++   .port = 81,
++   .file = "/",
++  },
++  {.url = "http://foo@foo.example.com:81/?foobar",
++   .rc = 0,
++   .scheme = "http",
++   .userinfo = "foo",
++   .host = "foo.example.com",
++   .port = 81,
++   .file = "/?foobar",
++  },
++  {.url = "http://foo@[1234::1]/",
++   .rc = 0,
++   .scheme = "http",
++   .userinfo = "foo",
++   .host = "[1234::1]",
++   .port = 80,
++   .file = "/",
++  },
++  {.url = "http://foo@[1234::1]/?foobar",
++   .rc = 0,
++   .scheme = "http",
++   .userinfo = "foo",
++   .host = "[1234::1]",
++   .port = 80,
++   .file = "/?foobar",
++  },
++  {.url = "http://foo@[1234::1]:81/",
++   .rc = 0,
++   .scheme = "http",
++   .userinfo = "foo",
++   .host = "[1234::1]",
++   .port = 81,
++   .file = "/",
++  },
++  {.url = "http://foo@[1234::1]:81/?foobar",
++   .rc = 0,
++   .scheme = "http",
++   .userinfo = "foo",
++   .host = "[1234::1]",
++   .port = 81,
++   .file = "/?foobar",
++  },
++  {.url = "https://foo.example.com/",
++   .rc = 0,
++   .scheme = "https",
++   .host = "foo.example.com",
++   .port = 443,
++   .file = "/",
++  },
++  {.url = "https://foo.example.com/?foobar",
++   .rc = 0,
++   .scheme = "https",
++   .host = "foo.example.com",
++   .port = 443,
++   .file = "/?foobar",
++  },
++  {.url = "https://[foo.example.com/",
++   .rc = -1,
++  },
++  {.url = "https://[foo.example.com/?foobar",
++   .rc = -1,
++  },
++  {.url = "https://foo.example.com:81/",
++   .rc = 0,
++   .scheme = "https",
++   .host = "foo.example.com",
++   .port = 81,
++   .file = "/",
++  },
++  {.url = "https://foo.example.com:81/?foobar",
++   .rc = 0,
++   .scheme = "https",
++   .host = "foo.example.com",
++   .port = 81,
++   .file = "/?foobar",
++  },
++  {.url = "https://[1234::1]/",
++   .rc = 0,
++   .scheme = "https",
++   .host = "[1234::1]",
++   .port = 443,
++   .file = "/",
++  },
++  {.url = "https://[1234::1]/?foobar",
++   .rc = 0,
++   .scheme = "https",
++   .host = "[1234::1]",
++   .port = 443,
++   .file = "/?foobar",
++  },
++  {.url = "https://[1234::1]:81/",
++   .rc = 0,
++   .scheme = "https",
++   .host = "[1234::1]",
++   .port = 81,
++   .file = "/",
++  },
++  {.url = "https://[1234::1]:81/?foobar",
++   .rc = 0,
++   .scheme = "https",
++   .host = "[1234::1]",
++   .port = 81,
++   .file = "/?foobar",
++  },
++  {.url = "https://foo@foo.example.com/",
++   .rc = 0,
++   .scheme = "https",
++   .userinfo = "foo",
++   .host = "foo.example.com",
++   .port = 443,
++   .file = "/",
++  },
++  {.url = "https://foo@foo.example.com/?foobar",
++   .rc = 0,
++   .scheme = "https",
++   .userinfo = "foo",
++   .host = "foo.example.com",
++   .port = 443,
++   .file = "/?foobar",
++  },
++  {.url = "https://foo@[foo.example.com/",
++   .rc = -1,
++  },
++  {.url = "https://f%6fo@[foo.example.com/?fooba%72",
++   .rc = -1,
++  },
++  {.url = "https://foo@foo.example.com:81/",
++   .rc = 0,
++   .scheme = "https",
++   .userinfo = "foo",
++   .host = "foo.example.com",
++   .port = 81,
++   .file = "/",
++  },
++  {.url = "https://foo@foo.example.com:81/?foobar",
++   .rc = 0,
++   .scheme = "https",
++   .userinfo = "foo",
++   .host = "foo.example.com",
++   .port = 81,
++   .file = "/?foobar",
++  },
++  {.url = "https://foo@[1234::1]/",
++   .rc = 0,
++   .scheme = "https",
++   .userinfo = "foo",
++   .host = "[1234::1]",
++   .port = 443,
++   .file = "/",
++  },
++  {.url = "https://foo@[1234::1]/?foobar",
++   .rc = 0,
++   .scheme = "https",
++   .userinfo = "foo",
++   .host = "[1234::1]",
++   .port = 443,
++   .file = "/?foobar",
++  },
++  {.url = "https://f%6fo@[12%334::1]:81/",
++   .rc = 0,
++   .scheme = "https",
++   .userinfo = "foo",
++   .host = "[1234::1]",
++   .port = 81,
++   .file = "/",
++  },
++  {.url = "https://foo@[1234::1]:81/?foobar",
++   .rc = 0,
++   .scheme = "https",
++   .userinfo = "foo",
++   .host = "[1234::1]",
++   .port = 81,
++   .file = "/?foobar",
++  },
++  {.url = "tftp://foo.e%78ample.com/foo/bar/b%61%7a",
++   .rc = 0,
++   .scheme = "tftp",
++   .host = "foo.example.com",
++   .port = 69,
++   .file = "/foo/bar/baz",
++  },
++  {.url = "tftp://foo.example.com/foo/bar/baz",
++   .rc = 0,
++   .scheme = "tftp",
++   .host = "foo.example.com",
++   .port = 69,
++   .file = "/foo/bar/baz",
++  },
++  {.url = "tftps://foo.example.com/foo/bar/baz",
++   .rc = 0,
++   .scheme = "tftps",
++   .host = "foo.example.com",
++   .port = 3713,
++   .file = "/foo/bar/baz",
++  },
++  {.url = "tftps://foo.example.com/foo/bar/baz;mode=netascii",
++   .rc = -1,
++  },
++  {.url = "tftps://foo.example.com/foo/bar/baz;mode=octet",
++   .rc = 0,
++   .scheme = "tftps",
++   .host = "foo.example.com",
++   .port = 3713,
++   .file = "/foo/bar/baz",
++  },
++  {.url = "tftps://foo.example.com/foo/bar/baz;mode=invalid",
++   .rc = -1,
++  },
++  {.url = "",
++  },
++};
++
++static int
++string_test (char *name, char *a, char *b)
++{
++  if ((a && !b) || (!a && b))
++    {
++      printf("expected %s \"%s\", got \"%s\"\n", name, a, b);
++      return -1;
++    }
++  if (a && b && strcmp(a, b))
++    {
++      printf("expected %s \"%s\", got \"%s\"\n", name, a, b);
++      return -1;
++    }
++  return 0;
++}
++
++int
++main(void)
++{
++	unsigned int i;
++	int rc;
++
++	for (i = 0; tests[i].url[0] != '\0'; i++)
++	{
++		char *scheme, *userinfo, *host, *file;
++		int port;
++
++		printf("======= url: \"%s\"\n", tests[i].url);
++		rc = extract_url_info(tests[i].url, strlen(tests[i].url) + 1,
++				      &scheme, &userinfo, &host, &port, &file);
++		if (tests[i].rc != rc)
++		  {
++		    printf("  extract_url_info(...) = %d\n", rc);
++		    exit(1);
++		  }
++		else if (rc >= 0)
++		  {
++		    if (string_test("scheme", tests[i].scheme, scheme) < 0)
++		      exit(1);
++		    if (string_test("userinfo", tests[i].userinfo, userinfo) < 0)
++		      exit(1);
++		    if (string_test("host", tests[i].host, host) < 0)
++		      exit(1);
++		    if (port != tests[i].port)
++		      {
++			printf("  bad port \"%d\" should have been \"%d\"\n",
++			       port, tests[i].port);
++			exit(1);
++		      }
++		    if (string_test("file", tests[i].file, file) < 0)
++		      exit(1);
++		  }
++		free(scheme);
++		free(userinfo);
++		free(host);
++		free(file);
++	}
++	printf("everything worked?!?\n");
++}
++#endif
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index 83fd69f4ada..fcaf1201e39 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -85,6 +85,7 @@ int EXPORT_FUNC(grub_strncmp) (const char *s1, const char *s2, grub_size_t n);
+ 
+ char *EXPORT_FUNC(grub_strchr) (const char *s, int c);
+ char *EXPORT_FUNC(grub_strrchr) (const char *s, int c);
++char *EXPORT_FUNC(grub_strchrnul) (const char *s, int c);
+ int EXPORT_FUNC(grub_strword) (const char *s, const char *w);
+ 
+ /* Copied from gnulib.
+@@ -207,6 +208,50 @@ grub_toupper (int c)
+   return c;
+ }
+ 
++static inline char *
++grub_strcasestr (const char *haystack, const char *needle)
++{
++  /* Be careful not to look at the entire extent of haystack or needle
++     until needed.  This is useful because of these two cases:
++       - haystack may be very long, and a match of needle found early,
++       - needle may be very long, and not even a short initial segment of
++       needle may be found in haystack.  */
++  if (*needle != '\0')
++    {
++      /* Speed up the following searches of needle by caching its first
++	 character.  */
++      char b = *needle++;
++
++      for (;; haystack++)
++	{
++	  if (*haystack == '\0')
++	    /* No match.  */
++	    return 0;
++	  if (grub_tolower(*haystack) == grub_tolower(b))
++	    /* The first character matches.  */
++	    {
++	      const char *rhaystack = haystack + 1;
++	      const char *rneedle = needle;
++
++	      for (;; rhaystack++, rneedle++)
++		{
++		  if (*rneedle == '\0')
++		    /* Found a match.  */
++		    return (char *) haystack;
++		  if (*rhaystack == '\0')
++		    /* No match.  */
++		    return 0;
++		  if (grub_tolower(*rhaystack) != grub_tolower(*rneedle))
++		    /* Nothing in this round.  */
++		    break;
++		}
++	    }
++	}
++    }
++  else
++    return (char *) haystack;
++}
++
+ static inline int
+ grub_strcasecmp (const char *s1, const char *s2)
+ {
+diff --git a/include/grub/net/url.h b/include/grub/net/url.h
+new file mode 100644
+index 00000000000..a215fa27d0a
+--- /dev/null
++++ b/include/grub/net/url.h
+@@ -0,0 +1,28 @@
++/* url.h - prototypes for url parsing functions */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2016  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_URL_HEADER
++#define GRUB_URL_HEADER	1
++
++int
++EXPORT_FUNC(extract_url_info) (const char *urlbuf, grub_size_t buflen,
++			       char **scheme, char **userinfo,
++			       char **host, int *port, char **file);
++
++#endif /* GRUB_URL_HEADER */
diff --git a/SOURCES/0075-efinet-and-bootp-add-support-for-dhcpv6.patch b/SOURCES/0075-efinet-and-bootp-add-support-for-dhcpv6.patch
new file mode 100644
index 0000000..97038c1
--- /dev/null
+++ b/SOURCES/0075-efinet-and-bootp-add-support-for-dhcpv6.patch
@@ -0,0 +1,660 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 8 Jun 2016 21:03:37 -0400
+Subject: [PATCH] efinet and bootp: add support for dhcpv6
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/bootp.c              | 174 +++++++++++++++++++++++++++++++++++++
+ grub-core/net/drivers/efi/efinet.c |  53 +++++++++--
+ grub-core/net/net.c                |  72 +++++++++++++++
+ grub-core/net/tftp.c               |   4 +
+ include/grub/efi/api.h             | 129 +++++++++++++++++++++++++--
+ include/grub/net.h                 |  60 +++++++++++++
+ 6 files changed, 478 insertions(+), 14 deletions(-)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index f03eeab2fb4..da3e454466b 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -23,6 +23,7 @@
+ #include <grub/net/ip.h>
+ #include <grub/net/netbuff.h>
+ #include <grub/net/udp.h>
++#include <grub/net/url.h>
+ #include <grub/datetime.h>
+ 
+ static char *
+@@ -349,6 +350,179 @@ grub_net_configure_by_dhcp_ack (const char *name,
+   return inter;
+ }
+ 
++struct grub_net_network_level_interface *
++grub_net_configure_by_dhcpv6_ack (const char *name,
++				  struct grub_net_card *card,
++				  grub_net_interface_flags_t flags
++				    __attribute__((__unused__)),
++				  const grub_net_link_level_address_t *hwaddr,
++				  const struct grub_net_dhcpv6_packet *packet,
++				  int is_def, char **device, char **path)
++{
++  struct grub_net_network_level_interface *inter = NULL;
++  struct grub_net_network_level_address addr;
++  int mask = -1;
++
++  if (!device || !path)
++    return NULL;
++
++  *device = 0;
++  *path = 0;
++
++  grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n",
++		hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2],
++		hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]);
++
++  if (is_def)
++    grub_net_default_server = 0;
++
++  if (is_def && !grub_net_default_server && packet)
++    {
++      const grub_uint8_t *options = packet->dhcp_options;
++      unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet);
++      unsigned int i;
++
++      for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); )
++	{
++	  grub_uint16_t num, len;
++	  grub_net_dhcpv6_option_t *opt =
++	    (grub_net_dhcpv6_option_t *)(options + i);
++
++	  num = grub_be_to_cpu16(opt->option_num);
++	  len = grub_be_to_cpu16(opt->option_len);
++
++	  grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len);
++
++	  if (len == 0)
++	    break;
++
++	  if (len + i > 1024)
++	    break;
++
++	  if (num == GRUB_NET_DHCP6_BOOTFILE_URL)
++	    {
++	      char *scheme, *userinfo, *host, *file;
++	      char *tmp;
++	      int hostlen;
++	      int port;
++	      int rc = extract_url_info ((const char *)opt->option_data,
++					 (grub_size_t)len,
++					 &scheme, &userinfo, &host, &port,
++					 &file);
++	      if (rc < 0)
++		continue;
++
++	      /* right now this only handles tftp. */
++	      if (grub_strcmp("tftp", scheme))
++		{
++		  grub_free (scheme);
++		  grub_free (userinfo);
++		  grub_free (host);
++		  grub_free (file);
++		  continue;
++		}
++	      grub_free (userinfo);
++
++	      hostlen = grub_strlen (host);
++	      if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']')
++		{
++		  tmp = host+1;
++		  host[hostlen-1] = '\0';
++		}
++	      else
++		tmp = host;
++
++	      *device = grub_xasprintf ("%s,%s", scheme, tmp);
++	      grub_free (scheme);
++	      grub_free (host);
++
++	      if (file && *file)
++		{
++		  tmp = grub_strrchr (file, '/');
++		  if (tmp)
++		    *(tmp+1) = '\0';
++		  else
++		    file[0] = '\0';
++		}
++	      else if (!file)
++		file = grub_strdup ("");
++
++	      if (file[0] == '/')
++		{
++		  *path = grub_strdup (file+1);
++		  grub_free (file);
++		}
++	      else
++		*path = file;
++	    }
++	  else if (num == GRUB_NET_DHCP6_IA_NA)
++	    {
++	      const grub_net_dhcpv6_option_t *ia_na_opt;
++	      const grub_net_dhcpv6_opt_ia_na_t *ia_na =
++		(const grub_net_dhcpv6_opt_ia_na_t *)opt;
++	      unsigned int left = len - OFFSET_OF (options, ia_na);
++	      unsigned int j;
++
++	      if ((grub_uint8_t *)ia_na + left >
++		  (grub_uint8_t *)options + option_max)
++		left -= ((grub_uint8_t *)ia_na + left)
++		        - ((grub_uint8_t *)options + option_max);
++
++	      if (len < OFFSET_OF (option_data, opt)
++			+ sizeof (grub_net_dhcpv6_option_t))
++		{
++		  grub_dprintf ("net",
++				"found dhcpv6 ia_na option with no address\n");
++		  continue;
++		}
++
++	      for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); )
++		{
++		  ia_na_opt = (const grub_net_dhcpv6_option_t *)
++			       (ia_na->options + j);
++		  grub_uint16_t ia_na_opt_num, ia_na_opt_len;
++
++		  ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num);
++		  ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len);
++		  if (ia_na_opt_len == 0)
++		    break;
++		  if (j + ia_na_opt_len > left)
++		    break;
++		  if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS)
++		    {
++		      const grub_net_dhcpv6_opt_ia_address_t *ia_addr;
++
++		      ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *)
++				 ia_na_opt;
++		      addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++		      grub_memcpy(addr.ipv6, ia_addr->ipv6_address,
++				  sizeof (ia_addr->ipv6_address));
++		      inter = grub_net_add_addr (name, card, &addr, hwaddr, 0);
++		    }
++
++		  j += ia_na_opt_len;
++		  left -= ia_na_opt_len;
++		}
++	    }
++
++	  i += len + 4;
++	}
++
++      grub_print_error ();
++    }
++
++  if (is_def)
++    {
++      grub_env_set ("net_default_interface", name);
++      grub_env_export ("net_default_interface");
++    }
++
++    if (inter)
++      grub_net_add_ipv6_local (inter, mask);
++    return inter;
++}
++
++
+ void
+ grub_net_process_dhcp (struct grub_net_buff *nb,
+ 		       struct grub_net_card *card)
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 5388f952ba9..a4daaa460bd 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -18,11 +18,15 @@
+ 
+ #include <grub/net/netbuff.h>
+ #include <grub/dl.h>
++#include <grub/env.h>
+ #include <grub/net.h>
++#include <grub/net/url.h>
+ #include <grub/time.h>
+ #include <grub/efi/api.h>
+ #include <grub/efi/efi.h>
+ #include <grub/i18n.h>
++#include <grub/lib/hexdump.h>
++#include <grub/types.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -329,7 +333,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 			  char **path)
+ {
+   struct grub_net_card *card;
+-  grub_efi_device_path_t *dp;
++  grub_efi_device_path_t *dp, *ldp = NULL;
+ 
+   dp = grub_efi_get_device_path (hnd);
+   if (! dp)
+@@ -340,14 +344,18 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+     grub_efi_device_path_t *cdp;
+     struct grub_efi_pxe *pxe;
+     struct grub_efi_pxe_mode *pxe_mode;
++
+     if (card->driver != &efidriver)
+       continue;
+     cdp = grub_efi_get_device_path (card->efi_handle);
+     if (! cdp)
+       continue;
++
++    ldp = grub_efi_find_last_device_path (dp);
++
+     if (grub_efi_compare_device_paths (dp, cdp) != 0)
+       {
+-	grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp;
++	grub_efi_device_path_t *dup_dp, *dup_ldp;
+ 	int match;
+ 
+ 	/* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6
+@@ -356,7 +364,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	   devices. We skip them when enumerating cards, so here we need to
+ 	   find matching MAC device.
+          */
+-	ldp = grub_efi_find_last_device_path (dp);
+ 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+ 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
+@@ -373,16 +380,46 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	if (!match)
+ 	  continue;
+       }
++
+     pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
+ 				  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+     if (! pxe)
+       continue;
++
+     pxe_mode = pxe->mode;
+-    grub_net_configure_by_dhcp_ack (card->name, card, 0,
+-				    (struct grub_net_bootp_packet *)
+-				    &pxe_mode->dhcp_ack,
+-				    sizeof (pxe_mode->dhcp_ack),
+-				    1, device, path);
++    if (pxe_mode->using_ipv6)
++      {
++	grub_net_link_level_address_t hwaddr;
++	struct grub_net_network_level_interface *intf;
++
++	grub_dprintf ("efinet", "using ipv6 and dhcpv6\n");
++	grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
++		      pxe_mode->dhcp_ack_received ? "yes" : "no",
++		      pxe_mode->dhcp_ack_received ? "" : " cannot continue");
++	if (!pxe_mode->dhcp_ack_received)
++	  continue;
++
++	hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++	grub_memcpy (hwaddr.mac,
++		     card->efi_net->mode->current_address,
++		     sizeof (hwaddr.mac));
++
++	intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr,
++	      (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6,
++	      1, device, path);
++	if (intf && device && path)
++	  grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
++      }
++    else
++      {
++	grub_dprintf ("efinet", "using ipv4 and dhcp\n");
++	grub_net_configure_by_dhcp_ack (card->name, card, 0,
++					(struct grub_net_bootp_packet *)
++					&pxe_mode->dhcp_ack,
++					sizeof (pxe_mode->dhcp_ack),
++					1, device, path);
++	grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
++      }
+     return;
+   }
+ }
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 16d2ce06d5a..4be228d9576 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -955,6 +955,78 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa
+   grub_net_network_level_interfaces = inter;
+ }
+ 
++int
++grub_ipv6_get_masksize (grub_uint16_t be_mask[8])
++{
++  grub_uint8_t *mask;
++  grub_uint16_t mask16[8];
++  int x, y;
++  int ret = 128;
++
++  grub_memcpy (mask16, be_mask, sizeof (mask16));
++  for (x = 0; x < 8; x++)
++    mask16[x] = grub_be_to_cpu16 (mask16[x]);
++
++  mask = (grub_uint8_t *)mask16;
++
++  for (x = 15; x >= 0; x--)
++    {
++      grub_uint8_t octet = mask[x];
++      if (!octet)
++	{
++	  ret -= 8;
++	  continue;
++	}
++      for (y = 0; y < 8; y++)
++	{
++	  if (octet & (1 << y))
++	    break;
++	  else
++	    ret--;
++	}
++      break;
++    }
++
++  return ret;
++}
++
++grub_err_t
++grub_net_add_ipv6_local (struct grub_net_network_level_interface *inter,
++			 int mask)
++{
++  struct grub_net_route *route;
++
++  if (inter->address.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6)
++    return 0;
++
++  if (mask == -1)
++      mask = grub_ipv6_get_masksize ((grub_uint16_t *)inter->address.ipv6);
++
++  if (mask == -1)
++    return 0;
++
++  route = grub_zalloc (sizeof (*route));
++  if (!route)
++    return grub_errno;
++
++  route->name = grub_xasprintf ("%s:local", inter->name);
++  if (!route->name)
++    {
++      grub_free (route);
++      return grub_errno;
++    }
++
++  route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++  grub_memcpy (route->target.ipv6.base, inter->address.ipv6,
++	       sizeof (inter->address.ipv6));
++  route->target.ipv6.masksize = mask;
++  route->is_gateway = 0;
++  route->interface = inter;
++
++  grub_net_route_register (route);
++
++  return 0;
++}
+ 
+ grub_err_t
+ grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter,
+diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
+index 7d90bf66e76..1157524fc50 100644
+--- a/grub-core/net/tftp.c
++++ b/grub-core/net/tftp.c
+@@ -379,19 +379,23 @@ tftp_open (struct grub_file *file, const char *filename)
+       return grub_errno;
+     }
+ 
++  grub_dprintf("tftp", "resolving address for %s\n", file->device->net->server);
+   err = grub_net_resolve_address (file->device->net->server, &addr);
+   if (err)
+     {
++      grub_dprintf("tftp", "Address resolution failed: %d\n", err);
+       destroy_pq (data);
+       grub_free (data);
+       return err;
+     }
+ 
++  grub_dprintf("tftp", "opening connection\n");
+   data->sock = grub_net_udp_open (addr,
+ 				  TFTP_SERVER_PORT, tftp_receive,
+ 				  file);
+   if (!data->sock)
+     {
++      grub_dprintf("tftp", "connection failed\n");
+       destroy_pq (data);
+       grub_free (data);
+       return grub_errno;
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index c7c9f0e1db1..28b6adf7648 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -572,10 +572,16 @@ typedef void *grub_efi_handle_t;
+ typedef void *grub_efi_event_t;
+ typedef grub_efi_uint64_t grub_efi_lba_t;
+ typedef grub_efi_uintn_t grub_efi_tpl_t;
+-typedef grub_uint8_t grub_efi_mac_address_t[32];
+-typedef grub_uint8_t grub_efi_ipv4_address_t[4];
+-typedef grub_uint16_t grub_efi_ipv6_address_t[8];
+-typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4)));
++typedef grub_efi_uint8_t grub_efi_mac_address_t[32];
++typedef grub_efi_uint8_t grub_efi_ipv4_address_t[4];
++typedef grub_efi_uint8_t grub_efi_ipv6_address_t[16];
++typedef union
++{
++  grub_efi_uint32_t addr[4];
++  grub_efi_ipv4_address_t v4;
++  grub_efi_ipv6_address_t v6;
++} grub_efi_ip_address_t __attribute__ ((aligned(4)));
++
+ typedef grub_efi_uint64_t grub_efi_physical_address_t;
+ typedef grub_efi_uint64_t grub_efi_virtual_address_t;
+ 
+@@ -1450,16 +1456,127 @@ struct grub_efi_simple_text_output_interface
+ };
+ typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t;
+ 
+-typedef grub_uint8_t grub_efi_pxe_packet_t[1472];
++typedef struct grub_efi_pxe_dhcpv4_packet
++{
++  grub_efi_uint8_t bootp_opcode;
++  grub_efi_uint8_t bootp_hwtype;
++  grub_efi_uint8_t bootp_hwaddr_len;
++  grub_efi_uint8_t bootp_gate_hops;
++  grub_efi_uint32_t bootp_ident;
++  grub_efi_uint16_t bootp_seconds;
++  grub_efi_uint16_t bootp_flags;
++  grub_efi_uint8_t bootp_ci_addr[4];
++  grub_efi_uint8_t bootp_yi_addr[4];
++  grub_efi_uint8_t bootp_si_addr[4];
++  grub_efi_uint8_t bootp_gi_addr[4];
++  grub_efi_uint8_t bootp_hw_addr[16];
++  grub_efi_uint8_t bootp_srv_name[64];
++  grub_efi_uint8_t bootp_boot_file[128];
++  grub_efi_uint32_t dhcp_magik;
++  grub_efi_uint8_t dhcp_options[56];
++} grub_efi_pxe_dhcpv4_packet_t;
++
++struct grub_efi_pxe_dhcpv6_packet
++{
++  grub_efi_uint32_t message_type:8;
++  grub_efi_uint32_t transaction_id:24;
++  grub_efi_uint8_t dhcp_options[1024];
++} GRUB_PACKED;
++typedef struct grub_efi_pxe_dhcpv6_packet grub_efi_pxe_dhcpv6_packet_t;
++
++typedef union
++{
++  grub_efi_uint8_t raw[1472];
++  grub_efi_pxe_dhcpv4_packet_t dhcpv4;
++  grub_efi_pxe_dhcpv6_packet_t dhcpv6;
++} grub_efi_pxe_packet_t;
++
++#define GRUB_EFI_PXE_MAX_IPCNT 8
++#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8
++#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8
++
++typedef struct grub_efi_pxe_ip_filter
++{
++  grub_efi_uint8_t filters;
++  grub_efi_uint8_t ip_count;
++  grub_efi_uint8_t reserved;
++  grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT];
++} grub_efi_pxe_ip_filter_t;
++
++typedef struct grub_efi_pxe_arp_entry
++{
++  grub_efi_ip_address_t ip_addr;
++  grub_efi_mac_address_t mac_addr;
++} grub_efi_pxe_arp_entry_t;
++
++typedef struct grub_efi_pxe_route_entry
++{
++  grub_efi_ip_address_t ip_addr;
++  grub_efi_ip_address_t subnet_mask;
++  grub_efi_ip_address_t gateway_addr;
++} grub_efi_pxe_route_entry_t;
++
++typedef struct grub_efi_pxe_icmp_error
++{
++  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];
++} grub_efi_pxe_icmp_error_t;
++
++typedef struct grub_efi_pxe_tftp_error
++{
++  grub_efi_uint8_t error_code;
++  grub_efi_char8_t error_string[127];
++} grub_efi_pxe_tftp_error_t;
+ 
+ typedef struct grub_efi_pxe_mode
+ {
+-  grub_uint8_t unused[52];
++  grub_efi_boolean_t started;
++  grub_efi_boolean_t ipv6_available;
++  grub_efi_boolean_t ipv6_supported;
++  grub_efi_boolean_t using_ipv6;
++  grub_efi_boolean_t bis_supported;
++  grub_efi_boolean_t bis_detected;
++  grub_efi_boolean_t auto_arp;
++  grub_efi_boolean_t send_guid;
++  grub_efi_boolean_t dhcp_discover_valid;
++  grub_efi_boolean_t dhcp_ack_received;
++  grub_efi_boolean_t proxy_offer_received;
++  grub_efi_boolean_t pxe_discover_valid;
++  grub_efi_boolean_t pxe_reply_received;
++  grub_efi_boolean_t pxe_bis_reply_received;
++  grub_efi_boolean_t icmp_error_received;
++  grub_efi_boolean_t tftp_error_received;
++  grub_efi_boolean_t make_callbacks;
++  grub_efi_uint8_t ttl;
++  grub_efi_uint8_t tos;
++  grub_efi_ip_address_t station_ip;
++  grub_efi_ip_address_t subnet_mask;
+   grub_efi_pxe_packet_t dhcp_discover;
+   grub_efi_pxe_packet_t dhcp_ack;
+   grub_efi_pxe_packet_t proxy_offer;
+   grub_efi_pxe_packet_t pxe_discover;
+   grub_efi_pxe_packet_t pxe_reply;
++  grub_efi_pxe_packet_t pxe_bis_reply;
++  grub_efi_pxe_ip_filter_t ip_filter;
++  grub_efi_uint32_t arp_cache_entries;
++  grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES];
++  grub_efi_uint32_t route_table_entries;
++  grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES];
++  grub_efi_pxe_icmp_error_t icmp_error;
++  grub_efi_pxe_tftp_error_t tftp_error;
+ } grub_efi_pxe_mode_t;
+ 
+ typedef struct grub_efi_pxe
+diff --git a/include/grub/net.h b/include/grub/net.h
+index 50d62ab0c8c..f8f3ec13acc 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -442,6 +442,51 @@ struct grub_net_bootp_packet
+   grub_uint8_t vendor[0];
+ } GRUB_PACKED;
+ 
++enum
++  {
++    GRUB_NET_DHCP6_IA_NA = 3,
++    GRUB_NET_DHCP6_IA_ADDRESS = 5,
++    GRUB_NET_DHCP6_BOOTFILE_URL = 59,
++  };
++
++struct grub_net_dhcpv6_option
++{
++  grub_uint16_t option_num;
++  grub_uint16_t option_len;
++  grub_uint8_t option_data[];
++} GRUB_PACKED;
++typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t;
++
++struct grub_net_dhcpv6_opt_ia_na
++{
++  grub_uint16_t option_num;
++  grub_uint16_t option_len;
++  grub_uint32_t iaid;
++  grub_uint32_t t1;
++  grub_uint32_t t2;
++  grub_uint8_t options[];
++} GRUB_PACKED;
++typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t;
++
++struct grub_net_dhcpv6_opt_ia_address
++{
++  grub_uint16_t option_num;
++  grub_uint16_t option_len;
++  grub_uint64_t ipv6_address[2];
++  grub_uint32_t preferred_lifetime;
++  grub_uint32_t valid_lifetime;
++  grub_uint8_t options[];
++} GRUB_PACKED;
++typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t;
++
++struct grub_net_dhcpv6_packet
++{
++  grub_uint32_t message_type:8;
++  grub_uint32_t transaction_id:24;
++  grub_uint8_t dhcp_options[1024];
++} GRUB_PACKED;
++typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t;
++
+ #define	GRUB_NET_BOOTP_RFC1048_MAGIC_0	0x63
+ #define	GRUB_NET_BOOTP_RFC1048_MAGIC_1	0x82
+ #define	GRUB_NET_BOOTP_RFC1048_MAGIC_2	0x53
+@@ -470,6 +515,21 @@ grub_net_configure_by_dhcp_ack (const char *name,
+ 				grub_size_t size,
+ 				int is_def, char **device, char **path);
+ 
++struct grub_net_network_level_interface *
++grub_net_configure_by_dhcpv6_ack (const char *name,
++				 struct grub_net_card *card,
++				 grub_net_interface_flags_t flags,
++				 const grub_net_link_level_address_t *hwaddr,
++				 const struct grub_net_dhcpv6_packet *packet,
++				 int is_def, char **device, char **path);
++
++int
++grub_ipv6_get_masksize(grub_uint16_t *mask);
++
++grub_err_t
++grub_net_add_ipv6_local (struct grub_net_network_level_interface *inf,
++			 int mask);
++
+ grub_err_t
+ grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf,
+ 			 int mask);
diff --git a/SOURCES/0076-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch b/SOURCES/0076-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch
new file mode 100644
index 0000000..7ea79d1
--- /dev/null
+++ b/SOURCES/0076-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch
@@ -0,0 +1,300 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 23 Jun 2016 11:01:39 -0400
+Subject: [PATCH] Add grub-get-kernel-settings and use it in 10_linux
+
+This patch adds grub-get-kernel-settings, which reads the system kernel
+installation configuration from /etc/sysconfig/kernel, and outputs
+${GRUB_...} variables suitable for evaluation by grub-mkconfig.  Those
+variables are then used by 10_linux to choose whether or not to create
+debug stanzas.
+
+Resolves: rhbz#1226325
+---
+ configure.ac                                   |  2 +
+ Makefile.util.def                              |  7 +++
+ .gitignore                                     |  2 +
+ util/bash-completion.d/grub-completion.bash.in | 22 ++++++++
+ util/grub-get-kernel-settings.3                | 20 +++++++
+ util/grub-get-kernel-settings.in               | 78 ++++++++++++++++++++++++++
+ util/grub-mkconfig.in                          |  3 +
+ util/grub.d/10_linux.in                        | 23 ++++++--
+ 8 files changed, 152 insertions(+), 5 deletions(-)
+ create mode 100644 util/grub-get-kernel-settings.3
+ create mode 100644 util/grub-get-kernel-settings.in
+
+diff --git a/configure.ac b/configure.ac
+index 71d1056969e..aa06ed59c8d 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -58,6 +58,7 @@ grub_TRANSFORM([grub-install])
+ grub_TRANSFORM([grub-mkconfig])
+ grub_TRANSFORM([grub-mkfont])
+ grub_TRANSFORM([grub-mkimage])
++grub_TRANSFORM([grub-get-kernel-settings])
+ grub_TRANSFORM([grub-glue-efi])
+ grub_TRANSFORM([grub-mklayout])
+ grub_TRANSFORM([grub-mkpasswd-pbkdf2])
+@@ -75,6 +76,7 @@ grub_TRANSFORM([grub-file])
+ grub_TRANSFORM([grub-bios-setup.3])
+ grub_TRANSFORM([grub-editenv.1])
+ grub_TRANSFORM([grub-fstest.3])
++grub_TRANSFORM([grub-get-kernel-settings.3])
+ grub_TRANSFORM([grub-glue-efi.3])
+ grub_TRANSFORM([grub-install.1])
+ grub_TRANSFORM([grub-kbdcomp.3])
+diff --git a/Makefile.util.def b/Makefile.util.def
+index fd91045bd6d..2d032643de7 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -714,6 +714,13 @@ script = {
+   installdir = sbin;
+ };
+ 
++script = {
++  name = grub-get-kernel-settings;
++  common = util/grub-get-kernel-settings.in;
++  mansection = 3;
++  installdir = sbin;
++};
++
+ script = {
+   name = grub-set-default;
+   common = util/grub-set-default.in;
+diff --git a/.gitignore b/.gitignore
+index 5066689bc0a..54795fa60be 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -68,6 +68,8 @@ grub-*.tar.*
+ /grub*-fs-tester
+ /grub*-fstest
+ /grub*-fstest.1
++/grub*-get-kernel-settings
++/grub*-get-kernel-settings.3
+ /grub*-glue-efi
+ /grub*-glue-efi.1
+ /grub*-install
+diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in
+index 44bf135b9f8..5c4acd496d4 100644
+--- a/util/bash-completion.d/grub-completion.bash.in
++++ b/util/bash-completion.d/grub-completion.bash.in
+@@ -264,6 +264,28 @@ have ${__grub_sparc64_setup_program} && \
+ unset __grub_sparc64_setup_program
+ 
+ 
++#
++# grub-get-kernel-settings
++#
++_grub_get_kernel_settings () {
++    local cur
++
++    COMPREPLY=()
++    cur=`_get_cword`
++
++    if [[ "$cur" == -* ]]; then
++        __grubcomp "$(__grub_get_options_from_help)"
++    else
++        # Default complete with a filename
++        _filedir
++    fi
++}
++__grub_get_kernel_settings_program="@grub_get_kernel_settings@"
++have ${__grub_get_kernel_settings_program} && \
++ complete -F _grub_get_kernel_settings -o filenames ${__grub_get_kernel_settings_program}
++unset __grub_get_kernel_settings_program
++
++
+ #
+ # grub-install
+ #
+diff --git a/util/grub-get-kernel-settings.3 b/util/grub-get-kernel-settings.3
+new file mode 100644
+index 00000000000..ba33330e28d
+--- /dev/null
++++ b/util/grub-get-kernel-settings.3
+@@ -0,0 +1,20 @@
++.TH GRUB-GET-KERNEL-SETTINGS 3 "Thu Jun 25 2015"
++.SH NAME
++\fBgrub-get-kernel-settings\fR \(em Evaluate the system's kernel installation settings for use while making a grub configuration file.
++
++.SH SYNOPSIS
++\fBgrub-get-kernel-settings\fR [OPTION]
++
++.SH DESCRIPTION
++\fBgrub-get-kernel-settings\fR reads the kernel installation settings on the host system, and emits a set of grub settings suitable for use when creating a grub configuration file.
++
++.SH OPTIONS
++.TP
++-h, --help
++Display program usage and exit.
++.TP
++-v, --version
++Display the current version.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-get-kernel-settings.in b/util/grub-get-kernel-settings.in
+new file mode 100644
+index 00000000000..12046219878
+--- /dev/null
++++ b/util/grub-get-kernel-settings.in
+@@ -0,0 +1,78 @@
++#!/bin/sh
++set -e
++
++# Evaluate new-kernel-pkg's configuration file.
++# Copyright (C) 2016 Free Software Foundation, Inc.
++#
++# GRUB is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# GRUB is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++
++PACKAGE_NAME=@PACKAGE_NAME@
++PACKAGE_VERSION=@PACKAGE_VERSION@
++datadir="@datadir@"
++if [ "x$pkgdatadir" = x ]; then
++    pkgdatadir="${datadir}/@PACKAGE@"
++fi
++
++self=`basename $0`
++
++export TEXTDOMAIN=@PACKAGE@
++export TEXTDOMAINDIR="@localedir@"
++
++. "${pkgdatadir}/grub-mkconfig_lib"
++
++# Usage: usage
++# Print the usage.
++usage () {
++    gettext_printf "Usage: %s [OPTION]\n" "$self"
++    gettext "Evaluate new-kernel-pkg configuration"; echo
++    echo
++    print_option_help "-h, --help" "$(gettext "print this message and exit")"
++    print_option_help "-v, --version" "$(gettext "print the version information and exit")"
++    echo
++}
++
++# Check the arguments.
++while test $# -gt 0
++do
++    option=$1
++    shift
++
++    case "$option" in
++    -h | --help)
++	usage
++	exit 0 ;;
++    -v | --version)
++	echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}"
++	exit 0 ;;
++    -*)
++	gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2
++	usage
++	exit 1
++	;;
++    # Explicitly ignore non-option arguments, for compatibility.
++    esac
++done
++
++if test -f /etc/sysconfig/kernel ; then
++    . /etc/sysconfig/kernel
++fi
++
++if [ "$MAKEDEBUG" = "yes" ]; then
++    echo GRUB_LINUX_MAKE_DEBUG=true
++    echo export GRUB_LINUX_MAKE_DEBUG
++    echo GRUB_CMDLINE_LINUX_DEBUG=\"systemd.log_level=debug systemd.log_target=kmsg\"
++    echo export GRUB_CMDLINE_LINUX_DEBUG
++    echo GRUB_LINUX_DEBUG_TITLE_POSTFIX=\" with debugging\"
++    echo export GRUB_LINUX_DEBUG_TITLE_POSTFIX
++fi
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index bdb9982aefb..8218f3d477f 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -45,6 +45,7 @@ grub_probe="${sbindir}/@grub_probe@"
+ grub_file="${bindir}/@grub_file@"
+ grub_editenv="${bindir}/@grub_editenv@"
+ grub_script_check="${bindir}/@grub_script_check@"
++grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@"
+ 
+ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
+@@ -158,6 +159,8 @@ if test -f ${sysconfdir}/default/grub ; then
+   . ${sysconfdir}/default/grub
+ fi
+ 
++eval "$("${grub_get_kernel_settings}")" || true
++
+ if [ "x$GRUB_DISABLE_UUID" != "xtrue" ]; then
+   if [ -z "$GRUB_DEVICE_UUID" ]; then
+     GRUB_DEVICE_UUID="$GRUB_DEVICE_UUID_GENERATED"
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index a8a8e2cf325..4e49ccdf742 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -111,7 +111,8 @@ linux_entry ()
+   os="$1"
+   version="$2"
+   type="$3"
+-  args="$4"
++  isdebug="$4"
++  args="$5"
+ 
+   if [ -z "$boot_device_id" ]; then
+       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+@@ -123,6 +124,9 @@ linux_entry ()
+ 	  quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)"
+ 	  title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
+       fi
++      if [ x$isdebug = xdebug ]; then
++	  title="$title${GRUB_LINUX_DEBUG_TITLE_POSTFIX}"
++      fi
+       echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+   else
+       echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+@@ -295,11 +299,15 @@ while [ "x$list" != "x" ] ; do
+   fi
+ 
+   if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then
+-    linux_entry "${OS}" "${version}" simple \
++    linux_entry "${OS}" "${version}" simple standard \
+     "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++    if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
++      linux_entry "${OS}" "${version}" simple debug \
++        "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}"
++    fi
+ 
+     submenu_indentation="$grub_tab"
+-    
++
+     if [ -z "$boot_device_id" ]; then
+ 	boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+     fi
+@@ -308,10 +316,15 @@ while [ "x$list" != "x" ] ; do
+     is_top_level=false
+   fi
+ 
+-  linux_entry "${OS}" "${version}" advanced \
++  linux_entry "${OS}" "${version}" advanced standard \
+               "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++  if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
++    linux_entry "${OS}" "${version}" advanced debug \
++                "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}"
++  fi
++
+   if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
+-    linux_entry "${OS}" "${version}" recovery \
++    linux_entry "${OS}" "${version}" recovery standard \
+                 "single ${GRUB_CMDLINE_LINUX}"
+   fi
+ 
diff --git a/SOURCES/0077-Normalize-slashes-in-tftp-paths.patch b/SOURCES/0077-Normalize-slashes-in-tftp-paths.patch
new file mode 100644
index 0000000..5ea5afa
--- /dev/null
+++ b/SOURCES/0077-Normalize-slashes-in-tftp-paths.patch
@@ -0,0 +1,55 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Lenny Szubowicz <lszubowi@redhat.com>
+Date: Mon, 29 Aug 2016 11:04:48 -0400
+Subject: [PATCH] Normalize slashes in tftp paths.
+
+Some tftp servers do not handle multiple consecutive slashes correctly;
+this patch avoids sending tftp requests with non-normalized paths.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/tftp.c | 24 +++++++++++++++++++++++-
+ 1 file changed, 23 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
+index 1157524fc50..5ca0a96a6f6 100644
+--- a/grub-core/net/tftp.c
++++ b/grub-core/net/tftp.c
+@@ -300,6 +300,25 @@ destroy_pq (tftp_data_t data)
+   grub_priority_queue_destroy (data->pq);
+ }
+ 
++/* Create a normalized copy of the filename.
++   Compress any string of consecutive forward slashes to a single forward
++   slash. */
++static void
++grub_normalize_filename (char *normalized, const char *filename)
++{
++  char *dest = normalized;
++  char *src = filename;
++
++  while (*src != '\0')
++    {
++      if (src[0] == '/' && src[1] == '/')
++	src++;
++      else
++	*dest++ = *src++;
++    }
++  *dest = '\0';
++}
++
+ static grub_err_t
+ tftp_open (struct grub_file *file, const char *filename)
+ {
+@@ -337,7 +356,10 @@ tftp_open (struct grub_file *file, const char *filename)
+   rrqlen = 0;
+ 
+   tftph->opcode = grub_cpu_to_be16_compile_time (TFTP_RRQ);
+-  grub_strcpy (rrq, filename);
++
++  /* Copy and normalize the filename to work-around issues on some tftp
++     servers when file names are being matched for remapping. */
++  grub_normalize_filename (rrq, filename);
+   rrqlen += grub_strlen (filename) + 1;
+   rrq += grub_strlen (filename) + 1;
+ 
diff --git a/SOURCES/0078-Fix-malformed-tftp-packets.patch b/SOURCES/0078-Fix-malformed-tftp-packets.patch
new file mode 100644
index 0000000..2445137
--- /dev/null
+++ b/SOURCES/0078-Fix-malformed-tftp-packets.patch
@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Mark Salter <msalter@redhat.com>
+Date: Tue, 7 Mar 2017 18:26:17 -0500
+Subject: [PATCH] Fix malformed tftp packets
+
+0088-Normalize-slashes-in-tftp-paths.patch collapses multiple contiguous
+slashes in a filename into one slash in the tftp packet filename field.
+However, the packet buffer pointer is advanced using the original name.
+This leaves unitialized data between the name field and the type field
+leading to tftp errors. Use the length of the normalized name to avoid
+this.
+
+Signed-off-by: Mark Salter <msalter@redhat.com>
+---
+ grub-core/net/tftp.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
+index 5ca0a96a6f6..dcd82494309 100644
+--- a/grub-core/net/tftp.c
++++ b/grub-core/net/tftp.c
+@@ -360,8 +360,8 @@ tftp_open (struct grub_file *file, const char *filename)
+   /* Copy and normalize the filename to work-around issues on some tftp
+      servers when file names are being matched for remapping. */
+   grub_normalize_filename (rrq, filename);
+-  rrqlen += grub_strlen (filename) + 1;
+-  rrq += grub_strlen (filename) + 1;
++  rrqlen += grub_strlen (rrq) + 1;
++  rrq += grub_strlen (rrq) + 1;
+ 
+   grub_strcpy (rrq, "octet");
+   rrqlen += grub_strlen ("octet") + 1;
diff --git a/SOURCES/0079-bz1374141-fix-incorrect-mask-for-ppc64.patch b/SOURCES/0079-bz1374141-fix-incorrect-mask-for-ppc64.patch
new file mode 100644
index 0000000..628ff7e
--- /dev/null
+++ b/SOURCES/0079-bz1374141-fix-incorrect-mask-for-ppc64.patch
@@ -0,0 +1,45 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Masahiro Matsuya <mmatsuya@redhat.com>
+Date: Sat, 29 Oct 2016 08:35:26 +0900
+Subject: [PATCH] bz1374141 fix incorrect mask for ppc64
+
+The netmask configured in firmware is not respected on ppc64 (big endian).
+When 255.255.252.0 is set as netmask in firmware, the following is the value of bootpath string in grub_ieee1275_parse_bootpath().
+
+ /vdevice/l-lan@30000002:speed=auto,duplex=auto,192.168.88.10,,192.168.89.113,192.168.88.1,5,5,255.255.252.0,512
+
+The netmask in this bootpath is no problem, since it's a value specified in firmware. But,
+The value of 'subnet_mask.ipv4' was set with 0xfffffc00, and __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4)) returned 16 (not 22).
+As a result, 16 was used for netmask wrongly.
+
+1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00)
+0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4)
+1111 1111 0000 0011 0000 0000 0000 0000 # ~grub_le_to_cpu32 (subnet_mask.ipv4)
+
+And, the count of zero with __builtin_ctz can be 16.
+This patch changes it as below.
+
+1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00)
+0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4)
+1111 1111 1111 1111 1111 1100 0000 0000 # grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4))
+0000 0000 0000 0000 0000 0011 1111 1111 # ~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4))
+
+The count of zero with __builtin_clz can be 22. (clz counts the number of one bits preceding the most significant zero bit)
+---
+ grub-core/net/drivers/ieee1275/ofnet.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
+index 002446be1c3..3df75357a70 100644
+--- a/grub-core/net/drivers/ieee1275/ofnet.c
++++ b/grub-core/net/drivers/ieee1275/ofnet.c
+@@ -220,8 +220,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath,
+                                  flags);
+       inter->vlantag = vlantag;
+       grub_net_add_ipv4_local (inter,
+-                          __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4)));
+-
++                          __builtin_clz (~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4))));
+     }
+ 
+   if (gateway_addr.ipv4 != 0)
diff --git a/SOURCES/0080-Make-grub_fatal-also-backtrace.patch b/SOURCES/0080-Make-grub_fatal-also-backtrace.patch
new file mode 100644
index 0000000..a9af329
--- /dev/null
+++ b/SOURCES/0080-Make-grub_fatal-also-backtrace.patch
@@ -0,0 +1,172 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 27 Jan 2016 09:22:42 -0500
+Subject: [PATCH] Make grub_fatal() also backtrace.
+
+---
+ grub-core/Makefile.core.def     |  3 ++
+ grub-core/kern/misc.c           |  8 +++++-
+ grub-core/lib/arm64/backtrace.c | 62 +++++++++++++++++++++++++++++++++++++++++
+ grub-core/lib/backtrace.c       |  2 ++
+ grub-core/lib/i386/backtrace.c  | 14 +++++++++-
+ 5 files changed, 87 insertions(+), 2 deletions(-)
+ create mode 100644 grub-core/lib/arm64/backtrace.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 991891a6e09..27563743ba9 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -175,6 +175,9 @@ kernel = {
+ 
+   softdiv = lib/division.c;
+ 
++  x86 = lib/i386/backtrace.c;
++  x86 = lib/backtrace.c;
++
+   i386 = kern/i386/dl.c;
+   i386_xen = kern/i386/dl.c;
+ 
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index f1fab700048..5ce89a40c68 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -24,6 +24,7 @@
+ #include <grub/term.h>
+ #include <grub/env.h>
+ #include <grub/i18n.h>
++#include <grub/backtrace.h>
+ 
+ union printf_arg
+ {
+@@ -1101,8 +1102,13 @@ grub_xasprintf (const char *fmt, ...)
+ static void __attribute__ ((noreturn))
+ grub_abort (void)
+ {
++#ifndef GRUB_UTIL
++#if defined(__i386__) || defined(__x86_64__)
++  grub_backtrace();
++#endif
++#endif
+   grub_printf ("\nAborted.");
+-  
++
+ #ifndef GRUB_UTIL
+   if (grub_term_inputs)
+ #endif
+diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c
+new file mode 100644
+index 00000000000..1079b5380e1
+--- /dev/null
++++ b/grub-core/lib/arm64/backtrace.c
+@@ -0,0 +1,62 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/misc.h>
++#include <grub/command.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/backtrace.h>
++
++#define MAX_STACK_FRAME 102400
++
++void
++grub_backtrace_pointer (int frame)
++{
++  while (1)
++    {
++      void *lp = __builtin_return_address (frame);
++      if (!lp)
++	break;
++
++      lp = __builtin_extract_return_addr (lp);
++
++      grub_printf ("%p: ", lp);
++      grub_backtrace_print_address (lp);
++      grub_printf (" (");
++      for (i = 0; i < 2; i++)
++	grub_printf ("%p,", ((void **)ptr) [i + 2]);
++      grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
++      nptr = *(void **)ptr;
++      if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
++	  || nptr == ptr)
++	{
++	  grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
++	  break;
++	}
++      ptr = nptr;
++    }
++}
++
++void
++grub_backtrace (void)
++{
++  grub_backtrace_pointer (1);
++}
++
+diff --git a/grub-core/lib/backtrace.c b/grub-core/lib/backtrace.c
+index 825a8800e25..c0ad6ab8be1 100644
+--- a/grub-core/lib/backtrace.c
++++ b/grub-core/lib/backtrace.c
+@@ -29,6 +29,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ void
+ grub_backtrace_print_address (void *addr)
+ {
++#ifndef GRUB_UTIL
+   grub_dl_t mod;
+ 
+   FOR_DL_MODULES (mod)
+@@ -44,6 +45,7 @@ grub_backtrace_print_address (void *addr)
+ 	}
+   }
+ 
++#endif
+   grub_printf ("%p", addr);
+ }
+ 
+diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c
+index c3e03c7275c..c67273db3ae 100644
+--- a/grub-core/lib/i386/backtrace.c
++++ b/grub-core/lib/i386/backtrace.c
+@@ -15,11 +15,23 @@
+  *  You should have received a copy of the GNU General Public License
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
++#include <config.h>
++#ifdef GRUB_UTIL
++#define REALLY_GRUB_UTIL GRUB_UTIL
++#undef GRUB_UTIL
++#endif
++
++#include <grub/symbol.h>
++#include <grub/dl.h>
++
++#ifdef REALLY_GRUB_UTIL
++#define GRUB_UTIL REALLY_GRUB_UTIL
++#undef REALLY_GRUB_UTIL
++#endif
+ 
+ #include <grub/misc.h>
+ #include <grub/command.h>
+ #include <grub/err.h>
+-#include <grub/dl.h>
+ #include <grub/mm.h>
+ #include <grub/term.h>
+ #include <grub/backtrace.h>
diff --git a/SOURCES/0081-Make-grub-editenv-build-again.patch b/SOURCES/0081-Make-grub-editenv-build-again.patch
new file mode 100644
index 0000000..64c001f
--- /dev/null
+++ b/SOURCES/0081-Make-grub-editenv-build-again.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 4 Mar 2016 16:29:13 -0500
+Subject: [PATCH] Make grub-editenv build again.
+
+36212460d3565b18439a3a8130b28e6c97702c6a split how some of the mkimage
+utility functions are defined, and they wind up being linked into
+grub-editenv.  Most utilities got fixed, but this one was missed.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ Makefile.util.def | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 2d032643de7..879e8eb98a4 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -237,6 +237,8 @@ program = {
+   extra_dist = grub-core/osdep/unix/compress.c;
+   extra_dist = grub-core/osdep/basic/compress.c;
+   common = util/mkimage.c;
++  common = util/grub-mkimage32.c;
++  common = util/grub-mkimage64.c;
+   common = grub-core/osdep/config.c;
+   common = util/config.c;
+   common = util/resolve.c;
diff --git a/SOURCES/0082-Fix-up-some-man-pages-rpmdiff-noticed.patch b/SOURCES/0082-Fix-up-some-man-pages-rpmdiff-noticed.patch
new file mode 100644
index 0000000..71b0a22
--- /dev/null
+++ b/SOURCES/0082-Fix-up-some-man-pages-rpmdiff-noticed.patch
@@ -0,0 +1,150 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 23 Sep 2014 09:58:49 -0400
+Subject: [PATCH] Fix up some man pages rpmdiff noticed.
+
+---
+ configure.ac             |  2 ++
+ util/grub-macbless.8     | 26 +++++++++++++++++++
+ util/grub-mkimage.1      |  2 +-
+ util/grub-syslinux2cfg.1 | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 94 insertions(+), 1 deletion(-)
+ create mode 100644 util/grub-macbless.8
+ create mode 100644 util/grub-syslinux2cfg.1
+
+diff --git a/configure.ac b/configure.ac
+index aa06ed59c8d..f69f8986791 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -80,6 +80,7 @@ grub_TRANSFORM([grub-get-kernel-settings.3])
+ grub_TRANSFORM([grub-glue-efi.3])
+ grub_TRANSFORM([grub-install.1])
+ grub_TRANSFORM([grub-kbdcomp.3])
++grub_TRANSFORM([grub-macbless.8])
+ grub_TRANSFORM([grub-menulst2cfg.1])
+ grub_TRANSFORM([grub-mkconfig.1])
+ grub_TRANSFORM([grub-mkfont.3])
+@@ -98,6 +99,7 @@ grub_TRANSFORM([grub-render-label.3])
+ grub_TRANSFORM([grub-script-check.3])
+ grub_TRANSFORM([grub-set-default.1])
+ grub_TRANSFORM([grub-sparc64-setup.3])
++grub_TRANSFORM([grub-syslinux2cfg.1])
+ 
+ # Optimization flag.  Allow user to override.
+ if test "x$TARGET_CFLAGS" = x; then
+diff --git a/util/grub-macbless.8 b/util/grub-macbless.8
+new file mode 100644
+index 00000000000..ae842f3a606
+--- /dev/null
++++ b/util/grub-macbless.8
+@@ -0,0 +1,26 @@
++.TH GRUB-MACBLESS 1 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-macbless\fR \(em Mac-style bless utility for HFS or HFS+
++
++.SH SYNOPSIS
++\fBgrub-macbless\fR [-p | --ppc] [-v | --verbose] [-x | --x86] \fIFILE\fR
++
++.SH DESCRIPTION
++\fBgrub-mkimage\fR blesses a file on an HFS or HFS+ file system, so that it
++can be used to boot a Mac.
++
++.SH OPTIONS
++.TP
++--ppc
++Bless the file for use on PPC-based Macs.
++
++.TP
++--verbose
++Print verbose messages.
++
++.TP
++--x86
++Bless the file for use on x86-based Macs.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-mkimage.1 b/util/grub-mkimage.1
+index 4dea4f54597..0eaaafe505b 100644
+--- a/util/grub-mkimage.1
++++ b/util/grub-mkimage.1
+@@ -17,7 +17,7 @@
+ [-v | --verbose] \fIMODULES\fR
+ 
+ .SH DESCRIPTION
+-\fBgrub-mkimage\fI builds a bootable image of GRUB.
++\fBgrub-mkimage\fR builds a bootable image of GRUB.
+ 
+ .SH OPTIONS
+ .TP
+diff --git a/util/grub-syslinux2cfg.1 b/util/grub-syslinux2cfg.1
+new file mode 100644
+index 00000000000..85309482718
+--- /dev/null
++++ b/util/grub-syslinux2cfg.1
+@@ -0,0 +1,65 @@
++.TH GRUB-SYSLINUX2CFG 1 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-syslinux2cfg\fR \(em Transform a syslinux config file into a GRUB config.
++
++.SH SYNOPSIS
++\fBgrub-syslinux2cfg\fR [-c | --cwd=\fRDIR\fI] [-r | --root=\fIDIR\fR] [-v | --verbose]
++.RE
++.RS 25
++[-t | --target-root=\fIDIR\fR] [-T | --target-cwd=\fIDIR\fR]
++.RE
++.RS 25
++[-o | --output=\fIFILE\fR] [[-i | --isolinux] |
++.RE
++.RS 46
++ [-s | --syslinux] |
++.RE
++.RS 46
++ [-p | --pxelinux]] \fIFILE\fR
++
++.SH DESCRIPTION
++\fBgrub-syslinux2cfg\fR builds a GRUB configuration file out of an existing
++syslinux configuration file.
++
++.SH OPTIONS
++.TP
++--cwd=\fIDIR\fR
++Set \fIDIR\fR as syslinux's working directory.  The default is to use the
++parent directory of the input file.
++
++.TP
++--root=\fIDIR\fR
++Set \fIDIR\fR as the root directory of the syslinux disk.  The default value
++is "/".
++
++.TP
++--verbose
++Print verbose messages.
++
++.TP
++--target-root=\fIDIR\fR
++Root directory as it will be seen at runtime.  The default value is "/".
++
++.TP
++--target-cwd=\fIDIR\fR
++Working directory of syslinux as it will be seen at runtime.  The default
++value is the parent directory of the input file.
++
++.TP
++--output=\fIFILE\fR
++Write the new config file to \fIFILE\fR.  The default value is standard output.
++
++.TP
++--isolinux
++Assume that the input file is an isolinux configuration file.
++
++.TP
++--pxelinux
++Assume that the input file is a pxelinux configuration file.
++
++.TP
++--syslinux
++Assume that the input file is a syslinux configuration file.
++
++.SH SEE ALSO
++.BR "info grub"
diff --git a/SOURCES/0083-Make-exit-take-a-return-code.patch b/SOURCES/0083-Make-exit-take-a-return-code.patch
new file mode 100644
index 0000000..b886e12
--- /dev/null
+++ b/SOURCES/0083-Make-exit-take-a-return-code.patch
@@ -0,0 +1,53 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 26 Feb 2014 21:49:12 -0500
+Subject: [PATCH] Make "exit" take a return code.
+
+This adds "exit" with a return code.  With this patch, any "exit"
+command /may/ include a return code, and on platforms that support
+returning with an exit status, we will do so.  By default we return the
+same exit status we did before this patch.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/emu/main.c | 6 ++++++
+ grub-core/kern/misc.c     | 9 +++++++++
+ 2 files changed, 15 insertions(+)
+
+diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c
+index 55ea5a11ccd..7e47ec81263 100644
+--- a/grub-core/kern/emu/main.c
++++ b/grub-core/kern/emu/main.c
+@@ -72,6 +72,12 @@ grub_exit (int retval __attribute__((unused)))
+   grub_reboot ();
+ }
+ 
++void
++grub_exit (int retval __attribute__((unused)))
++{
++  grub_reboot ();
++}
++
+ void
+ grub_machine_init (void)
+ {
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 5ce89a40c68..04371ac49f2 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -1120,6 +1120,15 @@ grub_abort (void)
+   grub_exit (1);
+ }
+ 
++#if defined (__clang__) && !defined (GRUB_UTIL)
++/* clang emits references to abort().  */
++void __attribute__ ((noreturn))
++abort (void)
++{
++  grub_abort ();
++}
++#endif
++
+ void
+ grub_fatal (const char *fmt, ...)
+ {
diff --git a/SOURCES/0084-arm64-make-sure-fdt-has-address-cells-and-size-cells.patch b/SOURCES/0084-arm64-make-sure-fdt-has-address-cells-and-size-cells.patch
new file mode 100644
index 0000000..e832337
--- /dev/null
+++ b/SOURCES/0084-arm64-make-sure-fdt-has-address-cells-and-size-cells.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Mark Salter <msalter@redhat.com>
+Date: Mon, 17 Apr 2017 08:44:29 -0400
+Subject: [PATCH] arm64: make sure fdt has #address-cells and #size-cells
+ properties
+
+Recent upstream changes to kexec-tools relies on #address-cells
+and #size-cells properties in the FDT. If grub2 needs to create
+a chosen node, it is likely because firmware did not provide one.
+In that case, set #address-cells and #size-cells properties to
+make sure they exist.
+---
+ grub-core/loader/arm64/linux.c | 16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index a1ac7a38867..93b5cd306eb 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -80,7 +80,21 @@ finalize_params_linux (void)
+ 
+   node = grub_fdt_find_subnode (fdt, 0, "chosen");
+   if (node < 0)
+-    node = grub_fdt_add_subnode (fdt, 0, "chosen");
++    {
++      /*
++       * If we have to create a chosen node, Make sure we
++       * have #address-cells and #size-cells properties.
++       */
++      retval = grub_fdt_set_prop32(fdt, 0, "#address-cells", 2);
++      if (retval)
++	goto failure;
++
++      retval = grub_fdt_set_prop32(fdt, 0, "#size-cells", 2);
++      if (retval)
++	goto failure;
++
++      node = grub_fdt_add_subnode (fdt, 0, "chosen");
++    }
+ 
+   if (node < 1)
+     goto failure;
diff --git a/SOURCES/0085-Make-our-info-pages-say-grub2-where-appropriate.patch b/SOURCES/0085-Make-our-info-pages-say-grub2-where-appropriate.patch
new file mode 100644
index 0000000..800f7f1
--- /dev/null
+++ b/SOURCES/0085-Make-our-info-pages-say-grub2-where-appropriate.patch
@@ -0,0 +1,1013 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 6 May 2016 18:43:08 -0400
+Subject: [PATCH] Make our info pages say "grub2" where appropriate.
+
+This needs to be hooked up to --program-transform=, but I haven't had
+time.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ docs/grub-dev.texi |   4 +-
+ docs/grub.texi     | 318 ++++++++++++++++++++++++++---------------------------
+ 2 files changed, 161 insertions(+), 161 deletions(-)
+
+diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
+index a9f4de6318c..3ce827ab726 100644
+--- a/docs/grub-dev.texi
++++ b/docs/grub-dev.texi
+@@ -1,7 +1,7 @@
+ \input texinfo
+ @c -*-texinfo-*-
+ @c %**start of header
+-@setfilename grub-dev.info
++@setfilename grub2-dev.info
+ @include version-dev.texi
+ @settitle GNU GRUB Developers Manual @value{VERSION}
+ @c Unify all our little indices for now.
+@@ -32,7 +32,7 @@ Invariant Sections.
+ 
+ @dircategory Kernel
+ @direntry
+-* grub-dev: (grub-dev).                 The GRand Unified Bootloader Dev
++* grub2-dev: (grub2-dev).                 The GRand Unified Bootloader Dev
+ @end direntry
+ 
+ @setchapternewpage odd
+diff --git a/docs/grub.texi b/docs/grub.texi
+index a7155c22ffe..2b7b7faf847 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -1,7 +1,7 @@
+ \input texinfo
+ @c -*-texinfo-*-
+ @c %**start of header
+-@setfilename grub.info
++@setfilename grub2.info
+ @include version.texi
+ @settitle GNU GRUB Manual @value{VERSION}
+ @c Unify all our little indices for now.
+@@ -32,15 +32,15 @@ Invariant Sections.
+ 
+ @dircategory Kernel
+ @direntry
+-* GRUB: (grub).                 The GRand Unified Bootloader
+-* grub-install: (grub)Invoking grub-install.    Install GRUB on your drive
+-* grub-mkconfig: (grub)Invoking grub-mkconfig.  Generate GRUB configuration
+-* grub-mkpasswd-pbkdf2: (grub)Invoking grub-mkpasswd-pbkdf2.
+-* grub-mkrelpath: (grub)Invoking grub-mkrelpath.
+-* grub-mkrescue: (grub)Invoking grub-mkrescue.  Make a GRUB rescue image
+-* grub-mount: (grub)Invoking grub-mount.        Mount a file system using GRUB
+-* grub-probe: (grub)Invoking grub-probe.        Probe device information
+-* grub-script-check: (grub)Invoking grub-script-check.
++* GRUB2: (grub2).                 The GRand Unified Bootloader
++* grub2-install: (grub2)Invoking grub2-install.    Install GRUB on your drive
++* grub2-mkconfig: (grub2)Invoking grub2-mkconfig.  Generate GRUB configuration
++* grub2-mkpasswd-pbkdf2: (grub2)Invoking grub2-mkpasswd-pbkdf2.
++* grub2-mkrelpath: (grub2)Invoking grub2-mkrelpath.
++* grub2-mkrescue: (grub2)Invoking grub2-mkrescue.  Make a GRUB rescue image
++* grub2-mount: (grub2)Invoking grub2-mount.        Mount a file system using GRUB
++* grub2-probe: (grub2)Invoking grub2-probe.        Probe device information
++* grub2-script-check: (grub2)Invoking grub2-script-check.
+ @end direntry
+ 
+ @setchapternewpage odd
+@@ -103,15 +103,15 @@ This edition documents version @value{VERSION}.
+ * Platform-specific operations:: Platform-specific operations
+ * Supported kernels::           The list of supported kernels
+ * Troubleshooting::             Error messages produced by GRUB
+-* Invoking grub-install::       How to use the GRUB installer
+-* Invoking grub-mkconfig::      Generate a GRUB configuration file
+-* Invoking grub-mkpasswd-pbkdf2::
++* Invoking grub2-install::       How to use the GRUB installer
++* Invoking grub2-mkconfig::      Generate a GRUB configuration file
++* Invoking grub2-mkpasswd-pbkdf2::
+                                 Generate GRUB password hashes
+-* Invoking grub-mkrelpath::     Make system path relative to its root
+-* Invoking grub-mkrescue::      Make a GRUB rescue image
+-* Invoking grub-mount::         Mount a file system using GRUB
+-* Invoking grub-probe::         Probe device information for GRUB
+-* Invoking grub-script-check::  Check GRUB script file for syntax errors
++* Invoking grub2-mkrelpath::     Make system path relative to its root
++* Invoking grub2-mkrescue::      Make a GRUB rescue image
++* Invoking grub2-mount::         Mount a file system using GRUB
++* Invoking grub2-probe::         Probe device information for GRUB
++* Invoking grub2-script-check::  Check GRUB script file for syntax errors
+ * Obtaining and Building GRUB:: How to obtain and build GRUB
+ * Reporting bugs::              Where you should send a bug report
+ * Future::                      Some future plans on GRUB
+@@ -230,7 +230,7 @@ surprising.
+ 
+ @item
+ @file{grub.cfg} is typically automatically generated by
+-@command{grub-mkconfig} (@pxref{Simple configuration}).  This makes it
++@command{grub2-mkconfig} (@pxref{Simple configuration}).  This makes it
+ easier to handle versioned kernel upgrades.
+ 
+ @item
+@@ -244,7 +244,7 @@ scripting language: variables, conditionals, and loops are available.
+ @item
+ A small amount of persistent storage is available across reboots, using the
+ @command{save_env} and @command{load_env} commands in GRUB and the
+-@command{grub-editenv} utility.  This is not available in all configurations
++@command{grub2-editenv} utility.  This is not available in all configurations
+ (@pxref{Environment block}).
+ 
+ @item
+@@ -549,7 +549,7 @@ On OS which have device nodes similar to Unix-like OS GRUB tools use the
+ OS name. E.g. for GNU/Linux:
+ 
+ @example
+-# @kbd{grub-install /dev/sda}
++# @kbd{grub2-install /dev/sda}
+ @end example
+ 
+ On AROS we use another syntax. For volumes:
+@@ -572,7 +572,7 @@ For disks we use syntax:
+ E.g.
+ 
+ @example
+-# @kbd{grub-install //:ata.device/0/0}
++# @kbd{grub2-install //:ata.device/0/0}
+ @end example
+ 
+ On Windows we use UNC path. For volumes it's typically
+@@ -599,7 +599,7 @@ For disks it's
+ E.g.
+ 
+ @example
+-# @kbd{grub-install \\?\PhysicalDrive0}
++# @kbd{grub2-install \\?\PhysicalDrive0}
+ @end example
+ 
+ Beware that you may need to further escape the backslashes depending on your
+@@ -609,7 +609,7 @@ When compiled with cygwin support then cygwin drive names are automatically
+ when needed. E.g.
+ 
+ @example
+-# @kbd{grub-install /dev/sda}
++# @kbd{grub2-install /dev/sda}
+ @end example
+ 
+ @node Installation
+@@ -622,7 +622,7 @@ from the source tarball, or as a package for your OS.
+ 
+ After you have done that, you need to install the boot loader on a
+ drive (floppy or hard disk) by using the utility
+-@command{grub-install} (@pxref{Invoking grub-install}) on a UNIX-like OS.
++@command{grub2-install} (@pxref{Invoking grub2-install}) on a UNIX-like OS.
+ 
+ GRUB comes with boot images, which are normally put in the directory
+ @file{/usr/lib/grub/<cpu>-<platform>} (for BIOS-based machines
+@@ -633,22 +633,22 @@ loader needs to find them (usually @file{/boot}) will be called
+ the @dfn{boot directory}.
+ 
+ @menu
+-* Installing GRUB using grub-install::
++* Installing GRUB using grub2-install::
+ * Making a GRUB bootable CD-ROM::
+ * Device map::
+ * BIOS installation::
+ @end menu
+ 
+ 
+-@node Installing GRUB using grub-install
+-@section Installing GRUB using grub-install
++@node Installing GRUB using grub2-install
++@section Installing GRUB using grub2-install
+ 
+ For information on where GRUB should be installed on PC BIOS platforms,
+ @pxref{BIOS installation}.
+ 
+ In order to install GRUB under a UNIX-like OS (such
+-as @sc{gnu}), invoke the program @command{grub-install} (@pxref{Invoking
+-grub-install}) as the superuser (@dfn{root}).
++as @sc{gnu}), invoke the program @command{grub2-install} (@pxref{Invoking
++grub2-install}) as the superuser (@dfn{root}).
+ 
+ The usage is basically very simple. You only need to specify one
+ argument to the program, namely, where to install the boot loader. The
+@@ -657,13 +657,13 @@ For example, under Linux the following will install GRUB into the MBR
+ of the first IDE disk:
+ 
+ @example
+-# @kbd{grub-install /dev/sda}
++# @kbd{grub2-install /dev/sda}
+ @end example
+ 
+ Likewise, under GNU/Hurd, this has the same effect:
+ 
+ @example
+-# @kbd{grub-install /dev/hd0}
++# @kbd{grub2-install /dev/hd0}
+ @end example
+ 
+ But all the above examples assume that GRUB should put images under
+@@ -677,7 +677,7 @@ boot floppy with a filesystem. Here is an example:
+ # @kbd{mke2fs /dev/fd0}
+ # @kbd{mount -t ext2 /dev/fd0 /mnt}
+ # @kbd{mkdir /mnt/boot}
+-# @kbd{grub-install --boot-directory=/mnt/boot /dev/fd0}
++# @kbd{grub2-install --boot-directory=/mnt/boot /dev/fd0}
+ # @kbd{umount /mnt}
+ @end group
+ @end example
+@@ -689,16 +689,16 @@ floppy instead of exposing the USB drive as a hard disk (they call it
+ @example
+ # @kbd{losetup /dev/loop0 /dev/sdb1}
+ # @kbd{mount /dev/loop0 /mnt/usb}
+-# @kbd{grub-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0}
++# @kbd{grub2-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0}
+ @end example
+ 
+ This install doesn't conflict with standard install as long as they are in
+ separate directories.
+ 
+-Note that @command{grub-install} is actually just a shell script and the
+-real task is done by other tools such as @command{grub-mkimage}. Therefore,
++Note that @command{grub2-install} is actually just a shell script and the
++real task is done by other tools such as @command{grub2-mkimage}. Therefore,
+ you may run those commands directly to install GRUB, without using
+-@command{grub-install}. Don't do that, however, unless you are very familiar
++@command{grub2-install}. Don't do that, however, unless you are very familiar
+ with the internals of GRUB. Installing a boot loader on a running OS may be
+ extremely dangerous.
+ 
+@@ -706,20 +706,20 @@ On EFI systems for fixed disk install you have to mount EFI System Partition.
+ If you mount it at @file{/boot/efi} then you don't need any special arguments:
+ 
+ @example
+-# @kbd{grub-install}
++# @kbd{grub2-install}
+ @end example
+ 
+ Otherwise you need to specify where your EFI System partition is mounted:
+ 
+ @example
+-# @kbd{grub-install --efi-directory=/mnt/efi}
++# @kbd{grub2-install --efi-directory=/mnt/efi}
+ @end example
+ 
+ For removable installs you have to use @option{--removable} and specify both
+ @option{--boot-directory} and @option{--efi-directory}:
+ 
+ @example
+-# @kbd{grub-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable}
++# @kbd{grub2-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable}
+ @end example
+ 
+ @node Making a GRUB bootable CD-ROM
+@@ -739,10 +739,10 @@ usually also need to include a configuration file @file{grub.cfg} and some
+ other GRUB modules.
+ 
+ To make a simple generic GRUB rescue CD, you can use the
+-@command{grub-mkrescue} program (@pxref{Invoking grub-mkrescue}):
++@command{grub2-mkrescue} program (@pxref{Invoking grub2-mkrescue}):
+ 
+ @example
+-$ @kbd{grub-mkrescue -o grub.iso}
++$ @kbd{grub2-mkrescue -o grub.iso}
+ @end example
+ 
+ You will often need to include other files in your image. To do this, first
+@@ -765,7 +765,7 @@ directory @file{iso/}.
+ Finally, make the image:
+ 
+ @example
+-$ @kbd{grub-mkrescue -o grub.iso iso}
++$ @kbd{grub2-mkrescue -o grub.iso iso}
+ @end example
+ 
+ This produces a file named @file{grub.iso}, which then can be burned
+@@ -781,7 +781,7 @@ storage devices.
+ @node Device map
+ @section The map between BIOS drives and OS devices
+ 
+-If the device map file exists, the GRUB utilities (@command{grub-probe},
++If the device map file exists, the GRUB utilities (@command{grub2-probe},
+ etc.) read it to map BIOS drives to OS devices.  This file consists of lines
+ like this:
+ 
+@@ -1225,23 +1225,23 @@ need to write the whole thing by hand.
+ @node Simple configuration
+ @section Simple configuration handling
+ 
+-The program @command{grub-mkconfig} (@pxref{Invoking grub-mkconfig})
++The program @command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig})
+ generates @file{grub.cfg} files suitable for most cases.  It is suitable for
+ use when upgrading a distribution, and will discover available kernels and
+ attempt to generate menu entries for them.
+ 
+-@command{grub-mkconfig} does have some limitations.  While adding extra
++@command{grub2-mkconfig} does have some limitations.  While adding extra
+ custom menu entries to the end of the list can be done by editing
+-@file{/etc/grub.d/40_custom} or creating @file{/boot/grub/custom.cfg},
++@file{/etc/grub.d/40_custom} or creating @file{/boot/grub2/custom.cfg},
+ changing the order of menu entries or changing their titles may require
+ making complex changes to shell scripts stored in @file{/etc/grub.d/}.  This
+ may be improved in the future.  In the meantime, those who feel that it
+ would be easier to write @file{grub.cfg} directly are encouraged to do so
+ (@pxref{Booting}, and @ref{Shell-like scripting}), and to disable any system
+-provided by their distribution to automatically run @command{grub-mkconfig}.
++provided by their distribution to automatically run @command{grub2-mkconfig}.
+ 
+ The file @file{/etc/default/grub} controls the operation of
+-@command{grub-mkconfig}.  It is sourced by a shell script, and so must be
++@command{grub2-mkconfig}.  It is sourced by a shell script, and so must be
+ valid POSIX shell input; normally, it will just be a sequence of
+ @samp{KEY=value} lines, but if the value contains spaces or other special
+ characters then it must be quoted.  For example:
+@@ -1279,7 +1279,7 @@ works it's not recommended since titles often contain unstable device names
+ and may be translated
+ 
+ If you set this to @samp{saved}, then the default menu entry will be that
+-saved by @samp{GRUB_SAVEDEFAULT} or @command{grub-set-default}.  This relies on
++saved by @samp{GRUB_SAVEDEFAULT} or @command{grub2-set-default}.  This relies on
+ the environment block, which may not be available in all situations
+ (@pxref{Environment block}).
+ 
+@@ -1290,7 +1290,7 @@ If this option is set to @samp{true}, then, when an entry is selected, save
+ it as a new default entry for use by future runs of GRUB.  This is only
+ useful if @samp{GRUB_DEFAULT=saved}; it is a separate option because
+ @samp{GRUB_DEFAULT=saved} is useful without this option, in conjunction with
+-@command{grub-set-default}.  Unset by default.
++@command{grub2-set-default}.  Unset by default.
+ This option relies on the environment block, which may not be available in
+ all situations (@pxref{Environment block}).
+ 
+@@ -1420,7 +1420,7 @@ intel-uc.img intel-ucode.img amd-uc.img amd-ucode.img early_ucode.cpio microcode
+ @end example
+ 
+ @item GRUB_DISABLE_LINUX_UUID
+-Normally, @command{grub-mkconfig} will generate menu entries that use
++Normally, @command{grub2-mkconfig} will generate menu entries that use
+ universally-unique identifiers (UUIDs) to identify the root filesystem to
+ the Linux kernel, using a @samp{root=UUID=...} kernel parameter.  This is
+ usually more reliable, but in some cases it may not be appropriate.  To
+@@ -1442,7 +1442,7 @@ If this option is set to @samp{true}, disable the generation of recovery
+ mode menu entries.
+ 
+ @item GRUB_DISABLE_UUID
+-Normally, @command{grub-mkconfig} will generate menu entries that use
++Normally, @command{grub2-mkconfig} will generate menu entries that use
+ universally-unique identifiers (UUIDs) to identify various filesystems to
+ search for files.  This is usually more reliable, but in some cases it may
+ not be appropriate.  To disable this use of UUIDs, set this option to
+@@ -1451,12 +1451,12 @@ not be appropriate.  To disable this use of UUIDs, set this option to
+ @item GRUB_VIDEO_BACKEND
+ If graphical video support is required, either because the @samp{gfxterm}
+ graphical terminal is in use or because @samp{GRUB_GFXPAYLOAD_LINUX} is set,
+-then @command{grub-mkconfig} will normally load all available GRUB video
++then @command{grub2-mkconfig} will normally load all available GRUB video
+ drivers and use the one most appropriate for your hardware.  If you need to
+ override this for some reason, then you can set this option.
+ 
+-After @command{grub-install} has been run, the available video drivers are
+-listed in @file{/boot/grub/video.lst}.
++After @command{grub2-install} has been run, the available video drivers are
++listed in @file{/boot/grub2/video.lst}.
+ 
+ @item GRUB_GFXMODE
+ Set the resolution used on the @samp{gfxterm} graphical terminal.  Note that
+@@ -1488,7 +1488,7 @@ boot sequence.  If you have problems, set this option to @samp{text} and
+ GRUB will tell Linux to boot in normal text mode.
+ 
+ @item GRUB_DISABLE_OS_PROBER
+-Normally, @command{grub-mkconfig} will try to use the external
++Normally, @command{grub2-mkconfig} will try to use the external
+ @command{os-prober} program, if installed, to discover other operating
+ systems installed on the same system and generate appropriate menu entries
+ for them.  Set this option to @samp{true} to disable this.
+@@ -1498,7 +1498,7 @@ List of space-separated FS UUIDs of filesystems to be ignored from os-prober
+ output. For efi chainloaders it's <UUID>@@<EFI FILE>
+ 
+ @item GRUB_DISABLE_SUBMENU
+-Normally, @command{grub-mkconfig} will generate top level menu entry for
++Normally, @command{grub2-mkconfig} will generate top level menu entry for
+ the kernel with highest version number and put all other found kernels
+ or alternative menu entries for recovery mode in submenu. For entries returned
+ by @command{os-prober} first entry will be put on top level and all others
+@@ -1506,11 +1506,11 @@ in submenu. If this option is set to @samp{y}, flat menu with all entries
+ on top level will be generated instead. Changing this option will require
+ changing existing values of @samp{GRUB_DEFAULT}, @samp{fallback} (@pxref{fallback})
+ and @samp{default} (@pxref{default}) environment variables as well as saved
+-default entry using @command{grub-set-default} and value used with
+-@command{grub-reboot}.
++default entry using @command{grub2-set-default} and value used with
++@command{grub2-reboot}.
+ 
+ @item GRUB_ENABLE_CRYPTODISK
+-If set to @samp{y}, @command{grub-mkconfig} and @command{grub-install} will
++If set to @samp{y}, @command{grub2-mkconfig} and @command{grub2-install} will
+ check for encrypted disks and generate additional commands needed to access
+ them during boot.  Note that in this case unattended boot is not possible
+ because GRUB will wait for passphrase to unlock encrypted container.
+@@ -1569,7 +1569,7 @@ confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or
+ 
+ @end table
+ 
+-For more detailed customisation of @command{grub-mkconfig}'s output, you may
++For more detailed customisation of @command{grub2-mkconfig}'s output, you may
+ edit the scripts in @file{/etc/grub.d} directly.
+ @file{/etc/grub.d/40_custom} is particularly useful for adding entire custom
+ menu entries; simply type the menu entries you want to add at the end of
+@@ -1831,7 +1831,7 @@ images as well.
+ Mount this partition on/mnt/boot and disable GRUB in all OSes and manually
+ install self-compiled latest GRUB with:
+ 
+-@code{grub-install --boot-directory=/mnt/boot /dev/sda}
++@code{grub2-install --boot-directory=/mnt/boot /dev/sda}
+ 
+ In all the OSes install GRUB tools but disable installing GRUB in bootsector,
+ so you'll have menu.lst and grub.cfg available for use. Also disable os-prober
+@@ -1841,20 +1841,20 @@ use by setting:
+ 
+ in /etc/default/grub
+ 
+-Then write a grub.cfg (/mnt/boot/grub/grub.cfg):
++Then write a grub.cfg (/mnt/boot/grub2/grub.cfg):
+ 
+ @example
+ 
+ menuentry "OS using grub2" @{
+    insmod xfs
+    search --set=root --label OS1 --hint hd0,msdos8
+-   configfile /boot/grub/grub.cfg
++   configfile /boot/grub2/grub.cfg
+ @}
+ 
+ menuentry "OS using grub2-legacy" @{
+    insmod ext2
+    search --set=root --label OS2 --hint hd0,msdos6
+-   legacy_configfile /boot/grub/menu.lst
++   legacy_configfile /boot/grub2/menu.lst
+ @}
+ 
+ menuentry "Windows XP" @{
+@@ -1917,15 +1917,15 @@ GRUB supports embedding a configuration file directly into the core image,
+ so that it is loaded before entering normal mode.  This is useful, for
+ example, when it is not straightforward to find the real configuration file,
+ or when you need to debug problems with loading that file.
+-@command{grub-install} uses this feature when it is not using BIOS disk
++@command{grub2-install} uses this feature when it is not using BIOS disk
+ functions or when installing to a different disk from the one containing
+ @file{/boot/grub}, in which case it needs to use the @command{search}
+ command (@pxref{search}) to find @file{/boot/grub}.
+ 
+ To embed a configuration file, use the @option{-c} option to
+-@command{grub-mkimage}.  The file is copied into the core image, so it may
++@command{grub2-mkimage}.  The file is copied into the core image, so it may
+ reside anywhere on the file system, and may be removed after running
+-@command{grub-mkimage}.
++@command{grub2-mkimage}.
+ 
+ After the embedded configuration file (if any) is executed, GRUB will load
+ the @samp{normal} module (@pxref{normal}), which will then read the real
+@@ -1960,13 +1960,13 @@ included in the core image:
+ @example
+ @group
+ search.fs_label grub root
+-if [ -e /boot/grub/example/test1.cfg ]; then
++if [ -e /boot/grub2/example/test1.cfg ]; then
+     set prefix=($root)/boot/grub
+-    configfile /boot/grub/example/test1.cfg
++    configfile /boot/grub2/example/test1.cfg
+ else
+-    if [ -e /boot/grub/example/test2.cfg ]; then
++    if [ -e /boot/grub2/example/test2.cfg ]; then
+         set prefix=($root)/boot/grub
+-        configfile /boot/grub/example/test2.cfg
++        configfile /boot/grub2/example/test2.cfg
+     else
+         echo "Could not find an example configuration file!"
+     fi
+@@ -2490,7 +2490,7 @@ grub-mknetdir --net-directory=/srv/tftp --subdir=/boot/grub -d /usr/lib/grub/i38
+ @end group
+ @end example
+ 
+-Then follow instructions printed out by grub-mknetdir on configuring your DHCP
++Then follow instructions printed out by grub2-mknetdir on configuring your DHCP
+ server.
+ 
+ The grub.cfg file is placed in the same directory as the path output by
+@@ -2675,7 +2675,7 @@ team are:
+ @end table
+ 
+ To take full advantage of this function, install GRUB into the MBR
+-(@pxref{Installing GRUB using grub-install}).
++(@pxref{Installing GRUB using grub2-install}).
+ 
+ If you have a laptop which has a similar feature and not in the above list
+ could you figure your address and contribute?
+@@ -2736,7 +2736,7 @@ bytes.
+ The sole function of @file{boot.img} is to read the first sector of the core
+ image from a local disk and jump to it.  Because of the size restriction,
+ @file{boot.img} cannot understand any file system structure, so
+-@command{grub-install} hardcodes the location of the first sector of the
++@command{grub2-install} hardcodes the location of the first sector of the
+ core image into @file{boot.img} when installing GRUB.
+ 
+ @item diskboot.img
+@@ -2766,7 +2766,7 @@ images.
+ 
+ @item core.img
+ This is the core image of GRUB.  It is built dynamically from the kernel
+-image and an arbitrary list of modules by the @command{grub-mkimage}
++image and an arbitrary list of modules by the @command{grub2-mkimage}
+ program.  Usually, it contains enough modules to access @file{/boot/grub},
+ and loads everything else (including menu handling, the ability to load
+ target operating systems, and so on) from the file system at run-time.  The
+@@ -2818,7 +2818,7 @@ GRUB 2 has no single Stage 2 image.  Instead, it loads modules from
+ In GRUB 2, images for booting from CD-ROM drives are now constructed using
+ @file{cdboot.img} and @file{core.img}, making sure that the core image
+ contains the @samp{iso9660} module.  It is usually best to use the
+-@command{grub-mkrescue} program for this.
++@command{grub2-mkrescue} program for this.
+ 
+ @item nbgrub
+ There is as yet no equivalent for @file{nbgrub} in GRUB 2; it was used by
+@@ -2974,8 +2974,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
+-example is @samp{(hd0,1)/boot/grub/grub.cfg}. This means the file
+-@file{/boot/grub/grub.cfg} in the first partition of the first hard
++example is @samp{(hd0,1)/boot/grub2/grub.cfg}. This means the file
++@file{/boot/grub2/grub.cfg} in the first partition of the first hard
+ 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,1)} by the command @samp{set root=(hd1,1)} (@pxref{set}),
+@@ -2983,8 +2983,8 @@ then @code{/boot/kernel} is the same as @code{(hd1,1)/boot/kernel}.
+ 
+ On ZFS filesystem the first path component must be
+ @var{volume}@samp{@@}[@var{snapshot}].
+-So @samp{/rootvol@@snap-129/boot/grub/grub.cfg} refers to file
+-@samp{/boot/grub/grub.cfg} in snapshot of volume @samp{rootvol} with name
++So @samp{/rootvol@@snap-129/boot/grub2/grub.cfg} refers to file
++@samp{/boot/grub2/grub.cfg} in snapshot of volume @samp{rootvol} with name
+ @samp{snap-129}.  Trailing @samp{@@} after volume name is mandatory even if
+ snapshot name is omitted.
+ 
+@@ -3387,7 +3387,7 @@ The more recent release of Minix would then be identified as
+ @samp{other>minix>minix-3.4.0}.
+ 
+ This variable is often set by @samp{GRUB_DEFAULT} (@pxref{Simple
+-configuration}), @command{grub-set-default}, or @command{grub-reboot}.
++configuration}), @command{grub2-set-default}, or @command{grub2-reboot}.
+ 
+ 
+ @node fallback
+@@ -3477,7 +3477,7 @@ If this variable is set, it names the language code that the
+ example, French would be named as @samp{fr}, and Simplified Chinese as
+ @samp{zh_CN}.
+ 
+-@command{grub-mkconfig} (@pxref{Simple configuration}) will try to set a
++@command{grub2-mkconfig} (@pxref{Simple configuration}) will try to set a
+ reasonable default for this variable based on the system locale.
+ 
+ 
+@@ -3485,10 +3485,10 @@ reasonable default for this variable based on the system locale.
+ @subsection locale_dir
+ 
+ If this variable is set, it names the directory where translation files may
+-be found (@pxref{gettext}), usually @file{/boot/grub/locale}.  Otherwise,
++be found (@pxref{gettext}), usually @file{/boot/grub2/locale}.  Otherwise,
+ internationalization is disabled.
+ 
+-@command{grub-mkconfig} (@pxref{Simple configuration}) will set a reasonable
++@command{grub2-mkconfig} (@pxref{Simple configuration}) will set a reasonable
+ default for this variable if internationalization is needed and any
+ translation files are available.
+ 
+@@ -3606,7 +3606,7 @@ input.  The default is not to pause output.
+ 
+ The location of the @samp{/boot/grub} directory as an absolute file name
+ (@pxref{File name syntax}).  This is normally set by GRUB at startup based
+-on information provided by @command{grub-install}.  GRUB modules are
++on information provided by @command{grub2-install}.  GRUB modules are
+ dynamically loaded from this directory, so it must be set correctly in order
+ for many parts of GRUB to work.
+ 
+@@ -3697,17 +3697,17 @@ GRUB provides an ``environment block'' which can be used to save a small
+ amount of state.
+ 
+ The environment block is a preallocated 1024-byte file, which normally lives
+-in @file{/boot/grub/grubenv} (although you should not assume this).  At boot
++in @file{/boot/grub2/grubenv} (although you should not assume this).  At boot
+ time, the @command{load_env} command (@pxref{load_env}) loads environment
+ variables from it, and the @command{save_env} (@pxref{save_env}) command
+ saves environment variables to it.  From a running system, the
+-@command{grub-editenv} utility can be used to edit the environment block.
++@command{grub2-editenv} utility can be used to edit the environment block.
+ 
+ For safety reasons, this storage is only available when installed on a plain
+ disk (no LVM or RAID), using a non-checksumming filesystem (no ZFS), and
+ using BIOS or EFI functions (no ATA, USB or IEEE1275).
+ 
+-@command{grub-mkconfig} uses this facility to implement
++@command{grub2-mkconfig} uses this facility to implement
+ @samp{GRUB_SAVEDEFAULT} (@pxref{Simple configuration}).
+ 
+ 
+@@ -4396,7 +4396,7 @@ Translate @var{string} into the current language.
+ 
+ The current language code is stored in the @samp{lang} variable in GRUB's
+ environment (@pxref{lang}).  Translation files in MO format are read from
+-@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub/locale}.
++@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub2/locale}.
+ @end deffn
+ 
+ 
+@@ -4791,7 +4791,7 @@ Define a user named @var{user} with password @var{clear-password}.
+ 
+ @deffn Command password_pbkdf2 user hashed-password
+ Define a user named @var{user} with password hash @var{hashed-password}.
+-Use @command{grub-mkpasswd-pbkdf2} (@pxref{Invoking grub-mkpasswd-pbkdf2})
++Use @command{grub2-mkpasswd-pbkdf2} (@pxref{Invoking grub2-mkpasswd-pbkdf2})
+ to generate password hashes.  @xref{Security}.
+ @end deffn
+ 
+@@ -5614,8 +5614,8 @@ The @samp{password} (@pxref{password}) and @samp{password_pbkdf2}
+ which has an associated password.  @samp{password} sets the password in
+ plain text, requiring @file{grub.cfg} to be secure; @samp{password_pbkdf2}
+ sets the password hashed using the Password-Based Key Derivation Function
+-(RFC 2898), requiring the use of @command{grub-mkpasswd-pbkdf2}
+-(@pxref{Invoking grub-mkpasswd-pbkdf2}) to generate password hashes.
++(RFC 2898), requiring the use of @command{grub2-mkpasswd-pbkdf2}
++(@pxref{Invoking grub2-mkpasswd-pbkdf2}) to generate password hashes.
+ 
+ In order to enable authentication support, the @samp{superusers} environment
+ variable must be set to a list of usernames, separated by any of spaces,
+@@ -5659,7 +5659,7 @@ menuentry "May be run by user1 or a superuser" --users user1 @{
+ @end group
+ @end example
+ 
+-The @command{grub-mkconfig} program does not yet have built-in support for
++The @command{grub2-mkconfig} program does not yet have built-in support for
+ generating configuration files with authentication.  You can use
+ @file{/etc/grub.d/40_custom} to add simple superuser authentication, by
+ adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2}
+@@ -5684,15 +5684,15 @@ verified with a public key currently trusted by GRUB
+ validation fails, then file @file{foo} cannot be opened.  This failure
+ may halt or otherwise impact the boot process.
+ 
+-@comment Unfortunately --pubkey is not yet supported by grub-install,
+-@comment but we should not bring up internal detail grub-mkimage here
++@comment Unfortunately --pubkey is not yet supported by grub2-install,
++@comment but we should not bring up internal detail grub2-mkimage here
+ @comment in the user guide (as opposed to developer's manual).
+ 
+ @comment An initial trusted public key can be embedded within the GRUB
+ @comment @file{core.img} using the @code{--pubkey} option to
+-@comment @command{grub-mkimage} (@pxref{Invoking grub-install}).  Presently it
+-@comment is necessary to write a custom wrapper around @command{grub-mkimage}
+-@comment using the @code{--grub-mkimage} flag to @command{grub-install}.
++@comment @command{grub2-mkimage} (@pxref{Invoking grub2-install}).  Presently it
++@comment is necessary to write a custom wrapper around @command{grub2-mkimage}
++@comment using the @code{--grub-mkimage} flag to @command{grub2-install}.
+ 
+ GRUB uses GPG-style detached signatures (meaning that a file
+ @file{foo.sig} will be produced when file @file{foo} is signed), and
+@@ -5712,8 +5712,8 @@ gpg --detach-sign /path/to/file
+ For successful validation of all of GRUB's subcomponents and the
+ loaded OS kernel, they must all be signed.  One way to accomplish this
+ is the following (after having already produced the desired
+-@file{grub.cfg} file, e.g., by running @command{grub-mkconfig}
+-(@pxref{Invoking grub-mkconfig}):
++@file{grub.cfg} file, e.g., by running @command{grub2-mkconfig}
++(@pxref{Invoking grub2-mkconfig}):
+ 
+ @example
+ @group
+@@ -5735,7 +5735,7 @@ See also: @ref{check_signatures}, @ref{verify_detached}, @ref{trust},
+ Note that internally signature enforcement is controlled by setting
+ the environment variable @code{check_signatures} equal to
+ @code{enforce}.  Passing one or more @code{--pubkey} options to
+-@command{grub-mkimage} implicitly defines @code{check_signatures}
++@command{grub2-mkimage} implicitly defines @code{check_signatures}
+ equal to @code{enforce} in @file{core.img} prior to processing any
+ configuration files.
+ 
+@@ -6092,10 +6092,10 @@ Required files are:
+ 
+ GRUB's normal start-up procedure involves setting the @samp{prefix}
+ environment variable to a value set in the core image by
+-@command{grub-install}, setting the @samp{root} variable to match, loading
++@command{grub2-install}, setting the @samp{root} variable to match, loading
+ the @samp{normal} module from the prefix, and running the @samp{normal}
+ command (@pxref{normal}).  This command is responsible for reading
+-@file{/boot/grub/grub.cfg}, running the menu, and doing all the useful
++@file{/boot/grub2/grub.cfg}, running the menu, and doing all the useful
+ things GRUB is supposed to do.
+ 
+ If, instead, you only get a rescue shell, this usually means that GRUB
+@@ -6121,8 +6121,8 @@ normal
+ 
+ However, any problem that leaves you in the rescue shell probably means that
+ GRUB was not correctly installed.  It may be more useful to try to reinstall
+-it properly using @kbd{grub-install @var{device}} (@pxref{Invoking
+-grub-install}).  When doing this, there are a few things to remember:
++it properly using @kbd{grub2-install @var{device}} (@pxref{Invoking
++grub2-install}).  When doing this, there are a few things to remember:
+ 
+ @itemize @bullet{}
+ @item
+@@ -6134,7 +6134,7 @@ is usually better to use UUIDs or file system labels and avoid depending on
+ drive ordering entirely.
+ 
+ @item
+-At least on BIOS systems, if you tell @command{grub-install} to install GRUB
++At least on BIOS systems, if you tell @command{grub2-install} to install GRUB
+ to a partition but GRUB has already been installed in the master boot
+ record, then the GRUB installation in the partition will be ignored.
+ 
+@@ -6154,21 +6154,21 @@ support has not yet been added to GRUB.
+ @end itemize
+ 
+ 
+-@node Invoking grub-install
+-@chapter Invoking grub-install
++@node Invoking grub2-install
++@chapter Invoking grub2-install
+ 
+-The program @command{grub-install} generates a GRUB core image using
+-@command{grub-mkimage} and installs it on your system.  You must specify the
++The program @command{grub2-install} generates a GRUB core image using
++@command{grub2-mkimage} and installs it on your system.  You must specify the
+ device name on which you want to install GRUB, like this:
+ 
+ @example
+-grub-install @var{install_device}
++grub2-install @var{install_device}
+ @end example
+ 
+ The device name @var{install_device} is an OS device name or a GRUB
+ device name.
+ 
+-@command{grub-install} accepts the following options:
++@command{grub2-install} accepts the following options:
+ 
+ @table @option
+ @item --help
+@@ -6184,13 +6184,13 @@ separate partition or a removable disk.
+ If this option is not specified then it defaults to @file{/boot}, so
+ 
+ @example
+-@kbd{grub-install /dev/sda}
++@kbd{grub2-install /dev/sda}
+ @end example
+ 
+ is equivalent to
+ 
+ @example
+-@kbd{grub-install --boot-directory=/boot/ /dev/sda}
++@kbd{grub2-install --boot-directory=/boot/ /dev/sda}
+ @end example
+ 
+ Here is an example in which you have a separate @dfn{boot} partition which is 
+@@ -6198,16 +6198,16 @@ mounted on
+ @file{/mnt/boot}:
+ 
+ @example
+-@kbd{grub-install --boot-directory=/mnt/boot /dev/sdb}
++@kbd{grub2-install --boot-directory=/mnt/boot /dev/sdb}
+ @end example
+ 
+ @item --recheck
+-Recheck the device map, even if @file{/boot/grub/device.map} already
++Recheck the device map, even if @file{/boot/grub2/device.map} already
+ exists. You should use this option whenever you add/remove a disk
+ into/from your computer.
+ 
+ @item --no-rs-codes
+-By default on x86 BIOS systems, @command{grub-install} will use some
++By default on x86 BIOS systems, @command{grub2-install} will use some
+ extra space in the bootloader embedding area for Reed-Solomon
+ error-correcting codes. This enables GRUB to still boot successfully
+ if some blocks are corrupted.  The exact amount of protection offered
+@@ -6220,17 +6220,17 @@ installation}) where GRUB does not reside in any unpartitioned space
+ outside of the MBR.  Disable the Reed-Solomon codes with this option.
+ @end table
+ 
+-@node Invoking grub-mkconfig
+-@chapter Invoking grub-mkconfig
++@node Invoking grub2-mkconfig
++@chapter Invoking grub2-mkconfig
+ 
+-The program @command{grub-mkconfig} generates a configuration file for GRUB
++The program @command{grub2-mkconfig} generates a configuration file for GRUB
+ (@pxref{Simple configuration}).
+ 
+ @example
+-grub-mkconfig -o /boot/grub/grub.cfg
++grub-mkconfig -o /boot/grub2/grub.cfg
+ @end example
+ 
+-@command{grub-mkconfig} accepts the following options:
++@command{grub2-mkconfig} accepts the following options:
+ 
+ @table @option
+ @item --help
+@@ -6246,17 +6246,17 @@ it to standard output.
+ @end table
+ 
+ 
+-@node Invoking grub-mkpasswd-pbkdf2
+-@chapter Invoking grub-mkpasswd-pbkdf2
++@node Invoking grub2-mkpasswd-pbkdf2
++@chapter Invoking grub2-mkpasswd-pbkdf2
+ 
+-The program @command{grub-mkpasswd-pbkdf2} generates password hashes for
++The program @command{grub2-mkpasswd-pbkdf2} generates password hashes for
+ GRUB (@pxref{Security}).
+ 
+ @example
+ grub-mkpasswd-pbkdf2
+ @end example
+ 
+-@command{grub-mkpasswd-pbkdf2} accepts the following options:
++@command{grub2-mkpasswd-pbkdf2} accepts the following options:
+ 
+ @table @option
+ @item -c @var{number}
+@@ -6274,23 +6274,23 @@ Length of the salt.  Defaults to 64.
+ @end table
+ 
+ 
+-@node Invoking grub-mkrelpath
+-@chapter Invoking grub-mkrelpath
++@node Invoking grub2-mkrelpath
++@chapter Invoking grub2-mkrelpath
+ 
+-The program @command{grub-mkrelpath} makes a file system path relative to
++The program @command{grub2-mkrelpath} makes a file system path relative to
+ the root of its containing file system.  For instance, if @file{/usr} is a
+ mount point, then:
+ 
+ @example
+-$ @kbd{grub-mkrelpath /usr/share/grub/unicode.pf2}
++$ @kbd{grub2-mkrelpath /usr/share/grub/unicode.pf2}
+ @samp{/share/grub/unicode.pf2}
+ @end example
+ 
+ This is mainly used internally by other GRUB utilities such as
+-@command{grub-mkconfig} (@pxref{Invoking grub-mkconfig}), but may
++@command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig}), but may
+ occasionally also be useful for debugging.
+ 
+-@command{grub-mkrelpath} accepts the following options:
++@command{grub2-mkrelpath} accepts the following options:
+ 
+ @table @option
+ @item --help
+@@ -6301,17 +6301,17 @@ Print the version number of GRUB and exit.
+ @end table
+ 
+ 
+-@node Invoking grub-mkrescue
+-@chapter Invoking grub-mkrescue
++@node Invoking grub2-mkrescue
++@chapter Invoking grub2-mkrescue
+ 
+-The program @command{grub-mkrescue} generates a bootable GRUB rescue image
++The program @command{grub2-mkrescue} generates a bootable GRUB rescue image
+ (@pxref{Making a GRUB bootable CD-ROM}).
+ 
+ @example
+ grub-mkrescue -o grub.iso
+ @end example
+ 
+-All arguments not explicitly listed as @command{grub-mkrescue} options are
++All arguments not explicitly listed as @command{grub2-mkrescue} options are
+ passed on directly to @command{xorriso} in @command{mkisofs} emulation mode.
+ Options passed to @command{xorriso} will normally be interpreted as
+ @command{mkisofs} options; if the option @samp{--} is used, then anything
+@@ -6326,7 +6326,7 @@ mkdir -p disk/boot/grub
+ grub-mkrescue -o grub.iso disk
+ @end example
+ 
+-@command{grub-mkrescue} accepts the following options:
++@command{grub2-mkrescue} accepts the following options:
+ 
+ @table @option
+ @item --help
+@@ -6354,15 +6354,15 @@ Use @var{file} as the @command{xorriso} program, rather than the built-in
+ default.
+ 
+ @item --grub-mkimage=@var{file}
+-Use @var{file} as the @command{grub-mkimage} program, rather than the
++Use @var{file} as the @command{grub2-mkimage} program, rather than the
+ built-in default.
+ @end table
+ 
+ 
+-@node Invoking grub-mount
+-@chapter Invoking grub-mount
++@node Invoking grub2-mount
++@chapter Invoking grub2-mount
+ 
+-The program @command{grub-mount} performs a read-only mount of any file
++The program @command{grub2-mount} performs a read-only mount of any file
+ system or file system image that GRUB understands, using GRUB's file system
+ drivers via FUSE.  (It is only available if FUSE development files were
+ present when GRUB was built.)  This has a number of uses:
+@@ -6394,13 +6394,13 @@ even if nobody has yet written a FUSE module specifically for that file
+ system type.
+ @end itemize
+ 
+-Using @command{grub-mount} is normally as simple as:
++Using @command{grub2-mount} is normally as simple as:
+ 
+ @example
+ grub-mount /dev/sda1 /mnt
+ @end example
+ 
+-@command{grub-mount} must be given one or more images and a mount point as
++@command{grub2-mount} must be given one or more images and a mount point as
+ non-option arguments (if it is given more than one image, it will treat them
+ as a RAID set), and also accepts the following options:
+ 
+@@ -6422,13 +6422,13 @@ Show debugging output for conditions matching @var{string}.
+ @item -K prompt|@var{file}
+ @itemx --zfs-key=prompt|@var{file}
+ Load a ZFS encryption key.  If you use @samp{prompt} as the argument,
+-@command{grub-mount} will read a passphrase from the terminal; otherwise, it
++@command{grub2-mount} will read a passphrase from the terminal; otherwise, it
+ will read key material from the specified file.
+ 
+ @item -r @var{device}
+ @itemx --root=@var{device}
+ Set the GRUB root device to @var{device}.  You do not normally need to set
+-this; @command{grub-mount} will automatically set the root device to the
++this; @command{grub2-mount} will automatically set the root device to the
+ root of the supplied file system.
+ 
+ If @var{device} is just a number, then it will be treated as a partition
+@@ -6446,10 +6446,10 @@ Print verbose messages.
+ @end table
+ 
+ 
+-@node Invoking grub-probe
+-@chapter Invoking grub-probe
++@node Invoking grub2-probe
++@chapter Invoking grub2-probe
+ 
+-The program @command{grub-probe} probes device information for a given path
++The program @command{grub2-probe} probes device information for a given path
+ or device.
+ 
+ @example
+@@ -6457,7 +6457,7 @@ grub-probe --target=fs /boot/grub
+ grub-probe --target=drive --device /dev/sda1
+ @end example
+ 
+-@command{grub-probe} must be given a path or device as a non-option
++@command{grub2-probe} must be given a path or device as a non-option
+ argument, and also accepts the following options:
+ 
+ @table @option
+@@ -6470,16 +6470,16 @@ Print the version number of GRUB and exit.
+ @item -d
+ @itemx --device
+ If this option is given, then the non-option argument is a system device
+-name (such as @samp{/dev/sda1}), and @command{grub-probe} will print
++name (such as @samp{/dev/sda1}), and @command{grub2-probe} will print
+ information about that device.  If it is not given, then the non-option
+ argument is a filesystem path (such as @samp{/boot/grub}), and
+-@command{grub-probe} will print information about the device containing that
++@command{grub2-probe} will print information about the device containing that
+ part of the filesystem.
+ 
+ @item -m @var{file}
+ @itemx --device-map=@var{file}
+ Use @var{file} as the device map (@pxref{Device map}) rather than the
+-default, usually @samp{/boot/grub/device.map}.
++default, usually @samp{/boot/grub2/device.map}.
+ 
+ @item -t @var{target}
+ @itemx --target=@var{target}
+@@ -6532,19 +6532,19 @@ Print verbose messages.
+ @end table
+ 
+ 
+-@node Invoking grub-script-check
+-@chapter Invoking grub-script-check
++@node Invoking grub2-script-check
++@chapter Invoking grub2-script-check
+ 
+-The program @command{grub-script-check} takes a GRUB script file
++The program @command{grub2-script-check} takes a GRUB script file
+ (@pxref{Shell-like scripting}) and checks it for syntax errors, similar to
+ commands such as @command{sh -n}.  It may take a @var{path} as a non-option
+ argument; if none is supplied, it will read from standard input.
+ 
+ @example
+-grub-script-check /boot/grub/grub.cfg
++grub-script-check /boot/grub2/grub.cfg
+ @end example
+ 
+-@command{grub-script-check} accepts the following options:
++@command{grub2-script-check} accepts the following options:
+ 
+ @table @option
+ @item --help
diff --git a/SOURCES/0086-print-more-debug-info-in-our-module-loader.patch b/SOURCES/0086-print-more-debug-info-in-our-module-loader.patch
new file mode 100644
index 0000000..bf2c42f
--- /dev/null
+++ b/SOURCES/0086-print-more-debug-info-in-our-module-loader.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 1 May 2017 11:19:40 -0400
+Subject: [PATCH] print more debug info in our module loader.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/efi/efi.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index e339f264b3a..562d6887e0e 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -313,13 +313,23 @@ grub_efi_modules_addr (void)
+     }
+ 
+   if (i == coff_header->num_sections)
+-    return 0;
++    {
++      grub_dprintf("sections", "section %d is last section; invalid.\n", i);
++      return 0;
++    }
+ 
+   info = (struct grub_module_info *) ((char *) image->image_base
+ 				      + section->virtual_address);
+-  if (info->magic != GRUB_MODULE_MAGIC)
+-    return 0;
++  if (section->name[0] != '.' && info->magic != GRUB_MODULE_MAGIC)
++    {
++      grub_dprintf("sections",
++		   "section %d has bad magic %08x, should be %08x\n",
++		   i, info->magic, GRUB_MODULE_MAGIC);
++      return 0;
++    }
+ 
++  grub_dprintf("sections", "returning section info for section %d: \"%s\"\n",
++	       i, section->name);
+   return (grub_addr_t) info;
+ }
+ 
diff --git a/SOURCES/0087-macos-just-build-chainloader-entries-don-t-try-any-x.patch b/SOURCES/0087-macos-just-build-chainloader-entries-don-t-try-any-x.patch
new file mode 100644
index 0000000..3a761c0
--- /dev/null
+++ b/SOURCES/0087-macos-just-build-chainloader-entries-don-t-try-any-x.patch
@@ -0,0 +1,124 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 24 May 2017 12:42:32 -0400
+Subject: [PATCH] macos: just build chainloader entries, don't try any xnu xnu.
+
+Since our bugs tell us that the xnu boot entries really just don't work
+most of the time, and they create piles of extra boot entries, because
+they can't quite figure out 32-vs-64 and other stuff like that.
+
+It's rediculous, and we should just boot their bootloader through the
+chainloader instead.
+
+So this patch does that.
+
+Resolves: rhbz#893179
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/30_os-prober.in | 78 +++++++++++----------------------------------
+ 1 file changed, 18 insertions(+), 60 deletions(-)
+
+diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
+index 9b8f5968e2d..13a3a6bc752 100644
+--- a/util/grub.d/30_os-prober.in
++++ b/util/grub.d/30_os-prober.in
+@@ -42,68 +42,25 @@ if [ -z "${OSPROBED}" ] ; then
+ fi
+ 
+ osx_entry() {
+-    if [ x$2 = x32 ]; then
+-        # TRANSLATORS: it refers to kernel architecture (32-bit)
+-	bitstr="$(gettext "(32-bit)")"
+-    else
+-        # TRANSLATORS: it refers to kernel architecture (64-bit)
+-	bitstr="$(gettext "(64-bit)")"
+-    fi
+     # TRANSLATORS: it refers on the OS residing on device %s
+     onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+-        cat << EOF
+-menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")'  {
++    hints=""
++    for hint in `"${grub_probe}" --device ${device} --target=efi_hints 2> /dev/null` ; do
++      hints="${hints} --hint=${hint}"
++    done
++    cat << EOF
++menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")'  {
+ EOF
+ 	save_default_entry | grub_add_tab
+ 	prepare_grub_to_access_device ${DEVICE} | grub_add_tab
+ 	cat << EOF
++	set gfxpayload=keep
+         load_video
+-        set do_resume=0
+-        if [ /var/vm/sleepimage -nt10 / ]; then
+-           if xnu_resume /var/vm/sleepimage; then
+-             set do_resume=1
+-           fi
+-        fi
+-        if [ \$do_resume = 0 ]; then
+-           xnu_uuid ${OSXUUID} uuid
+-           if [ -f /Extra/DSDT.aml ]; then
+-              acpi -e /Extra/DSDT.aml
+-           fi
+-           if [ /kernelcache -nt /System/Library/Extensions ]; then
+-              $1 /kernelcache boot-uuid=\${uuid} rd=*uuid
+-           elif [ -f /System/Library/Kernels/kernel ]; then
+-              $1 /System/Library/Kernels/kernel boot-uuid=\${uuid} rd=*uuid
+-              xnu_kextdir /System/Library/Extensions
+-           else
+-              $1 /mach_kernel boot-uuid=\${uuid} rd=*uuid
+-              if [ /System/Library/Extensions.mkext -nt /System/Library/Extensions ]; then
+-                xnu_mkext /System/Library/Extensions.mkext
+-              else
+-                xnu_kextdir /System/Library/Extensions
+-              fi
+-           fi
+-           if [ -f /Extra/Extensions.mkext ]; then
+-              xnu_mkext /Extra/Extensions.mkext
+-           fi
+-           if [ -d /Extra/Extensions ]; then
+-              xnu_kextdir /Extra/Extensions
+-           fi
+-           if [ -f /Extra/devprop.bin ]; then
+-              xnu_devprop_load /Extra/devprop.bin
+-           fi
+-           if [ -f /Extra/splash.jpg ]; then
+-              insmod jpeg
+-              xnu_splash /Extra/splash.jpg
+-           fi
+-           if [ -f /Extra/splash.png ]; then
+-              insmod png
+-              xnu_splash /Extra/splash.png
+-           fi
+-           if [ -f /Extra/splash.tga ]; then
+-              insmod tga
+-              xnu_splash /Extra/splash.tga
+-           fi
+-        fi
++	insmod part_gpt
++	insmod hfsplus
++	search --no-floppy --fs-uuid --set=root ${hints} $(grub_get_device_id "${DEVICE}")
++	chainloader (\$root)/System/Library/CoreServices/boot.efi
++	boot
+ }
+ EOF
+ }
+@@ -284,11 +241,12 @@ EOF
+       echo "$title_correction_code"
+     ;;
+     macosx)
+-      if [ "${UUID}" ]; then
+-	OSXUUID="${UUID}"
+-	osx_entry xnu_kernel 32
+-	osx_entry xnu_kernel64 64
+-      fi
++      for subdevice in ${DEVICE%[[:digit:]]*}* ; do
++	parttype="`"${grub_probe}" --device ${device} --target=gpt_parttype "${subdevice}" 2> /dev/null`"
++	if [[ "$parttype" = "426f6f74-0000-11aa-aa11-00306543ecac" ]]; then
++	  DEVICE="${subdevice}" osx_entry
++	fi
++      done
+     ;;
+     hurd)
+       onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
diff --git a/SOURCES/0088-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch b/SOURCES/0088-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch
new file mode 100644
index 0000000..eafb894
--- /dev/null
+++ b/SOURCES/0088-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch
@@ -0,0 +1,703 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jeff Mahoney <jeffm@suse.com>
+Date: Wed, 18 Dec 2013 09:57:04 +0000
+Subject: [PATCH] grub2/btrfs: Add ability to boot from subvolumes
+
+This patch adds the ability to specify a different root on a btrfs
+filesystem too boot from other than the default one.
+
+btrfs-list-snapshots <dev> will list the subvolumes available on the
+filesystem.
+
+set btrfs_subvol=<path> and set btrfs_subvolid=<subvolid> will specify
+which subvolume to use and any pathnames provided with either of those
+variables set will start using that root. If the subvolume or subvolume id
+doesn't exist, then an error case will result.
+
+It is possible to boot into a separate GRUB instance by exporting the
+variable and loading the config file from the subvolume.
+
+Signed-off-by: Jeff Mahoney <jeffm@suse.com>
+---
+ grub-core/fs/btrfs.c | 552 +++++++++++++++++++++++++++++++++++++++++++++++++--
+ include/grub/btrfs.h |   1 +
+ 2 files changed, 533 insertions(+), 20 deletions(-)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index be195448dbe..51ed63d429b 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -29,6 +29,9 @@
+ #include <minilzo.h>
+ #include <grub/i18n.h>
+ #include <grub/btrfs.h>
++#include <grub/command.h>
++#include <grub/env.h>
++#include <grub/extcmd.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -64,9 +67,11 @@ struct grub_btrfs_superblock
+   grub_uint64_t generation;
+   grub_uint64_t root_tree;
+   grub_uint64_t chunk_tree;
+-  grub_uint8_t dummy2[0x20];
++  grub_uint8_t dummy2[0x18];
++  grub_uint64_t bytes_used;
+   grub_uint64_t root_dir_objectid;
+-  grub_uint8_t dummy3[0x41];
++  grub_uint64_t num_devices;
++  grub_uint8_t dummy3[0x39];
+   struct grub_btrfs_device this_device;
+   char label[0x100];
+   grub_uint8_t dummy4[0x100];
+@@ -105,6 +110,7 @@ struct grub_btrfs_data
+   grub_uint64_t exttree;
+   grub_size_t extsize;
+   struct grub_btrfs_extent_data *extent;
++  grub_uint64_t fs_tree;
+ };
+ 
+ struct grub_btrfs_chunk_item
+@@ -171,6 +177,14 @@ struct grub_btrfs_leaf_descriptor
+   } *data;
+ };
+ 
++struct grub_btrfs_root_ref
++{
++  grub_uint64_t dirid;
++  grub_uint64_t sequence;
++  grub_uint16_t name_len;
++  const char name[0];
++} __attribute__ ((packed));
++
+ struct grub_btrfs_time
+ {
+   grub_int64_t sec;
+@@ -215,6 +229,14 @@ struct grub_btrfs_extent_data
+ 
+ #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
+ 
++#define GRUB_BTRFS_ROOT_TREE_OBJECTID 1ULL
++#define GRUB_BTRFS_FS_TREE_OBJECTID 5ULL
++#define GRUB_BTRFS_ROOT_REF_KEY     156
++#define GRUB_BTRFS_ROOT_ITEM_KEY     132
++
++static grub_uint64_t btrfs_default_subvolid = 0;
++static char *btrfs_default_subvol = NULL;
++
+ static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2,
+   256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2
+ };
+@@ -837,6 +859,62 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr,
+   return GRUB_ERR_NONE;
+ }
+ 
++static grub_err_t
++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
++            grub_uint64_t objectid, grub_uint64_t offset,
++            grub_uint64_t *fs_root);
++
++static grub_err_t
++lookup_root_by_id(struct grub_btrfs_data *data, grub_uint64_t id)
++{
++  grub_err_t err;
++  grub_uint64_t tree;
++
++  err = get_fs_root(data, data->sblock.root_tree, id, -1, &tree);
++  if (!err)
++    data->fs_tree = tree;
++  return err;
++}
++
++static grub_err_t
++find_path (struct grub_btrfs_data *data,
++	   const char *path, struct grub_btrfs_key *key,
++	   grub_uint64_t *tree, grub_uint8_t *type);
++
++static grub_err_t
++lookup_root_by_name(struct grub_btrfs_data *data, const char *path)
++{
++  grub_err_t err;
++  grub_uint64_t tree = 0;
++  grub_uint8_t type;
++  struct grub_btrfs_key key;
++
++  err = find_path (data, path, &key, &tree, &type);
++  if (err)
++      return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path);
++
++  if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0)
++    return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path);
++
++  data->fs_tree = tree;
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused)))
++{
++  if (btrfs_default_subvol)
++    return lookup_root_by_name(data, btrfs_default_subvol);
++
++  if (btrfs_default_subvolid)
++    return lookup_root_by_id(data, btrfs_default_subvolid);
++
++  data->fs_tree = 0;
++
++  return GRUB_ERR_NONE;
++}
++
++
+ static struct grub_btrfs_data *
+ grub_btrfs_mount (grub_device_t dev)
+ {
+@@ -872,6 +950,13 @@ grub_btrfs_mount (grub_device_t dev)
+   data->devices_attached[0].dev = dev;
+   data->devices_attached[0].id = data->sblock.this_device.device_id;
+ 
++  err = btrfs_handle_subvol (data);
++  if (err)
++    {
++      grub_free (data);
++      return NULL;
++    }
++
+   return data;
+ }
+ 
+@@ -1232,6 +1317,91 @@ get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key,
+   return GRUB_ERR_NONE;
+ }
+ 
++static grub_err_t
++find_pathname(struct grub_btrfs_data *data, grub_uint64_t objectid,
++              grub_uint64_t fs_root, const char *name, char **pathname)
++{
++  grub_err_t err;
++  struct grub_btrfs_key key = {
++    .object_id = objectid,
++    .type = GRUB_BTRFS_ITEM_TYPE_INODE_REF,
++    .offset = 0,
++  };
++  struct grub_btrfs_key key_out;
++  struct grub_btrfs_leaf_descriptor desc;
++  char *p = grub_strdup (name);
++  grub_disk_addr_t elemaddr;
++  grub_size_t elemsize;
++  grub_size_t alloc = grub_strlen(name) + 1;
++
++  err = lower_bound(data, &key, &key_out, fs_root,
++                    &elemaddr, &elemsize, &desc, 0);
++  if (err)
++    return grub_error(err, "lower_bound caught %d\n", err);
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
++    next(data, &desc, &elemaddr, &elemsize, &key_out);
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
++    {
++      return grub_error(GRUB_ERR_FILE_NOT_FOUND,
++                        "Can't find inode ref for {%"PRIuGRUB_UINT64_T
++                        ", %u, %"PRIuGRUB_UINT64_T"} %"PRIuGRUB_UINT64_T
++                        "/%"PRIuGRUB_SIZE"\n",
++                        key_out.object_id, key_out.type,
++                        key_out.offset, elemaddr, elemsize);
++    }
++
++
++  while (key_out.type == GRUB_BTRFS_ITEM_TYPE_INODE_REF &&
++         key_out.object_id != key_out.offset) {
++    struct grub_btrfs_inode_ref *inode_ref;
++    char *new;
++
++    inode_ref = grub_malloc(elemsize + 1);
++    if (!inode_ref)
++      return grub_error(GRUB_ERR_OUT_OF_MEMORY,
++                        "couldn't allocate memory for inode_ref (%"PRIuGRUB_SIZE")\n", elemsize);
++
++    err = grub_btrfs_read_logical(data, elemaddr, inode_ref, elemsize, 0);
++    if (err)
++      return grub_error(err, "read_logical caught %d\n", err);
++
++    alloc += grub_le_to_cpu16 (inode_ref->n) + 2;
++    new = grub_malloc(alloc);
++    if (!new)
++      return grub_error(GRUB_ERR_OUT_OF_MEMORY,
++                        "couldn't allocate memory for name (%"PRIuGRUB_SIZE")\n", alloc);
++
++    grub_memcpy(new, inode_ref->name, grub_le_to_cpu16 (inode_ref->n));
++    if (p)
++      {
++        new[grub_le_to_cpu16 (inode_ref->n)] = '/';
++        grub_strcpy (new + grub_le_to_cpu16 (inode_ref->n) + 1, p);
++        grub_free(p);
++      }
++    else
++      new[grub_le_to_cpu16 (inode_ref->n)] = 0;
++    grub_free(inode_ref);
++
++    p = new;
++
++    key.object_id = key_out.offset;
++
++    err = lower_bound(data, &key, &key_out, fs_root, &elemaddr,
++                      &elemsize, &desc, 0);
++    if (err)
++      return grub_error(err, "lower_bound caught %d\n", err);
++
++    if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF)
++      next(data, &desc, &elemaddr, &elemsize, &key_out);
++
++  }
++
++  *pathname = p;
++  return 0;
++}
++
+ static grub_err_t
+ find_path (struct grub_btrfs_data *data,
+ 	   const char *path, struct grub_btrfs_key *key,
+@@ -1250,14 +1420,26 @@ find_path (struct grub_btrfs_data *data,
+   char *origpath = NULL;
+   unsigned symlinks_max = 32;
+ 
+-  err = get_root (data, key, tree, type);
+-  if (err)
+-    return err;
+-
+   origpath = grub_strdup (path);
+   if (!origpath)
+     return grub_errno;
+ 
++  if (data->fs_tree)
++    {
++      *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++      *tree = data->fs_tree;
++      /* This is a tree root, so everything starts at objectid 256 */
++      key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
++      key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++      key->offset = 0;
++    }
++  else
++    {
++      err = get_root (data, key, tree, type);
++      if (err)
++	return err;
++    }
++
+   while (1)
+     {
+       while (path[0] == '/')
+@@ -1430,9 +1612,21 @@ find_path (struct grub_btrfs_data *data,
+ 	  path = path_alloc = tmp;
+ 	  if (path[0] == '/')
+ 	    {
+-	      err = get_root (data, key, tree, type);
+-	      if (err)
+-		return err;
++	      if (data->fs_tree)
++		{
++		  *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++		  *tree = data->fs_tree;
++		  /* This is a tree root, so everything starts at objectid 256 */
++		  key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
++		  key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++		  key->offset = 0;
++		}
++	      else
++		{
++		  err = get_root (data, key, tree, type);
++		  if (err)
++		    return err;
++		}
+ 	    }
+ 	  continue;
+ 	}
+@@ -1673,18 +1867,10 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len)
+ 				 data->tree, file->offset, buf, len);
+ }
+ 
+-static grub_err_t
+-grub_btrfs_uuid (grub_device_t device, char **uuid)
++static char *
++btrfs_unparse_uuid(struct grub_btrfs_data *data)
+ {
+-  struct grub_btrfs_data *data;
+-
+-  *uuid = NULL;
+-
+-  data = grub_btrfs_mount (device);
+-  if (!data)
+-    return grub_errno;
+-
+-  *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
++  return  grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
+ 			  grub_be_to_cpu16 (data->sblock.uuid[0]),
+ 			  grub_be_to_cpu16 (data->sblock.uuid[1]),
+ 			  grub_be_to_cpu16 (data->sblock.uuid[2]),
+@@ -1693,6 +1879,20 @@ grub_btrfs_uuid (grub_device_t device, char **uuid)
+ 			  grub_be_to_cpu16 (data->sblock.uuid[5]),
+ 			  grub_be_to_cpu16 (data->sblock.uuid[6]),
+ 			  grub_be_to_cpu16 (data->sblock.uuid[7]));
++}
++
++static grub_err_t
++grub_btrfs_uuid (grub_device_t device, char **uuid)
++{
++  struct grub_btrfs_data *data;
++
++  *uuid = NULL;
++
++  data = grub_btrfs_mount (device);
++  if (!data)
++    return grub_errno;
++
++  *uuid = btrfs_unparse_uuid(data);
+ 
+   grub_btrfs_unmount (data);
+ 
+@@ -1749,6 +1949,242 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)),
+ }
+ #endif
+ 
++static grub_err_t
++grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc,
++		     char **argv)
++{
++  grub_device_t dev;
++  char *devname;
++  struct grub_btrfs_data *data;
++  char *uuid;
++
++  if (argc < 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
++
++  devname = grub_file_get_device_name(argv[0]);
++
++  if (!devname)
++    return grub_errno;
++
++  dev = grub_device_open (devname);
++  grub_free (devname);
++  if (!dev)
++    return grub_errno;
++
++  data = grub_btrfs_mount (dev);
++  if (!data)
++    {
++      grub_device_close(dev);
++      return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to open fs");
++    }
++
++  if (data->sblock.label)
++    grub_printf("Label: '%s' ", data->sblock.label);
++  else
++    grub_printf("Label: none ");
++
++  uuid = btrfs_unparse_uuid(data);
++
++  grub_printf(" uuid: %s\n\tTotal devices %" PRIuGRUB_UINT64_T
++              " FS bytes used %" PRIuGRUB_UINT64_T "\n",
++	      uuid, grub_cpu_to_le64(data->sblock.num_devices),
++	      grub_cpu_to_le64(data->sblock.bytes_used));
++
++  grub_btrfs_unmount (data);
++
++  return 0;
++}
++
++static grub_err_t
++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
++            grub_uint64_t objectid, grub_uint64_t offset,
++            grub_uint64_t *fs_root)
++{
++  grub_err_t err;
++  struct grub_btrfs_key key_in = {
++    .object_id = objectid,
++    .type = GRUB_BTRFS_ROOT_ITEM_KEY,
++    .offset = offset,
++  }, key_out;
++  struct grub_btrfs_leaf_descriptor desc;
++  grub_disk_addr_t elemaddr;
++  grub_size_t elemsize;
++  struct grub_btrfs_root_item ri;
++
++  err = lower_bound(data, &key_in, &key_out, tree,
++                    &elemaddr, &elemsize, &desc, 0);
++
++  if (err)
++    return err;
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM || elemaddr == 0)
++    return grub_error(GRUB_ERR_FILE_NOT_FOUND,
++                    N_("can't find fs root for subvol %"PRIuGRUB_UINT64_T"\n"),
++                    key_in.object_id);
++
++  err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri), 0);
++  if (err)
++    return err;
++
++  *fs_root = ri.tree;
++
++  return GRUB_ERR_NONE;
++}
++
++static const struct grub_arg_option options[] = {
++  {"output", 'o', 0, N_("Output to a variable instead of the console."),
++   N_("VARNAME"), ARG_TYPE_STRING},
++  {"path-only", 'p', 0, N_("Show only the path of the subvolume."), 0, 0},
++  {"id-only", 'i', 0, N_("Show only the id of the subvolume."), 0, 0},
++  {0, 0, 0, 0, 0, 0}
++};
++
++static grub_err_t
++grub_cmd_btrfs_list_subvols (struct grub_extcmd_context *ctxt,
++			     int argc, char **argv)
++{
++  struct grub_btrfs_data *data;
++  grub_device_t dev;
++  char *devname;
++  grub_uint64_t tree;
++  struct grub_btrfs_key key_in = {
++    .object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID),
++    .type = GRUB_BTRFS_ROOT_REF_KEY,
++    .offset = 0,
++  }, key_out;
++  struct grub_btrfs_leaf_descriptor desc;
++  grub_disk_addr_t elemaddr;
++  grub_uint64_t fs_root = 0;
++  grub_size_t elemsize;
++  grub_size_t allocated = 0;
++  int r = 0;
++  grub_err_t err;
++  char *buf = NULL;
++  int print = 1;
++  int path_only = ctxt->state[1].set;
++  int num_only = ctxt->state[2].set;
++  char *varname = NULL;
++  char *output = NULL;
++
++  if (ctxt->state[0].set) {
++    varname = ctxt->state[0].arg;
++    print = 0;
++  }
++
++  if (argc < 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
++
++  devname = grub_file_get_device_name(argv[0]);
++  if (!devname)
++    return grub_errno;
++
++  dev = grub_device_open (devname);
++  grub_free (devname);
++  if (!dev)
++    return grub_errno;
++
++  data = grub_btrfs_mount(dev);
++  if (!data)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "could not open device");
++
++  tree = data->sblock.root_tree;
++  err = get_fs_root(data, tree, grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID),
++                    0, &fs_root);
++  if (err)
++    goto out;
++
++  err = lower_bound(data, &key_in, &key_out, tree,
++                    &elemaddr, &elemsize, &desc, 0);
++
++  if (err)
++    {
++      grub_btrfs_unmount(data);
++      return err;
++    }
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF || elemaddr == 0)
++    {
++      r = next(data, &desc, &elemaddr, &elemsize, &key_out);
++    }
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) {
++    err = GRUB_ERR_FILE_NOT_FOUND;
++    grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root refs"));
++    goto out;
++  }
++
++  do
++    {
++      struct grub_btrfs_root_ref *ref;
++      char *p = NULL;
++
++      if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF)
++        {
++          r = 0;
++          break;
++        }
++
++      if (elemsize > allocated)
++        {
++          grub_free(buf);
++          allocated = 2 * elemsize;
++          buf = grub_malloc(allocated + 1);
++          if (!buf)
++            {
++              r = -grub_errno;
++              break;
++            }
++        }
++      ref = (struct grub_btrfs_root_ref *)buf;
++
++      err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0);
++      if (err)
++        {
++          r = -err;
++          break;
++        }
++        buf[elemsize] = 0;
++
++      find_pathname(data, ref->dirid, fs_root, ref->name, &p);
++
++      if (print)
++        {
++          if (num_only)
++            grub_printf("ID %"PRIuGRUB_UINT64_T"\n", key_out.offset);
++          else if (path_only)
++            grub_printf("%s\n", p);
++          else
++            grub_printf("ID %"PRIuGRUB_UINT64_T" path %s\n", key_out.offset, p);
++        } else {
++          char *old = output;
++          if (num_only)
++            output = grub_xasprintf("%s%"PRIuGRUB_UINT64_T"\n",
++                                    old ?: "", key_out.offset);
++          else if (path_only)
++            output = grub_xasprintf("%s%s\n", old ?: "", p);
++          else
++            output = grub_xasprintf("%sID %"PRIuGRUB_UINT64_T" path %s\n",
++                                    old ?: "", key_out.offset, p);
++
++          if (old)
++            grub_free(old);
++        }
++
++      r = next(data, &desc, &elemaddr, &elemsize, &key_out);
++  } while(r > 0);
++
++  if (output)
++    grub_env_set(varname, output);
++
++out:
++  free_iterator(&desc);
++  grub_btrfs_unmount(data);
++
++  grub_device_close (dev);
++
++  return 0;
++}
++
+ static struct grub_fs grub_btrfs_fs = {
+   .name = "btrfs",
+   .dir = grub_btrfs_dir,
+@@ -1764,12 +2200,88 @@ static struct grub_fs grub_btrfs_fs = {
+ #endif
+ };
+ 
++static grub_command_t cmd_info;
++static grub_extcmd_t cmd_list_subvols;
++
++static char *
++subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)),
++                  const char *val)
++{
++  unsigned long long result = 0;
++
++  grub_errno = GRUB_ERR_NONE;
++  if (*val)
++    {
++      result = grub_strtoull(val, NULL, 10);
++      if (grub_errno)
++        return NULL;
++    }
++
++  grub_free (btrfs_default_subvol);
++  btrfs_default_subvol = NULL;
++  btrfs_default_subvolid = result;
++  return grub_strdup(val);
++}
++
++static const char *
++subvolid_get_env (struct grub_env_var *var __attribute__ ((unused)),
++                  const char *val __attribute__ ((unused)))
++{
++  if (btrfs_default_subvol)
++    return grub_xasprintf("subvol:%s", btrfs_default_subvol);
++  else if (btrfs_default_subvolid)
++    return grub_xasprintf("%"PRIuGRUB_UINT64_T, btrfs_default_subvolid);
++  else
++    return "";
++}
++
++static char *
++subvol_set_env (struct grub_env_var *var __attribute__ ((unused)),
++                const char *val)
++{
++  grub_free (btrfs_default_subvol);
++  btrfs_default_subvol = grub_strdup (val);
++  btrfs_default_subvolid = 0;
++  return grub_strdup(val);
++}
++
++static const char *
++subvol_get_env (struct grub_env_var *var __attribute__ ((unused)),
++                const char *val __attribute__ ((unused)))
++{
++  if (btrfs_default_subvol)
++    return btrfs_default_subvol;
++  else if (btrfs_default_subvolid)
++    return grub_xasprintf("subvolid:%" PRIuGRUB_UINT64_T,
++                          btrfs_default_subvolid);
++  else
++    return "";
++}
++
+ GRUB_MOD_INIT (btrfs)
+ {
+   grub_fs_register (&grub_btrfs_fs);
++  cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info,
++				   "DEVICE",
++				   "Print BtrFS info about DEVICE.");
++  cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols",
++					 grub_cmd_btrfs_list_subvols, 0,
++					 "[-p|-n] [-o var] DEVICE",
++					 "Print list of BtrFS subvolumes on "
++					 "DEVICE.", options);
++  grub_register_variable_hook ("btrfs_subvol", subvol_get_env,
++                               subvol_set_env);
++  grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env,
++                               subvolid_set_env);
+ }
+ 
+ GRUB_MOD_FINI (btrfs)
+ {
++  grub_register_variable_hook ("btrfs_subvol", NULL, NULL);
++  grub_register_variable_hook ("btrfs_subvolid", NULL, NULL);
++  grub_unregister_command (cmd_info);
++  grub_unregister_extcmd (cmd_list_subvols);
+   grub_fs_unregister (&grub_btrfs_fs);
+ }
++
++// vim: si et sw=2:
+diff --git a/include/grub/btrfs.h b/include/grub/btrfs.h
+index 9d93fb6c182..234ad976771 100644
+--- a/include/grub/btrfs.h
++++ b/include/grub/btrfs.h
+@@ -29,6 +29,7 @@ enum
+     GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84,
+     GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF = 0x90,
+     GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8,
++    GRUB_BTRFS_ITEM_TYPE_ROOT_REF = 0x9c,
+     GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4
+   };
+ 
diff --git a/SOURCES/0089-export-btrfs_subvol-and-btrfs_subvolid.patch b/SOURCES/0089-export-btrfs_subvol-and-btrfs_subvolid.patch
new file mode 100644
index 0000000..a0989e8
--- /dev/null
+++ b/SOURCES/0089-export-btrfs_subvol-and-btrfs_subvolid.patch
@@ -0,0 +1,26 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Wed, 18 Dec 2013 09:57:04 +0000
+Subject: [PATCH] export btrfs_subvol and btrfs_subvolid
+
+We should export btrfs_subvol and btrfs_subvolid to have both visible
+to subsidiary configuration files loaded using configfile.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+---
+ grub-core/fs/btrfs.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 51ed63d429b..88d727d161f 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -2273,6 +2273,8 @@ GRUB_MOD_INIT (btrfs)
+                                subvol_set_env);
+   grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env,
+                                subvolid_set_env);
++  grub_env_export ("btrfs_subvol");
++  grub_env_export ("btrfs_subvolid");
+ }
+ 
+ GRUB_MOD_FINI (btrfs)
diff --git a/SOURCES/0090-grub2-btrfs-03-follow_default.patch b/SOURCES/0090-grub2-btrfs-03-follow_default.patch
new file mode 100644
index 0000000..26e91f1
--- /dev/null
+++ b/SOURCES/0090-grub2-btrfs-03-follow_default.patch
@@ -0,0 +1,196 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 21 Aug 2014 03:39:11 +0000
+Subject: [PATCH] grub2-btrfs-03-follow_default
+
+---
+ grub-core/fs/btrfs.c | 107 ++++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 76 insertions(+), 31 deletions(-)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 88d727d161f..a47d297567f 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -920,6 +920,7 @@ grub_btrfs_mount (grub_device_t dev)
+ {
+   struct grub_btrfs_data *data;
+   grub_err_t err;
++  const char *relpath = grub_env_get ("btrfs_relative_path");
+ 
+   if (!dev->disk)
+     {
+@@ -950,11 +951,14 @@ grub_btrfs_mount (grub_device_t dev)
+   data->devices_attached[0].dev = dev;
+   data->devices_attached[0].id = data->sblock.this_device.device_id;
+ 
+-  err = btrfs_handle_subvol (data);
+-  if (err)
++  if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
+     {
+-      grub_free (data);
+-      return NULL;
++      err = btrfs_handle_subvol (data);
++      if (err)
++      {
++        grub_free (data);
++        return NULL;
++      }
+     }
+ 
+   return data;
+@@ -1414,24 +1418,39 @@ find_path (struct grub_btrfs_data *data,
+   grub_size_t allocated = 0;
+   struct grub_btrfs_dir_item *direl = NULL;
+   struct grub_btrfs_key key_out;
++  int follow_default;
+   const char *ctoken;
+   grub_size_t ctokenlen;
+   char *path_alloc = NULL;
+   char *origpath = NULL;
+   unsigned symlinks_max = 32;
++  const char *relpath = grub_env_get ("btrfs_relative_path");
+ 
++  follow_default = 0;
+   origpath = grub_strdup (path);
+   if (!origpath)
+     return grub_errno;
+ 
+-  if (data->fs_tree)
++  if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
+     {
+-      *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
+-      *tree = data->fs_tree;
+-      /* This is a tree root, so everything starts at objectid 256 */
+-      key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
+-      key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
+-      key->offset = 0;
++      if (data->fs_tree)
++        {
++          *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++          *tree = data->fs_tree;
++          /* This is a tree root, so everything starts at objectid 256 */
++          key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
++          key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++          key->offset = 0;
++        }
++      else
++        {
++          *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++          *tree = data->sblock.root_tree;
++          key->object_id = data->sblock.root_dir_objectid;
++          key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++          key->offset = 0;
++          follow_default = 1;
++        }
+     }
+   else
+     {
+@@ -1442,15 +1461,23 @@ find_path (struct grub_btrfs_data *data,
+ 
+   while (1)
+     {
+-      while (path[0] == '/')
+-	path++;
+-      if (!path[0])
+-	break;
+-      slash = grub_strchr (path, '/');
+-      if (!slash)
+-	slash = path + grub_strlen (path);
+-      ctoken = path;
+-      ctokenlen = slash - path;
++      if (!follow_default)
++	{
++	  while (path[0] == '/')
++	    path++;
++	  if (!path[0])
++	    break;
++	  slash = grub_strchr (path, '/');
++	  if (!slash)
++	    slash = path + grub_strlen (path);
++	  ctoken = path;
++	  ctokenlen = slash - path;
++	}
++      else
++	{
++	  ctoken = "default";
++	  ctokenlen = sizeof ("default") - 1;
++	}
+ 
+       if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
+ 	{
+@@ -1461,7 +1488,9 @@ find_path (struct grub_btrfs_data *data,
+ 
+       if (ctokenlen == 1 && ctoken[0] == '.')
+ 	{
+-	  path = slash;
++	  if (!follow_default)
++	    path = slash;
++	  follow_default = 0;
+ 	  continue;
+ 	}
+       if (ctokenlen == 2 && ctoken[0] == '.' && ctoken[1] == '.')
+@@ -1492,8 +1521,9 @@ find_path (struct grub_btrfs_data *data,
+ 	  *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
+ 	  key->object_id = key_out.offset;
+ 
+-	  path = slash;
+-
++	  if (!follow_default)
++	    path = slash;
++	  follow_default = 0;
+ 	  continue;
+ 	}
+ 
+@@ -1562,7 +1592,9 @@ find_path (struct grub_btrfs_data *data,
+ 	  return err;
+ 	}
+ 
+-      path = slash;
++      if (!follow_default)
++	path = slash;
++      follow_default = 0;
+       if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK)
+ 	{
+ 	  struct grub_btrfs_inode inode;
+@@ -1612,14 +1644,26 @@ find_path (struct grub_btrfs_data *data,
+ 	  path = path_alloc = tmp;
+ 	  if (path[0] == '/')
+ 	    {
+-	      if (data->fs_tree)
++              if (relpath && (relpath[0] == '1' || relpath[0] == 'y'))
+ 		{
+-		  *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
+-		  *tree = data->fs_tree;
+-		  /* This is a tree root, so everything starts at objectid 256 */
+-		  key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
+-		  key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
+-		  key->offset = 0;
++	          if (data->fs_tree)
++		    {
++		      *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++		      *tree = data->fs_tree;
++		      /* This is a tree root, so everything starts at objectid 256 */
++		      key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK);
++		      key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++		      key->offset = 0;
++		    }
++		  else
++		    {
++	              *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY;
++	              *tree = data->sblock.root_tree;
++	              key->object_id = data->sblock.root_dir_objectid;
++	              key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++	              key->offset = 0;
++	              follow_default = 1;
++		    }
+ 		}
+ 	      else
+ 		{
+@@ -2275,6 +2319,7 @@ GRUB_MOD_INIT (btrfs)
+                                subvolid_set_env);
+   grub_env_export ("btrfs_subvol");
+   grub_env_export ("btrfs_subvolid");
++  grub_env_export ("btrfs_relative_path");
+ }
+ 
+ GRUB_MOD_FINI (btrfs)
diff --git a/SOURCES/0091-grub2-btrfs-04-grub2-install.patch b/SOURCES/0091-grub2-btrfs-04-grub2-install.patch
new file mode 100644
index 0000000..af81616
--- /dev/null
+++ b/SOURCES/0091-grub2-btrfs-04-grub2-install.patch
@@ -0,0 +1,174 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 21 Aug 2014 03:39:11 +0000
+Subject: [PATCH] grub2-btrfs-04-grub2-install
+
+---
+ grub-core/osdep/linux/getroot.c |  7 +++++++
+ grub-core/osdep/unix/config.c   | 17 +++++++++++++++--
+ util/config.c                   | 10 ++++++++++
+ util/grub-install.c             | 15 +++++++++++++++
+ util/grub-mkrelpath.c           |  6 ++++++
+ include/grub/emu/config.h       |  1 +
+ 6 files changed, 54 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
+index 6d9f4e5faa2..5d50dd6f8dc 100644
+--- a/grub-core/osdep/linux/getroot.c
++++ b/grub-core/osdep/linux/getroot.c
+@@ -376,6 +376,7 @@ get_btrfs_fs_prefix (const char *mount_path)
+   return NULL;
+ }
+ 
++int use_relative_path_on_btrfs = 0;
+ 
+ char **
+ grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
+@@ -519,6 +520,12 @@ again:
+ 	{
+ 	  ret = grub_find_root_devices_from_btrfs (dir);
+ 	  fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
++	  if (use_relative_path_on_btrfs)
++	    {
++	      if (fs_prefix)
++	        free (fs_prefix);
++	      fs_prefix = xstrdup ("/");
++	    }
+ 	}
+       else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0)
+ 	{
+diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c
+index 65effa9f3a7..b637c58efb7 100644
+--- a/grub-core/osdep/unix/config.c
++++ b/grub-core/osdep/unix/config.c
+@@ -82,6 +82,19 @@ grub_util_load_config (struct grub_util_config *cfg)
+   if (v)
+     cfg->grub_distributor = xstrdup (v);
+ 
++  v = getenv ("SUSE_BTRFS_SNAPSHOT_BOOTING");
++  if (v)
++    {
++      if (grub_strncmp(v, "true", sizeof ("true") - 1) == 0)
++        {
++          cfg->is_suse_btrfs_snapshot_enabled = 1;
++        }
++      else
++        {
++          cfg->is_suse_btrfs_snapshot_enabled = 0;
++        }
++    }
++
+   cfgfile = grub_util_get_config_filename ();
+   if (!grub_util_is_regular (cfgfile))
+     return;
+@@ -105,8 +118,8 @@ grub_util_load_config (struct grub_util_config *cfg)
+       *ptr++ = *iptr;
+     }
+ 
+-  strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" "
+-	  "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\"");
++  strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\nSUSE_BTRFS_SNAPSHOT_BOOTING=%s\\n\" "
++	  "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\" \"$SUSE_BTRFS_SNAPSHOT_BOOTING\"");
+ 
+   argv[2] = script;
+   argv[3] = '\0';
+diff --git a/util/config.c b/util/config.c
+index ebcdd8f5e22..f044a880a76 100644
+--- a/util/config.c
++++ b/util/config.c
+@@ -42,6 +42,16 @@ grub_util_parse_config (FILE *f, struct grub_util_config *cfg, int simple)
+ 	    cfg->is_cryptodisk_enabled = 1;
+ 	  continue;
+ 	}
++      if (grub_strncmp (ptr, "SUSE_BTRFS_SNAPSHOT_BOOTING=",
++			sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1) == 0)
++	{
++	  ptr += sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1;
++	  if (*ptr == '"' || *ptr == '\'')
++	    ptr++;
++	  if (grub_strncmp(ptr, "true", sizeof ("true") - 1) == 0)
++	    cfg->is_suse_btrfs_snapshot_enabled = 1;
++	  continue;
++	}
+       if (grub_strncmp (ptr, "GRUB_DISTRIBUTOR=",
+ 			sizeof ("GRUB_DISTRIBUTOR=") - 1) == 0)
+ 	{
+diff --git a/util/grub-install.c b/util/grub-install.c
+index 78d0138cb0a..4375c161955 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -816,6 +816,8 @@ fill_core_services (const char *core_services)
+   free (sysv_plist);
+ }
+ 
++extern int use_relative_path_on_btrfs;
++
+ int
+ main (int argc, char *argv[])
+ {
+@@ -849,6 +851,9 @@ main (int argc, char *argv[])
+ 
+   grub_util_load_config (&config);
+ 
++  if (config.is_suse_btrfs_snapshot_enabled)
++    use_relative_path_on_btrfs = 1;
++
+   if (!bootloader_id && config.grub_distributor)
+     {
+       char *ptr;
+@@ -1321,6 +1326,16 @@ main (int argc, char *argv[])
+       fprintf (load_cfg_f, "set debug='%s'\n",
+ 	      debug_image);
+     }
++
++  if (config.is_suse_btrfs_snapshot_enabled
++      && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0)
++    {
++      if (!load_cfg_f)
++        load_cfg_f = grub_util_fopen (load_cfg, "wb");
++      have_load_cfg = 1;
++      fprintf (load_cfg_f, "set btrfs_relative_path='y'\n");
++    }
++
+   char *prefix_drive = NULL;
+   char *install_drive = NULL;
+ 
+diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c
+index 47a241a391b..5db7a9a7d97 100644
+--- a/util/grub-mkrelpath.c
++++ b/util/grub-mkrelpath.c
+@@ -40,9 +40,12 @@ struct arguments
+ };
+ 
+ static struct argp_option options[] = {
++  {"relative",  'r', 0, 0, "use relative path on btrfs", 0},
+   { 0, 0, 0, 0, 0, 0 }
+ };
+ 
++extern int use_relative_path_on_btrfs;
++
+ static error_t
+ argp_parser (int key, char *arg, struct argp_state *state)
+ {
+@@ -52,6 +55,9 @@ argp_parser (int key, char *arg, struct argp_state *state)
+ 
+   switch (key)
+     {
++    case 'r':
++      use_relative_path_on_btrfs = 1;
++      break;
+     case ARGP_KEY_ARG:
+       if (state->arg_num == 0)
+ 	arguments->pathname = xstrdup (arg);
+diff --git a/include/grub/emu/config.h b/include/grub/emu/config.h
+index 875d5896ce1..c9a7e5f4ade 100644
+--- a/include/grub/emu/config.h
++++ b/include/grub/emu/config.h
+@@ -37,6 +37,7 @@ struct grub_util_config
+ {
+   int is_cryptodisk_enabled;
+   char *grub_distributor;
++  int is_suse_btrfs_snapshot_enabled;
+ };
+ 
+ void
diff --git a/SOURCES/0092-grub2-btrfs-05-grub2-mkconfig.patch b/SOURCES/0092-grub2-btrfs-05-grub2-mkconfig.patch
new file mode 100644
index 0000000..d7bfb4d
--- /dev/null
+++ b/SOURCES/0092-grub2-btrfs-05-grub2-mkconfig.patch
@@ -0,0 +1,127 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 21 Aug 2014 03:39:11 +0000
+Subject: [PATCH] grub2-btrfs-05-grub2-mkconfig
+
+---
+ util/grub-mkconfig.in       |  3 ++-
+ util/grub-mkconfig_lib.in   |  4 ++++
+ util/grub.d/00_header.in    | 24 +++++++++++++++++++++++-
+ util/grub.d/10_linux.in     |  4 ++++
+ util/grub.d/20_linux_xen.in |  4 ++++
+ 5 files changed, 37 insertions(+), 2 deletions(-)
+
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index 8218f3d477f..4248b9341ab 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -258,7 +258,8 @@ export GRUB_DEFAULT \
+   GRUB_BADRAM \
+   GRUB_OS_PROBER_SKIP_LIST \
+   GRUB_DISABLE_SUBMENU \
+-  GRUB_DEFAULT_DTB
++  GRUB_DEFAULT_DTB \
++  SUSE_BTRFS_SNAPSHOT_BOOTING
+ 
+ if test "x${grub_cfg}" != "x"; then
+   rm -f "${grub_cfg}.new"
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index 113a41f9409..b3aae534ddc 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -52,7 +52,11 @@ grub_warn ()
+ 
+ make_system_path_relative_to_its_root ()
+ {
++  if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] ; then
++  "${grub_mkrelpath}" -r "$1"
++  else
+   "${grub_mkrelpath}" "$1"
++  fi
+ }
+ 
+ is_path_readable_by_grub ()
+diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
+index 858b526c925..e2a53300126 100644
+--- a/util/grub.d/00_header.in
++++ b/util/grub.d/00_header.in
+@@ -27,6 +27,14 @@ export TEXTDOMAINDIR="@localedir@"
+ 
+ . "$pkgdatadir/grub-mkconfig_lib"
+ 
++if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] &&
++   [ "x${GRUB_FS}" = "xbtrfs" ] ; then
++    cat <<EOF
++set btrfs_relative_path="y"
++export btrfs_relative_path
++EOF
++fi
++
+ # Do this as early as possible, since other commands might depend on it.
+ # (e.g. the `loadfont' command might need lvm or raid modules)
+ for i in ${GRUB_PRELOAD_MODULES} ; do
+@@ -45,7 +53,9 @@ if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT
+ cat << EOF
+ set pager=1
+ 
+-if [ -s \$prefix/grubenv ]; then
++if [ -f \${config_directory}/grubenv ]; then
++  load_env -f \${config_directory}/grubenv
++elif [ -s \$prefix/grubenv ]; then
+   load_env
+ fi
+ EOF
+@@ -356,3 +366,15 @@ fi
+ if [ "x${GRUB_BADRAM}" != "x" ] ; then
+   echo "badram ${GRUB_BADRAM}"
+ fi
++
++if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] &&
++   [ "x${GRUB_FS}" = "xbtrfs" ] ; then
++    # Note: No $snapshot_num on *read-only* rollback!  (bsc#901487)
++    cat <<EOF
++if [ -n "\$extra_cmdline" ]; then
++  submenu "Bootable snapshot #\$snapshot_num" {
++    menuentry "If OK, run 'snapper rollback' and reboot." { true; }
++  }
++fi
++EOF
++fi
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 4e49ccdf742..d9a05937e46 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -66,10 +66,14 @@ fi
+ 
+ case x"$GRUB_FS" in
+     xbtrfs)
++	if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then
++	GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}"
++	else
+ 	rootsubvol="`make_system_path_relative_to_its_root /`"
+ 	rootsubvol="${rootsubvol#/}"
+ 	if [ "x${rootsubvol}" != x ]; then
+ 	    GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
++	fi
+ 	fi;;
+     xzfs)
+ 	rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
+diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
+index 972a4b5a03d..bcdc3ceac02 100644
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -73,10 +73,14 @@ fi
+ 
+ case x"$GRUB_FS" in
+     xbtrfs)
++	if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then
++	GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}"
++	else
+ 	rootsubvol="`make_system_path_relative_to_its_root /`"
+ 	rootsubvol="${rootsubvol#/}"
+ 	if [ "x${rootsubvol}" != x ]; then
+ 	    GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
++	fi
+ 	fi;;
+     xzfs)
+ 	rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
diff --git a/SOURCES/0093-grub2-btrfs-06-subvol-mount.patch b/SOURCES/0093-grub2-btrfs-06-subvol-mount.patch
new file mode 100644
index 0000000..493f133
--- /dev/null
+++ b/SOURCES/0093-grub2-btrfs-06-subvol-mount.patch
@@ -0,0 +1,537 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Fri, 22 May 2015 11:45:25 +0000
+Subject: [PATCH] grub2-btrfs-06-subvol-mount
+
+---
+ grub-core/fs/btrfs.c            | 195 +++++++++++++++++++++++++++++++++++++++-
+ grub-core/osdep/linux/getroot.c | 148 +++++++++++++++++++++++++++++-
+ util/grub-install.c             |  49 ++++++++++
+ include/grub/emu/getroot.h      |   5 ++
+ 4 files changed, 392 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index a47d297567f..2e36ac47e8a 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -32,6 +32,7 @@
+ #include <grub/command.h>
+ #include <grub/env.h>
+ #include <grub/extcmd.h>
++#include <grub/list.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -245,6 +246,12 @@ static grub_err_t
+ grub_btrfs_read_logical (struct grub_btrfs_data *data,
+ 			 grub_disk_addr_t addr, void *buf, grub_size_t size,
+ 			 int recursion_depth);
++static grub_err_t
++get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key,
++	  grub_uint64_t *tree, grub_uint8_t *type);
++
++grub_uint64_t
++find_mtab_subvol_tree (const char *path, char **path_in_subvol);
+ 
+ static grub_err_t
+ read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb)
+@@ -887,9 +894,26 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path)
+   grub_err_t err;
+   grub_uint64_t tree = 0;
+   grub_uint8_t type;
++  grub_uint64_t saved_tree;
+   struct grub_btrfs_key key;
+ 
++  if (path[0] == '\0')
++    {
++      data->fs_tree = 0;
++      return GRUB_ERR_NONE;
++    }
++
++  err = get_root (data, &key, &tree, &type);
++  if (err)
++    return err;
++
++  saved_tree = data->fs_tree;
++  data->fs_tree = tree;
++
+   err = find_path (data, path, &key, &tree, &type);
++
++  data->fs_tree = saved_tree;
++
+   if (err)
+       return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path);
+ 
+@@ -1758,11 +1782,20 @@ grub_btrfs_dir (grub_device_t device, const char *path,
+   int r = 0;
+   grub_uint64_t tree;
+   grub_uint8_t type;
++  char *new_path = NULL;
+ 
+   if (!data)
+     return grub_errno;
+ 
+-  err = find_path (data, path, &key_in, &tree, &type);
++  tree = find_mtab_subvol_tree (path, &new_path);
++
++  if (tree)
++    data->fs_tree = tree;
++
++  err = find_path (data, new_path ? new_path : path, &key_in, &tree, &type);
++  if (new_path)
++    grub_free (new_path);
++
+   if (err)
+     {
+       grub_btrfs_unmount (data);
+@@ -1864,11 +1897,21 @@ grub_btrfs_open (struct grub_file *file, const char *name)
+   struct grub_btrfs_inode inode;
+   grub_uint8_t type;
+   struct grub_btrfs_key key_in;
++  grub_uint64_t tree;
++  char *new_path = NULL;
+ 
+   if (!data)
+     return grub_errno;
+ 
+-  err = find_path (data, name, &key_in, &data->tree, &type);
++  tree = find_mtab_subvol_tree (name, &new_path);
++
++  if (tree)
++    data->fs_tree = tree;
++
++  err = find_path (data, new_path ? new_path : name, &key_in, &data->tree, &type);
++  if (new_path)
++    grub_free (new_path);
++
+   if (err)
+     {
+       grub_btrfs_unmount (data);
+@@ -2039,6 +2082,150 @@ grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc,
+   return 0;
+ }
+ 
++struct grub_btrfs_mtab
++{
++  struct grub_btrfs_mtab *next;
++  struct grub_btrfs_mtab **prev;
++  char *path;
++  char *subvol;
++  grub_uint64_t tree;
++};
++
++typedef struct grub_btrfs_mtab* grub_btrfs_mtab_t;
++
++static struct grub_btrfs_mtab *btrfs_mtab;
++
++#define FOR_GRUB_MTAB(var) FOR_LIST_ELEMENTS (var, btrfs_mtab)
++#define FOR_GRUB_MTAB_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE((var), (next), btrfs_mtab)
++
++static void
++add_mountpoint (const char *path, const char *subvol, grub_uint64_t tree)
++{
++  grub_btrfs_mtab_t m = grub_malloc (sizeof (*m));
++
++  m->path = grub_strdup (path);
++  m->subvol = grub_strdup (subvol);
++  m->tree = tree;
++  grub_list_push (GRUB_AS_LIST_P (&btrfs_mtab), GRUB_AS_LIST (m));
++}
++
++static grub_err_t
++grub_cmd_btrfs_mount_subvol (grub_command_t cmd __attribute__ ((unused)), int argc,
++		     char **argv)
++{
++  char *devname, *dirname, *subvol;
++  struct grub_btrfs_key key_in;
++  grub_uint8_t type;
++  grub_uint64_t tree;
++  grub_uint64_t saved_tree;
++  grub_err_t err;
++  struct grub_btrfs_data *data = NULL;
++  grub_device_t dev = NULL;
++
++  if (argc < 3)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "required <dev> <dir> and <subvol>");
++
++  devname = grub_file_get_device_name(argv[0]);
++  dev = grub_device_open (devname);
++  grub_free (devname);
++
++  if (!dev)
++    {
++      err = grub_errno;
++      goto err_out;
++    }
++
++  dirname = argv[1];
++  subvol = argv[2];
++
++  data = grub_btrfs_mount (dev);
++  if (!data)
++    {
++      err = grub_errno;
++      goto err_out;
++    }
++
++  err = find_path (data, dirname, &key_in, &tree, &type);
++  if (err)
++    goto err_out;
++
++  if (type !=  GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY)
++    {
++      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
++      goto err_out;
++    }
++
++  err = get_root (data, &key_in, &tree, &type);
++
++  if (err)
++    goto err_out;
++
++  saved_tree = data->fs_tree;
++  data->fs_tree = tree;
++  err = find_path (data, subvol, &key_in, &tree, &type);
++  data->fs_tree = saved_tree;
++
++  if (err)
++    goto err_out;
++
++  if (key_in.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0)
++    {
++      err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", subvol);
++      goto err_out;
++    }
++
++  grub_btrfs_unmount (data);
++  grub_device_close (dev);
++  add_mountpoint (dirname, subvol, tree);
++
++  return GRUB_ERR_NONE;
++
++err_out:
++
++  if (data)
++    grub_btrfs_unmount (data);
++
++  if (dev)
++    grub_device_close (dev);
++
++  return err;
++}
++
++grub_uint64_t
++find_mtab_subvol_tree (const char *path, char **path_in_subvol)
++{
++  grub_btrfs_mtab_t m, cm;
++  grub_uint64_t tree;
++
++  if (!path || !path_in_subvol)
++    return 0;
++
++  *path_in_subvol = NULL;
++  tree = 0;
++  cm = NULL;
++
++  FOR_GRUB_MTAB (m)
++    {
++      if (grub_strncmp (path, m->path, grub_strlen (m->path)) == 0)
++	{
++	  if (!cm)
++	    cm = m;
++	  else
++	    if (grub_strcmp (m->path, cm->path) > 0)
++	      cm = m;
++	}
++    }
++
++  if (cm)
++    {
++      const char *s = path + grub_strlen (cm->path);
++      *path_in_subvol = (s[0] == '\0') ? grub_strdup ("/") : grub_strdup (s);
++      tree = cm->tree;
++    }
++
++  return tree;
++}
++
+ static grub_err_t
+ get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree,
+             grub_uint64_t objectid, grub_uint64_t offset,
+@@ -2245,6 +2432,7 @@ static struct grub_fs grub_btrfs_fs = {
+ };
+ 
+ static grub_command_t cmd_info;
++static grub_command_t cmd_mount_subvol;
+ static grub_extcmd_t cmd_list_subvols;
+ 
+ static char *
+@@ -2308,6 +2496,9 @@ GRUB_MOD_INIT (btrfs)
+   cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info,
+ 				   "DEVICE",
+ 				   "Print BtrFS info about DEVICE.");
++  cmd_mount_subvol = grub_register_command("btrfs-mount-subvol", grub_cmd_btrfs_mount_subvol,
++				   "DEVICE DIRECTORY SUBVOL",
++				   "Set btrfs DEVICE the DIRECTORY a mountpoint of SUBVOL.");
+   cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols",
+ 					 grub_cmd_btrfs_list_subvols, 0,
+ 					 "[-p|-n] [-o var] DEVICE",
+diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
+index 5d50dd6f8dc..4c5a13022dc 100644
+--- a/grub-core/osdep/linux/getroot.c
++++ b/grub-core/osdep/linux/getroot.c
+@@ -107,6 +107,14 @@ struct btrfs_ioctl_search_key
+   grub_uint32_t unused[9];
+ };
+ 
++struct btrfs_ioctl_search_header {
++  grub_uint64_t transid;
++  grub_uint64_t objectid;
++  grub_uint64_t offset;
++  grub_uint32_t type;
++  grub_uint32_t len;
++};
++
+ struct btrfs_ioctl_search_args {
+   struct btrfs_ioctl_search_key key;
+   grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key))
+@@ -378,6 +386,109 @@ get_btrfs_fs_prefix (const char *mount_path)
+ 
+ int use_relative_path_on_btrfs = 0;
+ 
++static char *
++get_btrfs_subvol (const char *path)
++{
++  struct btrfs_ioctl_ino_lookup_args args;
++  grub_uint64_t tree_id;
++  int fd = -1;
++  char *ret = NULL;
++
++  fd = open (path, O_RDONLY);
++
++  if (fd < 0)
++    return NULL;
++
++  memset (&args, 0, sizeof(args));
++  args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID;
++
++  if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
++    goto error;
++
++  tree_id = args.treeid;
++
++  while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID)
++    {
++      struct btrfs_ioctl_search_args sargs;
++      struct grub_btrfs_root_backref *br;
++      struct btrfs_ioctl_search_header *search_header;
++      char *old;
++      grub_uint16_t len;
++      grub_uint64_t inode_id;
++
++      memset (&sargs, 0, sizeof(sargs));
++
++      sargs.key.tree_id = 1;
++      sargs.key.min_objectid = tree_id;
++      sargs.key.max_objectid = tree_id;
++
++      sargs.key.min_offset = 0;
++      sargs.key.max_offset = ~0ULL;
++      sargs.key.min_transid = 0;
++      sargs.key.max_transid = ~0ULL;
++      sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
++      sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
++
++      sargs.key.nr_items = 1;
++
++      if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0)
++	goto error;
++
++      if (sargs.key.nr_items == 0)
++	goto error;
++
++      search_header = (struct btrfs_ioctl_search_header *)sargs.buf;
++      br = (struct grub_btrfs_root_backref *) (search_header + 1);
++
++      len = grub_le_to_cpu16 (br->n);
++      inode_id = grub_le_to_cpu64 (br->inode_id);
++      tree_id = search_header->offset;
++
++      old = ret;
++      ret = malloc (len + 1);
++      memcpy (ret, br->name, len);
++      ret[len] = '\0';
++
++      if (inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID)
++	{
++	  char *s;
++
++	  memset(&args, 0, sizeof(args));
++	  args.treeid = search_header->offset;
++	  args.objectid = inode_id;
++
++	  if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
++	    goto error;
++
++	  s = xasprintf ("%s%s", args.name, ret);
++	  free (ret);
++	  ret = s;
++	}
++
++      if (old)
++	{
++	  char *s = xasprintf ("%s/%s", ret, old);
++	  free (ret);
++	  free (old);
++	  ret = s;
++	}
++    }
++
++  close (fd);
++  return ret;
++
++error:
++
++  if (fd >= 0)
++    close (fd);
++  if (ret)
++    free (ret);
++
++  return NULL;
++}
++
++void (*grub_find_root_btrfs_mount_path_hook)(const char *mount_path);
++
+ char **
+ grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
+ {
+@@ -519,12 +630,15 @@ again:
+       else if (grub_strcmp (entries[i].fstype, "btrfs") == 0)
+ 	{
+ 	  ret = grub_find_root_devices_from_btrfs (dir);
+-	  fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
+ 	  if (use_relative_path_on_btrfs)
+ 	    {
+-	      if (fs_prefix)
+-	        free (fs_prefix);
+ 	      fs_prefix = xstrdup ("/");
++	      if (grub_find_root_btrfs_mount_path_hook)
++		grub_find_root_btrfs_mount_path_hook (entries[i].enc_path);
++	    }
++	  else
++	    {
++	      fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
+ 	    }
+ 	}
+       else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0)
+@@ -1150,6 +1264,34 @@ grub_util_get_grub_dev_os (const char *os_dev)
+   return grub_dev;
+ }
+ 
++
++char *
++grub_util_get_btrfs_subvol (const char *path, char **mount_path)
++{
++  char *mp = NULL;
++
++  if (mount_path)
++    *mount_path = NULL;
++
++  auto void
++  mount_path_hook (const char *m)
++  {
++    mp = strdup (m);
++  }
++
++  grub_find_root_btrfs_mount_path_hook = mount_path_hook;
++  grub_free (grub_find_root_devices_from_mountinfo (path, NULL));
++  grub_find_root_btrfs_mount_path_hook = NULL;
++
++  if (!mp)
++    return NULL;
++
++  if (mount_path)
++    *mount_path = mp;
++
++  return get_btrfs_subvol (mp);
++}
++
+ char *
+ grub_make_system_path_relative_to_its_root_os (const char *path)
+ {
+diff --git a/util/grub-install.c b/util/grub-install.c
+index 4375c161955..a0ad99729fd 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -1535,6 +1535,55 @@ main (int argc, char *argv[])
+       prefix_drive = xasprintf ("(%s)", grub_drives[0]);
+     }
+ 
++#ifdef __linux__
++
++  if (config.is_suse_btrfs_snapshot_enabled
++      && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0)
++    {
++      char *subvol = NULL;
++      char *mount_path = NULL;
++      char **rootdir_devices = NULL;
++      char *rootdir_path = grub_util_path_concat (2, "/", rootdir);
++
++      if (grub_util_is_directory (rootdir_path))
++	rootdir_devices = grub_guess_root_devices (rootdir_path);
++
++      free (rootdir_path);
++
++      if (rootdir_devices && rootdir_devices[0])
++	if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0)
++	  subvol = grub_util_get_btrfs_subvol (platdir, &mount_path);
++
++      if (subvol && mount_path)
++	{
++	  char *def_subvol;
++
++	  def_subvol = grub_util_get_btrfs_subvol ("/", NULL);
++
++	  if (def_subvol)
++	    {
++	      if (!load_cfg_f)
++		load_cfg_f = grub_util_fopen (load_cfg, "wb");
++	      have_load_cfg = 1;
++
++	      if (grub_strcmp (subvol, def_subvol) != 0)
++		fprintf (load_cfg_f, "btrfs-mount-subvol ($root) %s %s\n", mount_path, subvol);
++	      free (def_subvol);
++	    }
++	}
++
++      for (curdev = rootdir_devices; *curdev; curdev++)
++	free (*curdev);
++      if (rootdir_devices)
++	free (rootdir_devices);
++      if (subvol)
++	free (subvol);
++      if (mount_path)
++	free (mount_path);
++    }
++
++#endif
++
+   char mkimage_target[200];
+   const char *core_name = NULL;
+ 
+diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h
+index 73fa2d34abb..9c642ae3fe3 100644
+--- a/include/grub/emu/getroot.h
++++ b/include/grub/emu/getroot.h
+@@ -53,6 +53,11 @@ char **
+ grub_find_root_devices_from_mountinfo (const char *dir, char **relroot);
+ #endif
+ 
++#ifdef __linux__
++char *
++grub_util_get_btrfs_subvol (const char *path, char **mount_path);
++#endif
++
+ /* Devmapper functions provided by getroot_devmapper.c.  */
+ void
+ grub_util_pull_devmapper (const char *os_dev);
diff --git a/SOURCES/0094-No-more-Bootable-Snapshot-submenu-in-grub.cfg.patch b/SOURCES/0094-No-more-Bootable-Snapshot-submenu-in-grub.cfg.patch
new file mode 100644
index 0000000..b51b025
--- /dev/null
+++ b/SOURCES/0094-No-more-Bootable-Snapshot-submenu-in-grub.cfg.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Dusty Mabe <dusty@dustymabe.com>
+Date: Sat, 18 Jul 2015 15:38:08 +0000
+Subject: [PATCH] No more "Bootable Snapshot" submenu in grub.cfg.
+
+This breaks grubby (run on kernel upgrades) because grubby just
+does a search for "menuentry".
+---
+ util/grub.d/00_header.in | 12 ------------
+ 1 file changed, 12 deletions(-)
+
+diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
+index e2a53300126..8a16fea347e 100644
+--- a/util/grub.d/00_header.in
++++ b/util/grub.d/00_header.in
+@@ -366,15 +366,3 @@ fi
+ if [ "x${GRUB_BADRAM}" != "x" ] ; then
+   echo "badram ${GRUB_BADRAM}"
+ fi
+-
+-if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] &&
+-   [ "x${GRUB_FS}" = "xbtrfs" ] ; then
+-    # Note: No $snapshot_num on *read-only* rollback!  (bsc#901487)
+-    cat <<EOF
+-if [ -n "\$extra_cmdline" ]; then
+-  submenu "Bootable snapshot #\$snapshot_num" {
+-    menuentry "If OK, run 'snapper rollback' and reboot." { true; }
+-  }
+-fi
+-EOF
+-fi
diff --git a/SOURCES/0095-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch b/SOURCES/0095-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch
new file mode 100644
index 0000000..a413446
--- /dev/null
+++ b/SOURCES/0095-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andrei Borzenkov <arvidjaar@gmail.com>
+Date: Tue, 21 Jun 2016 16:44:17 +0000
+Subject: [PATCH] Fallback to old subvol name scheme to support old snapshot
+ config
+
+Ref: bsc#953538
+---
+ grub-core/fs/btrfs.c | 32 +++++++++++++++++++++++++++++++-
+ 1 file changed, 31 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 2e36ac47e8a..4a31d39ee74 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -924,11 +924,41 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path)
+   return GRUB_ERR_NONE;
+ }
+ 
++static grub_err_t
++lookup_root_by_name_fallback(struct grub_btrfs_data *data, const char *path)
++{
++  grub_err_t err;
++  grub_uint64_t tree = 0;
++  grub_uint8_t type;
++  struct grub_btrfs_key key;
++
++  err = find_path (data, path, &key, &tree, &type);
++  if (err)
++      return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path);
++
++  if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0)
++    return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path);
++
++  data->fs_tree = tree;
++  return GRUB_ERR_NONE;
++}
++
+ static grub_err_t
+ btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused)))
+ {
+   if (btrfs_default_subvol)
+-    return lookup_root_by_name(data, btrfs_default_subvol);
++    {
++      grub_err_t err;
++      err = lookup_root_by_name(data, btrfs_default_subvol);
++
++      /* Fallback to old schemes */
++      if (err == GRUB_ERR_FILE_NOT_FOUND)
++	{
++	  err = GRUB_ERR_NONE;
++	  return lookup_root_by_name_fallback(data, btrfs_default_subvol);
++	}
++      return err;
++    }
+ 
+   if (btrfs_default_subvolid)
+     return lookup_root_by_id(data, btrfs_default_subvolid);
diff --git a/SOURCES/0096-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch b/SOURCES/0096-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch
new file mode 100644
index 0000000..0f4ce50
--- /dev/null
+++ b/SOURCES/0096-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch
@@ -0,0 +1,272 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 11 May 2017 08:56:57 +0000
+Subject: [PATCH] Grub not working correctly with btrfs snapshots (bsc#1026511)
+
+---
+ grub-core/fs/btrfs.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 238 insertions(+)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 4a31d39ee74..7002ad81b7e 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -2446,6 +2446,238 @@ out:
+   return 0;
+ }
+ 
++static grub_err_t
++grub_btrfs_get_parent_subvol_path (struct grub_btrfs_data *data,
++		grub_uint64_t child_id,
++		const char *child_path,
++		grub_uint64_t *parent_id,
++		char **path_out)
++{
++  grub_uint64_t fs_root = 0;
++  struct grub_btrfs_key key_in = {
++    .object_id = child_id,
++    .type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF,
++    .offset = 0,
++  }, key_out;
++  struct grub_btrfs_root_ref *ref;
++  char *buf;
++  struct grub_btrfs_leaf_descriptor desc;
++  grub_size_t elemsize;
++  grub_disk_addr_t elemaddr;
++  grub_err_t err;
++  char *parent_path;
++
++  *parent_id = 0;
++  *path_out = 0;
++
++  err = lower_bound(data, &key_in, &key_out, data->sblock.root_tree,
++                    &elemaddr, &elemsize, &desc, 0);
++  if (err)
++    return err;
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF || elemaddr == 0)
++    next(data, &desc, &elemaddr, &elemsize, &key_out);
++
++  if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF)
++    {
++      free_iterator(&desc);
++      return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root backrefs"));
++    }
++
++  buf = grub_malloc(elemsize + 1);
++  if (!buf)
++    {
++      free_iterator(&desc);
++      return grub_errno;
++    }
++
++  err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0);
++  if (err)
++    {
++      grub_free(buf);
++      free_iterator(&desc);
++      return err;
++    }
++
++  buf[elemsize] = 0;
++  ref = (struct grub_btrfs_root_ref *)buf;
++
++  err = get_fs_root(data, data->sblock.root_tree, grub_le_to_cpu64 (key_out.offset),
++                    0, &fs_root);
++  if (err)
++    {
++      grub_free(buf);
++      free_iterator(&desc);
++      return err;
++    }
++
++  find_pathname(data, grub_le_to_cpu64 (ref->dirid), fs_root, ref->name, &parent_path);
++
++  if (child_path)
++    {
++      *path_out = grub_xasprintf ("%s/%s", parent_path, child_path);
++      grub_free (parent_path);
++    }
++  else
++    *path_out = parent_path;
++
++  *parent_id = grub_le_to_cpu64 (key_out.offset);
++
++  grub_free(buf);
++  free_iterator(&desc);
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_btrfs_get_default_subvolume_id (struct grub_btrfs_data *data, grub_uint64_t *id)
++{
++  grub_err_t err;
++  grub_disk_addr_t elemaddr;
++  grub_size_t elemsize;
++  struct grub_btrfs_key key, key_out;
++  struct grub_btrfs_dir_item *direl = NULL;
++  const char *ctoken = "default";
++  grub_size_t ctokenlen = sizeof ("default") - 1;
++
++  *id = 0;
++  key.object_id = data->sblock.root_dir_objectid;
++  key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM;
++  key.offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen));
++  err = lower_bound (data, &key, &key_out, data->sblock.root_tree, &elemaddr, &elemsize,
++			 NULL, 0);
++  if (err)
++    return err;
++
++  if (key_cmp (&key, &key_out) != 0)
++    return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
++
++  struct grub_btrfs_dir_item *cdirel;
++  direl = grub_malloc (elemsize + 1);
++  err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize, 0);
++  if (err)
++    {
++      grub_free (direl);
++      return err;
++    }
++  for (cdirel = direl;
++       (grub_uint8_t *) cdirel - (grub_uint8_t *) direl
++       < (grub_ssize_t) elemsize;
++       cdirel = (void *) ((grub_uint8_t *) (direl + 1)
++       + grub_le_to_cpu16 (cdirel->n)
++       + grub_le_to_cpu16 (cdirel->m)))
++    {
++      if (ctokenlen == grub_le_to_cpu16 (cdirel->n)
++        && grub_memcmp (cdirel->name, ctoken, ctokenlen) == 0)
++      break;
++    }
++  if ((grub_uint8_t *) cdirel - (grub_uint8_t *) direl
++      >= (grub_ssize_t) elemsize)
++    {
++      grub_free (direl);
++      err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
++      return err;
++    }
++
++  if (cdirel->key.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM)
++    {
++      grub_free (direl);
++      err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found"));
++      return err;
++    }
++
++  *id = grub_le_to_cpu64 (cdirel->key.object_id);
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_btrfs_get_default_subvol (struct grub_extcmd_context *ctxt,
++			     int argc, char **argv)
++{
++  char *devname;
++  grub_device_t dev;
++  struct grub_btrfs_data *data;
++  grub_err_t err;
++  grub_uint64_t id;
++  char *subvol = NULL;
++  grub_uint64_t subvolid = 0;
++  char *varname = NULL;
++  char *output = NULL;
++  int path_only = ctxt->state[1].set;
++  int num_only = ctxt->state[2].set;
++
++  if (ctxt->state[0].set)
++    varname = ctxt->state[0].arg;
++
++  if (argc < 1)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
++
++  devname = grub_file_get_device_name(argv[0]);
++  if (!devname)
++    return grub_errno;
++
++  dev = grub_device_open (devname);
++  grub_free (devname);
++  if (!dev)
++    return grub_errno;
++
++  data = grub_btrfs_mount(dev);
++  if (!data)
++    {
++      grub_device_close (dev);
++      grub_dprintf ("btrfs", "failed to open fs\n");
++      grub_errno = GRUB_ERR_NONE;
++      return 0;
++    }
++
++  err = grub_btrfs_get_default_subvolume_id (data, &subvolid);
++  if (err)
++    {
++      grub_btrfs_unmount (data);
++      grub_device_close (dev);
++      return err;
++    }
++
++  id = subvolid;
++  while (id != GRUB_BTRFS_ROOT_VOL_OBJECTID)
++    {
++      grub_uint64_t parent_id;
++      char *path_out;
++
++      err = grub_btrfs_get_parent_subvol_path (data, grub_cpu_to_le64 (id), subvol, &parent_id, &path_out);
++      if (err)
++	{
++	  grub_btrfs_unmount (data);
++	  grub_device_close (dev);
++	  return err;
++	}
++
++      if (subvol)
++        grub_free (subvol);
++      subvol = path_out;
++      id = parent_id;
++    }
++
++  if (num_only && path_only)
++      output = grub_xasprintf ("%"PRIuGRUB_UINT64_T" /%s", subvolid, subvol);
++  else if (num_only)
++      output = grub_xasprintf ("%"PRIuGRUB_UINT64_T, subvolid);
++  else
++      output = grub_xasprintf ("/%s", subvol);
++
++  if (varname)
++    grub_env_set(varname, output);
++  else
++    grub_printf ("%s\n", output);
++
++  grub_free (output);
++  grub_free (subvol);
++
++  grub_btrfs_unmount (data);
++  grub_device_close (dev);
++
++  return GRUB_ERR_NONE;
++}
++
+ static struct grub_fs grub_btrfs_fs = {
+   .name = "btrfs",
+   .dir = grub_btrfs_dir,
+@@ -2464,6 +2696,7 @@ static struct grub_fs grub_btrfs_fs = {
+ static grub_command_t cmd_info;
+ static grub_command_t cmd_mount_subvol;
+ static grub_extcmd_t cmd_list_subvols;
++static grub_extcmd_t cmd_get_default_subvol;
+ 
+ static char *
+ subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)),
+@@ -2534,6 +2767,11 @@ GRUB_MOD_INIT (btrfs)
+ 					 "[-p|-n] [-o var] DEVICE",
+ 					 "Print list of BtrFS subvolumes on "
+ 					 "DEVICE.", options);
++  cmd_get_default_subvol = grub_register_extcmd("btrfs-get-default-subvol",
++					 grub_cmd_btrfs_get_default_subvol, 0,
++					 "[-p|-n] [-o var] DEVICE",
++					 "Print default BtrFS subvolume on "
++					 "DEVICE.", options);
+   grub_register_variable_hook ("btrfs_subvol", subvol_get_env,
+                                subvol_set_env);
+   grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env,
diff --git a/SOURCES/0097-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch b/SOURCES/0097-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch
new file mode 100644
index 0000000..9a4a5c2
--- /dev/null
+++ b/SOURCES/0097-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch
@@ -0,0 +1,72 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 1 Jun 2017 09:59:56 -0400
+Subject: [PATCH] Add grub_efi_allocate_pool() and grub_efi_free_pool()
+ wrappers.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ include/grub/efi/efi.h | 36 ++++++++++++++++++++++++++++++++----
+ 1 file changed, 32 insertions(+), 4 deletions(-)
+
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index 39480b38674..09a18e56302 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -24,6 +24,10 @@
+ #include <grub/dl.h>
+ #include <grub/efi/api.h>
+ 
++/* Variables.  */
++extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
++extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
++
+ /* Functions.  */
+ void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_efi_guid_t *protocol,
+ 					     void *registration);
+@@ -60,6 +64,33 @@ EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size,
+ 				      grub_efi_uintn_t *descriptor_size,
+ 				      grub_efi_uint32_t *descriptor_version);
+ void grub_efi_memory_fini (void);
++
++static inline grub_efi_status_t
++__attribute__((__unused__))
++grub_efi_allocate_pool (grub_efi_memory_type_t pool_type,
++			grub_efi_uintn_t buffer_size,
++			void **buffer)
++{
++  grub_efi_boot_services_t *b;
++  grub_efi_status_t status;
++
++  b = grub_efi_system_table->boot_services;
++  status = efi_call_3 (b->allocate_pool, pool_type, buffer_size, buffer);
++  return status;
++}
++
++static inline grub_efi_status_t
++__attribute__((__unused__))
++grub_efi_free_pool (void *buffer)
++{
++  grub_efi_boot_services_t *b;
++  grub_efi_status_t status;
++
++  b = grub_efi_system_table->boot_services;
++  status = efi_call_1 (b->free_pool, buffer);
++  return status;
++}
++
+ grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle);
+ void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp);
+ char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp);
+@@ -109,10 +140,7 @@ void grub_efi_init (void);
+ void grub_efi_fini (void);
+ void grub_efi_set_prefix (void);
+ 
+-/* Variables.  */
+-extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table);
+-extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle);
+-
++/* More variables.  */
+ extern int EXPORT_VAR(grub_efi_is_finished);
+ 
+ struct grub_net_card;
diff --git a/SOURCES/0098-Use-grub_efi_.-memory-helpers-where-reasonable.patch b/SOURCES/0098-Use-grub_efi_.-memory-helpers-where-reasonable.patch
new file mode 100644
index 0000000..0dc026f
--- /dev/null
+++ b/SOURCES/0098-Use-grub_efi_.-memory-helpers-where-reasonable.patch
@@ -0,0 +1,106 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 1 Jun 2017 10:06:38 -0400
+Subject: [PATCH] Use grub_efi_...() memory helpers where reasonable.
+
+This uses grub_efi_allocate_pool(), grub_efi_free_pool(), and
+grub_efi_free_pages() instead of open-coded efi_call_N() calls, so we
+get more reasonable type checking.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/efi/chainloader.c | 24 +++++++++---------------
+ 1 file changed, 9 insertions(+), 15 deletions(-)
+
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index 5cd9b6e08a8..106eb10a362 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -65,7 +65,7 @@ grub_chainloader_unload (void)
+ 
+   b = grub_efi_system_table->boot_services;
+   efi_call_1 (b->unload_image, image_handle);
+-  efi_call_2 (b->free_pages, address, pages);
++  grub_efi_free_pages (address, pages);
+ 
+   grub_free (file_path);
+   grub_free (cmdline);
+@@ -108,7 +108,7 @@ grub_chainloader_boot (void)
+     }
+ 
+   if (exit_data)
+-    efi_call_1 (b->free_pool, exit_data);
++    grub_efi_free_pool (exit_data);
+ 
+   grub_loader_unset ();
+ 
+@@ -500,10 +500,9 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
+ static grub_efi_boolean_t
+ handle_image (void *data, grub_efi_uint32_t datasize)
+ {
+-  grub_efi_boot_services_t *b;
+   grub_efi_loaded_image_t *li, li_bak;
+   grub_efi_status_t efi_status;
+-  char *buffer = NULL;
++  void *buffer = NULL;
+   char *buffer_aligned = NULL;
+   grub_efi_uint32_t i;
+   struct grub_pe32_section_table *section;
+@@ -514,8 +513,6 @@ handle_image (void *data, grub_efi_uint32_t datasize)
+   int found_entry_point = 0;
+   int rc;
+ 
+-  b = grub_efi_system_table->boot_services;
+-
+   rc = read_header (data, datasize, &context);
+   if (rc < 0)
+     {
+@@ -555,8 +552,8 @@ handle_image (void *data, grub_efi_uint32_t datasize)
+   grub_dprintf ("chain", "image size is %08"PRIxGRUB_UINT64_T", datasize is %08x\n",
+ 	       context.image_size, datasize);
+ 
+-  efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA,
+-			   buffer_size, &buffer);
++  efi_status = grub_efi_allocate_pool (GRUB_EFI_LOADER_DATA, buffer_size,
++				       &buffer);
+ 
+   if (efi_status != GRUB_EFI_SUCCESS)
+     {
+@@ -788,14 +785,14 @@ handle_image (void *data, grub_efi_uint32_t datasize)
+ 
+   grub_dprintf ("chain", "entry_point returned %ld\n", efi_status);
+   grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t));
+-  efi_status = efi_call_1 (b->free_pool, buffer);
++  efi_status = grub_efi_free_pool (buffer);
+ 
+   return 1;
+ 
+ error_exit:
+   grub_dprintf ("chain", "error_exit: grub_errno: %d\n", grub_errno);
+   if (buffer)
+-      efi_call_1 (b->free_pool, buffer);
++    grub_efi_free_pool (buffer);
+ 
+   return 0;
+ }
+@@ -803,10 +800,7 @@ error_exit:
+ static grub_err_t
+ grub_secureboot_chainloader_unload (void)
+ {
+-  grub_efi_boot_services_t *b;
+-
+-  b = grub_efi_system_table->boot_services;
+-  efi_call_2 (b->free_pages, address, pages);
++  grub_efi_free_pages (address, pages);
+   grub_free (file_path);
+   grub_free (cmdline);
+   cmdline = 0;
+@@ -1073,7 +1067,7 @@ fail:
+   grub_free (file_path);
+ 
+   if (address)
+-    efi_call_2 (b->free_pages, address, pages);
++    grub_efi_free_pages (address, pages);
+ 
+   if (cmdline)
+     grub_free (cmdline);
diff --git a/SOURCES/0099-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch b/SOURCES/0099-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch
new file mode 100644
index 0000000..004fced
--- /dev/null
+++ b/SOURCES/0099-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 1 Jun 2017 10:07:50 -0400
+Subject: [PATCH] Add PRIxGRUB_EFI_STATUS and use it.
+
+This avoids syntax checkers getting confused about if it's llx or lx.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/efi/chainloader.c | 3 ++-
+ include/grub/efi/api.h             | 8 ++++++++
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
+index 106eb10a362..3630b0cbf2d 100644
+--- a/grub-core/loader/efi/chainloader.c
++++ b/grub-core/loader/efi/chainloader.c
+@@ -783,7 +783,8 @@ handle_image (void *data, grub_efi_uint32_t datasize)
+   efi_status = efi_call_2 (entry_point, grub_efi_image_handle,
+ 			   grub_efi_system_table);
+ 
+-  grub_dprintf ("chain", "entry_point returned %ld\n", efi_status);
++  grub_dprintf ("chain", "entry_point returned 0x%"PRIxGRUB_EFI_STATUS"\n",
++		efi_status);
+   grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t));
+   efi_status = grub_efi_free_pool (buffer);
+ 
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 28b6adf7648..e5b521bd9be 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -527,6 +527,14 @@ typedef grub_uint8_t grub_efi_char8_t;
+ typedef grub_uint16_t grub_efi_char16_t;
+ 
+ typedef grub_efi_intn_t grub_efi_status_t;
++/* Make grub_efi_status_t reasonably printable. */
++#if GRUB_CPU_SIZEOF_VOID_P == 8
++#define PRIxGRUB_EFI_STATUS "lx"
++#define PRIdGRUB_EFI_STATUS "ld"
++#else
++#define PRIxGRUB_EFI_STATUS "llx"
++#define PRIdGRUB_EFI_STATUS "lld"
++#endif
+ 
+ #define GRUB_EFI_ERROR_CODE(value)	\
+   ((((grub_efi_status_t) 1) << (sizeof (grub_efi_status_t) * 8 - 1)) | (value))
diff --git a/SOURCES/0100-Don-t-use-dynamic-sized-arrays-since-we-don-t-build-.patch b/SOURCES/0100-Don-t-use-dynamic-sized-arrays-since-we-don-t-build-.patch
new file mode 100644
index 0000000..882cf5d
--- /dev/null
+++ b/SOURCES/0100-Don-t-use-dynamic-sized-arrays-since-we-don-t-build-.patch
@@ -0,0 +1,43 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 26 Jun 2017 12:42:57 -0400
+Subject: [PATCH] Don't use dynamic sized arrays since we don't build with
+ -std=c99
+
+---
+ grub-core/net/net.c | 17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 4be228d9576..fa3e2912643 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -1853,14 +1853,25 @@ grub_net_search_configfile (char *config)
+     {
+       /* By the Client UUID. */
+ 
+-      char client_uuid_var[sizeof ("net_") + grub_strlen (inf->name) +
+-                           sizeof ("_clientuuid") + 1];
+-      grub_snprintf (client_uuid_var, sizeof (client_uuid_var),
++      char *client_uuid_var;
++      grub_size_t client_uuid_var_size;
++
++      client_uuid_var_size = grub_snprintf (NULL, 0,
++                     "net_%s_clientuuid", inf->name);
++      if (client_uuid_var_size <= 0)
++	continue;
++      client_uuid_var_size += 1;
++      client_uuid_var = grub_malloc(client_uuid_var_size);
++      if (!client_uuid_var)
++	continue;
++      grub_snprintf (client_uuid_var, client_uuid_var_size,
+                      "net_%s_clientuuid", inf->name);
+ 
+       const char *client_uuid;
+       client_uuid = grub_env_get (client_uuid_var);
+ 
++      grub_free(client_uuid_var);
++
+       if (client_uuid)
+         {
+           grub_strcpy (suffix, client_uuid);
diff --git a/SOURCES/0101-don-t-ignore-const.patch b/SOURCES/0101-don-t-ignore-const.patch
new file mode 100644
index 0000000..6b4d390
--- /dev/null
+++ b/SOURCES/0101-don-t-ignore-const.patch
@@ -0,0 +1,22 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 26 Jun 2017 12:43:22 -0400
+Subject: [PATCH] don't ignore const
+
+---
+ grub-core/net/tftp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
+index dcd82494309..f90071353ad 100644
+--- a/grub-core/net/tftp.c
++++ b/grub-core/net/tftp.c
+@@ -307,7 +307,7 @@ static void
+ grub_normalize_filename (char *normalized, const char *filename)
+ {
+   char *dest = normalized;
+-  char *src = filename;
++  const char *src = filename;
+ 
+   while (*src != '\0')
+     {
diff --git a/SOURCES/0102-don-t-use-int-for-efi-status.patch b/SOURCES/0102-don-t-use-int-for-efi-status.patch
new file mode 100644
index 0000000..6328df9
--- /dev/null
+++ b/SOURCES/0102-don-t-use-int-for-efi-status.patch
@@ -0,0 +1,22 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 26 Jun 2017 12:44:59 -0400
+Subject: [PATCH] don't use int for efi status
+
+---
+ grub-core/kern/efi/efi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index 562d6887e0e..bcae7f4699d 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -166,7 +166,7 @@ grub_reboot (void)
+ void
+ grub_exit (int retval)
+ {
+-  int rc = GRUB_EFI_LOAD_ERROR;
++  grub_efi_status_t rc = GRUB_EFI_LOAD_ERROR;
+ 
+   if (retval == 0)
+     rc = GRUB_EFI_SUCCESS;
diff --git a/SOURCES/0103-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch b/SOURCES/0103-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch
new file mode 100644
index 0000000..1d6f4c4
--- /dev/null
+++ b/SOURCES/0103-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 26 Jun 2017 12:46:23 -0400
+Subject: [PATCH] make GRUB_MOD_INIT() declare its function prototypes.
+
+---
+ include/grub/dl.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/include/grub/dl.h b/include/grub/dl.h
+index 2bca56ce0e8..b1ed3c33317 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -54,6 +54,7 @@ grub_mod_fini (void)
+ 
+ #define GRUB_MOD_INIT(name)	\
+ static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \
++extern void grub_##name##_init (void); \
+ void \
+ grub_##name##_init (void) { grub_mod_init (0); } \
+ static void \
+@@ -61,6 +62,7 @@ grub_mod_init (grub_dl_t mod __attribute__ ((unused)))
+ 
+ #define GRUB_MOD_FINI(name)	\
+ static void grub_mod_fini (void) __attribute__ ((used)); \
++extern void grub_##name##_fini (void); \
+ void \
+ grub_##name##_fini (void) { grub_mod_fini (); } \
+ static void \
diff --git a/SOURCES/0104-editenv-handle-relative-symlinks.patch b/SOURCES/0104-editenv-handle-relative-symlinks.patch
new file mode 100644
index 0000000..20e1686
--- /dev/null
+++ b/SOURCES/0104-editenv-handle-relative-symlinks.patch
@@ -0,0 +1,50 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jonathan Lebon <jlebon@redhat.com>
+Date: Mon, 14 Aug 2017 14:37:20 -0400
+Subject: [PATCH] editenv: handle relative symlinks
+
+Handle symlinks with targets relative to the containing dir. This
+ensures that the rename operation does not depend on the cwd.
+
+Resolves: rhbz#1479960
+
+Signed-off-by: Jonathan Lebon <jlebon@redhat.com>
+---
+ util/editenv.c | 16 ++++++++++++++--
+ 1 file changed, 14 insertions(+), 2 deletions(-)
+
+diff --git a/util/editenv.c b/util/editenv.c
+index d8d1dad6ab9..41bc7cb1c9a 100644
+--- a/util/editenv.c
++++ b/util/editenv.c
+@@ -28,6 +28,7 @@
+ 
+ #include <errno.h>
+ #include <string.h>
++#include <libgen.h>
+ 
+ #define DEFAULT_ENVBLK_SIZE	1024
+ 
+@@ -87,9 +88,20 @@ grub_util_create_envblk_file (const char *name)
+ 	  continue;
+ 	}
+ 
+-      free (rename_target);
+       linkbuf[retsize] = '\0';
+-      rename_target = linkbuf;
++      if (linkbuf[0] == '/')
++        {
++          free (rename_target);
++          rename_target = linkbuf;
++        }
++      else
++        {
++          char *dbuf = xstrdup (rename_target);
++          const char *dir = dirname (dbuf);
++          free (rename_target);
++          rename_target = xasprintf("%s/%s", dir, linkbuf);
++          free (dbuf);
++        }
+     }
+ 
+   int rc = grub_util_rename (namenew, rename_target);
diff --git a/SOURCES/0105-Make-libgrub.pp-depend-on-config-util.h.patch b/SOURCES/0105-Make-libgrub.pp-depend-on-config-util.h.patch
new file mode 100644
index 0000000..dc24fb1
--- /dev/null
+++ b/SOURCES/0105-Make-libgrub.pp-depend-on-config-util.h.patch
@@ -0,0 +1,45 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 23 Aug 2017 10:37:27 -0400
+Subject: [PATCH] Make libgrub.pp depend on config-util.h
+
+If you build with "make -j48" a lot, sometimes you see:
+
+gcc -E -DHAVE_CONFIG_H -I. -I..  -Wall -W -DGRUB_UTIL=1 -D_FILE_OFFSET_BITS=64 -I./include -DGRUB_FILE=\"grub_script.tab.h\" -I. -I.. -I. -I.. -I../include -I./include -I../grub-core/lib/libgcrypt-grub/src/  -I../grub-core/lib/minilzo -I../grub-core/lib/xzembed -DMINILZO_HAVE_CONFIG_H -Wall -W -DGRUB_UTIL=1 -D_FILE_OFFSET_BITS=64 -I./include -DGRUB_FILE=\"grub_script.tab.h\" -I. -I.. -I. -I.. -I../include -I./include -I../grub-core/lib/libgcrypt-grub/src/  -I./grub-core/gnulib -I../grub-core/gnulib -I/builddir/build/BUILD/grub-2.02/grub-aarch64-efi-2.02 -D_FILE_OFFSET_BITS=64 \
+  -D'GRUB_MOD_INIT(x)=@MARKER@x@' grub_script.tab.h grub_script.yy.h ../grub-core/commands/blocklist.c ../grub-core/commands/macbless.c ../grub-core/commands/xnu_uuid.c ../grub-core/commands/testload.c ../grub-core/commands/ls.c ../grub-core/disk/dmraid_nvidia.c ../grub-core/disk/loopback.c ../grub-core/disk/lvm.c ../grub-core/disk/mdraid_linux.c ../grub-core/disk/mdraid_linux_be.c ../grub-core/disk/mdraid1x_linux.c ../grub-core/disk/raid5_recover.c ../grub-core/disk/raid6_recover.c ../grub-core/font/font.c ../grub-core/gfxmenu/font.c ../grub-core/normal/charset.c ../grub-core/video/fb/fbblit.c ../grub-core/video/fb/fbutil.c ../grub-core/video/fb/fbfill.c ../grub-core/video/fb/video_fb.c ../grub-core/video/video.c ../grub-core/video/capture.c ../grub-core/video/colors.c ../grub-core/unidata.c ../grub-core/io/bufio.c ../grub-core/fs/affs.c ../grub-core/fs/afs.c ../grub-core/fs/bfs.c ../grub-core/fs/btrfs.c ../grub-core/fs/cbfs.c ../grub-core/fs/cpio.c ../grub-core/fs/cpio_be.c ../grub-core/fs/odc.c ../grub-core/fs/newc.c ../grub-core/fs/ext2.c ../grub-core/fs/fat.c ../grub-core/fs/exfat.c ../grub-core/fs/fshelp.c ../grub-core/fs/hfs.c ../grub-core/fs/hfsplus.c ../grub-core/fs/hfspluscomp.c ../grub-core/fs/iso9660.c ../grub-core/fs/jfs.c ../grub-core/fs/minix.c ../grub-core/fs/minix2.c ../grub-core/fs/minix3.c ../grub-core/fs/minix_be.c ../grub-core/fs/minix2_be.c ../grub-core/fs/minix3_be.c ../grub-core/fs/nilfs2.c ../grub-core/fs/ntfs.c ../grub-core/fs/ntfscomp.c ../grub-core/fs/reiserfs.c ../grub-core/fs/romfs.c ../grub-core/fs/sfs.c ../grub-core/fs/squash4.c ../grub-core/fs/tar.c ../grub-core/fs/udf.c ../grub-core/fs/ufs2.c ../grub-core/fs/ufs.c ../grub-core/fs/ufs_be.c ../grub-core/fs/xfs.c ../grub-core/fs/zfs/zfscrypt.c ../grub-core/fs/zfs/zfs.c ../grub-core/fs/zfs/zfsinfo.c ../grub-core/fs/zfs/zfs_lzjb.c ../grub-core/fs/zfs/zfs_lz4.c ../grub-core/fs/zfs/zfs_sha256.c ../grub-core/fs/zfs/zfs_fletcher.c ../grub-core/lib/envblk.c ../grub-core/lib/hexdump.c ../grub-core/lib/LzFind.c ../grub-core/lib/LzmaEnc.c ../grub-core/lib/crc.c ../grub-core/lib/adler32.c ../grub-core/lib/crc64.c ../grub-core/normal/datetime.c ../grub-core/normal/misc.c ../grub-core/partmap/acorn.c ../grub-core/partmap/amiga.c ../grub-core/partmap/apple.c ../grub-core/partmap/sun.c ../grub-core/partmap/plan.c ../grub-core/partmap/dvh.c ../grub-core/partmap/sunpc.c ../grub-core/partmap/bsdlabel.c ../grub-core/partmap/dfly.c ../grub-core/script/function.c ../grub-core/script/lexer.c ../grub-core/script/main.c ../grub-core/script/script.c ../grub-core/script/argv.c ../grub-core/io/gzio.c ../grub-core/io/xzio.c ../grub-core/io/lzopio.c ../grub-core/kern/ia64/dl_helper.c ../grub-core/kern/arm/dl_helper.c ../grub-core/kern/arm64/dl_helper.c ../grub-core/lib/minilzo/minilzo.c ../grub-core/lib/xzembed/xz_dec_bcj.c ../grub-core/lib/xzembed/xz_dec_lzma2.c ../grub-core/lib/xzembed/xz_dec_stream.c ../util/misc.c ../grub-core/kern/command.c ../grub-core/kern/device.c ../grub-core/kern/disk.c ../grub-core/lib/disk.c ../util/getroot.c ../grub-core/osdep/unix/getroot.c ../grub-core/osdep/getroot.c ../grub-core/osdep/devmapper/getroot.c ../grub-core/osdep/relpath.c ../grub-core/kern/emu/hostdisk.c ../grub-core/osdep/devmapper/hostdisk.c ../grub-core/osdep/hostdisk.c ../grub-core/osdep/unix/hostdisk.c ../grub-core/osdep/exec.c ../grub-core/osdep/sleep.c ../grub-core/osdep/password.c ../grub-core/kern/emu/misc.c ../grub-core/kern/emu/mm.c ../grub-core/kern/env.c ../grub-core/kern/err.c ../grub-core/kern/file.c ../grub-core/kern/fs.c ../grub-core/kern/list.c ../grub-core/kern/misc.c ../grub-core/kern/partition.c ../grub-core/lib/crypto.c ../grub-core/disk/luks.c ../grub-core/disk/geli.c ../grub-core/disk/cryptodisk.c ../grub-core/disk/AFSplitter.c ../grub-core/lib/pbkdf2.c ../grub-core/commands/extcmd.c ../grub-core/lib/arg.c ../grub-core/disk/ldm.c ../grub-core/disk/diskfilter.c ../grub-core/partmap/gpt.c ../grub-core/partmap/msdos.c ../grub-core/fs/proc.c ../grub-core/fs/archelp.c > libgrub.pp || (rm -f libgrub.pp; exit 1)
+rm -f stamp-h1
+touch ../config-util.h.in
+cd . && /bin/sh ./config.status config-util.h
+config.status: creating config-util.h
+In file included from ../include/grub/mm.h:25:0,
+                 from ../include/grub/disk.h:29,
+                 from ../include/grub/file.h:26,
+                 from ../grub-core/fs/btrfs.c:21:
+./config.h:38:10: fatal error: ./config-util.h: No such file or directory
+ #include <config-util.h>
+          ^~~~~~~~~~~~~~~
+compilation terminated.
+make: *** [Makefile:13098: libgrub.pp] Error 1
+
+This is because libgrub.pp is built with -DGRUB_UTIL=1, which means
+it'll try to include config-util.h, but a parallel make is actually
+building that file.  I think.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ Makefile.am | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 7795baeb654..c7b0e6a9c46 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -37,7 +37,7 @@ grub_script.yy.c: grub_script.yy.h
+ CLEANFILES += grub_script.yy.c grub_script.yy.h
+ 
+ # For libgrub.a
+-libgrub.pp: grub_script.tab.h grub_script.yy.h $(libgrubmods_a_SOURCES) $(libgrubkern_a_SOURCES)
++libgrub.pp: config-util.h grub_script.tab.h grub_script.yy.h $(libgrubmods_a_SOURCES) $(libgrubkern_a_SOURCES)
+ 	$(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgrubmods_a_CPPFLAGS) $(libgrubkern_a_CPPFLAGS) $(CPPFLAGS) \
+ 	  -D'GRUB_MOD_INIT(x)=@MARKER@x@' $^ > $@ || (rm -f $@; exit 1)
+ CLEANFILES += libgrub.pp
diff --git a/SOURCES/0106-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch b/SOURCES/0106-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch
new file mode 100644
index 0000000..51f5458
--- /dev/null
+++ b/SOURCES/0106-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 20 Apr 2017 13:29:06 -0400
+Subject: [PATCH] Don't guess /boot/efi/ as HFS+ on ppc machines in
+ grub-install
+
+This should never be trying this, and since we've consolidated the
+grubenv to always be on /boot/efi/EFI/fedora/, this code causes it to
+always make the wrong decision.
+
+Resolves: rhbz#1484474
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-install.c | 12 +-----------
+ 1 file changed, 1 insertion(+), 11 deletions(-)
+
+diff --git a/util/grub-install.c b/util/grub-install.c
+index a0ad99729fd..16f137ca854 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -1159,18 +1159,8 @@ main (int argc, char *argv[])
+ 	  char *d;
+ 
+ 	  is_guess = 1;
+-	  d = grub_util_path_concat (2, bootdir, "macppc");
+-	  if (!grub_util_is_directory (d))
+-	    {
+-	      free (d);
+-	      d = grub_util_path_concat (2, bootdir, "efi");
+-	    }
+ 	  /* Find the Mac HFS(+) System Partition.  */
+-	  if (!grub_util_is_directory (d))
+-	    {
+-	      free (d);
+-	      d = grub_util_path_concat (2, bootdir, "EFI");
+-	    }
++	  d = grub_util_path_concat (2, bootdir, "macppc");
+ 	  if (!grub_util_is_directory (d))
+ 	    {
+ 	      free (d);
diff --git a/SOURCES/0107-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch b/SOURCES/0107-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch
new file mode 100644
index 0000000..c26a3d5
--- /dev/null
+++ b/SOURCES/0107-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 19 Oct 2017 11:29:11 -0400
+Subject: [PATCH] 20_linux_xen: load xen or multiboot{,2} modules as needed.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub.d/20_linux_xen.in | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
+index bcdc3ceac02..2bc03fd36b9 100644
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -136,6 +136,8 @@ linux_entry ()
+         else
+             xen_rm_opts="no-real-mode edd=off"
+         fi
++	insmod ${module_loader}
++	insmod ${xen_loader}
+ 	${xen_loader}	${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts}
+ 	echo	'$(echo "$lmessage" | grub_quote)'
+ 	${module_loader}	${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args}
+@@ -145,6 +147,7 @@ EOF
+     message="$(gettext_printf "Loading initial ramdisk ...")"
+     sed "s/^/$submenu_indentation/" << EOF
+ 	echo	'$(echo "$message" | grub_quote)'
++	insmod ${module_loader}
+ 	${module_loader}	--nounzip   ${rel_dirname}/${initrd}
+ EOF
+   fi
diff --git a/SOURCES/0108-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch b/SOURCES/0108-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch
new file mode 100644
index 0000000..acfb116
--- /dev/null
+++ b/SOURCES/0108-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch
@@ -0,0 +1,211 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 7 Nov 2017 17:12:17 -0500
+Subject: [PATCH] Make pmtimer tsc calibration not take 51 seconds to fail.
+
+On my laptop running at 2.4GHz, if I run a VM where tsc calibration
+using pmtimer will fail presuming a broken pmtimer, it takes ~51 seconds
+to do so (as measured with the stopwatch on my phone), with a tsc delta
+of 0x1cd1c85300, or around 125 billion cycles.
+
+If instead of trying to wait for 5-200ms to show up on the pmtimer, we try
+to wait for 5-200us, it decides it's broken in ~0x2626aa0 TSCs, aka ~2.4
+million cycles, or more or less instantly.
+
+Additionally, this reading the pmtimer was returning 0xffffffff anyway,
+and that's obviously an invalid return.  I've added a check for that and
+0 so we don't bother waiting for the test if what we're seeing is dead
+pins with no response at all.
+
+If "debug" is includes "pmtimer", you will see one of the following
+three outcomes.  If pmtimer gives all 0 or all 1 bits, you will see:
+
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 1
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 2
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 3
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 4
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 5
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 6
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 7
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 8
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 9
+kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 10
+kern/i386/tsc_pmtimer.c:78: timer is broken; giving up.
+
+This outcome was tested using qemu+kvm with UEFI (OVMF) firmware and
+these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX
+
+If pmtimer gives any other bit patterns but is not actually marching
+forward fast enough to use for clock calibration, you will see:
+
+kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations)
+kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0
+
+This outcome was tested using grub compiled with GRUB_PMTIMER_IGNORE_BAD_READS
+defined (so as not to trip the bad read test) using qemu+kvm with UEFI
+(OVMF) firmware, and these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX
+
+If pmtimer actually works, you'll see something like:
+
+kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations)
+kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0
+
+This outcome was tested using qemu+kvm with UEFI (OVMF) firmware, and
+these options: -machine pc-i440fx-2.4 -cpu Broadwell-noTSX
+
+I've also tested this outcome on a real Intel Xeon E3-1275v3 on an Intel
+Server Board S1200V3RPS using the SDV.RP.B8 "Release" build here:
+https://firmware.intel.com/sites/default/files/UEFIDevKit_S1200RP_vB8.zip
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/i386/tsc_pmtimer.c | 109 +++++++++++++++++++++++++++++++-------
+ 1 file changed, 89 insertions(+), 20 deletions(-)
+
+diff --git a/grub-core/kern/i386/tsc_pmtimer.c b/grub-core/kern/i386/tsc_pmtimer.c
+index c9c36169978..ca15c3aacd7 100644
+--- a/grub-core/kern/i386/tsc_pmtimer.c
++++ b/grub-core/kern/i386/tsc_pmtimer.c
+@@ -28,40 +28,101 @@
+ #include <grub/acpi.h>
+ #include <grub/cpu/io.h>
+ 
++/*
++ * Define GRUB_PMTIMER_IGNORE_BAD_READS if you're trying to test a timer that's
++ * present but doesn't keep time well.
++ */
++// #define GRUB_PMTIMER_IGNORE_BAD_READS
++
+ grub_uint64_t
+ grub_pmtimer_wait_count_tsc (grub_port_t pmtimer,
+ 			     grub_uint16_t num_pm_ticks)
+ {
+   grub_uint32_t start;
+-  grub_uint32_t last;
+-  grub_uint32_t cur, end;
++  grub_uint64_t cur, end;
+   grub_uint64_t start_tsc;
+   grub_uint64_t end_tsc;
+-  int num_iter = 0;
++  unsigned int num_iter = 0;
++#ifndef GRUB_PMTIMER_IGNORE_BAD_READS
++  int bad_reads = 0;
++#endif
+ 
+-  start = grub_inl (pmtimer) & 0xffffff;
+-  last = start;
++  /*
++   * Some timers are 24-bit and some are 32-bit, but it doesn't make much
++   * difference to us.  Caring which one we have isn't really worth it since
++   * the low-order digits will give us enough data to calibrate TSC.  So just
++   * mask the top-order byte off.
++   */
++  cur = start = grub_inl (pmtimer) & 0xffffffUL;
+   end = start + num_pm_ticks;
+   start_tsc = grub_get_tsc ();
+   while (1)
+     {
+-      cur = grub_inl (pmtimer) & 0xffffff;
+-      if (cur < last)
+-	cur |= 0x1000000;
+-      num_iter++;
++      cur &= 0xffffffffff000000ULL;
++      cur |= grub_inl (pmtimer) & 0xffffffUL;
++
++      end_tsc = grub_get_tsc();
++
++#ifndef GRUB_PMTIMER_IGNORE_BAD_READS
++      /*
++       * If we get 10 reads in a row that are obviously dead pins, there's no
++       * reason to do this thousands of times.
++       */
++      if (cur == 0xffffffUL || cur == 0)
++	{
++	  bad_reads++;
++	  grub_dprintf ("pmtimer",
++			"pmtimer: 0x%"PRIxGRUB_UINT64_T" bad_reads: %d\n",
++			cur, bad_reads);
++	  grub_dprintf ("pmtimer", "timer is broken; giving up.\n");
++
++	  if (bad_reads == 10)
++	    return 0;
++	}
++#endif
++
++      if (cur < start)
++	cur += 0x1000000;
++
+       if (cur >= end)
+ 	{
+-	  end_tsc = grub_get_tsc ();
++	  grub_dprintf ("pmtimer", "pmtimer delta is 0x%"PRIxGRUB_UINT64_T"\n",
++			cur - start);
++	  grub_dprintf ("pmtimer", "tsc delta is 0x%"PRIxGRUB_UINT64_T"\n",
++			end_tsc - start_tsc);
+ 	  return end_tsc - start_tsc;
+ 	}
+-      /* Check for broken PM timer.
+-	 50000000 TSCs is between 5 ms (10GHz) and 200 ms (250 MHz)
+-	 if after this time we still don't have 1 ms on pmtimer, then
+-	 pmtimer is broken.
++
++      /*
++       * Check for broken PM timer.  1ms at 10GHz should be 1E+7 TSCs; at
++       * 250MHz it should be 2.5E6.  So if after 4E+7 TSCs on a 10GHz machine,
++       * we should have seen pmtimer show 4ms of change (i.e. cur =~
++       * start+14320); on a 250MHz machine that should be 16ms (start+57280).
++       * If after this a time we still don't have 1ms on pmtimer, then pmtimer
++       * is broken.
++       *
++       * Likewise, if our code is perfectly efficient and introduces no delays
++       * whatsoever, on a 10GHz system we should see a TSC delta of 3580 in
++       * ~3580 iterations.  On a 250MHz machine that should be ~900 iterations.
++       *
++       * With those factors in mind, there are two limits here.  There's a hard
++       * limit here at 8x our desired pm timer delta, picked as an arbitrarily
++       * large value that's still not a lot of time to humans, because if we
++       * get that far this is either an implausibly fast machine or the pmtimer
++       * is not running.  And there's another limit on 4x our 10GHz tsc delta
++       * without seeing cur converge on our target value.
+        */
+-      if ((num_iter & 0xffffff) == 0 && grub_get_tsc () - start_tsc > 5000000) {
+-	return 0;
+-      }
++      if ((++num_iter > (grub_uint32_t)num_pm_ticks << 3UL) ||
++	  end_tsc - start_tsc > 40000000)
++	{
++	  grub_dprintf ("pmtimer",
++			"pmtimer delta is 0x%"PRIxGRUB_UINT64_T" (%u iterations)\n",
++			cur - start, num_iter);
++	  grub_dprintf ("pmtimer",
++			"tsc delta is implausible: 0x%"PRIxGRUB_UINT64_T"\n",
++			end_tsc - start_tsc);
++	  return 0;
++	}
+     }
+ }
+ 
+@@ -74,12 +135,20 @@ grub_tsc_calibrate_from_pmtimer (void)
+ 
+   fadt = grub_acpi_find_fadt ();
+   if (!fadt)
+-    return 0;
++    {
++      grub_dprintf ("pmtimer", "No FADT found; not using pmtimer.\n");
++      return 0;
++    }
+   pmtimer = fadt->pmtimer;
+   if (!pmtimer)
+-    return 0;
++    {
++      grub_dprintf ("pmtimer", "FADT does not specify pmtimer; skipping.\n");
++      return 0;
++    }
+ 
+-  /* It's 3.579545 MHz clock. Wait 1 ms.  */
++  /*
++   * It's 3.579545 MHz clock. Wait 1 ms.
++   */
+   tsc_diff = grub_pmtimer_wait_count_tsc (pmtimer, 3580);
+   if (tsc_diff == 0)
+     return 0;
diff --git a/SOURCES/0109-align-struct-efi_variable-better.patch b/SOURCES/0109-align-struct-efi_variable-better.patch
new file mode 100644
index 0000000..65bc91b
--- /dev/null
+++ b/SOURCES/0109-align-struct-efi_variable-better.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 27 Feb 2018 13:55:35 -0500
+Subject: [PATCH] align struct efi_variable better...
+
+---
+ include/grub/efiemu/runtime.h | 2 +-
+ include/grub/types.h          | 1 +
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/include/grub/efiemu/runtime.h b/include/grub/efiemu/runtime.h
+index 36d2dedf47e..9d93ba88bac 100644
+--- a/include/grub/efiemu/runtime.h
++++ b/include/grub/efiemu/runtime.h
+@@ -33,5 +33,5 @@ struct efi_variable
+   grub_uint32_t namelen;
+   grub_uint32_t size;
+   grub_efi_uint32_t attributes;
+-} GRUB_PACKED;
++} GRUB_PACKED GRUB_ALIGNED(8);
+ #endif /* ! GRUB_EFI_EMU_RUNTIME_HEADER */
+diff --git a/include/grub/types.h b/include/grub/types.h
+index b93e4820194..f6a9723971d 100644
+--- a/include/grub/types.h
++++ b/include/grub/types.h
+@@ -29,6 +29,7 @@
+ #else
+ #define GRUB_PACKED __attribute__ ((packed))
+ #endif
++#define GRUB_ALIGNED(x) __attribute__((aligned (x)))
+ 
+ #ifdef GRUB_BUILD
+ # define GRUB_CPU_SIZEOF_VOID_P	BUILD_SIZEOF_VOID_P
diff --git a/SOURCES/0110-Add-quicksort-implementation.patch b/SOURCES/0110-Add-quicksort-implementation.patch
new file mode 100644
index 0000000..06fe563
--- /dev/null
+++ b/SOURCES/0110-Add-quicksort-implementation.patch
@@ -0,0 +1,322 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 9 Dec 2016 15:39:47 -0500
+Subject: [PATCH] Add quicksort implementation
+
+This will be used to sort the boot menu entries that are read from
+the BootLoaderSpec config files.
+---
+ grub-core/kern/qsort.c | 279 +++++++++++++++++++++++++++++++++++++++++++++++++
+ include/grub/misc.h    |  15 +++
+ 2 files changed, 294 insertions(+)
+ create mode 100644 grub-core/kern/qsort.c
+
+diff --git a/grub-core/kern/qsort.c b/grub-core/kern/qsort.c
+new file mode 100644
+index 00000000000..7f3fc9ffdae
+--- /dev/null
++++ b/grub-core/kern/qsort.c
+@@ -0,0 +1,279 @@
++/* quicksort
++ * This file from the GNU C Library.
++ * Copyright (C) 1991-2016 Free Software Foundation, Inc.
++ * Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
++ *
++ *  GRUB  --  GRand Unified Bootloader
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++/* If you consider tuning this algorithm, you should consult first:
++   Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
++   Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993.  */
++
++#include <grub/types.h>
++#include <grub/misc.h>
++#include <grub/mm.h>
++
++#define CHAR_BIT 8
++
++/* Byte-wise swap two items of size SIZE. */
++#define SWAP(a, b, size)						      \
++  do									      \
++    {									      \
++      grub_size_t __size = (size);						      \
++      char *__a = (a), *__b = (b);					      \
++      do								      \
++	{								      \
++	  char __tmp = *__a;						      \
++	  *__a++ = *__b;						      \
++	  *__b++ = __tmp;						      \
++	} while (--__size > 0);						      \
++    } while (0)
++
++/* Discontinue quicksort algorithm when partition gets below this size.
++   This particular magic number was chosen to work best on a Sun 4/260. */
++#define MAX_THRESH 4
++
++/* Stack node declarations used to store unfulfilled partition obligations. */
++typedef struct
++  {
++    char *lo;
++    char *hi;
++  } stack_node;
++
++/* The next 4 #defines implement a very fast in-line stack abstraction. */
++/* The stack needs log (total_elements) entries (we could even subtract
++   log(MAX_THRESH)).  Since total_elements has type grub_size_t, we get as
++   upper bound for log (total_elements):
++   bits per byte (CHAR_BIT) * sizeof(grub_size_t).  */
++#define STACK_SIZE	(CHAR_BIT * sizeof(grub_size_t))
++#define PUSH(low, high)	((void) ((top->lo = (low)), (top->hi = (high)), ++top))
++#define	POP(low, high)	((void) (--top, (low = top->lo), (high = top->hi)))
++#define	STACK_NOT_EMPTY	(stack < top)
++
++
++/* Order size using quicksort.  This implementation incorporates
++   four optimizations discussed in Sedgewick:
++
++   1. Non-recursive, using an explicit stack of pointer that store the
++      next array partition to sort.  To save time, this maximum amount
++      of space required to store an array of SIZE_MAX is allocated on the
++      stack.  Assuming a 32-bit (64 bit) integer for grub_size_t, this needs
++      only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
++      Pretty cheap, actually.
++
++   2. Chose the pivot element using a median-of-three decision tree.
++      This reduces the probability of selecting a bad pivot value and
++      eliminates certain extraneous comparisons.
++
++   3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
++      insertion sort to order the MAX_THRESH items within each partition.
++      This is a big win, since insertion sort is faster for small, mostly
++      sorted array segments.
++
++   4. The larger of the two sub-partitions is always pushed onto the
++      stack first, with the algorithm then concentrating on the
++      smaller partition.  This *guarantees* no more than log (total_elems)
++      stack size is needed (actually O(1) in this case)!  */
++
++void
++grub_qsort (void *const pbase, grub_size_t total_elems, grub_size_t size,
++	    grub_compar_d_fn_t cmp, void *arg)
++{
++  char *base_ptr = (char *) pbase;
++
++  const grub_size_t max_thresh = MAX_THRESH * size;
++
++  if (total_elems == 0)
++    /* Avoid lossage with unsigned arithmetic below.  */
++    return;
++
++  if (total_elems > MAX_THRESH)
++    {
++      char *lo = base_ptr;
++      char *hi = &lo[size * (total_elems - 1)];
++      stack_node stack[STACK_SIZE];
++      stack_node *top = stack;
++
++      PUSH (NULL, NULL);
++
++      while (STACK_NOT_EMPTY)
++        {
++          char *left_ptr;
++          char *right_ptr;
++
++	  /* Select median value from among LO, MID, and HI. Rearrange
++	     LO and HI so the three values are sorted. This lowers the
++	     probability of picking a pathological pivot value and
++	     skips a comparison for both the LEFT_PTR and RIGHT_PTR in
++	     the while loops. */
++
++	  char *mid = lo + size * ((hi - lo) / size >> 1);
++
++	  if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
++	    SWAP (mid, lo, size);
++	  if ((*cmp) ((void *) hi, (void *) mid, arg) < 0)
++	    SWAP (mid, hi, size);
++	  else
++	    goto jump_over;
++	  if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
++	    SWAP (mid, lo, size);
++	jump_over:;
++
++	  left_ptr  = lo + size;
++	  right_ptr = hi - size;
++
++	  /* Here's the famous ``collapse the walls'' section of quicksort.
++	     Gotta like those tight inner loops!  They are the main reason
++	     that this algorithm runs much faster than others. */
++	  do
++	    {
++	      while ((*cmp) ((void *) left_ptr, (void *) mid, arg) < 0)
++		left_ptr += size;
++
++	      while ((*cmp) ((void *) mid, (void *) right_ptr, arg) < 0)
++		right_ptr -= size;
++
++	      if (left_ptr < right_ptr)
++		{
++		  SWAP (left_ptr, right_ptr, size);
++		  if (mid == left_ptr)
++		    mid = right_ptr;
++		  else if (mid == right_ptr)
++		    mid = left_ptr;
++		  left_ptr += size;
++		  right_ptr -= size;
++		}
++	      else if (left_ptr == right_ptr)
++		{
++		  left_ptr += size;
++		  right_ptr -= size;
++		  break;
++		}
++	    }
++	  while (left_ptr <= right_ptr);
++
++          /* Set up pointers for next iteration.  First determine whether
++             left and right partitions are below the threshold size.  If so,
++             ignore one or both.  Otherwise, push the larger partition's
++             bounds on the stack and continue sorting the smaller one. */
++
++          if ((grub_size_t) (right_ptr - lo) <= max_thresh)
++            {
++              if ((grub_size_t) (hi - left_ptr) <= max_thresh)
++		/* Ignore both small partitions. */
++                POP (lo, hi);
++              else
++		/* Ignore small left partition. */
++                lo = left_ptr;
++            }
++          else if ((grub_size_t) (hi - left_ptr) <= max_thresh)
++	    /* Ignore small right partition. */
++            hi = right_ptr;
++          else if ((right_ptr - lo) > (hi - left_ptr))
++            {
++	      /* Push larger left partition indices. */
++              PUSH (lo, right_ptr);
++              lo = left_ptr;
++            }
++          else
++            {
++	      /* Push larger right partition indices. */
++              PUSH (left_ptr, hi);
++              hi = right_ptr;
++            }
++        }
++    }
++
++  /* Once the BASE_PTR array is partially sorted by quicksort the rest
++     is completely sorted using insertion sort, since this is efficient
++     for partitions below MAX_THRESH size. BASE_PTR points to the beginning
++     of the array to sort, and END_PTR points at the very last element in
++     the array (*not* one beyond it!). */
++
++#define min(x, y) ((x) < (y) ? (x) : (y))
++
++  {
++    char *const end_ptr = &base_ptr[size * (total_elems - 1)];
++    char *tmp_ptr = base_ptr;
++    char *thresh = min(end_ptr, base_ptr + max_thresh);
++    char *run_ptr;
++
++    /* Find smallest element in first threshold and place it at the
++       array's beginning.  This is the smallest array element,
++       and the operation speeds up insertion sort's inner loop. */
++
++    for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
++      if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
++        tmp_ptr = run_ptr;
++
++    if (tmp_ptr != base_ptr)
++      SWAP (tmp_ptr, base_ptr, size);
++
++    /* Insertion sort, running from left-hand-side up to right-hand-side.  */
++
++    run_ptr = base_ptr + size;
++    while ((run_ptr += size) <= end_ptr)
++      {
++	tmp_ptr = run_ptr - size;
++	while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
++	  tmp_ptr -= size;
++
++	tmp_ptr += size;
++        if (tmp_ptr != run_ptr)
++          {
++            char *trav;
++
++	    trav = run_ptr + size;
++	    while (--trav >= run_ptr)
++              {
++                char c = *trav;
++                char *hi, *lo;
++
++                for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
++                  *hi = *lo;
++                *hi = c;
++              }
++          }
++      }
++  }
++}
++
++void *
++grub_bsearch (const void *key, const void *base, grub_size_t nmemb, grub_size_t size,
++	 grub_compar_d_fn_t compar, void *state)
++{
++  grub_size_t l, u, idx;
++  const void *p;
++  int comparison;
++
++  l = 0;
++  u = nmemb;
++  while (l < u)
++    {
++      idx = (l + u) / 2;
++      p = (void *) (((const char *) base) + (idx * size));
++      comparison = (*compar) (key, p, state);
++      if (comparison < 0)
++	u = idx;
++      else if (comparison > 0)
++	l = idx + 1;
++      else
++	return (void *) p;
++    }
++
++  return NULL;
++}
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index fcaf1201e39..cbfae75a1b4 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -507,4 +507,19 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file,
+ #define grub_max(a, b) (((a) > (b)) ? (a) : (b))
+ #define grub_min(a, b) (((a) < (b)) ? (a) : (b))
+ 
++typedef int (*grub_compar_d_fn_t) (const void *p0, const void *p1, void *state);
++
++void *EXPORT_FUNC(grub_bsearch) (const void *key,
++			    const void *base,
++			    grub_size_t nmemb,
++			    grub_size_t size,
++			    grub_compar_d_fn_t compar,
++			    void *state);
++
++void EXPORT_FUNC(grub_qsort) (void *const pbase,
++			 grub_size_t total_elems,
++			 grub_size_t size,
++			 grub_compar_d_fn_t cmp,
++			 void *state);
++
+ #endif /* ! GRUB_MISC_HEADER */
diff --git a/SOURCES/0111-Add-blscfg-command-support-to-parse-BootLoaderSpec-c.patch b/SOURCES/0111-Add-blscfg-command-support-to-parse-BootLoaderSpec-c.patch
new file mode 100644
index 0000000..63b0529
--- /dev/null
+++ b/SOURCES/0111-Add-blscfg-command-support-to-parse-BootLoaderSpec-c.patch
@@ -0,0 +1,1157 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 9 Dec 2016 15:40:58 -0500
+Subject: [PATCH] Add blscfg command support to parse BootLoaderSpec config
+ fragments
+
+The BootLoaderSpec (BLS) defines a scheme where different bootloaders can
+share a format for boot items and a configuration directory that accepts
+these common configurations as drop-in files.
+
+GRUB2 already has a blscfg modle that can parse the config snippets using
+the bls_import command, change it to blscfg and improve the BLS support.
+---
+ grub-core/Makefile.core.def  |   4 +-
+ grub-core/commands/blscfg.c  | 796 ++++++++++++++++++++++++++++++++++++++++---
+ grub-core/commands/loadenv.c |  77 +----
+ grub-core/commands/loadenv.h |  93 +++++
+ include/grub/compiler.h      |   2 +
+ 5 files changed, 840 insertions(+), 132 deletions(-)
+ create mode 100644 grub-core/commands/loadenv.h
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 27563743ba9..96ccb402125 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -129,6 +129,7 @@ kernel = {
+   common = kern/rescue_parser.c;
+   common = kern/rescue_reader.c;
+   common = kern/term.c;
++  common = kern/qsort.c;
+ 
+   noemu = kern/compiler-rt.c;
+   noemu = kern/mm.c;
+@@ -774,8 +775,7 @@ module = {
+ module = {
+   name = blscfg;
+   common = commands/blscfg.c;
+-  enable = i386_efi;
+-  enable = x86_64_efi;
++  enable = efi;
+   enable = i386_pc;
+ };
+ 
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 4274aca5a9d..86796c8cd83 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -30,32 +30,405 @@
+ #include <grub/env.h>
+ #include <grub/file.h>
+ #include <grub/normal.h>
++#include <grub/lib/envblk.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
++#include "loadenv.h"
++
++#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
++#define GRUB_BOOT_DEVICE "($root)"
+ #ifdef GRUB_MACHINE_EFI
+ #define GRUB_LINUX_CMD "linuxefi"
+ #define GRUB_INITRD_CMD "initrdefi"
+-#define GRUB_BLS_CONFIG_PATH "/EFI/fedora/loader/entries/"
+-#define GRUB_BOOT_DEVICE "($boot)"
+ #else
+ #define GRUB_LINUX_CMD "linux"
+ #define GRUB_INITRD_CMD "initrd"
+-#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
+-#define GRUB_BOOT_DEVICE "($root)"
+ #endif
+ 
+-static int parse_entry (
++#define grub_free(x) ({grub_dprintf("blscfg", "%s freeing %p\n", __func__, x); grub_free(x); })
++
++struct keyval
++{
++  const char *key;
++  char *val;
++};
++
++struct bls_entry
++{
++  struct keyval **keyvals;
++  int nkeyvals;
++};
++
++static struct bls_entry **entries;
++static int nentries;
++
++static struct bls_entry *bls_new_entry(void)
++{
++  struct bls_entry **new_entries;
++  struct bls_entry *entry;
++  int new_n = nentries + 1;
++
++  new_entries = grub_realloc (entries,  new_n * sizeof (struct bls_entry *));
++  if (!new_entries)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		  "couldn't find space for BLS entry list");
++      return NULL;
++    }
++
++  entries = new_entries;
++
++  entry = grub_malloc (sizeof (*entry));
++  if (!entry)
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		  "couldn't find space for BLS entry list");
++      return NULL;
++    }
++
++  grub_memset (entry, 0, sizeof (*entry));
++  entries[nentries] = entry;
++
++  nentries = new_n;
++
++  return entry;
++}
++
++static int bls_add_keyval(struct bls_entry *entry, char *key, char *val)
++{
++  char *k, *v;
++  struct keyval **kvs, *kv;
++  int new_n = entry->nkeyvals + 1;
++
++  kvs = grub_realloc (entry->keyvals, new_n * sizeof (struct keyval *));
++  if (!kvs)
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		       "couldn't find space for BLS entry");
++  entry->keyvals = kvs;
++
++  kv = grub_malloc (sizeof (struct keyval));
++  if (!kv)
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		       "couldn't find space for BLS entry");
++
++  k = grub_strdup (key);
++  if (!k)
++    {
++      grub_free (kv);
++      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			 "couldn't find space for BLS entry");
++    }
++
++  v = grub_strdup (val);
++  if (!v)
++    {
++      grub_free (k);
++      grub_free (kv);
++      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			 "couldn't find space for BLS entry");
++    }
++
++  kv->key = k;
++  kv->val = v;
++
++  entry->keyvals[entry->nkeyvals] = kv;
++  grub_dprintf("blscfg", "new keyval at %p:%p:%p\n", entry->keyvals[entry->nkeyvals], k, v);
++  entry->nkeyvals = new_n;
++
++  return 0;
++}
++
++static void bls_free_entry(struct bls_entry *entry)
++{
++  int i;
++
++  grub_dprintf("blscfg", "%s got here\n", __func__);
++  for (i = 0; i < entry->nkeyvals; i++)
++    {
++      struct keyval *kv = entry->keyvals[i];
++      grub_free ((void *)kv->key);
++      grub_free (kv->val);
++      grub_free (kv);
++    }
++
++  grub_free (entry->keyvals);
++  grub_memset (entry, 0, sizeof (*entry));
++  grub_free (entry);
++}
++
++static int keyval_cmp (const void *p0, const void *p1,
++		       void *state UNUSED)
++{
++  const struct keyval *kv0 = *(struct keyval * const *)p0;
++  const struct keyval *kv1 = *(struct keyval * const *)p1;
++  int rc;
++
++  rc = grub_strcmp(kv0->key, kv1->key);
++
++  return rc;
++}
++
++/* Find they value of the key named by keyname.  If there are allowed to be
++ * more than one, pass a pointer to an int set to -1 the first time, and pass
++ * the same pointer through each time after, and it'll return them in sorted
++ * order. */
++static char *bls_get_val(struct bls_entry *entry, const char *keyname, int *last)
++{
++  char *foo = (char *)"";
++  struct keyval *kv = NULL, **kvp, key = {keyname, foo}, *keyp = &key;
++
++  /* if we've already found an entry that matches, just iterate */
++  if (last && *last >= 0)
++    {
++      int next = ++last[0];
++
++      if (next == entry->nkeyvals)
++	{
++done:
++	  *last = -1;
++	  return NULL;
++	}
++
++      kv = entry->keyvals[next];
++      if (grub_strcmp (keyname, kv->key))
++	goto done;
++
++      return kv->val;
++    }
++
++  kvp = grub_bsearch(&keyp, &entry->keyvals[0], entry->nkeyvals,
++		    sizeof (struct keyval *), keyval_cmp, NULL);
++  if (kvp)
++    kv = *kvp;
++
++  if (kv)
++    {
++      /* if we've got uninitialized but present state, track back until we find
++       * the first match */
++      if (last)
++	{
++	  grub_dprintf("blscfg", "%s trying to find another entry because last was set\n", __func__);
++	  /* figure out the position of this entry in the array */
++	  int idx;
++	  for (idx = 0 ; idx < entry->nkeyvals; idx++)
++	    if (entry->keyvals[idx] == kv)
++	      break;
++	  *last = idx;
++
++	  while (idx > 0)
++	    {
++	      struct keyval *kvtmp = entry->keyvals[idx-1];
++	      if (idx == 0 || grub_strcmp (keyname, kvtmp->key))
++		{
++		  /* if we're at the start, or if the previous entry doesn't
++		   * match, then we're done */
++		  *last = idx;
++		  break;
++		}
++	      else
++		/* but if it does match, keep going backwards */
++		idx--;
++	    }
++	}
++
++      return kv->val;
++    }
++  return NULL;
++}
++
++#define goto_return(x) ({ ret = (x); goto finish; })
++
++/* compare alpha and numeric segments of two versions */
++/* return 1: a is newer than b */
++/*        0: a and b are the same version */
++/*       -1: b is newer than a */
++static int vercmp(const char * a, const char * b)
++{
++    char oldch1, oldch2;
++    char *abuf, *bbuf;
++    char *str1, *str2;
++    char * one, * two;
++    int rc;
++    int isnum;
++    int ret = 0;
++
++  grub_dprintf("blscfg", "%s got here\n", __func__);
++    if (!grub_strcmp(a, b))
++	    return 0;
++
++    abuf = grub_malloc(grub_strlen(a) + 1);
++    bbuf = grub_malloc(grub_strlen(b) + 1);
++    str1 = abuf;
++    str2 = bbuf;
++    grub_strcpy(str1, a);
++    grub_strcpy(str2, b);
++
++    one = str1;
++    two = str2;
++
++    /* loop through each version segment of str1 and str2 and compare them */
++    while (*one || *two) {
++	while (*one && !grub_isalnum(*one) && *one != '~') one++;
++	while (*two && !grub_isalnum(*two) && *two != '~') two++;
++
++	/* handle the tilde separator, it sorts before everything else */
++	if (*one == '~' || *two == '~') {
++	    if (*one != '~') goto_return (1);
++	    if (*two != '~') goto_return (-1);
++	    one++;
++	    two++;
++	    continue;
++	}
++
++	/* If we ran to the end of either, we are finished with the loop */
++	if (!(*one && *two)) break;
++
++	str1 = one;
++	str2 = two;
++
++	/* grab first completely alpha or completely numeric segment */
++	/* leave one and two pointing to the start of the alpha or numeric */
++	/* segment and walk str1 and str2 to end of segment */
++	if (grub_isdigit(*str1)) {
++	    while (*str1 && grub_isdigit(*str1)) str1++;
++	    while (*str2 && grub_isdigit(*str2)) str2++;
++	    isnum = 1;
++	} else {
++	    while (*str1 && grub_isalpha(*str1)) str1++;
++	    while (*str2 && grub_isalpha(*str2)) str2++;
++	    isnum = 0;
++	}
++
++	/* save character at the end of the alpha or numeric segment */
++	/* so that they can be restored after the comparison */
++	oldch1 = *str1;
++	*str1 = '\0';
++	oldch2 = *str2;
++	*str2 = '\0';
++
++	/* this cannot happen, as we previously tested to make sure that */
++	/* the first string has a non-null segment */
++	if (one == str1) goto_return(-1);	/* arbitrary */
++
++	/* take care of the case where the two version segments are */
++	/* different types: one numeric, the other alpha (i.e. empty) */
++	/* numeric segments are always newer than alpha segments */
++	/* XXX See patch #60884 (and details) from bugzilla #50977. */
++	if (two == str2) goto_return (isnum ? 1 : -1);
++
++	if (isnum) {
++	    grub_size_t onelen, twolen;
++	    /* this used to be done by converting the digit segments */
++	    /* to ints using atoi() - it's changed because long  */
++	    /* digit segments can overflow an int - this should fix that. */
++
++	    /* throw away any leading zeros - it's a number, right? */
++	    while (*one == '0') one++;
++	    while (*two == '0') two++;
++
++	    /* whichever number has more digits wins */
++	    onelen = grub_strlen(one);
++	    twolen = grub_strlen(two);
++	    if (onelen > twolen) goto_return (1);
++	    if (twolen > onelen) goto_return (-1);
++	}
++
++	/* grub_strcmp will return which one is greater - even if the two */
++	/* segments are alpha or if they are numeric.  don't return  */
++	/* if they are equal because there might be more segments to */
++	/* compare */
++	rc = grub_strcmp(one, two);
++	if (rc) goto_return (rc < 1 ? -1 : 1);
++
++	/* restore character that was replaced by null above */
++	*str1 = oldch1;
++	one = str1;
++	*str2 = oldch2;
++	two = str2;
++    }
++
++    /* this catches the case where all numeric and alpha segments have */
++    /* compared identically but the segment sepparating characters were */
++    /* different */
++    if ((!*one) && (!*two)) goto_return (0);
++
++    /* whichever version still has characters left over wins */
++    if (!*one) goto_return (-1); else goto_return (1);
++
++finish:
++    grub_free (abuf);
++    grub_free (bbuf);
++    return ret;
++}
++
++typedef int (*void_cmp_t)(void *, void *);
++
++static int nulcmp(char *s0, char *s1, void_cmp_t cmp)
++{
++  grub_dprintf("blscfg", "%s got here\n", __func__);
++  if (s1 && !s0)
++    return 1;
++  if (s0 && !s1)
++    return -1;
++  if (!s0 && !s1)
++    return 0;
++  if (cmp)
++    return cmp(s0, s1);
++  return grub_strcmp(s0, s1);
++}
++
++static int
++bls_keyval_cmp(struct bls_entry *e0, struct bls_entry *e1, const char *keyname)
++{
++  char *val0, *val1;
++
++  val0 = bls_get_val (e0, keyname, NULL);
++  val1 = bls_get_val (e1, keyname, NULL);
++
++  if (val1 && !val0)
++    return 1;
++
++  if (val0 && !val1)
++    return -1;
++
++  if (!val0 && !val1)
++    return 0;
++
++  return nulcmp(val0, val1, (void_cmp_t)vercmp);
++}
++
++static int bls_cmp(const void *p0, const void *p1, void *state UNUSED)
++{
++  struct bls_entry * e0 = *(struct bls_entry **)p0;
++  struct bls_entry * e1 = *(struct bls_entry **)p1;
++  int rc = 0;
++
++  rc = bls_keyval_cmp (e0, e1, "id");
++
++  if (rc == 0)
++    rc = bls_keyval_cmp (e0, e1, "title");
++
++  if (rc == 0)
++    rc = bls_keyval_cmp (e0, e1, "linux");
++
++  return rc;
++}
++
++static int read_entry (
+     const char *filename,
+-    const struct grub_dirhook_info *info __attribute__ ((unused)),
+-    void *data __attribute__ ((unused)))
++    const struct grub_dirhook_info *info UNUSED,
++    void *data)
+ {
+   grub_size_t n;
+   char *p;
+   grub_file_t f = NULL;
+   grub_off_t sz;
+-  char *title = NULL, *options = NULL, *clinux = NULL, *initrd = NULL, *src = NULL;
+-  const char *args[2] = { NULL, NULL };
++  struct bls_entry *entry;
++  const char *dirname= (const char *)data;
++  const char *devid = grub_env_get ("boot");
++
++  grub_dprintf ("blscfg", "filename: \"%s\"\n", filename);
+ 
+   if (filename[0] == '.')
+     return 0;
+@@ -67,7 +440,7 @@ static int parse_entry (
+   if (grub_strcmp (filename + n - 5, ".conf") != 0)
+     return 0;
+ 
+-  p = grub_xasprintf (GRUB_BLS_CONFIG_PATH "%s", filename);
++  p = grub_xasprintf ("(%s)%s/%s", devid, dirname, filename);
+ 
+   f = grub_file_open (p);
+   if (!f)
+@@ -77,54 +450,169 @@ static int parse_entry (
+   if (sz == GRUB_FILE_SIZE_UNKNOWN || sz > 1024*1024)
+     goto finish;
+ 
++  entry = bls_new_entry();
++  if (!entry)
++    goto finish;
++
+   for (;;)
+     {
+       char *buf;
++      char *separator;
++      int rc;
+ 
+       buf = grub_file_getline (f);
+       if (!buf)
+ 	break;
+ 
+-      if (grub_strncmp (buf, "title ", 6) == 0)
+-	{
+-	  grub_free (title);
+-	  title = grub_strdup (buf + 6);
+-	  if (!title)
+-	    goto finish;
+-	}
+-      else if (grub_strncmp (buf, "options ", 8) == 0)
+-	{
+-	  grub_free (options);
+-	  options = grub_strdup (buf + 8);
+-	  if (!options)
+-	    goto finish;
+-	}
+-      else if (grub_strncmp (buf, "linux ", 6) == 0)
+-	{
+-	  grub_free (clinux);
+-	  clinux = grub_strdup (buf + 6);
+-	  if (!clinux)
+-	    goto finish;
+-	}
+-      else if (grub_strncmp (buf, "initrd ", 7) == 0)
++      while (buf && buf[0] && (buf[0] == ' ' || buf[0] == '\t'))
++	buf++;
++      if (buf[0] == '#')
++	continue;
++
++      separator = grub_strchr (buf, ' ');
++
++      if (!separator)
++	separator = grub_strchr (buf, '\t');
++
++      if (!separator || separator[1] == '\0')
+ 	{
+-	  grub_free (initrd);
+-	  initrd = grub_strdup (buf + 7);
+-	  if (!initrd)
+-	    goto finish;
++	  grub_free (buf);
++	  break;
+ 	}
+ 
+-      grub_free(buf);
++      separator[0] = '\0';
++
++      rc = bls_add_keyval (entry, buf, separator+1);
++      grub_free (buf);
++      if (rc < 0)
++	break;
++    }
++
++  grub_qsort(&entry->keyvals[0], entry->nkeyvals, sizeof (struct keyval *),
++	     keyval_cmp, NULL);
++
++finish:
++  grub_free (p);
++
++  if (f)
++    grub_file_close (f);
++
++  return 0;
++}
++
++static grub_envblk_t saved_env = NULL;
++
++static int
++save_var (const char *name, const char *value, void *whitelist UNUSED)
++{
++  const char *val = grub_env_get (name);
++  grub_dprintf("blscfg", "saving \"%s\"\n", name);
++
++  if (val)
++    grub_envblk_set (saved_env, name, value);
++
++  return 0;
++}
++
++static int
++unset_var (const char *name, const char *value UNUSED, void *whitelist)
++{
++  grub_dprintf("blscfg", "restoring \"%s\"\n", name);
++  if (! whitelist)
++    {
++      grub_env_unset (name);
++      return 0;
+     }
+ 
+-  if (!linux)
++  if (test_whitelist_membership (name,
++				 (const grub_env_whitelist_t *) whitelist))
++    grub_env_unset (name);
++
++  return 0;
++}
++
++static char **bls_make_list (struct bls_entry *entry, const char *key, int *num)
++{
++  int last = -1;
++  char *val;
++
++  int nlist = 0;
++  char **list = NULL;
++
++  list = grub_malloc (sizeof (char *));
++  if (!list)
++    return NULL;
++  list[0] = NULL;
++
++  while (1)
++    {
++      char **new;
++
++      val = bls_get_val (entry, key, &last);
++      if (!val)
++	break;
++
++      new = grub_realloc (list, (nlist + 2) * sizeof (char *));
++      if (!new)
++	break;
++
++      list = new;
++      list[nlist++] = val;
++      list[nlist] = NULL;
++  }
++
++  if (num)
++    *num = nlist;
++
++  return list;
++}
++
++static void create_entry (struct bls_entry *entry, const char *cfgfile)
++{
++  int argc = 0;
++  const char **argv = NULL;
++
++  char *title = NULL;
++  char *clinux = NULL;
++  char *options = NULL;
++  char *initrd = NULL;
++  char *id = NULL;
++  char *hotkey = NULL;
++
++  char *users = NULL;
++  char **classes = NULL;
++
++  char **args = NULL;
++
++  char *src = NULL;
++  int i;
++
++  grub_dprintf("blscfg", "%s got here\n", __func__);
++  clinux = bls_get_val (entry, "linux", NULL);
++  if (!clinux)
+     {
+-      grub_printf ("Skipping file %s with no 'linux' key.", p);
++      grub_dprintf ("blscfg", "Skipping file %s with no 'linux' key.\n", cfgfile);
+       goto finish;
+     }
+ 
+-  args[0] = title ? title : filename;
++  title = bls_get_val (entry, "title", NULL);
++  options = bls_get_val (entry, "options", NULL);
++  initrd = bls_get_val (entry, "initrd", NULL);
++  id = bls_get_val (entry, "id", NULL);
+ 
++  hotkey = bls_get_val (entry, "grub_hotkey", NULL);
++  users = bls_get_val (entry, "grub_users", NULL);
++  classes = bls_make_list (entry, "grub_class", NULL);
++  args = bls_make_list (entry, "grub_arg", &argc);
++
++  argc += 1;
++  argv = grub_malloc ((argc + 1) * sizeof (char *));
++  argv[0] = title ? title : clinux;
++  for (i = 1; i < argc; i++)
++    argv[i] = args[i-1];
++  argv[argc] = NULL;
++
++  grub_dprintf("blscfg", "adding menu entry for \"%s\"\n", title);
+   src = grub_xasprintf ("load_video\n"
+ 			"set gfx_payload=keep\n"
+ 			"insmod gzio\n"
+@@ -133,40 +621,219 @@ static int parse_entry (
+ 			GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "",
+ 			initrd ? GRUB_INITRD_CMD " " : "", initrd ? GRUB_BOOT_DEVICE : "", initrd ? initrd : "", initrd ? "\n" : "");
+ 
+-  grub_normal_add_menu_entry (1, args, NULL, NULL, "bls", NULL, NULL, src, 0);
++  grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0);
+ 
+ finish:
+-  grub_free (p);
+-  grub_free (title);
+-  grub_free (options);
+-  grub_free (clinux);
+-  grub_free (initrd);
+-  grub_free (src);
++  if (classes)
++      grub_free (classes);
++  grub_dprintf("blscfg", "%s got here\n", __func__);
++  if (args)
++      grub_free (args);
++
++  if (argv)
++      grub_free (argv);
++
++  if (src)
++      grub_free (src);
++  grub_dprintf("blscfg", "%s got here\n", __func__);
++}
++
++struct find_entry_info {
++	grub_device_t dev;
++	grub_fs_t fs;
++	int efi;
++};
++
++/*
++ * filename: if the directory is /EFI/something/ , filename is "something"
++ * info: unused
++ * data: the filesystem object the file is on.
++ */
++static int find_entry (const char *filename,
++		       const struct grub_dirhook_info *dirhook_info UNUSED,
++		       void *data)
++{
++  struct find_entry_info *info = (struct find_entry_info *)data;
++  grub_file_t f = NULL;
++  char *grubenv_path = NULL;
++  grub_envblk_t env = NULL;
++  char *default_blsdir = NULL;
++  const char *blsdir = NULL;
++  char *saved_env_buf = NULL;
++  int r = 0;
++  const char *devid = grub_env_get ("boot");
++
++  grub_dprintf("blscfg", "%s got here\n", __func__);
++  if (!grub_strcmp (filename, ".") ||
++      !grub_strcmp (filename, ".."))
++    return 0;
++
++  if (info->efi && !grub_strcasecmp (filename, "boot"))
++    return 0;
++
++  saved_env_buf = grub_malloc (512);
++
++  // set a default blsdir
++  if (info->efi)
++    default_blsdir = grub_xasprintf ("/EFI/%s%s", filename,
++				     GRUB_BLS_CONFIG_PATH);
++  else
++    default_blsdir = grub_xasprintf ("%s", GRUB_BLS_CONFIG_PATH);
++
++  grub_env_set ("blsdir", default_blsdir);
++  grub_dprintf ("blscfg", "default_blsdir: \"%s\"\n", default_blsdir);
++
++  /*
++   * try to load a grubenv from /EFI/wherever/grubenv
++   */
++  if (info->efi)
++    grubenv_path = grub_xasprintf ("(%s)/EFI/%s/grubenv", devid, filename);
++  else
++    grubenv_path = grub_xasprintf ("(%s)/grub2/grubenv", devid);
++
++  grub_dprintf ("blscfg", "looking for \"%s\"\n", grubenv_path);
++  f = grub_file_open (grubenv_path);
++
++  grub_dprintf ("blscfg", "%s it\n", f ? "found" : "did not find");
++  grub_free (grubenv_path);
++  if (f)
++    {
++      grub_off_t sz;
++
++      grub_dprintf ("blscfg", "getting size\n");
++      sz = grub_file_size (f);
++      if (sz == GRUB_FILE_SIZE_UNKNOWN || sz > 1024*1024)
++	goto finish;
++
++      grub_dprintf ("blscfg", "reading env\n");
++      env = read_envblk_file (f);
++      if (!env)
++	goto finish;
++      grub_dprintf ("blscfg", "read env file\n");
++
++      grub_memset (saved_env_buf, '#', 512);
++      grub_memcpy (saved_env_buf, GRUB_ENVBLK_SIGNATURE,
++		   sizeof (GRUB_ENVBLK_SIGNATURE));
++      grub_dprintf ("blscfg", "saving env\n");
++      saved_env = grub_envblk_open (saved_env_buf, 512);
++      if (!saved_env)
++	goto finish;
++
++      // save everything listed in "env" with values from our existing grub env
++      grub_envblk_iterate (env, NULL, save_var);
++      // set everything from our loaded grubenv into the real grub env
++      grub_envblk_iterate (env, NULL, set_var);
++    }
++  else
++    {
++      grub_err_t e;
++      grub_dprintf ("blscfg", "no such file\n");
++      do
++	{
++	  e = grub_error_pop();
++	} while (e);
++
++    }
++
++  blsdir = grub_env_get ("blsdir");
++  if (!blsdir)
++    goto finish;
++
++  grub_dprintf ("blscfg", "blsdir: \"%s\"\n", blsdir);
++  if (blsdir[0] != '/' && info->efi)
++    blsdir = grub_xasprintf ("/EFI/%s/%s/", filename, blsdir);
++  else
++    blsdir = grub_strdup (blsdir);
++
++  if (!blsdir)
++    goto finish;
++
++  grub_dprintf ("blscfg", "blsdir: \"%s\"\n", blsdir);
++  r = info->fs->dir (info->dev, blsdir, read_entry, (char *)blsdir);
++  if (r != 0) {
++      grub_dprintf ("blscfg", "read_entry returned error\n");
++      grub_err_t e;
++      do
++	{
++	  e = grub_error_pop();
++	} while (e);
++  }
++
++  grub_dprintf ("blscfg", "Sorting %d entries\n", nentries);
++  grub_qsort(&entries[0], nentries, sizeof (struct bls_entry *), bls_cmp, NULL);
++
++  grub_dprintf ("blscfg", "%s Creating %d entries from bls\n", __func__, nentries);
++  for (r = nentries - 1; r >= 0; r--)
++      create_entry(entries[r], filename);
++
++  for (r = 0; r < nentries; r++)
++      bls_free_entry (entries[r]);
++finish:
++  nentries = 0;
++
++  grub_free (entries);
++  entries = NULL;
++
++  grub_free ((char *)blsdir);
++
++  grub_env_unset ("blsdir");
++
++  if (saved_env)
++    {
++      // remove everything from the real environment that's defined in env
++      grub_envblk_iterate (env, NULL, unset_var);
++
++      // re-set the things from our original environment
++      grub_envblk_iterate (saved_env, NULL, set_var);
++      grub_envblk_close (saved_env);
++      saved_env = NULL;
++    }
++  else if (saved_env_buf)
++    {
++      // if we have a saved environment, grub_envblk_close() freed this.
++      grub_free (saved_env_buf);
++    }
++
++  if (env)
++    grub_envblk_close (env);
+ 
+   if (f)
+     grub_file_close (f);
+ 
++  grub_free (default_blsdir);
++
+   return 0;
+ }
+ 
+ static grub_err_t
+-grub_cmd_bls_import (grub_extcmd_context_t ctxt __attribute__ ((unused)),
+-		     int argc __attribute__ ((unused)),
+-		     char **args __attribute__ ((unused)))
++grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED,
++		     int argc UNUSED,
++		     char **args UNUSED)
+ {
+   grub_fs_t fs;
+   grub_device_t dev;
+   static grub_err_t r;
+   const char *devid;
++  struct find_entry_info info =
++    {
++      .dev = NULL,
++      .fs = NULL,
++      .efi = 0,
++    };
+ 
+-  devid = grub_env_get ("root");
++
++  grub_dprintf ("blscfg", "finding boot\n");
++  devid = grub_env_get ("boot");
+   if (!devid)
+-    return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "root");
++    return grub_error (GRUB_ERR_FILE_NOT_FOUND,
++		       N_("variable `%s' isn't set"), "boot");
+ 
++  grub_dprintf ("blscfg", "opening %s\n", devid);
+   dev = grub_device_open (devid);
+   if (!dev)
+     return grub_errno;
+ 
++  grub_dprintf ("blscfg", "probing fs\n");
+   fs = grub_fs_probe (dev);
+   if (!fs)
+     {
+@@ -174,7 +841,17 @@ grub_cmd_bls_import (grub_extcmd_context_t ctxt __attribute__ ((unused)),
+       goto finish;
+     }
+ 
+-  r = fs->dir (dev, GRUB_BLS_CONFIG_PATH, parse_entry, NULL);
++  info.dev = dev;
++  info.fs = fs;
++#ifdef GRUB_MACHINE_EFI
++  info.efi = 1;
++  grub_dprintf ("blscfg", "scanning /EFI/\n");
++  r = fs->dir (dev, "/EFI/", find_entry, &info);
++#else
++  info.efi = 0;
++  grub_dprintf ("blscfg", "scanning %s\n", GRUB_BLS_CONFIG_PATH);
++  r = fs->dir (dev, "/", find_entry, &info);
++#endif
+ 
+ finish:
+   if (dev)
+@@ -184,18 +861,27 @@ finish:
+ }
+ 
+ static grub_extcmd_t cmd;
++static grub_extcmd_t oldcmd;
+ 
+ GRUB_MOD_INIT(bls)
+ {
+-  cmd = grub_register_extcmd ("bls_import",
+-			      grub_cmd_bls_import,
++  grub_dprintf("blscfg", "%s got here\n", __func__);
++  cmd = grub_register_extcmd ("blscfg",
++			      grub_cmd_blscfg,
+ 			      0,
+ 			      NULL,
+ 			      N_("Import Boot Loader Specification snippets."),
+ 			      NULL);
++  oldcmd = grub_register_extcmd ("bls_import",
++				 grub_cmd_blscfg,
++				 0,
++				 NULL,
++				 N_("Import Boot Loader Specification snippets."),
++				 NULL);
+ }
+ 
+ GRUB_MOD_FINI(bls)
+ {
+   grub_unregister_extcmd (cmd);
++  grub_unregister_extcmd (oldcmd);
+ }
+diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c
+index acd93d123ed..91c99456091 100644
+--- a/grub-core/commands/loadenv.c
++++ b/grub-core/commands/loadenv.c
+@@ -28,6 +28,8 @@
+ #include <grub/extcmd.h>
+ #include <grub/i18n.h>
+ 
++#include "loadenv.h"
++
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+ static const struct grub_arg_option options[] =
+@@ -84,81 +86,6 @@ open_envblk_file (char *filename, int untrusted)
+   return file;
+ }
+ 
+-static grub_envblk_t
+-read_envblk_file (grub_file_t file)
+-{
+-  grub_off_t offset = 0;
+-  char *buf;
+-  grub_size_t size = grub_file_size (file);
+-  grub_envblk_t envblk;
+-
+-  buf = grub_malloc (size);
+-  if (! buf)
+-    return 0;
+-
+-  while (size > 0)
+-    {
+-      grub_ssize_t ret;
+-
+-      ret = grub_file_read (file, buf + offset, size);
+-      if (ret <= 0)
+-        {
+-          grub_free (buf);
+-          return 0;
+-        }
+-
+-      size -= ret;
+-      offset += ret;
+-    }
+-
+-  envblk = grub_envblk_open (buf, offset);
+-  if (! envblk)
+-    {
+-      grub_free (buf);
+-      grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
+-      return 0;
+-    }
+-
+-  return envblk;
+-}
+-
+-struct grub_env_whitelist
+-{
+-  grub_size_t len;
+-  char **list;
+-};
+-typedef struct grub_env_whitelist grub_env_whitelist_t;
+-
+-static int
+-test_whitelist_membership (const char* name,
+-                           const grub_env_whitelist_t* whitelist)
+-{
+-  grub_size_t i;
+-
+-  for (i = 0; i < whitelist->len; i++)
+-    if (grub_strcmp (name, whitelist->list[i]) == 0)
+-      return 1;  /* found it */
+-
+-  return 0;  /* not found */
+-}
+-
+-/* Helper for grub_cmd_load_env.  */
+-static int
+-set_var (const char *name, const char *value, void *whitelist)
+-{
+-  if (! whitelist)
+-    {
+-      grub_env_set (name, value);
+-      return 0;
+-    }
+-
+-  if (test_whitelist_membership (name,
+-				 (const grub_env_whitelist_t *) whitelist))
+-    grub_env_set (name, value);
+-
+-  return 0;
+-}
+-
+ static grub_err_t
+ grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args)
+ {
+diff --git a/grub-core/commands/loadenv.h b/grub-core/commands/loadenv.h
+new file mode 100644
+index 00000000000..952f46121bd
+--- /dev/null
++++ b/grub-core/commands/loadenv.h
+@@ -0,0 +1,93 @@
++/* loadenv.c - command to load/save environment variable.  */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2008,2009,2010  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++static grub_envblk_t UNUSED
++read_envblk_file (grub_file_t file)
++{
++  grub_off_t offset = 0;
++  char *buf;
++  grub_size_t size = grub_file_size (file);
++  grub_envblk_t envblk;
++
++  buf = grub_malloc (size);
++  if (! buf)
++    return 0;
++
++  while (size > 0)
++    {
++      grub_ssize_t ret;
++
++      ret = grub_file_read (file, buf + offset, size);
++      if (ret <= 0)
++        {
++          grub_free (buf);
++          return 0;
++        }
++
++      size -= ret;
++      offset += ret;
++    }
++
++  envblk = grub_envblk_open (buf, offset);
++  if (! envblk)
++    {
++      grub_free (buf);
++      grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
++      return 0;
++    }
++
++  return envblk;
++}
++
++struct grub_env_whitelist
++{
++  grub_size_t len;
++  char **list;
++};
++typedef struct grub_env_whitelist grub_env_whitelist_t;
++
++static int UNUSED
++test_whitelist_membership (const char* name,
++                           const grub_env_whitelist_t* whitelist)
++{
++  grub_size_t i;
++
++  for (i = 0; i < whitelist->len; i++)
++    if (grub_strcmp (name, whitelist->list[i]) == 0)
++      return 1;  /* found it */
++
++  return 0;  /* not found */
++}
++
++/* Helper for grub_cmd_load_env.  */
++static int UNUSED
++set_var (const char *name, const char *value, void *whitelist)
++{
++  if (! whitelist)
++    {
++      grub_env_set (name, value);
++      return 0;
++    }
++
++  if (test_whitelist_membership (name,
++				 (const grub_env_whitelist_t *) whitelist))
++    grub_env_set (name, value);
++
++  return 0;
++}
+diff --git a/include/grub/compiler.h b/include/grub/compiler.h
+index c9e1d7a73dc..9859ff4cc79 100644
+--- a/include/grub/compiler.h
++++ b/include/grub/compiler.h
+@@ -48,4 +48,6 @@
+ #  define WARN_UNUSED_RESULT
+ #endif
+ 
++#define UNUSED __attribute__((__unused__))
++
+ #endif /* ! GRUB_COMPILER_HEADER */
diff --git a/SOURCES/0112-Add-BLS-support-to-grub-mkconfig.patch b/SOURCES/0112-Add-BLS-support-to-grub-mkconfig.patch
new file mode 100644
index 0000000..75698fd
--- /dev/null
+++ b/SOURCES/0112-Add-BLS-support-to-grub-mkconfig.patch
@@ -0,0 +1,167 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 9 Dec 2016 15:40:29 -0500
+Subject: [PATCH] Add BLS support to grub-mkconfig
+
+GRUB now has BootLoaderSpec support, the user can choose to use this by
+setting GRUB_ENABLE_BLSCFG to true in /etc/default/grub. On this setup,
+the boot menu entries are not added to the grub.cfg, instead BLS config
+files are parsed by blscfg command and the entries created dynamically.
+---
+ util/grub-mkconfig.in     |  3 ++-
+ util/grub-mkconfig_lib.in | 29 +++++++++++++++++++----------
+ util/grub.d/10_linux.in   | 37 +++++++++++++++++++++++++++++++++++--
+ 3 files changed, 56 insertions(+), 13 deletions(-)
+
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index 4248b9341ab..c20171919d9 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -259,7 +259,8 @@ export GRUB_DEFAULT \
+   GRUB_OS_PROBER_SKIP_LIST \
+   GRUB_DISABLE_SUBMENU \
+   GRUB_DEFAULT_DTB \
+-  SUSE_BTRFS_SNAPSHOT_BOOTING
++  SUSE_BTRFS_SNAPSHOT_BOOTING \
++  GRUB_ENABLE_BLSCFG
+ 
+ if test "x${grub_cfg}" != "x"; then
+   rm -f "${grub_cfg}.new"
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index b3aae534ddc..1acc1d01c39 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -30,6 +30,9 @@ fi
+ if test "x$grub_file" = x; then
+   grub_file="${bindir}/@grub_file@"
+ fi
++if test "x$grub_editenv" = x; then
++  grub_editenv="${bindir}/@grub_editenv@"
++fi
+ if test "x$grub_mkrelpath" = x; then
+   grub_mkrelpath="${bindir}/@grub_mkrelpath@"
+ fi
+@@ -127,10 +130,16 @@ EOF
+ 
+ prepare_grub_to_access_device ()
+ {
++  local device=$1 && shift
++  if [ "$#" -gt 0 ]; then
++    local variable=$1 && shift
++  else
++    local variable=root
++  fi
+   old_ifs="$IFS"
+   IFS='
+ '
+-  partmap="`"${grub_probe}" --device $@ --target=partmap`"
++  partmap="`"${grub_probe}" --device ${device} --target=partmap`"
+   for module in ${partmap} ; do
+     case "${module}" in
+       netbsd | openbsd)
+@@ -141,34 +150,34 @@ prepare_grub_to_access_device ()
+   done
+ 
+   # Abstraction modules aren't auto-loaded.
+-  abstraction="`"${grub_probe}" --device $@ --target=abstraction`"
++  abstraction="`"${grub_probe}" --device ${device} --target=abstraction`"
+   for module in ${abstraction} ; do
+     echo "insmod ${module}"
+   done
+ 
+-  fs="`"${grub_probe}" --device $@ --target=fs`"
++  fs="`"${grub_probe}" --device ${device} --target=fs`"
+   for module in ${fs} ; do
+     echo "insmod ${module}"
+   done
+ 
+   if [ x$GRUB_ENABLE_CRYPTODISK = xy ]; then
+-      for uuid in `"${grub_probe}" --device $@ --target=cryptodisk_uuid`; do
++      for uuid in `"${grub_probe}" --device ${device} --target=cryptodisk_uuid`; do
+ 	  echo "cryptomount -u $uuid"
+       done
+   fi
+ 
+   # If there's a filesystem UUID that GRUB is capable of identifying, use it;
+   # otherwise set root as per value in device.map.
+-  fs_hint="`"${grub_probe}" --device $@ --target=compatibility_hint`"
++  fs_hint="`"${grub_probe}" --device ${device} --target=compatibility_hint`"
+   if [ "x$fs_hint" != x ]; then
+-    echo "set root='$fs_hint'"
++    echo "set ${variable}='$fs_hint'"
+   fi
+-  if [ "x$GRUB_DISABLE_UUID" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then
+-    hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints=
++  if [ "x$GRUB_DISABLE_UUID" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device ${device} --target=fs_uuid 2> /dev/null`" ; then
++    hints="`"${grub_probe}" --device ${device} --target=hints_string 2> /dev/null`" || hints=
+     echo "if [ x\$feature_platform_search_hint = xy ]; then"
+-    echo "  search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}"
++    echo "  search --no-floppy --fs-uuid --set=${variable} ${hints} ${fs_uuid}"
+     echo "else"
+-    echo "  search --no-floppy --fs-uuid --set=root ${fs_uuid}"
++    echo "  search --no-floppy --fs-uuid --set=${variable} ${fs_uuid}"
+     echo "fi"
+   fi
+   IFS="$old_ifs"
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index d9a05937e46..839f1fdb655 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -121,6 +121,34 @@ linux_entry ()
+   if [ -z "$boot_device_id" ]; then
+       boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+   fi
++
++  if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then
++    if [ x$dirname = x/ ]; then
++      if [ -z "${prepare_root_cache}" ]; then
++        prepare_grub_to_access_device ${GRUB_DEVICE}
++      fi
++    else
++      if [ -z "${prepare_boot_cache}" ]; then
++        prepare_grub_to_access_device ${GRUB_DEVICE_BOOT}
++      fi
++    fi
++
++    bootefi_device="`${grub_probe} --target=device /boot/efi/`"
++    prepare_grub_to_access_device ${bootefi_device} boot
++
++    cat << EOF
++insmod blscfg
++blscfg
++if [ -s \$prefix/grubenv ]; then
++  load_env
++fi
++EOF
++
++    ${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
++
++    exit 0
++  fi
++
+   if [ x$type != xsimple ] ; then
+       title=$(mktitle "$type" "$version")
+       if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
+@@ -223,7 +251,10 @@ submenu_indentation=""
+ is_top_level=true
+ while [ "x$list" != "x" ] ; do
+   linux=`version_find_latest $list`
+-  gettext_printf "Found linux image: %s\n" "$linux" >&2
++  if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then
++    gettext_printf "Found linux image: %s\n" "$linux" >&2
++  fi
++
+   basename=`basename $linux`
+   dirname=`dirname $linux`
+   rel_dirname=`make_system_path_relative_to_its_root $dirname`
+@@ -262,7 +293,9 @@ while [ "x$list" != "x" ] ; do
+     for i in ${initrd}; do
+       initrd_display="${initrd_display} ${dirname}/${i}"
+     done
+-    gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
++    if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then
++      gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
++    fi
+   fi
+ 
+   fdt=
diff --git a/SOURCES/0113-Remove-duplicated-grub_exit-definition-for-grub-emu-.patch b/SOURCES/0113-Remove-duplicated-grub_exit-definition-for-grub-emu-.patch
new file mode 100644
index 0000000..53bf22e
--- /dev/null
+++ b/SOURCES/0113-Remove-duplicated-grub_exit-definition-for-grub-emu-.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 6 Feb 2018 11:02:09 +0100
+Subject: [PATCH] Remove duplicated grub_exit() definition for grub-emu
+ platform
+
+The grub_exit() function signature was changed on all platforms to take a
+return code, but latter on a following commit the grub_exit() for the emu
+platform was duplicated. It causes a build error so remove the duplicated
+function definition.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/kern/emu/main.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c
+index 7e47ec81263..55ea5a11ccd 100644
+--- a/grub-core/kern/emu/main.c
++++ b/grub-core/kern/emu/main.c
+@@ -72,12 +72,6 @@ grub_exit (int retval __attribute__((unused)))
+   grub_reboot ();
+ }
+ 
+-void
+-grub_exit (int retval __attribute__((unused)))
+-{
+-  grub_reboot ();
+-}
+-
+ void
+ grub_machine_init (void)
+ {
diff --git a/SOURCES/0114-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch b/SOURCES/0114-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch
new file mode 100644
index 0000000..204abbc
--- /dev/null
+++ b/SOURCES/0114-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch
@@ -0,0 +1,26 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 6 Feb 2018 11:16:28 +0100
+Subject: [PATCH] Don't attempt to backtrace on grub_abort() for grub-emu
+
+The emu platform doesn't have a grub_backtrace() implementation, so this
+causes a build error. Don't attempt to call this when building grub-emu.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/kern/misc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 04371ac49f2..636f97e1ba1 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -1103,7 +1103,7 @@ static void __attribute__ ((noreturn))
+ grub_abort (void)
+ {
+ #ifndef GRUB_UTIL
+-#if defined(__i386__) || defined(__x86_64__)
++#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU)
+   grub_backtrace();
+ #endif
+ #endif
diff --git a/SOURCES/0115-Enable-blscfg-command-for-the-emu-platform.patch b/SOURCES/0115-Enable-blscfg-command-for-the-emu-platform.patch
new file mode 100644
index 0000000..5a2f7b7
--- /dev/null
+++ b/SOURCES/0115-Enable-blscfg-command-for-the-emu-platform.patch
@@ -0,0 +1,164 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 2 Feb 2018 11:36:29 +0100
+Subject: [PATCH] Enable blscfg command for the emu platform
+
+Allow grub-emu to call a blscfg command. This may be useful for platforms
+that don't support GRUB, so grub-emu can be used to parse the BLS configs
+and kexec a new kernel using that information.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/Makefile.core.def |  1 +
+ grub-core/commands/blscfg.c | 46 +++++++++++++++++++++++++++++++++++----------
+ 2 files changed, 37 insertions(+), 10 deletions(-)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 96ccb402125..e52d776887a 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -777,6 +777,7 @@ module = {
+   common = commands/blscfg.c;
+   enable = efi;
+   enable = i386_pc;
++  enable = emu;
+ };
+ 
+ module = {
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 86796c8cd83..e0b65534af4 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -37,7 +37,12 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #include "loadenv.h"
+ 
+ #define GRUB_BLS_CONFIG_PATH "/loader/entries/"
++#ifdef GRUB_MACHINE_EMU
++#define GRUB_BOOT_DEVICE "/boot"
++#else
+ #define GRUB_BOOT_DEVICE "($root)"
++#endif
++
+ #ifdef GRUB_MACHINE_EFI
+ #define GRUB_LINUX_CMD "linuxefi"
+ #define GRUB_INITRD_CMD "initrdefi"
+@@ -46,6 +51,13 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define GRUB_INITRD_CMD "initrd"
+ #endif
+ 
++enum
++  {
++    PLATFORM_EFI,
++    PLATFORM_EMU,
++    PLATFORM_BIOS,
++  };
++
+ #define grub_free(x) ({grub_dprintf("blscfg", "%s freeing %p\n", __func__, x); grub_free(x); })
+ 
+ struct keyval
+@@ -641,7 +653,7 @@ finish:
+ struct find_entry_info {
+ 	grub_device_t dev;
+ 	grub_fs_t fs;
+-	int efi;
++	int platform;
+ };
+ 
+ /*
+@@ -668,13 +680,16 @@ static int find_entry (const char *filename,
+       !grub_strcmp (filename, ".."))
+     return 0;
+ 
+-  if (info->efi && !grub_strcasecmp (filename, "boot"))
++  if (info->platform == PLATFORM_EFI && !grub_strcasecmp (filename, "boot"))
+     return 0;
+ 
+   saved_env_buf = grub_malloc (512);
+ 
+   // set a default blsdir
+-  if (info->efi)
++  if (info->platform == PLATFORM_EMU)
++    default_blsdir = grub_xasprintf ("%s%s", GRUB_BOOT_DEVICE,
++				     GRUB_BLS_CONFIG_PATH);
++  else if (info->platform == PLATFORM_EFI)
+     default_blsdir = grub_xasprintf ("/EFI/%s%s", filename,
+ 				     GRUB_BLS_CONFIG_PATH);
+   else
+@@ -686,7 +701,7 @@ static int find_entry (const char *filename,
+   /*
+    * try to load a grubenv from /EFI/wherever/grubenv
+    */
+-  if (info->efi)
++  if (info->platform == PLATFORM_EFI)
+     grubenv_path = grub_xasprintf ("(%s)/EFI/%s/grubenv", devid, filename);
+   else
+     grubenv_path = grub_xasprintf ("(%s)/grub2/grubenv", devid);
+@@ -740,7 +755,7 @@ static int find_entry (const char *filename,
+     goto finish;
+ 
+   grub_dprintf ("blscfg", "blsdir: \"%s\"\n", blsdir);
+-  if (blsdir[0] != '/' && info->efi)
++  if (blsdir[0] != '/' && info->platform == PLATFORM_EFI)
+     blsdir = grub_xasprintf ("/EFI/%s/%s/", filename, blsdir);
+   else
+     blsdir = grub_strdup (blsdir);
+@@ -818,15 +833,21 @@ grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED,
+     {
+       .dev = NULL,
+       .fs = NULL,
+-      .efi = 0,
++      .platform = PLATFORM_BIOS,
+     };
+ 
+ 
+   grub_dprintf ("blscfg", "finding boot\n");
++
++#ifdef GRUB_MACHINE_EMU
++  devid = "host";
++  grub_env_set ("boot", devid);
++#else
+   devid = grub_env_get ("boot");
+   if (!devid)
+     return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ 		       N_("variable `%s' isn't set"), "boot");
++#endif
+ 
+   grub_dprintf ("blscfg", "opening %s\n", devid);
+   dev = grub_device_open (devid);
+@@ -844,11 +865,16 @@ grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED,
+   info.dev = dev;
+   info.fs = fs;
+ #ifdef GRUB_MACHINE_EFI
+-  info.efi = 1;
++  info.platform = PLATFORM_EFI;
+   grub_dprintf ("blscfg", "scanning /EFI/\n");
+   r = fs->dir (dev, "/EFI/", find_entry, &info);
++#elif GRUB_MACHINE_EMU
++  info.platform = PLATFORM_EMU;
++  grub_dprintf ("blscfg", "scanning %s%s\n", GRUB_BOOT_DEVICE,
++		GRUB_BLS_CONFIG_PATH);
++  r = fs->dir (dev, "/boot/loader/",
++	       find_entry, &info);
+ #else
+-  info.efi = 0;
+   grub_dprintf ("blscfg", "scanning %s\n", GRUB_BLS_CONFIG_PATH);
+   r = fs->dir (dev, "/", find_entry, &info);
+ #endif
+@@ -863,7 +889,7 @@ finish:
+ static grub_extcmd_t cmd;
+ static grub_extcmd_t oldcmd;
+ 
+-GRUB_MOD_INIT(bls)
++GRUB_MOD_INIT(blscfg)
+ {
+   grub_dprintf("blscfg", "%s got here\n", __func__);
+   cmd = grub_register_extcmd ("blscfg",
+@@ -880,7 +906,7 @@ GRUB_MOD_INIT(bls)
+ 				 NULL);
+ }
+ 
+-GRUB_MOD_FINI(bls)
++GRUB_MOD_FINI(blscfg)
+ {
+   grub_unregister_extcmd (cmd);
+   grub_unregister_extcmd (oldcmd);
diff --git a/SOURCES/0116-Add-linux-and-initrd-commands-for-grub-emu.patch b/SOURCES/0116-Add-linux-and-initrd-commands-for-grub-emu.patch
new file mode 100644
index 0000000..d2368f3
--- /dev/null
+++ b/SOURCES/0116-Add-linux-and-initrd-commands-for-grub-emu.patch
@@ -0,0 +1,347 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Tue, 6 Feb 2018 09:09:00 +0100
+Subject: [PATCH] Add linux and initrd commands for grub-emu
+
+When using grub-emu, the linux and initrd commands are used as arguments
+to the kexec command line tool, to allow booting the selected menu entry.
+---
+ grub-core/Makefile.core.def  |   1 -
+ grub-core/kern/emu/main.c    |   4 +
+ grub-core/kern/emu/misc.c    |  18 ++++-
+ grub-core/loader/emu/linux.c | 172 +++++++++++++++++++++++++++++++++++++++++++
+ include/grub/emu/exec.h      |   4 +-
+ include/grub/emu/hostfile.h  |   3 +-
+ include/grub/emu/misc.h      |   3 +
+ grub-core/Makefile.am        |   1 +
+ 8 files changed, 202 insertions(+), 4 deletions(-)
+ create mode 100644 grub-core/loader/emu/linux.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index e52d776887a..067b97a4221 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -1710,7 +1710,6 @@ module = {
+ 
+   common = loader/linux.c;
+   common = lib/cmdline.c;
+-  enable = noemu;
+ 
+   efi = loader/efi/linux.c;
+ };
+diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c
+index 55ea5a11ccd..846fe9715ec 100644
+--- a/grub-core/kern/emu/main.c
++++ b/grub-core/kern/emu/main.c
+@@ -107,6 +107,7 @@ static struct argp_option options[] = {
+    N_("use GRUB files in the directory DIR [default=%s]"), 0},
+   {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
+   {"hold",     'H', N_("SECS"),      OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0},
++  {"kexec",       'X', 0,      0, N_("try the untryable."), 0},
+   { 0, 0, 0, 0, 0, 0 }
+ };
+ 
+@@ -164,6 +165,9 @@ argp_parser (int key, char *arg, struct argp_state *state)
+     case 'v':
+       verbosity++;
+       break;
++    case 'X':
++      grub_util_set_kexecute();
++      break;
+ 
+     case ARGP_KEY_ARG:
+       {
+diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c
+index 82012a72fcb..3d3a4a4a975 100644
+--- a/grub-core/kern/emu/misc.c
++++ b/grub-core/kern/emu/misc.c
+@@ -37,6 +37,7 @@
+ #include <grub/emu/misc.h>
+ 
+ int verbosity;
++int kexecute;
+ 
+ void
+ grub_util_warn (const char *fmt, ...)
+@@ -80,7 +81,7 @@ grub_util_error (const char *fmt, ...)
+   vfprintf (stderr, fmt, ap);
+   va_end (ap);
+   fprintf (stderr, ".\n");
+-  exit (1);
++  grub_exit (1);
+ }
+ 
+ void *
+@@ -140,6 +141,9 @@ void
+ __attribute__ ((noreturn))
+ grub_exit (int rc)
+ {
++#if defined (GRUB_KERNEL)
++  grub_reboot();
++#endif
+   exit (rc < 0 ? 1 : rc);
+ }
+ #endif
+@@ -201,3 +205,15 @@ grub_util_load_image (const char *path, char *buf)
+ 
+   fclose (fp);
+ }
++
++void
++grub_util_set_kexecute(void)
++{
++  kexecute++;
++}
++
++int
++grub_util_get_kexecute(void)
++{
++  return kexecute;
++}
+diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c
+new file mode 100644
+index 00000000000..fda9e00d24c
+--- /dev/null
++++ b/grub-core/loader/emu/linux.c
+@@ -0,0 +1,172 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/loader.h>
++#include <grub/dl.h>
++#include <grub/command.h>
++#include <grub/time.h>
++
++#include <grub/emu/exec.h>
++#include <grub/emu/hostfile.h>
++#include <grub/emu/misc.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static grub_dl_t my_mod;
++
++static char *kernel_path;
++static char *initrd_path;
++static char *boot_cmdline;
++
++static grub_err_t
++grub_linux_boot (void)
++{
++  grub_err_t rc = GRUB_ERR_NONE;
++  char *initrd_param;
++  const char *kexec[] = { "kexec", "-l", kernel_path, boot_cmdline, NULL, NULL };
++  const char *systemctl[] = { "systemctl", "kexec", NULL };
++  int kexecute = grub_util_get_kexecute();
++
++  if (initrd_path) {
++    initrd_param = grub_xasprintf("--initrd=%s", initrd_path);
++    kexec[3] = initrd_param;
++    kexec[4] = boot_cmdline;
++  } else {
++    initrd_param = grub_xasprintf("%s", "");
++  }
++
++  grub_printf("%serforming 'kexec -l %s %s %s'\n",
++	(kexecute) ? "P" : "Not p",
++	kernel_path, initrd_param, boot_cmdline);
++
++  if (kexecute)
++    rc = grub_util_exec(kexec);
++
++  grub_free(initrd_param);
++
++  if (rc != GRUB_ERR_NONE) {
++    grub_error (rc, N_("Error trying to perform kexec load operation."));
++    grub_sleep (3);
++    return rc;
++  }
++  if (kexecute < 1)
++    grub_fatal (N_("Use '"PACKAGE"-emu --kexec' to force a system restart."));
++
++  grub_printf("Performing 'systemctl kexec' (%s) ",
++		(kexecute==1) ? "do-or-die" : "just-in-case");
++  rc = grub_util_exec (systemctl);
++
++  if (kexecute == 1)
++    grub_fatal (N_("Error trying to perform 'systemctl kexec'"));
++
++  /* need to check read-only root before resetting hard!? */
++  grub_printf("Performing 'kexec -e'");
++  kexec[1] = "-e";
++  kexec[2] = NULL;
++  rc = grub_util_exec(kexec);
++  if ( rc != GRUB_ERR_NONE )
++    grub_fatal (N_("Error trying to directly perform 'kexec -e'."));
++
++  return rc;
++}
++
++static grub_err_t
++grub_linux_unload (void)
++{
++  grub_dl_unref (my_mod);
++  if ( boot_cmdline != NULL )
++    grub_free (boot_cmdline);
++  boot_cmdline = NULL;
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[])
++{
++  int i;
++  char *tempstr;
++
++  grub_dl_ref (my_mod);
++
++  if (argc == 0)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
++
++  if ( !grub_util_is_regular(argv[0]) )
++    return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("Cannot find kernel file %s"), argv[0]);
++
++  if ( kernel_path != NULL )
++    grub_free(kernel_path);
++
++  kernel_path = grub_xasprintf("%s", argv[0]);
++
++  if ( boot_cmdline != NULL ) {
++    grub_free(boot_cmdline);
++    boot_cmdline = NULL;
++  }
++
++  if ( argc > 1 )
++  {
++    boot_cmdline = grub_xasprintf("--command-line=%s", argv[1]);
++    for ( i = 2; i < argc; i++ ) {
++      tempstr = grub_xasprintf("%s %s", boot_cmdline, argv[i]);
++      grub_free(boot_cmdline);
++      boot_cmdline = tempstr;
++    }
++  }
++
++  grub_loader_set (grub_linux_boot, grub_linux_unload, 0);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[])
++{
++  if (argc == 0)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
++
++  if ( !grub_util_is_regular(argv[0]) )
++    return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("Cannot find initrd file %s"), argv[0]);
++
++  if ( initrd_path != NULL )
++    grub_free(initrd_path);
++
++  initrd_path = grub_xasprintf("%s", argv[0]);
++
++  grub_dl_unref (my_mod);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_command_t cmd_linux, cmd_initrd;
++
++GRUB_MOD_INIT(linux)
++{
++  cmd_linux = grub_register_command ("linux", grub_cmd_linux, 0, N_("Load Linux."));
++  cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, 0, N_("Load initrd."));
++  my_mod = mod;
++  kernel_path = NULL;
++  initrd_path = NULL;
++  boot_cmdline = NULL;
++}
++
++GRUB_MOD_FINI(linux)
++{
++  grub_unregister_command (cmd_linux);
++  grub_unregister_command (cmd_initrd);
++}
+diff --git a/include/grub/emu/exec.h b/include/grub/emu/exec.h
+index d1073ef86af..1b61b4a2e5d 100644
+--- a/include/grub/emu/exec.h
++++ b/include/grub/emu/exec.h
+@@ -23,6 +23,8 @@
+ #include <stdarg.h>
+ 
+ #include <sys/types.h>
++#include <grub/symbol.h>
++
+ pid_t
+ grub_util_exec_pipe (const char *const *argv, int *fd);
+ pid_t
+@@ -32,7 +34,7 @@ int
+ grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file,
+ 			     const char *stdout_file, const char *stderr_file);
+ int
+-grub_util_exec (const char *const *argv);
++EXPORT_FUNC(grub_util_exec) (const char *const *argv);
+ int
+ grub_util_exec_redirect (const char *const *argv, const char *stdin_file,
+ 			 const char *stdout_file);
+diff --git a/include/grub/emu/hostfile.h b/include/grub/emu/hostfile.h
+index 8e37d5acb42..12c937a1af9 100644
+--- a/include/grub/emu/hostfile.h
++++ b/include/grub/emu/hostfile.h
+@@ -22,6 +22,7 @@
+ #include <grub/disk.h>
+ #include <grub/partition.h>
+ #include <sys/types.h>
++#include <grub/symbol.h>
+ #include <grub/osdep/hostfile.h>
+ 
+ int
+@@ -29,7 +30,7 @@ grub_util_is_directory (const char *path);
+ int
+ grub_util_is_special_file (const char *path);
+ int
+-grub_util_is_regular (const char *path);
++EXPORT_FUNC(grub_util_is_regular) (const char *path);
+ 
+ char *
+ grub_util_path_concat (size_t n, ...);
+diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h
+index df6085bcb7c..a653132e36a 100644
+--- a/include/grub/emu/misc.h
++++ b/include/grub/emu/misc.h
+@@ -60,6 +60,9 @@ void EXPORT_FUNC(grub_util_warn) (const char *fmt, ...) __attribute__ ((format (
+ void EXPORT_FUNC(grub_util_info) (const char *fmt, ...) __attribute__ ((format (__printf__, 1, 2)));
+ void EXPORT_FUNC(grub_util_error) (const char *fmt, ...) __attribute__ ((format (__printf__, 1, 2), noreturn));
+ 
++void EXPORT_FUNC(grub_util_set_kexecute) (void);
++int EXPORT_FUNC(grub_util_get_kexecute) (void) WARN_UNUSED_RESULT;
++
+ grub_uint64_t EXPORT_FUNC (grub_util_get_cpu_time_ms) (void);
+ 
+ #ifdef HAVE_DEVICE_MAPPER
+diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
+index 9c69aa88626..0108c0d4233 100644
+--- a/grub-core/Makefile.am
++++ b/grub-core/Makefile.am
+@@ -274,6 +274,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/net.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostdisk.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostfile.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/exec.h
+ if COND_GRUB_EMU_SDL
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h
+ endif
diff --git a/SOURCES/0117-Fix-the-efidir-in-grub-setpassword.patch b/SOURCES/0117-Fix-the-efidir-in-grub-setpassword.patch
new file mode 100644
index 0000000..2d815e2
--- /dev/null
+++ b/SOURCES/0117-Fix-the-efidir-in-grub-setpassword.patch
@@ -0,0 +1,24 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 15 Mar 2018 14:12:54 -0400
+Subject: [PATCH] Fix the efidir in grub-setpassword
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-setpassword.in | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub-setpassword.in b/util/grub-setpassword.in
+index d7924af5192..cf70257eed6 100644
+--- a/util/grub-setpassword.in
++++ b/util/grub-setpassword.in
+@@ -1,7 +1,8 @@
+ #!/bin/sh -e
+ 
++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/')
+ if [ -d /sys/firmware/efi/efivars/ ]; then
+-    grubdir=`echo "/@bootdirname@/efi/EFI/redhat/" | sed 's,//*,/,g'`
++    grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
+ else
+     grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
+ fi
diff --git a/SOURCES/0118-Add-grub2-switch-to-blscfg.patch b/SOURCES/0118-Add-grub2-switch-to-blscfg.patch
new file mode 100644
index 0000000..17984a2
--- /dev/null
+++ b/SOURCES/0118-Add-grub2-switch-to-blscfg.patch
@@ -0,0 +1,345 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 15 Mar 2018 14:12:40 -0400
+Subject: [PATCH] Add grub2-switch-to-blscfg
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ Makefile.util.def             |   7 ++
+ .gitignore                    |   2 +
+ util/grub-switch-to-blscfg.8  |  25 ++++
+ util/grub-switch-to-blscfg.in | 262 ++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 296 insertions(+)
+ create mode 100644 util/grub-switch-to-blscfg.8
+ create mode 100644 util/grub-switch-to-blscfg.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 879e8eb98a4..f4fbd250630 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -1348,6 +1348,13 @@ program = {
+   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
+ };
+ 
++script = {
++  name = grub-switch-to-blscfg;
++  common = util/grub-switch-to-blscfg.in;
++  mansection = 8;
++  installdir = sbin;
++};
++
+ program = {
+   name = grub-glue-efi;
+   mansection = 1;
+diff --git a/.gitignore b/.gitignore
+index 54795fa60be..42475592123 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -121,6 +121,8 @@ grub-*.tar.*
+ /grub*-sparc64-setup.8
+ /grub*-syslinux2cfg
+ /grub*-syslinux2cfg.1
++/grub*-switch-to-blscfg
++/grub*-switch-to-blscfg.8
+ /grub_fstest.pp
+ /grub_fstest_init.c
+ /grub_fstest_init.lst
+diff --git a/util/grub-switch-to-blscfg.8 b/util/grub-switch-to-blscfg.8
+new file mode 100644
+index 00000000000..134dfc62a7b
+--- /dev/null
++++ b/util/grub-switch-to-blscfg.8
+@@ -0,0 +1,25 @@
++.TH GRUB-SWITCH-TO-BLSCFG 1 "Wed Feb 26 2014"
++.SH NAME
++\fBgrub-switch-to-blscfg\fR \(em Switch to using BLS config files.
++
++.SH SYNOPSIS
++\fBgrub-switch-to-blscfg\fR [--grub-directory=\fIDIR\fR] [--config-file=\fIFILE\fR] [--grub-defaults=\fIFILE\fR]
++
++.SH DESCRIPTION
++\fBgrub-switch-to-blscfg\fR reconfigures grub-mkconfig to use BLS-style config files, and then regenerates the GRUB configuration.
++
++.SH OPTIONS
++.TP
++--grub-directory=\fIDIR\fR
++Search for grub.cfg under \fIDIR\fR.  The default value is \fI/boot/efi/EFI/\fBVENDOR\fR on UEFI machines and \fI/boot/grub2\fR elsewhere.
++
++.TP
++--config-file=\fIFILE\fR
++The grub config file to use.  The default value is \fI/etc/grub2-efi.cfg\fR on UEFI machines and \fI/etc/grub2.cfg\fR elsewhere.  Symbolic links will be followed.
++
++.TP
++--grub-defaults=\fIFILE\fR
++The defaults file for grub-mkconfig.  The default value is \fI/etc/default/grub\fR.
++
++.SH SEE ALSO
++.BR "info grub"
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+new file mode 100644
+index 00000000000..3ae5e4ea8d0
+--- /dev/null
++++ b/util/grub-switch-to-blscfg.in
+@@ -0,0 +1,262 @@
++#! /bin/sh
++#
++# Set a default boot entry for GRUB.
++# Copyright (C) 2004,2009  Free Software Foundation, Inc.
++#
++# GRUB is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# GRUB is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++
++#set -eu
++
++# Initialize some variables.
++prefix=@prefix@
++exec_prefix=@exec_prefix@
++bindir=@bindir@
++sysconfdir="@sysconfdir@"
++PACKAGE_NAME=@PACKAGE_NAME@
++PACKAGE_VERSION=@PACKAGE_VERSION@
++datarootdir="@datarootdir@"
++datadir="@datadir@"
++if [ ! -v pkgdatadir ]; then
++    pkgdatadir="${datadir}/@PACKAGE@"
++fi
++
++self=`basename $0`
++
++grub_editenv=${bindir}/@grub_editenv@
++etcdefaultgrub=/etc/default/grub
++
++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/')
++if [ -d /sys/firmware/efi/efivars/ ]; then
++    startlink=/etc/grub2-efi.cfg
++    grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
++    blsdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/loader/entries" | sed 's,//*,/,g'`
++else
++    startlink=/etc/grub2.cfg
++    grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
++    blsdir=`echo "/@bootdirname@" | sed 's,//*,/,g'`
++fi
++
++backupsuffix=.bak
++
++export TEXTDOMAIN=@PACKAGE@
++export TEXTDOMAINDIR="@localedir@"
++
++. "${pkgdatadir}/grub-mkconfig_lib"
++
++# Usage: usage
++# Print the usage.
++usage () {
++    gettext_printf "Usage: %s\n" "$self"
++    gettext "Switch to BLS config files.\n"; echo
++    echo
++    print_option_help "-h, --help" "$(gettext "print this message and exit")"
++    print_option_help "-V, --version" "$(gettext "print the version information and exit")"
++    echo
++    print_option_help "--backup-suffix=$(gettext "SUFFIX")" "$backupsuffix"
++    print_option_help "--bls-directory=$(gettext "DIR")" "$blsdir"
++    print_option_help "--config-file=$(gettext "FILE")" "$startlink"
++    print_option_help "--grub-defaults=$(gettext "FILE")" "$etcdefaultgrub"
++    print_option_help "--grub-directory=$(gettext "DIR")" "$grubdir"
++    # echo
++    # gettext "Report bugs to <bug-grub@gnu.org>."; echo
++}
++
++argument () {
++    opt=$1
++    shift
++
++    if test $# -eq 0; then
++        gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2
++        exit 1
++    fi
++    echo $1
++}
++
++# Check the arguments.
++while test $# -gt 0
++do
++    option=$1
++    shift
++
++    case "$option" in
++    -h | --help)
++        usage
++        exit 0 ;;
++    -V | --version)
++        echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}"
++        exit 0 ;;
++
++    --backup-suffix)
++        backupsuffix=`argument $option "$@"`
++        shift
++        ;;
++    --backup-suffix=*)
++        backupsuffix=`echo "$option" | sed 's/--backup-suffix=//'`
++        ;;
++
++    --bls-directory)
++        blsdir=`argument $option "$@"`
++        shift
++        ;;
++    --bls-directory=*)
++        blsdir=`echo "$option" | sed 's/--bls-directory=//'`
++        ;;
++
++    --config-file)
++        startlink=`argument $option "$@"`
++        shift
++        ;;
++    --config-file=*)
++        startlink=`echo "$option" | sed 's/--config-file=//'`
++        ;;
++
++    --grub-defaults)
++        etcdefaultgrub=`argument $option "$@"`
++        shift
++        ;;
++    --grub-defaults=*)
++        etcdefaultgrub=`echo "$option" | sed 's/--grub-defaults=//'`
++        ;;
++
++    --grub-directory)
++        grubdir=`argument $option "$@"`
++        shift
++        ;;
++    --grub-directory=*)
++        grubdir=`echo "$option" | sed 's/--grub-directory=//'`
++        ;;
++
++    *)
++        gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2
++        usage
++        exit 1
++        ;;
++    esac
++done
++
++find_grub_cfg() {
++    local candidate=""
++    while [[ -e "${candidate}" || $# -gt 0 ]]
++    do
++        if [[ ! -e "${candidate}" ]] ; then
++            candidate="$1"
++            shift
++        fi
++
++        if [[ -L "${candidate}" ]]; then
++            candidate="$(realpath "${candidate}")"
++        fi
++
++        if [[ -f "${candidate}" ]]; then
++            export GRUB_CONFIG_FILE="${candidate}"
++            return 0
++        fi
++    done
++    return 1
++}
++
++if ! find_grub_cfg ${startlink} ${grubdir}/grub.cfg ; then
++  gettext_printf "Couldn't find config file\n" 1>&2
++  exit 1
++fi
++
++if [[ ! -d "${blsdir}" ]]; then
++    install -m 700 -d "${blsdir}"
++fi
++
++if [[ -f /etc/machine-id ]]; then
++    MACHINE_ID=$(cat /etc/machine-id)
++else
++    MACHINE_ID=$(dmesg | sha256sum)
++fi
++
++mkbls() {
++    local kernelver=$1 && shift
++    local datetime=$1 && shift
++
++    local debugname=""
++    local flavor=""
++
++    if [[ "$kernelver" == *\+* ]] ; then
++        local flavor=-"${kernelver##*+}"
++        if [[ "${flavor}" == "-debug" ]]; then
++            local debugname=" with debugging"
++        fi
++    fi
++    (
++        source /etc/os-release
++
++        cat <<EOF
++title ${NAME} (${kernelver}) ${VERSION}${debugname}
++linux /vmlinuz-${kernelver}
++initrd /initramfs-${kernelver}.img
++options \$kernelopts
++id ${ID}-${datetime}-${kernelver}
++grub_users \$grub_users
++grub_arg --unrestricted
++grub_class kernel${flavor}
++EOF
++    ) | cat
++}
++
++for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
++    if [[ ! -d "/lib/modules/${kernelver}" ]] ; then
++        continue
++    fi
++    if [[ ! -f "/boot/vmlinuz-${kernelver}" ]]; then
++        continue
++    fi
++    bls_target="${blsdir}/${MACHINE_ID}-${kernelver}.conf"
++    kernel_dir="/lib/modules/${kernelver}"
++    if [[ -f "${kernel_dir}/bls.conf" ]]; then
++        cp -af "${kernel_dir}/bls.conf" "${bls_target}"
++    else
++        mkbls "${kernelver}" \
++            "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${kernel_dir}")")" \
++            >"${bls_target}"
++    fi
++done
++
++GENERATE=0
++if grep '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" \
++        | grep -vq '^GRUB_ENABLE_BLSCFG="*true"*\s*$' ; then
++    if ! sed -i"${backupsuffix}" \
++            -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=true,' \
++            "${etcdefaultgrub}" ; then
++        gettext_printf "Updating %s failed\n" "${etcdefaultgrub}"
++        exit 1
++    fi
++    GENERATE=1
++elif ! grep -q '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" ; then
++    if ! echo 'GRUB_ENABLE_BLSCFG=true' >> "${etcdefaultgrub}" ; then
++        gettext_printf "Updating %s failed\n" "${etcdefaultgrub}"
++        exit 1
++    fi
++    GENERATE=1
++fi
++
++if [[ "${GENERATE}" -eq 1 ]] ; then
++    cp -af "${GRUB_CONFIG_FILE}" "${GRUB_CONFIG_FILE}${backupsuffix}"
++    if ! grub2-mkconfig -o "${GRUB_CONFIG_FILE}" ; then
++        cp -af "${GRUB_CONFIG_FILE}${backupsuffix}" "${GRUB_CONFIG_FILE}"
++        sed -i"${backupsuffix}" \
++            -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=false,' \
++            /etc/default/grub
++        gettext_printf "Updating %s failed\n" "${GRUB_CONFIG_FILE}"
++        exit 1
++    fi
++fi
++
++# Bye.
++exit 0
diff --git a/SOURCES/0119-Add-grub_debug_enabled.patch b/SOURCES/0119-Add-grub_debug_enabled.patch
new file mode 100644
index 0000000..d8e4bde
--- /dev/null
+++ b/SOURCES/0119-Add-grub_debug_enabled.patch
@@ -0,0 +1,60 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 30 Nov 2017 15:11:39 -0500
+Subject: [PATCH] Add grub_debug_enabled()
+
+---
+ grub-core/kern/misc.c | 21 ++++++++++++++++-----
+ include/grub/misc.h   |  1 +
+ 2 files changed, 17 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 636f97e1ba1..e758ab3416d 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -159,17 +159,28 @@ int grub_err_printf (const char *fmt, ...)
+ __attribute__ ((alias("grub_printf")));
+ #endif
+ 
++int
++grub_debug_enabled (const char * condition)
++{
++  const char *debug;
++
++  debug = grub_env_get ("debug");
++  if (!debug)
++    return 0;
++
++  if (grub_strword (debug, "all") || grub_strword (debug, condition))
++    return 1;
++
++  return 0;
++}
++
+ void
+ grub_real_dprintf (const char *file, const int line, const char *condition,
+ 		   const char *fmt, ...)
+ {
+   va_list args;
+-  const char *debug = grub_env_get ("debug");
+ 
+-  if (! debug)
+-    return;
+-
+-  if (grub_strword (debug, "all") || grub_strword (debug, condition))
++  if (grub_debug_enabled (condition))
+     {
+       grub_printf ("%s:%d: ", file, line);
+       va_start (args, fmt);
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index cbfae75a1b4..f7473c154f0 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -367,6 +367,7 @@ grub_puts (const char *s)
+ }
+ 
+ int EXPORT_FUNC(grub_puts_) (const char *s);
++int EXPORT_FUNC(grub_debug_enabled) (const char *condition);
+ void EXPORT_FUNC(grub_real_dprintf) (const char *file,
+                                      const int line,
+                                      const char *condition,
diff --git a/SOURCES/0120-make-better-backtraces.patch b/SOURCES/0120-make-better-backtraces.patch
new file mode 100644
index 0000000..e017c77
--- /dev/null
+++ b/SOURCES/0120-make-better-backtraces.patch
@@ -0,0 +1,908 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 6 Nov 2017 18:31:56 -0500
+Subject: [PATCH] make better backtraces
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ Makefile.util.def                       |   6 ++
+ grub-core/Makefile.core.def             |  15 ++--
+ grub-core/{lib => commands}/backtrace.c |   2 +-
+ grub-core/gdb/cstub.c                   |   1 -
+ grub-core/kern/arm64/backtrace.c        |  94 ++++++++++++++++++++++++
+ grub-core/kern/backtrace.c              |  97 +++++++++++++++++++++++++
+ grub-core/kern/dl.c                     |  45 ++++++++++++
+ grub-core/kern/i386/backtrace.c         | 125 ++++++++++++++++++++++++++++++++
+ grub-core/kern/i386/pc/init.c           |   4 +-
+ grub-core/kern/ieee1275/init.c          |   1 -
+ grub-core/kern/misc.c                   |  13 ++--
+ grub-core/kern/mm.c                     |   6 +-
+ grub-core/lib/arm64/backtrace.c         |  62 ----------------
+ grub-core/lib/i386/backtrace.c          |  78 --------------------
+ include/grub/backtrace.h                |  10 ++-
+ include/grub/dl.h                       |   2 +
+ include/grub/kernel.h                   |   3 +
+ grub-core/kern/arm/efi/startup.S        |   2 +
+ grub-core/kern/arm/startup.S            |   2 +
+ grub-core/kern/arm64/efi/startup.S      |   2 +
+ grub-core/kern/i386/qemu/startup.S      |   3 +-
+ grub-core/kern/ia64/efi/startup.S       |   3 +-
+ grub-core/kern/sparc64/ieee1275/crt0.S  |   3 +-
+ grub-core/Makefile.am                   |   1 +
+ 24 files changed, 414 insertions(+), 166 deletions(-)
+ rename grub-core/{lib => commands}/backtrace.c (98%)
+ create mode 100644 grub-core/kern/arm64/backtrace.c
+ create mode 100644 grub-core/kern/backtrace.c
+ create mode 100644 grub-core/kern/i386/backtrace.c
+ delete mode 100644 grub-core/lib/arm64/backtrace.c
+ delete mode 100644 grub-core/lib/i386/backtrace.c
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index f4fbd250630..cbd661d6348 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -49,6 +49,12 @@ library = {
+   common = grub-core/partmap/msdos.c;
+   common = grub-core/fs/proc.c;
+   common = grub-core/fs/archelp.c;
++  common = grub-core/kern/backtrace.c;
++
++  x86 = grub-core/kern/i386/backtrace.c;
++  i386_xen = grub-core/kern/i386/backtrace.c;
++  x86_64_xen = grub-core/kern/i386/backtrace.c;
++  arm64 = grub-core/kern/arm64/backtrace.c;
+ };
+ 
+ library = {
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 067b97a4221..cb24f92a431 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -130,6 +130,12 @@ kernel = {
+   common = kern/rescue_reader.c;
+   common = kern/term.c;
+   common = kern/qsort.c;
++  common = kern/backtrace.c;
++
++  x86 = kern/i386/backtrace.c;
++  i386_xen = kern/i386/backtrace.c;
++  x86_64_xen = kern/i386/backtrace.c;
++  arm64 = kern/arm64/backtrace.c;
+ 
+   noemu = kern/compiler-rt.c;
+   noemu = kern/mm.c;
+@@ -176,9 +182,6 @@ kernel = {
+ 
+   softdiv = lib/division.c;
+ 
+-  x86 = lib/i386/backtrace.c;
+-  x86 = lib/backtrace.c;
+-
+   i386 = kern/i386/dl.c;
+   i386_xen = kern/i386/dl.c;
+ 
+@@ -2277,13 +2280,11 @@ module = {
+ 
+ module = {
+   name = backtrace;
+-  x86 = lib/i386/backtrace.c;
+-  i386_xen = lib/i386/backtrace.c;
+-  x86_64_xen = lib/i386/backtrace.c;
+-  common = lib/backtrace.c;
++  common = commands/backtrace.c;
+   enable = x86;
+   enable = i386_xen;
+   enable = x86_64_xen;
++  enable = arm64;
+ };
+ 
+ module = {
+diff --git a/grub-core/lib/backtrace.c b/grub-core/commands/backtrace.c
+similarity index 98%
+rename from grub-core/lib/backtrace.c
+rename to grub-core/commands/backtrace.c
+index c0ad6ab8be1..8b5ec3913b5 100644
+--- a/grub-core/lib/backtrace.c
++++ b/grub-core/commands/backtrace.c
+@@ -54,7 +54,7 @@ grub_cmd_backtrace (grub_command_t cmd __attribute__ ((unused)),
+ 		    int argc __attribute__ ((unused)),
+ 		    char **args __attribute__ ((unused)))
+ {
+-  grub_backtrace ();
++  grub_backtrace (1);
+   return 0;
+ }
+ 
+diff --git a/grub-core/gdb/cstub.c b/grub-core/gdb/cstub.c
+index b64acd70fee..99281472d36 100644
+--- a/grub-core/gdb/cstub.c
++++ b/grub-core/gdb/cstub.c
+@@ -215,7 +215,6 @@ grub_gdb_trap (int trap_no)
+       grub_printf ("Unhandled exception 0x%x at ", trap_no);
+       grub_backtrace_print_address ((void *) grub_gdb_regs[PC]);
+       grub_printf ("\n");
+-      grub_backtrace_pointer ((void *) grub_gdb_regs[EBP]);
+       grub_fatal ("Unhandled exception");
+     }
+ 
+diff --git a/grub-core/kern/arm64/backtrace.c b/grub-core/kern/arm64/backtrace.c
+new file mode 100644
+index 00000000000..019c6fdfef2
+--- /dev/null
++++ b/grub-core/kern/arm64/backtrace.c
+@@ -0,0 +1,94 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/misc.h>
++#include <grub/command.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/backtrace.h>
++
++#define MAX_STACK_FRAME 102400
++
++struct fplr
++{
++  void *lr;
++  struct fplr *fp;
++};
++
++void
++grub_backtrace_pointer (void *frame, unsigned int skip)
++{
++  unsigned int x = 0;
++  struct fplr *fplr = (struct fplr *)frame;
++
++  while (fplr)
++    {
++      const char *name = NULL;
++      char *addr = NULL;
++
++      grub_dprintf("backtrace", "fp is %p next_fp is %p\n",
++		   fplr, fplr->fp);
++
++      if (x >= skip)
++	{
++	  name = grub_get_symbol_by_addr (fplr->lr, 1);
++	  if (name)
++	    addr = grub_resolve_symbol (name);
++	  grub_backtrace_print_address (fplr->lr);
++
++	  if (addr && addr != fplr->lr)
++	    grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr,
++			 (void *)((grub_uint64_t)fplr->lr - (grub_uint64_t)addr));
++	  else
++	    grub_printf(" %s() %p \n", name ? name : "unknown", addr);
++
++	}
++
++      x += 1;
++
++      if (fplr->fp < fplr ||
++	  (grub_uint64_t)fplr->fp - (grub_uint64_t)fplr > MAX_STACK_FRAME ||
++	  fplr->fp == fplr)
++	{
++	  break;
++	}
++      fplr = fplr->fp;
++    }
++}
++
++asm ("\t.global \"_text\"\n"
++     "_text:\n"
++     "\t.quad .text\n"
++     "\t.global \"_data\"\n"
++     "_data:\n"
++     "\t.quad .data\n"
++     );
++
++extern grub_uint64_t _text;
++extern grub_uint64_t _data;
++
++void
++grub_backtrace_arch (unsigned int skip)
++{
++  grub_printf ("Backtrace (.text %p .data %p):\n",
++	       (void *)_text, (void *)_data);
++  skip += 1;
++  grub_backtrace_pointer(__builtin_frame_address(0), skip);
++}
+diff --git a/grub-core/kern/backtrace.c b/grub-core/kern/backtrace.c
+new file mode 100644
+index 00000000000..4a82e865cc6
+--- /dev/null
++++ b/grub-core/kern/backtrace.c
+@@ -0,0 +1,97 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/misc.h>
++#include <grub/command.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/backtrace.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static void
++grub_backtrace_print_address_default (void *addr)
++{
++#ifndef GRUB_UTIL
++  grub_dl_t mod;
++  void *start_addr;
++
++  FOR_DL_MODULES (mod)
++  {
++    grub_dl_segment_t segment;
++    for (segment = mod->segment; segment; segment = segment->next)
++      if (segment->addr <= addr && (grub_uint8_t *) segment->addr
++	  + segment->size > (grub_uint8_t *) addr)
++	{
++	  grub_printf ("%s.%x+%" PRIxGRUB_SIZE, mod->name,
++		       segment->section,
++		       (grub_size_t)
++		       ((grub_uint8_t *)addr - (grub_uint8_t *)segment->addr));
++	  return;
++	}
++  }
++
++  start_addr = grub_resolve_symbol ("_start");
++  if (start_addr && start_addr < addr)
++    grub_printf ("kernel+%" PRIxGRUB_SIZE,
++		 (grub_size_t)
++		  ((grub_uint8_t *)addr - (grub_uint8_t *)start_addr));
++  else
++#endif
++    grub_printf ("%p", addr);
++}
++
++static void
++grub_backtrace_pointer_default (void *frame __attribute__((__unused__)),
++				unsigned int skip __attribute__((__unused__)))
++{
++  return;
++}
++
++void
++grub_backtrace_pointer (void *frame, unsigned int skip)
++     __attribute__((__weak__,
++		    __alias__(("grub_backtrace_pointer_default"))));
++
++void
++grub_backtrace_print_address (void *addr)
++     __attribute__((__weak__,
++		    __alias__(("grub_backtrace_print_address_default"))));
++
++static void
++grub_backtrace_arch_default(unsigned int skip)
++{
++  grub_backtrace_pointer(__builtin_frame_address(0), skip + 1);
++}
++
++void grub_backtrace_arch (unsigned int skip)
++     __attribute__((__weak__, __alias__(("grub_backtrace_arch_default"))));
++
++void grub_backtrace (unsigned int skip)
++{
++  grub_backtrace_arch(skip + 1);
++}
++
++void grub_debug_backtrace (const char * const debug,
++			   unsigned int skip)
++{
++  if (grub_debug_enabled (debug))
++    grub_backtrace (skip + 1);
++}
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index 621070918d4..5028d157c46 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -124,6 +124,50 @@ grub_dl_resolve_symbol (const char *name)
+   return 0;
+ }
+ 
++void *
++grub_resolve_symbol (const char *name)
++{
++	grub_symbol_t sym;
++
++	sym = grub_dl_resolve_symbol (name);
++	if (sym)
++		return sym->addr;
++	return NULL;
++}
++
++const char *
++grub_get_symbol_by_addr(const void *addr, int isfunc)
++{
++  unsigned int i;
++  grub_symbol_t before = NULL, after = NULL;
++  for (i = 0; i < GRUB_SYMTAB_SIZE; i++)
++    {
++      grub_symbol_t sym;
++      for (sym = grub_symtab[i]; sym; sym = sym->next)
++	{
++	  //grub_printf ("addr 0x%08llx symbol %s\n", (unsigned long long)sym->addr, sym->name);
++	  if (sym->addr > addr)
++	    {
++	      if (!after || sym->addr > after->addr)
++		after = sym;
++	    }
++
++	  if (isfunc != sym->isfunc)
++	    continue;
++	  if (sym->addr > addr)
++	    continue;
++
++	  if ((!before && sym->addr <= addr) || (before && before->addr <= sym->addr))
++	    before = sym;
++	}
++    }
++
++  if (before && addr < after->addr)
++    return before->name;
++
++  return NULL;
++}
++
+ /* Register a symbol with the name NAME and the address ADDR.  */
+ grub_err_t
+ grub_dl_register_symbol (const char *name, void *addr, int isfunc,
+@@ -336,6 +380,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
+   const char *str;
+   Elf_Word size, entsize;
+ 
++  grub_dprintf ("modules", "Resolving symbols for \"%s\"\n", mod->name);
+   for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
+        i < e->e_shnum;
+        i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
+diff --git a/grub-core/kern/i386/backtrace.c b/grub-core/kern/i386/backtrace.c
+new file mode 100644
+index 00000000000..2413f9a57db
+--- /dev/null
++++ b/grub-core/kern/i386/backtrace.c
+@@ -0,0 +1,125 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/misc.h>
++#include <grub/command.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/mm.h>
++#include <grub/term.h>
++#include <grub/backtrace.h>
++
++#define MAX_STACK_FRAME 102400
++
++void
++grub_backtrace_pointer (void *frame, unsigned int skip)
++{
++  void **ebp = (void **)frame;
++  unsigned long x = 0;
++
++  while (ebp)
++    {
++      void **next_ebp = (void **)ebp[0];
++      const char *name = NULL;
++      char *addr = NULL;
++
++      grub_dprintf("backtrace", "ebp is %p next_ebp is %p\n", ebp, next_ebp);
++
++      if (x >= skip)
++	{
++	  name = grub_get_symbol_by_addr (ebp[1], 1);
++	  if (name)
++	    addr = grub_resolve_symbol (name);
++	  grub_backtrace_print_address (ebp[1]);
++
++	  if (addr && addr != ebp[1])
++	    grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr,
++			 (char *)((char *)ebp[1] - addr));
++	  else
++	    grub_printf(" %s() %p \n", name ? name : "unknown", addr);
++
++#if 0
++	  grub_printf ("(");
++	  for (i = 0, arg = ebp[2]; arg != next_ebp && i < 12; arg++, i++)
++	    grub_printf ("%p,", arg);
++	  grub_printf (")\n");
++#endif
++	}
++
++      x += 1;
++
++      if (next_ebp < ebp || next_ebp - ebp > MAX_STACK_FRAME || next_ebp == ebp)
++	{
++	  //grub_printf ("Invalid stack frame at %p (%p)\n", ebp, next_ebp);
++	  break;
++	}
++      ebp = next_ebp;
++    }
++}
++
++#if defined (__x86_64__)
++asm ("\t.global \"_text\"\n"
++     "_text:\n"
++     "\t.quad .text\n"
++     "\t.global \"_data\"\n"
++     "_data:\n"
++     "\t.quad .data\n"
++     );
++#elif defined(__i386__)
++asm ("\t.global \"_text\"\n"
++     "_text:\n"
++     "\t.long .text\n"
++     "\t.global \"_data\"\n"
++     "_data:\n"
++     "\t.long .data\n"
++     );
++#else
++#warning I dunno...
++#endif
++
++extern unsigned long _text;
++extern unsigned long _data;
++
++#ifdef GRUB_UTIL
++#define EXT_C(x) x
++#endif
++
++void
++grub_backtrace_arch (unsigned int skip)
++{
++  grub_printf ("Backtrace (.text %p .data %p):\n",
++	       (void *)_text, (void *)_data);
++  skip += 1;
++#if defined (__x86_64__)
++  asm volatile ("movq %%rbp, %%rdi\n"
++		"movq 0, %%rsi\n"
++		"movl %0, %%esi\n"
++		"call " EXT_C("grub_backtrace_pointer")
++		:
++		: "r" (skip));
++#elif defined(__i386__)
++  asm volatile ("addl $8, %%esp\n"
++		"pushl %0\n"
++		"pushl %%ebp\n"
++		"call " EXT_C("grub_backtrace_pointer")
++		:
++		: "r" (skip));
++#else
++  grub_backtrace_pointer(__builtin_frame_address(0), skip);
++#endif
++}
+diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c
+index 27bc68b8a53..b51d0abfa6e 100644
+--- a/grub-core/kern/i386/pc/init.c
++++ b/grub-core/kern/i386/pc/init.c
+@@ -153,7 +153,7 @@ compact_mem_regions (void)
+ }
+ 
+ grub_addr_t grub_modbase;
+-extern grub_uint8_t _start[], _edata[];
++extern grub_uint8_t _edata[];
+ 
+ /* Helper for grub_machine_init.  */
+ static int
+@@ -217,7 +217,7 @@ grub_machine_init (void)
+   /* This has to happen before any BIOS calls. */
+   grub_via_workaround_init ();
+ 
+-  grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start);
++  grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - (grub_uint8_t *)_start);
+ 
+   /* Initialize the console as early as possible.  */
+   grub_console_init ();
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index e01bc6eab19..e731a57a47b 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -60,7 +60,6 @@
+ #define HEAP_MAX_ADDR		(unsigned long) (32 * 1024 * 1024)
+ #endif
+ 
+-extern char _start[];
+ extern char _end[];
+ 
+ #ifdef __sparc__
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index e758ab3416d..5c2d2039d0b 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -1110,15 +1110,15 @@ grub_xasprintf (const char *fmt, ...)
+ }
+ 
+ /* Abort GRUB. This function does not return.  */
+-static void __attribute__ ((noreturn))
++static inline void __attribute__ ((noreturn))
+ grub_abort (void)
+ {
+-#ifndef GRUB_UTIL
+-#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU)
+-  grub_backtrace();
++#if !defined(GRUB_MACHINE_EMU) && !defined(GRUB_UTIL)
++  grub_backtrace (1);
++#else
++  grub_printf ("\n");
+ #endif
+-#endif
+-  grub_printf ("\nAborted.");
++  grub_printf ("Aborted.");
+ 
+ #ifndef GRUB_UTIL
+   if (grub_term_inputs)
+@@ -1145,6 +1145,7 @@ grub_fatal (const char *fmt, ...)
+ {
+   va_list ap;
+ 
++  grub_printf ("\n");
+   va_start (ap, fmt);
+   grub_vprintf (_(fmt), ap);
+   va_end (ap);
+diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
+index ee88ff61187..002cbfa4f3d 100644
+--- a/grub-core/kern/mm.c
++++ b/grub-core/kern/mm.c
+@@ -95,13 +95,13 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r)
+       break;
+ 
+   if (! *r)
+-    grub_fatal ("out of range pointer %p", ptr);
++    grub_fatal ("out of range pointer %p\n", ptr);
+ 
+   *p = (grub_mm_header_t) ptr - 1;
+   if ((*p)->magic == GRUB_MM_FREE_MAGIC)
+-    grub_fatal ("double free at %p", *p);
++    grub_fatal ("double free at %p\n", *p);
+   if ((*p)->magic != GRUB_MM_ALLOC_MAGIC)
+-    grub_fatal ("alloc magic is broken at %p: %lx", *p,
++    grub_fatal ("alloc magic is broken at %p: %lx\n", *p,
+ 		(unsigned long) (*p)->magic);
+ }
+ 
+diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c
+deleted file mode 100644
+index 1079b5380e1..00000000000
+--- a/grub-core/lib/arm64/backtrace.c
++++ /dev/null
+@@ -1,62 +0,0 @@
+-/*
+- *  GRUB  --  GRand Unified Bootloader
+- *  Copyright (C) 2009  Free Software Foundation, Inc.
+- *
+- *  GRUB is free software: you can redistribute it and/or modify
+- *  it under the terms of the GNU General Public License as published by
+- *  the Free Software Foundation, either version 3 of the License, or
+- *  (at your option) any later version.
+- *
+- *  GRUB is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+- */
+-
+-#include <grub/misc.h>
+-#include <grub/command.h>
+-#include <grub/err.h>
+-#include <grub/dl.h>
+-#include <grub/mm.h>
+-#include <grub/term.h>
+-#include <grub/backtrace.h>
+-
+-#define MAX_STACK_FRAME 102400
+-
+-void
+-grub_backtrace_pointer (int frame)
+-{
+-  while (1)
+-    {
+-      void *lp = __builtin_return_address (frame);
+-      if (!lp)
+-	break;
+-
+-      lp = __builtin_extract_return_addr (lp);
+-
+-      grub_printf ("%p: ", lp);
+-      grub_backtrace_print_address (lp);
+-      grub_printf (" (");
+-      for (i = 0; i < 2; i++)
+-	grub_printf ("%p,", ((void **)ptr) [i + 2]);
+-      grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
+-      nptr = *(void **)ptr;
+-      if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
+-	  || nptr == ptr)
+-	{
+-	  grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
+-	  break;
+-	}
+-      ptr = nptr;
+-    }
+-}
+-
+-void
+-grub_backtrace (void)
+-{
+-  grub_backtrace_pointer (1);
+-}
+-
+diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c
+deleted file mode 100644
+index c67273db3ae..00000000000
+--- a/grub-core/lib/i386/backtrace.c
++++ /dev/null
+@@ -1,78 +0,0 @@
+-/*
+- *  GRUB  --  GRand Unified Bootloader
+- *  Copyright (C) 2009  Free Software Foundation, Inc.
+- *
+- *  GRUB is free software: you can redistribute it and/or modify
+- *  it under the terms of the GNU General Public License as published by
+- *  the Free Software Foundation, either version 3 of the License, or
+- *  (at your option) any later version.
+- *
+- *  GRUB is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+- */
+-#include <config.h>
+-#ifdef GRUB_UTIL
+-#define REALLY_GRUB_UTIL GRUB_UTIL
+-#undef GRUB_UTIL
+-#endif
+-
+-#include <grub/symbol.h>
+-#include <grub/dl.h>
+-
+-#ifdef REALLY_GRUB_UTIL
+-#define GRUB_UTIL REALLY_GRUB_UTIL
+-#undef REALLY_GRUB_UTIL
+-#endif
+-
+-#include <grub/misc.h>
+-#include <grub/command.h>
+-#include <grub/err.h>
+-#include <grub/mm.h>
+-#include <grub/term.h>
+-#include <grub/backtrace.h>
+-
+-#define MAX_STACK_FRAME 102400
+-
+-void
+-grub_backtrace_pointer (void *ebp)
+-{
+-  void *ptr, *nptr;
+-  unsigned i;
+-
+-  ptr = ebp;
+-  while (1)
+-    {
+-      grub_printf ("%p: ", ptr);
+-      grub_backtrace_print_address (((void **) ptr)[1]);
+-      grub_printf (" (");
+-      for (i = 0; i < 2; i++)
+-	grub_printf ("%p,", ((void **)ptr) [i + 2]);
+-      grub_printf ("%p)\n", ((void **)ptr) [i + 2]);
+-      nptr = *(void **)ptr;
+-      if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME
+-	  || nptr == ptr)
+-	{
+-	  grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr);
+-	  break;
+-	}
+-      ptr = nptr;
+-    }
+-}
+-
+-void
+-grub_backtrace (void)
+-{
+-#ifdef __x86_64__
+-  asm volatile ("movq %%rbp, %%rdi\n"
+-		"callq *%%rax": :"a"(grub_backtrace_pointer));
+-#else
+-  asm volatile ("movl %%ebp, %%eax\n"
+-		"calll *%%ecx": :"c"(grub_backtrace_pointer));
+-#endif
+-}
+-
+diff --git a/include/grub/backtrace.h b/include/grub/backtrace.h
+index 395519762f0..275cf85e2d3 100644
+--- a/include/grub/backtrace.h
++++ b/include/grub/backtrace.h
+@@ -19,8 +19,14 @@
+ #ifndef GRUB_BACKTRACE_HEADER
+ #define GRUB_BACKTRACE_HEADER	1
+ 
+-void grub_backtrace (void);
+-void grub_backtrace_pointer (void *ptr);
++#include <grub/symbol.h>
++#include <grub/types.h>
++
++void EXPORT_FUNC(grub_debug_backtrace) (const char * const debug,
++					unsigned int skip);
++void EXPORT_FUNC(grub_backtrace) (unsigned int skip);
++void grub_backtrace_arch (unsigned int skip);
++void grub_backtrace_pointer (void *ptr, unsigned int skip);
+ void grub_backtrace_print_address (void *addr);
+ 
+ #endif
+diff --git a/include/grub/dl.h b/include/grub/dl.h
+index b1ed3c33317..7b5bfb07ce6 100644
+--- a/include/grub/dl.h
++++ b/include/grub/dl.h
+@@ -244,6 +244,8 @@ grub_dl_get (const char *name)
+ 
+ #endif
+ 
++void * EXPORT_FUNC(grub_resolve_symbol) (const char *name);
++const char * EXPORT_FUNC(grub_get_symbol_by_addr) (const void *addr, int isfunc);
+ grub_err_t grub_dl_register_symbol (const char *name, void *addr,
+ 				    int isfunc, grub_dl_t mod);
+ 
+diff --git a/include/grub/kernel.h b/include/grub/kernel.h
+index ecd88ca72c6..ae69218af20 100644
+--- a/include/grub/kernel.h
++++ b/include/grub/kernel.h
+@@ -108,6 +108,9 @@ grub_addr_t grub_modules_get_end (void);
+ 
+ #endif
+ 
++void EXPORT_FUNC(start) (void);
++void EXPORT_FUNC(_start) (void);
++
+ /* The start point of the C code.  */
+ void grub_main (void) __attribute__ ((noreturn));
+ 
+diff --git a/grub-core/kern/arm/efi/startup.S b/grub-core/kern/arm/efi/startup.S
+index 9f8265315a9..f3bc41f9d0f 100644
+--- a/grub-core/kern/arm/efi/startup.S
++++ b/grub-core/kern/arm/efi/startup.S
+@@ -23,6 +23,8 @@
+ 	.file 	"startup.S"
+ 	.text
+ 	.arm
++	.globl	start, _start
++FUNCTION(start)
+ FUNCTION(_start)
+ 	/*
+ 	 *  EFI_SYSTEM_TABLE and EFI_HANDLE are passed in r1/r0.
+diff --git a/grub-core/kern/arm/startup.S b/grub-core/kern/arm/startup.S
+index 3946fe8e183..5679a1d00ad 100644
+--- a/grub-core/kern/arm/startup.S
++++ b/grub-core/kern/arm/startup.S
+@@ -48,6 +48,8 @@
+ 	
+ 	.text
+ 	.arm
++	.globl	start, _start
++FUNCTION(start)
+ FUNCTION(_start)
+ 	b	codestart
+ 	
+diff --git a/grub-core/kern/arm64/efi/startup.S b/grub-core/kern/arm64/efi/startup.S
+index 666a7ee3c92..41676bdb2b8 100644
+--- a/grub-core/kern/arm64/efi/startup.S
++++ b/grub-core/kern/arm64/efi/startup.S
+@@ -19,7 +19,9 @@
+ #include <grub/symbol.h>
+ 
+ 	.file 	"startup.S"
++	.globl start, _start
+ 	.text
++FUNCTION(start)
+ FUNCTION(_start)
+ 	/*
+ 	 *  EFI_SYSTEM_TABLE and EFI_HANDLE are passed in x1/x0.
+diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S
+index 0d89858d9b3..939f182fc74 100644
+--- a/grub-core/kern/i386/qemu/startup.S
++++ b/grub-core/kern/i386/qemu/startup.S
+@@ -24,7 +24,8 @@
+ 
+ 	.text
+ 	.code32
+-	.globl _start
++	.globl start, _start
++start:
+ _start:
+ 	jmp	codestart
+ 
+diff --git a/grub-core/kern/ia64/efi/startup.S b/grub-core/kern/ia64/efi/startup.S
+index d75c6d7cc74..8f2a593e529 100644
+--- a/grub-core/kern/ia64/efi/startup.S
++++ b/grub-core/kern/ia64/efi/startup.S
+@@ -24,8 +24,9 @@
+ 	.psr lsb
+ 	.lsb
+ 
+-	.global _start
++	.global start, _start
+ 	.proc _start
++start:
+ _start:
+ 	alloc loc0=ar.pfs,2,4,0,0
+ 	mov loc1=rp
+diff --git a/grub-core/kern/sparc64/ieee1275/crt0.S b/grub-core/kern/sparc64/ieee1275/crt0.S
+index 03b916f0534..701bf63abcf 100644
+--- a/grub-core/kern/sparc64/ieee1275/crt0.S
++++ b/grub-core/kern/sparc64/ieee1275/crt0.S
+@@ -22,7 +22,8 @@
+ 
+ 	.text
+ 	.align	4
+-	.globl	_start
++	.globl	start, _start
++start:
+ _start:
+ 	ba	codestart
+ 	 mov  %o4, %o0
+diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
+index 0108c0d4233..f36200bd688 100644
+--- a/grub-core/Makefile.am
++++ b/grub-core/Makefile.am
+@@ -66,6 +66,7 @@ CLEANFILES += grub_script.yy.c grub_script.yy.h
+ 
+ include $(srcdir)/Makefile.core.am
+ 
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/backtrace.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cache.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h
diff --git a/SOURCES/0121-normal-don-t-draw-our-startup-message-if-debug-is-se.patch b/SOURCES/0121-normal-don-t-draw-our-startup-message-if-debug-is-se.patch
new file mode 100644
index 0000000..d2a8fd0
--- /dev/null
+++ b/SOURCES/0121-normal-don-t-draw-our-startup-message-if-debug-is-se.patch
@@ -0,0 +1,23 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 9 Nov 2017 15:58:52 -0500
+Subject: [PATCH] normal: don't draw our startup message if debug is set
+
+---
+ grub-core/normal/main.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index b69f9e738fa..04ae9ed02f6 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -419,6 +419,9 @@ grub_normal_reader_init (int nested)
+   const char *msg_esc = _("ESC at any time exits.");
+   char *msg_formatted;
+ 
++  if (grub_env_get ("debug") != NULL)
++    return 0;
++
+   msg_formatted = grub_xasprintf (_("Minimal BASH-like line editing is supported. For "
+ 				    "the first word, TAB lists possible command completions. Anywhere "
+ 				    "else TAB lists possible device or file completions. %s"),
diff --git a/SOURCES/0122-Work-around-some-minor-include-path-weirdnesses.patch b/SOURCES/0122-Work-around-some-minor-include-path-weirdnesses.patch
new file mode 100644
index 0000000..460d792
--- /dev/null
+++ b/SOURCES/0122-Work-around-some-minor-include-path-weirdnesses.patch
@@ -0,0 +1,137 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 16 Mar 2018 13:28:57 -0400
+Subject: [PATCH] Work around some minor include path weirdnesses
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ include/grub/arm/efi/console.h    | 24 ++++++++++++++++++++++++
+ include/grub/arm64/efi/console.h  | 24 ++++++++++++++++++++++++
+ include/grub/i386/efi/console.h   | 24 ++++++++++++++++++++++++
+ include/grub/x86_64/efi/console.h | 24 ++++++++++++++++++++++++
+ 4 files changed, 96 insertions(+)
+ create mode 100644 include/grub/arm/efi/console.h
+ create mode 100644 include/grub/arm64/efi/console.h
+ create mode 100644 include/grub/i386/efi/console.h
+ create mode 100644 include/grub/x86_64/efi/console.h
+
+diff --git a/include/grub/arm/efi/console.h b/include/grub/arm/efi/console.h
+new file mode 100644
+index 00000000000..1592f6f76b5
+--- /dev/null
++++ b/include/grub/arm/efi/console.h
+@@ -0,0 +1,24 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2002,2005,2006,2007  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_ARM_EFI_CONSOLE_H
++#define GRUB_ARM_EFI_CONSOLE_H
++
++#include <efi/console.h>
++
++#endif /* ! GRUB_ARM_EFI_CONSOLE_H */
+diff --git a/include/grub/arm64/efi/console.h b/include/grub/arm64/efi/console.h
+new file mode 100644
+index 00000000000..95689339384
+--- /dev/null
++++ b/include/grub/arm64/efi/console.h
+@@ -0,0 +1,24 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2002,2005,2006,2007  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_ARM64_EFI_CONSOLE_H
++#define GRUB_ARM64_EFI_CONSOLE_H
++
++#include <efi/console.h>
++
++#endif /* ! GRUB_ARM64_EFI_CONSOLE_H */
+diff --git a/include/grub/i386/efi/console.h b/include/grub/i386/efi/console.h
+new file mode 100644
+index 00000000000..9231375cb07
+--- /dev/null
++++ b/include/grub/i386/efi/console.h
+@@ -0,0 +1,24 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2002,2005,2006,2007  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_I386_EFI_CONSOLE_H
++#define GRUB_I386_EFI_CONSOLE_H
++
++#include <efi/console.h>
++
++#endif /* ! GRUB_I386_EFI_CONSOLE_H */
+diff --git a/include/grub/x86_64/efi/console.h b/include/grub/x86_64/efi/console.h
+new file mode 100644
+index 00000000000..dba9d8678d0
+--- /dev/null
++++ b/include/grub/x86_64/efi/console.h
+@@ -0,0 +1,24 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2002,2005,2006,2007  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_X86_64_EFI_CONSOLE_H
++#define GRUB_X86_64_EFI_CONSOLE_H
++
++#include <efi/console.h>
++
++#endif /* ! GRUB_X86_64_EFI_CONSOLE_H */
diff --git a/SOURCES/0123-Make-it-possible-to-enabled-build-id-sha1.patch b/SOURCES/0123-Make-it-possible-to-enabled-build-id-sha1.patch
new file mode 100644
index 0000000..2ed085c
--- /dev/null
+++ b/SOURCES/0123-Make-it-possible-to-enabled-build-id-sha1.patch
@@ -0,0 +1,61 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 25 Jun 2015 15:41:06 -0400
+Subject: [PATCH] Make it possible to enabled --build-id=sha1
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ configure.ac |  8 ++++++++
+ acinclude.m4 | 19 +++++++++++++++++++
+ 2 files changed, 27 insertions(+)
+
+diff --git a/configure.ac b/configure.ac
+index f69f8986791..359cac3c26b 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1386,7 +1386,15 @@ grub_PROG_TARGET_CC
+ if test "x$TARGET_APPLE_LINKER" != x1 ; then
+ grub_PROG_OBJCOPY_ABSOLUTE
+ fi
++
++AC_ARG_ENABLE([build-id],
++	      [AS_HELP_STRING([--enable-build-id],
++                             [ask the linker to supply build-id notes (default=no)])])
++if test x$enable_build_id = xyes; then
++grub_PROG_LD_BUILD_ID_SHA1
++else
+ grub_PROG_LD_BUILD_ID_NONE
++fi
+ if test "x$target_cpu" = xi386; then
+   if test "$platform" != emu && test "x$TARGET_APPLE_LINKER" != x1 ; then
+     if test ! -z "$TARGET_IMG_LDSCRIPT"; then
+diff --git a/acinclude.m4 b/acinclude.m4
+index 78cdf6e1d01..242e829ff23 100644
+--- a/acinclude.m4
++++ b/acinclude.m4
+@@ -136,6 +136,25 @@ if test "x$grub_cv_prog_ld_build_id_none" = xyes; then
+ fi
+ ])
+ 
++dnl Supply --build-id=sha1 to ld if building modules.
++dnl This suppresses warnings from ld on some systems
++AC_DEFUN([grub_PROG_LD_BUILD_ID_SHA1],
++[AC_MSG_CHECKING([whether linker accepts --build-id=sha1])
++AC_CACHE_VAL(grub_cv_prog_ld_build_id_sha1,
++[save_LDFLAGS="$LDFLAGS"
++LDFLAGS="$LDFLAGS -Wl,--build-id=sha1"
++AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
++	       [grub_cv_prog_ld_build_id_sha1=yes],
++	       [grub_cv_prog_ld_build_id_sha1=no])
++LDFLAGS="$save_LDFLAGS"
++])
++AC_MSG_RESULT([$grub_cv_prog_ld_build_id_sha1])
++
++if test "x$grub_cv_prog_ld_build_id_sha1" = xyes; then
++  TARGET_LDFLAGS="$TARGET_LDFLAGS -Wl,--build-id=sha1"
++fi
++])
++
+ dnl Check nm
+ AC_DEFUN([grub_PROG_NM_WORKS],
+ [AC_MSG_CHECKING([whether nm works])
diff --git a/SOURCES/0124-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch b/SOURCES/0124-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch
new file mode 100644
index 0000000..8bd5548
--- /dev/null
+++ b/SOURCES/0124-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch
@@ -0,0 +1,56 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Sun, 28 Jun 2015 13:09:58 -0400
+Subject: [PATCH] Add grub_qdprintf() - grub_dprintf() without the file+line
+ number.
+
+This just makes copy+paste of our debug loading info easier.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/misc.c | 18 ++++++++++++++++++
+ include/grub/misc.h   |  2 ++
+ 2 files changed, 20 insertions(+)
+
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 5c2d2039d0b..0e89c483d5e 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -190,6 +190,24 @@ grub_real_dprintf (const char *file, const int line, const char *condition,
+     }
+ }
+ 
++void
++grub_qdprintf (const char *condition, const char *fmt, ...)
++{
++  va_list args;
++  const char *debug = grub_env_get ("debug");
++
++  if (! debug)
++    return;
++
++  if (grub_strword (debug, "all") || grub_strword (debug, condition))
++    {
++      va_start (args, fmt);
++      grub_vprintf (fmt, args);
++      va_end (args);
++      grub_refresh ();
++    }
++}
++
+ #define PREALLOC_SIZE 255
+ 
+ int
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index f7473c154f0..5f1c1c1be4e 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -372,6 +372,8 @@ void EXPORT_FUNC(grub_real_dprintf) (const char *file,
+                                      const int line,
+                                      const char *condition,
+                                      const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 4, 5)));
++void EXPORT_FUNC(grub_qdprintf) (const char *condition,
++				 const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 2, 3)));
+ int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args);
+ int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...)
+      __attribute__ ((format (GNU_PRINTF, 3, 4)));
diff --git a/SOURCES/0125-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch b/SOURCES/0125-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch
new file mode 100644
index 0000000..f3e24d5
--- /dev/null
+++ b/SOURCES/0125-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch
@@ -0,0 +1,178 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 25 Jun 2015 15:11:36 -0400
+Subject: [PATCH] Make a "gdb" dprintf that tells us load addresses.
+
+This makes a grub_dprintf() call during platform init and during module
+loading that tells us the virtual addresses of the .text and .data
+sections of grub-core/kernel.exec and any modules it loads.
+
+Specifically, it displays them in the gdb "add-symbol-file" syntax, with
+the presumption that there's a variable $grubdir that reflects the path
+to any such binaries.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/dl.c       | 50 +++++++++++++++++++++++++++++++++++++++++++++++
+ grub-core/kern/efi/efi.c  |  4 ++--
+ grub-core/kern/efi/init.c | 26 +++++++++++++++++++++++-
+ include/grub/efi/efi.h    |  2 +-
+ 4 files changed, 78 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index 5028d157c46..eb8b969cded 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -501,6 +501,23 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name)
+       return s;
+   return NULL;
+ }
++static long
++grub_dl_find_section_index (Elf_Ehdr *e, const char *name)
++{
++  Elf_Shdr *s;
++  const char *str;
++  unsigned i;
++
++  s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
++  str = (char *) e + s->sh_offset;
++
++  for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
++       i < e->e_shnum;
++       i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
++    if (grub_strcmp (str + s->sh_name, name) == 0)
++      return (long)i;
++  return -1;
++}
+ 
+ /* Me, Vladimir Serbinenko, hereby I add this module check as per new
+    GNU module policy. Note that this license check is informative only.
+@@ -644,6 +661,37 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
+ 
+   return GRUB_ERR_NONE;
+ }
++static void
++grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e)
++{
++  void *text, *data = NULL;
++  long idx;
++
++  idx = grub_dl_find_section_index (e, ".text");
++  if (idx < 0)
++    return;
++
++  text = grub_dl_get_section_addr (mod, idx);
++  if (!text)
++    return;
++
++  idx = grub_dl_find_section_index (e, ".data");
++  if (idx >= 0)
++    data = grub_dl_get_section_addr (mod, idx);
++
++  if (data)
++    grub_qdprintf ("gdb", "add-symbol-file \\\n"
++		          "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug "
++			  "\\\n %p -s .data %p\n",
++		  GRUB_TARGET_CPU, GRUB_PLATFORM,
++		  mod->name, text, data);
++  else
++    grub_qdprintf ("gdb", "add-symbol-file \\\n"
++			   "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug "
++			   "\\\n%p\n",
++		  GRUB_TARGET_CPU, GRUB_PLATFORM,
++		  mod->name, text);
++}
+ 
+ /* Load a module from core memory.  */
+ grub_dl_t
+@@ -703,6 +751,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size)
+   grub_dprintf ("modules", "module name: %s\n", mod->name);
+   grub_dprintf ("modules", "init function: %p\n", mod->init);
+ 
++  grub_dl_print_gdb_info (mod, e);
++
+   if (grub_dl_add (mod))
+     {
+       grub_dl_unload (mod);
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index bcae7f4699d..a2a732ffc0d 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -283,7 +283,7 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
+ /* Search the mods section from the PE32/PE32+ image. This code uses
+    a PE32 header, but should work with PE32+ as well.  */
+ grub_addr_t
+-grub_efi_modules_addr (void)
++grub_efi_section_addr (const char *section_name)
+ {
+   grub_efi_loaded_image_t *image;
+   struct grub_pe32_header *header;
+@@ -308,7 +308,7 @@ grub_efi_modules_addr (void)
+        i < coff_header->num_sections;
+        i++, section++)
+     {
+-      if (grub_strcmp (section->name, "mods") == 0)
++      if (grub_strcmp (section->name, section_name) == 0)
+ 	break;
+     }
+ 
+diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
+index 71d2279a0c1..e6183a4c44d 100644
+--- a/grub-core/kern/efi/init.c
++++ b/grub-core/kern/efi/init.c
+@@ -59,10 +59,33 @@ grub_efi_env_init (void)
+   grub_free (envblk_s.buf);
+ }
+ 
++static void
++grub_efi_print_gdb_info (void)
++{
++  grub_addr_t text;
++  grub_addr_t data;
++
++  text = grub_efi_section_addr (".text");
++  if (!text)
++    return;
++
++  data = grub_efi_section_addr (".data");
++  if (data)
++    grub_qdprintf ("gdb",
++		  "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/"
++		  "kernel.exec %p -s .data %p\n",
++		  GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text, (void *)data);
++  else
++    grub_qdprintf ("gdb",
++		  "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/"
++		  "kernel.exec %p\n",
++		  GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text);
++}
++
+ void
+ grub_efi_init (void)
+ {
+-  grub_modbase = grub_efi_modules_addr ();
++  grub_modbase = grub_efi_section_addr ("mods");
+   /* First of all, initialize the console so that GRUB can display
+      messages.  */
+   grub_console_init ();
+@@ -74,6 +97,7 @@ grub_efi_init (void)
+ 	      0, 0, 0, NULL);
+ 
+   grub_efi_env_init ();
++  grub_efi_print_gdb_info ();
+   grub_efidisk_init ();
+ }
+ 
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index 09a18e56302..570a69361a5 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -132,7 +132,7 @@ grub_err_t grub_armxx_efi_linux_check_image(struct linux_armxx_kernel_header *lh
+ grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, char *args);
+ #endif
+ 
+-grub_addr_t grub_efi_modules_addr (void);
++grub_addr_t grub_efi_section_addr (const char *section);
+ 
+ void grub_efi_mm_init (void);
+ void grub_efi_mm_fini (void);
diff --git a/SOURCES/0126-Only-attempt-to-scan-different-BLS-directories-on-EF.patch b/SOURCES/0126-Only-attempt-to-scan-different-BLS-directories-on-EF.patch
new file mode 100644
index 0000000..52a1085
--- /dev/null
+++ b/SOURCES/0126-Only-attempt-to-scan-different-BLS-directories-on-EF.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 3 Apr 2018 15:42:47 +0200
+Subject: [PATCH] Only attempt to scan different BLS directories on EFI
+ machines
+
+Current BLS support attempted to scan for BLS directories, but this only
+makes sense on EFI, where BLS fragments are in /loader/$vendor/entries.
+
+For BIOS, only either the default /loader/entries path should be scanned
+or the BLS directory defined in the blsdir GRUB 2 environment variable.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index e0b65534af4..e775c6b8794 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -676,8 +676,8 @@ static int find_entry (const char *filename,
+   const char *devid = grub_env_get ("boot");
+ 
+   grub_dprintf("blscfg", "%s got here\n", __func__);
+-  if (!grub_strcmp (filename, ".") ||
+-      !grub_strcmp (filename, ".."))
++  if (filename && (!grub_strcmp (filename, ".") ||
++		   !grub_strcmp (filename, "..")))
+     return 0;
+ 
+   if (info->platform == PLATFORM_EFI && !grub_strcasecmp (filename, "boot"))
+@@ -872,11 +872,10 @@ grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED,
+   info.platform = PLATFORM_EMU;
+   grub_dprintf ("blscfg", "scanning %s%s\n", GRUB_BOOT_DEVICE,
+ 		GRUB_BLS_CONFIG_PATH);
+-  r = fs->dir (dev, "/boot/loader/",
+-	       find_entry, &info);
++  find_entry(NULL, NULL, &info);
+ #else
+   grub_dprintf ("blscfg", "scanning %s\n", GRUB_BLS_CONFIG_PATH);
+-  r = fs->dir (dev, "/", find_entry, &info);
++  find_entry(NULL, NULL, &info);
+ #endif
+ 
+ finish:
diff --git a/SOURCES/0127-Core-TPM-support.patch b/SOURCES/0127-Core-TPM-support.patch
new file mode 100644
index 0000000..43ab689
--- /dev/null
+++ b/SOURCES/0127-Core-TPM-support.patch
@@ -0,0 +1,786 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Tue, 14 Jul 2015 17:06:35 -0700
+Subject: [PATCH] Core TPM support
+
+Add support for performing basic TPM measurements. Right now this only
+supports extending PCRs statically and only on UEFI and BIOS systems, but
+will measure all modules as they're loaded.
+---
+ grub-core/Makefile.core.def  |   3 +
+ grub-core/kern/dl.c          |   3 +
+ grub-core/kern/efi/tpm.c     | 282 +++++++++++++++++++++++++++++++++++++++++++
+ grub-core/kern/i386/pc/tpm.c | 132 ++++++++++++++++++++
+ grub-core/kern/tpm.c         |  13 ++
+ include/grub/efi/tpm.h       | 153 +++++++++++++++++++++++
+ include/grub/tpm.h           |  91 ++++++++++++++
+ grub-core/Makefile.am        |   1 +
+ 8 files changed, 678 insertions(+)
+ create mode 100644 grub-core/kern/efi/tpm.c
+ create mode 100644 grub-core/kern/i386/pc/tpm.c
+ create mode 100644 grub-core/kern/tpm.c
+ create mode 100644 include/grub/efi/tpm.h
+ create mode 100644 include/grub/tpm.h
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index cb24f92a431..420831bc89e 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -131,6 +131,7 @@ kernel = {
+   common = kern/term.c;
+   common = kern/qsort.c;
+   common = kern/backtrace.c;
++  common = kern/tpm.c;
+ 
+   x86 = kern/i386/backtrace.c;
+   i386_xen = kern/i386/backtrace.c;
+@@ -199,6 +200,7 @@ kernel = {
+   efi = kern/acpi.c;
+   efi = kern/efi/acpi.c;
+   efi = lib/envblk.c;
++  efi = kern/efi/tpm.c;
+   i386_coreboot = kern/i386/pc/acpi.c;
+   i386_multiboot = kern/i386/pc/acpi.c;
+   i386_coreboot = kern/acpi.c;
+@@ -245,6 +247,7 @@ kernel = {
+ 
+   i386_pc = kern/i386/pc/init.c;
+   i386_pc = kern/i386/pc/mmap.c;
++  i386_pc = kern/i386/pc/tpm.c;
+   i386_pc = term/i386/pc/console.c;
+ 
+   i386_qemu = bus/pci.c;
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index eb8b969cded..387d1e6446d 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -33,6 +33,7 @@
+ #include <grub/cache.h>
+ #include <grub/i18n.h>
+ #include <grub/efi/sb.h>
++#include <grub/tpm.h>
+ 
+ /* Platforms where modules are in a readonly area of memory.  */
+ #if defined(GRUB_MACHINE_QEMU)
+@@ -829,6 +830,8 @@ grub_dl_load_file (const char *filename)
+      opens of the same device.  */
+   grub_file_close (file);
+ 
++  grub_tpm_measure(core, size, GRUB_TPM_PCR, filename);
++
+   mod = grub_dl_load_core (core, size);
+   grub_free (core);
+   if (! mod)
+diff --git a/grub-core/kern/efi/tpm.c b/grub-core/kern/efi/tpm.c
+new file mode 100644
+index 00000000000..c9fb3c133f3
+--- /dev/null
++++ b/grub-core/kern/efi/tpm.c
+@@ -0,0 +1,282 @@
++#include <grub/err.h>
++#include <grub/i18n.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/efi/tpm.h>
++#include <grub/mm.h>
++#include <grub/tpm.h>
++#include <grub/term.h>
++
++static grub_efi_guid_t tpm_guid = EFI_TPM_GUID;
++static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID;
++
++static grub_efi_boolean_t grub_tpm_present(grub_efi_tpm_protocol_t *tpm)
++{
++  grub_efi_status_t status;
++  TCG_EFI_BOOT_SERVICE_CAPABILITY caps;
++  grub_uint32_t flags;
++  grub_efi_physical_address_t eventlog, lastevent;
++
++  caps.Size = (grub_uint8_t)sizeof(caps);
++
++  status = efi_call_5(tpm->status_check, tpm, &caps, &flags, &eventlog,
++		      &lastevent);
++
++  if (status != GRUB_EFI_SUCCESS || caps.TPMDeactivatedFlag
++      || !caps.TPMPresentFlag)
++    return 0;
++
++  return 1;
++}
++
++static grub_efi_boolean_t grub_tpm2_present(grub_efi_tpm2_protocol_t *tpm)
++{
++  grub_efi_status_t status;
++  EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
++
++  caps.Size = (grub_uint8_t)sizeof(caps);
++
++  status = efi_call_2(tpm->get_capability, tpm, &caps);
++
++  if (status != GRUB_EFI_SUCCESS || !caps.TPMPresentFlag)
++    return 0;
++
++  return 1;
++}
++
++static grub_efi_boolean_t grub_tpm_handle_find(grub_efi_handle_t *tpm_handle,
++					       grub_efi_uint8_t *protocol_version)
++{
++  grub_efi_handle_t *handles;
++  grub_efi_uintn_t num_handles;
++
++  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm_guid, NULL,
++				    &num_handles);
++  if (handles && num_handles > 0) {
++    *tpm_handle = handles[0];
++    *protocol_version = 1;
++    return 1;
++  }
++
++  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm2_guid, NULL,
++				    &num_handles);
++  if (handles && num_handles > 0) {
++    *tpm_handle = handles[0];
++    *protocol_version = 2;
++    return 1;
++  }
++
++  return 0;
++}
++
++static grub_err_t
++grub_tpm1_execute(grub_efi_handle_t tpm_handle,
++		  PassThroughToTPM_InputParamBlock *inbuf,
++		  PassThroughToTPM_OutputParamBlock *outbuf)
++{
++  grub_efi_status_t status;
++  grub_efi_tpm_protocol_t *tpm;
++  grub_uint32_t inhdrsize = sizeof(*inbuf) - sizeof(inbuf->TPMOperandIn);
++  grub_uint32_t outhdrsize = sizeof(*outbuf) - sizeof(outbuf->TPMOperandOut);
++
++  tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid,
++				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++  if (!grub_tpm_present(tpm))
++    return 0;
++
++  /* UEFI TPM protocol takes the raw operand block, no param block header */
++  status = efi_call_5 (tpm->pass_through_to_tpm, tpm,
++		       inbuf->IPBLength - inhdrsize, inbuf->TPMOperandIn,
++		       outbuf->OPBLength - outhdrsize, outbuf->TPMOperandOut);
++
++  switch (status) {
++  case GRUB_EFI_SUCCESS:
++    return 0;
++  case GRUB_EFI_DEVICE_ERROR:
++    return grub_error (GRUB_ERR_IO, N_("Command failed"));
++  case GRUB_EFI_INVALID_PARAMETER:
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
++  case GRUB_EFI_BUFFER_TOO_SMALL:
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
++  case GRUB_EFI_NOT_FOUND:
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
++  default:
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
++  }
++}
++
++static grub_err_t
++grub_tpm2_execute(grub_efi_handle_t tpm_handle,
++		  PassThroughToTPM_InputParamBlock *inbuf,
++		  PassThroughToTPM_OutputParamBlock *outbuf)
++{
++  grub_efi_status_t status;
++  grub_efi_tpm2_protocol_t *tpm;
++  grub_uint32_t inhdrsize = sizeof(*inbuf) - sizeof(inbuf->TPMOperandIn);
++  grub_uint32_t outhdrsize = sizeof(*outbuf) - sizeof(outbuf->TPMOperandOut);
++
++  tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid,
++				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++  if (!grub_tpm2_present(tpm))
++    return 0;
++
++  /* UEFI TPM protocol takes the raw operand block, no param block header */
++  status = efi_call_5 (tpm->submit_command, tpm,
++		       inbuf->IPBLength - inhdrsize, inbuf->TPMOperandIn,
++		       outbuf->OPBLength - outhdrsize, outbuf->TPMOperandOut);
++
++  switch (status) {
++  case GRUB_EFI_SUCCESS:
++    return 0;
++  case GRUB_EFI_DEVICE_ERROR:
++    return grub_error (GRUB_ERR_IO, N_("Command failed"));
++  case GRUB_EFI_INVALID_PARAMETER:
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
++  case GRUB_EFI_BUFFER_TOO_SMALL:
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
++  case GRUB_EFI_NOT_FOUND:
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
++  default:
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
++  }
++}
++
++grub_err_t
++grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
++		 PassThroughToTPM_OutputParamBlock *outbuf)
++{
++  grub_efi_handle_t tpm_handle;
++   grub_uint8_t protocol_version;
++
++  /* It's not a hard failure for there to be no TPM */
++  if (!grub_tpm_handle_find(&tpm_handle, &protocol_version))
++    return 0;
++
++  if (protocol_version == 1) {
++    return grub_tpm1_execute(tpm_handle, inbuf, outbuf);
++  } else {
++    return grub_tpm2_execute(tpm_handle, inbuf, outbuf);
++  }
++}
++
++typedef struct {
++	grub_uint32_t pcrindex;
++	grub_uint32_t eventtype;
++	grub_uint8_t digest[20];
++	grub_uint32_t eventsize;
++	grub_uint8_t event[1];
++} Event;
++
++
++static grub_err_t
++grub_tpm1_log_event(grub_efi_handle_t tpm_handle, unsigned char *buf,
++		    grub_size_t size, grub_uint8_t pcr,
++		    const char *description)
++{
++  Event *event;
++  grub_efi_status_t status;
++  grub_efi_tpm_protocol_t *tpm;
++  grub_efi_physical_address_t lastevent;
++  grub_uint32_t algorithm;
++  grub_uint32_t eventnum = 0;
++
++  tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid,
++				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++  if (!grub_tpm_present(tpm))
++    return 0;
++
++  event = grub_zalloc(sizeof (Event) + grub_strlen(description) + 1);
++  if (!event)
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		       N_("cannot allocate TPM event buffer"));
++
++  event->pcrindex = pcr;
++  event->eventtype = EV_IPL;
++  event->eventsize = grub_strlen(description) + 1;
++  grub_memcpy(event->event, description, event->eventsize);
++
++  algorithm = TCG_ALG_SHA;
++  status = efi_call_7 (tpm->log_extend_event, tpm, buf, (grub_uint64_t) size,
++		       algorithm, event, &eventnum, &lastevent);
++
++  switch (status) {
++  case GRUB_EFI_SUCCESS:
++    return 0;
++  case GRUB_EFI_DEVICE_ERROR:
++    return grub_error (GRUB_ERR_IO, N_("Command failed"));
++  case GRUB_EFI_INVALID_PARAMETER:
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
++  case GRUB_EFI_BUFFER_TOO_SMALL:
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
++  case GRUB_EFI_NOT_FOUND:
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
++  default:
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
++  }
++}
++
++static grub_err_t
++grub_tpm2_log_event(grub_efi_handle_t tpm_handle, unsigned char *buf,
++		   grub_size_t size, grub_uint8_t pcr,
++		   const char *description)
++{
++  EFI_TCG2_EVENT *event;
++  grub_efi_status_t status;
++  grub_efi_tpm2_protocol_t *tpm;
++
++  tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid,
++				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++  if (!grub_tpm2_present(tpm))
++    return 0;
++
++  event = grub_zalloc(sizeof (EFI_TCG2_EVENT) + grub_strlen(description) + 1);
++  if (!event)
++    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++		       N_("cannot allocate TPM event buffer"));
++
++  event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
++  event->Header.HeaderVersion = 1;
++  event->Header.PCRIndex = pcr;
++  event->Header.EventType = EV_IPL;
++  event->Size = sizeof(*event) - sizeof(event->Event) + grub_strlen(description) + 1;
++  grub_memcpy(event->Event, description, grub_strlen(description) + 1);
++
++  status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, buf,
++		       (grub_uint64_t) size, event);
++
++  switch (status) {
++  case GRUB_EFI_SUCCESS:
++    return 0;
++  case GRUB_EFI_DEVICE_ERROR:
++    return grub_error (GRUB_ERR_IO, N_("Command failed"));
++  case GRUB_EFI_INVALID_PARAMETER:
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter"));
++  case GRUB_EFI_BUFFER_TOO_SMALL:
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small"));
++  case GRUB_EFI_NOT_FOUND:
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable"));
++  default:
++    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error"));
++  }
++}
++
++grub_err_t
++grub_tpm_log_event(unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
++		   const char *description)
++{
++  grub_efi_handle_t tpm_handle;
++  grub_efi_uint8_t protocol_version;
++
++  if (!grub_tpm_handle_find(&tpm_handle, &protocol_version))
++    return 0;
++
++  if (protocol_version == 1) {
++    return grub_tpm1_log_event(tpm_handle, buf, size, pcr, description);
++  } else {
++    return grub_tpm2_log_event(tpm_handle, buf, size, pcr, description);
++  }
++}
+diff --git a/grub-core/kern/i386/pc/tpm.c b/grub-core/kern/i386/pc/tpm.c
+new file mode 100644
+index 00000000000..8c6c1e6ece2
+--- /dev/null
++++ b/grub-core/kern/i386/pc/tpm.c
+@@ -0,0 +1,132 @@
++#include <grub/err.h>
++#include <grub/i18n.h>
++#include <grub/mm.h>
++#include <grub/tpm.h>
++#include <grub/misc.h>
++#include <grub/i386/pc/int.h>
++
++#define TCPA_MAGIC 0x41504354
++
++int tpm_present(void);
++
++int tpm_present(void)
++{
++  struct grub_bios_int_registers regs;
++
++  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
++  regs.eax = 0xbb00;
++  regs.ebx = TCPA_MAGIC;
++  grub_bios_interrupt (0x1a, &regs);
++
++  if (regs.eax == 0)
++    return 1;
++
++  return 0;
++}
++
++grub_err_t
++grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
++		 PassThroughToTPM_OutputParamBlock *outbuf)
++{
++  struct grub_bios_int_registers regs;
++  grub_addr_t inaddr, outaddr;
++
++  if (!tpm_present())
++    return 0;
++
++  inaddr = (grub_addr_t) inbuf;
++  outaddr = (grub_addr_t) outbuf;
++  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
++  regs.eax = 0xbb02;
++  regs.ebx = TCPA_MAGIC;
++  regs.ecx = 0;
++  regs.edx = 0;
++  regs.es = (inaddr & 0xffff0000) >> 4;
++  regs.edi = inaddr & 0xffff;
++  regs.ds = outaddr >> 4;
++  regs.esi = outaddr & 0xf;
++
++  grub_bios_interrupt (0x1a, &regs);
++
++  if (regs.eax)
++    return grub_error (GRUB_ERR_IO, N_("TPM error %x\n"), regs.eax);
++
++  return 0;
++}
++
++typedef struct {
++	grub_uint32_t pcrindex;
++	grub_uint32_t eventtype;
++	grub_uint8_t digest[20];
++	grub_uint32_t eventdatasize;
++	grub_uint8_t event[0];
++} GRUB_PACKED Event;
++
++typedef struct {
++	grub_uint16_t ipblength;
++	grub_uint16_t reserved;
++	grub_uint32_t hashdataptr;
++	grub_uint32_t hashdatalen;
++	grub_uint32_t pcr;
++	grub_uint32_t reserved2;
++	grub_uint32_t logdataptr;
++	grub_uint32_t logdatalen;
++} GRUB_PACKED EventIncoming;
++
++typedef struct {
++	grub_uint16_t opblength;
++	grub_uint16_t reserved;
++	grub_uint32_t eventnum;
++	grub_uint8_t  hashvalue[20];
++} GRUB_PACKED EventOutgoing;
++
++grub_err_t
++grub_tpm_log_event(unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
++		   const char *description)
++{
++	struct grub_bios_int_registers regs;
++	EventIncoming incoming;
++	EventOutgoing outgoing;
++	Event *event;
++	grub_uint32_t datalength;
++
++	if (!tpm_present())
++		return 0;
++
++	datalength = grub_strlen(description);
++	event = grub_zalloc(datalength + sizeof(Event));
++	if (!event)
++		return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++				   N_("cannot allocate TPM event buffer"));
++
++	event->pcrindex = pcr;
++	event->eventtype = 0x0d;
++	event->eventdatasize = grub_strlen(description);
++	grub_memcpy(event->event, description, datalength);
++
++	incoming.ipblength = sizeof(incoming);
++	incoming.hashdataptr = (grub_uint32_t)buf;
++	incoming.hashdatalen = size;
++	incoming.pcr = pcr;
++	incoming.logdataptr = (grub_uint32_t)event;
++	incoming.logdatalen = datalength + sizeof(Event);
++
++	regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
++	regs.eax = 0xbb01;
++	regs.ebx = TCPA_MAGIC;
++	regs.ecx = 0;
++	regs.edx = 0;
++	regs.es = (((grub_addr_t) &incoming) & 0xffff0000) >> 4;
++	regs.edi = ((grub_addr_t) &incoming) & 0xffff;
++	regs.ds = (((grub_addr_t) &outgoing) & 0xffff0000) >> 4;
++	regs.esi = ((grub_addr_t) &outgoing) & 0xffff;
++
++	grub_bios_interrupt (0x1a, &regs);
++
++	grub_free(event);
++
++	if (regs.eax)
++		return grub_error (GRUB_ERR_IO, N_("TPM error %x\n"), regs.eax);
++
++	return 0;
++}
+diff --git a/grub-core/kern/tpm.c b/grub-core/kern/tpm.c
+new file mode 100644
+index 00000000000..1a991876c83
+--- /dev/null
++++ b/grub-core/kern/tpm.c
+@@ -0,0 +1,13 @@
++#include <grub/err.h>
++#include <grub/i18n.h>
++#include <grub/misc.h>
++#include <grub/mm.h>
++#include <grub/tpm.h>
++#include <grub/term.h>
++
++grub_err_t
++grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
++		  const char *description)
++{
++  return grub_tpm_log_event(buf, size, pcr, description);
++}
+diff --git a/include/grub/efi/tpm.h b/include/grub/efi/tpm.h
+new file mode 100644
+index 00000000000..e2aff4a3c22
+--- /dev/null
++++ b/include/grub/efi/tpm.h
+@@ -0,0 +1,153 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2015  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_EFI_TPM_HEADER
++#define GRUB_EFI_TPM_HEADER 1
++
++#define EFI_TPM_GUID {0xf541796d, 0xa62e, 0x4954, {0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd }};
++#define EFI_TPM2_GUID {0x607f766c, 0x7455, 0x42be, {0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f }};
++
++typedef struct {
++  grub_efi_uint8_t Major;
++  grub_efi_uint8_t Minor;
++  grub_efi_uint8_t RevMajor;
++  grub_efi_uint8_t RevMinor;
++} TCG_VERSION;
++
++typedef struct _TCG_EFI_BOOT_SERVICE_CAPABILITY {
++  grub_efi_uint8_t          Size;                /// Size of this structure.
++  TCG_VERSION    StructureVersion;
++  TCG_VERSION    ProtocolSpecVersion;
++  grub_efi_uint8_t          HashAlgorithmBitmap; /// Hash algorithms .
++  char        TPMPresentFlag;      /// 00h = TPM not present.
++  char        TPMDeactivatedFlag;  /// 01h = TPM currently deactivated.
++} TCG_EFI_BOOT_SERVICE_CAPABILITY;
++
++typedef struct {
++  grub_efi_uint32_t PCRIndex;
++  grub_efi_uint32_t EventType;
++  grub_efi_uint8_t digest[20];
++  grub_efi_uint32_t EventSize;
++  grub_efi_uint8_t  Event[1];
++} TCG_PCR_EVENT;
++
++struct grub_efi_tpm_protocol
++{
++  grub_efi_status_t (*status_check) (struct grub_efi_tpm_protocol *this,
++				     TCG_EFI_BOOT_SERVICE_CAPABILITY *ProtocolCapability,
++				     grub_efi_uint32_t *TCGFeatureFlags,
++				     grub_efi_physical_address_t *EventLogLocation,
++				     grub_efi_physical_address_t *EventLogLastEntry);
++  grub_efi_status_t (*hash_all) (struct grub_efi_tpm_protocol *this,
++				 grub_efi_uint8_t *HashData,
++				 grub_efi_uint64_t HashLen,
++				 grub_efi_uint32_t AlgorithmId,
++				 grub_efi_uint64_t *HashedDataLen,
++				 grub_efi_uint8_t **HashedDataResult);
++  grub_efi_status_t (*log_event) (struct grub_efi_tpm_protocol *this,
++				  TCG_PCR_EVENT *TCGLogData,
++				  grub_efi_uint32_t *EventNumber,
++				  grub_efi_uint32_t Flags);
++  grub_efi_status_t (*pass_through_to_tpm) (struct grub_efi_tpm_protocol *this,
++					    grub_efi_uint32_t TpmInputParameterBlockSize,
++					    grub_efi_uint8_t *TpmInputParameterBlock,
++					    grub_efi_uint32_t TpmOutputParameterBlockSize,
++					    grub_efi_uint8_t *TpmOutputParameterBlock);
++  grub_efi_status_t (*log_extend_event) (struct grub_efi_tpm_protocol *this,
++					 grub_efi_physical_address_t HashData,
++					 grub_efi_uint64_t HashDataLen,
++					 grub_efi_uint32_t AlgorithmId,
++					 TCG_PCR_EVENT *TCGLogData,
++					 grub_efi_uint32_t *EventNumber,
++					 grub_efi_physical_address_t *EventLogLastEntry);
++};
++
++typedef struct grub_efi_tpm_protocol grub_efi_tpm_protocol_t;
++
++typedef grub_efi_uint32_t EFI_TCG2_EVENT_LOG_BITMAP;
++typedef grub_efi_uint32_t EFI_TCG2_EVENT_LOG_FORMAT;
++typedef grub_efi_uint32_t EFI_TCG2_EVENT_ALGORITHM_BITMAP;
++
++typedef struct tdEFI_TCG2_VERSION {
++  grub_efi_uint8_t Major;
++  grub_efi_uint8_t Minor;
++} GRUB_PACKED EFI_TCG2_VERSION;
++
++typedef struct tdEFI_TCG2_BOOT_SERVICE_CAPABILITY {
++  grub_efi_uint8_t Size;
++  EFI_TCG2_VERSION StructureVersion;
++  EFI_TCG2_VERSION ProtocolVersion;
++  EFI_TCG2_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap;
++  EFI_TCG2_EVENT_LOG_BITMAP SupportedEventLogs;
++  grub_efi_boolean_t TPMPresentFlag;
++  grub_efi_uint16_t MaxCommandSize;
++  grub_efi_uint16_t MaxResponseSize;
++  grub_efi_uint32_t ManufacturerID;
++  grub_efi_uint32_t NumberOfPcrBanks;
++  EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrBanks;
++} EFI_TCG2_BOOT_SERVICE_CAPABILITY;
++
++typedef grub_efi_uint32_t TCG_PCRINDEX;
++typedef grub_efi_uint32_t TCG_EVENTTYPE;
++
++typedef struct tdEFI_TCG2_EVENT_HEADER {
++  grub_efi_uint32_t HeaderSize;
++  grub_efi_uint16_t HeaderVersion;
++  TCG_PCRINDEX PCRIndex;
++  TCG_EVENTTYPE EventType;
++} GRUB_PACKED EFI_TCG2_EVENT_HEADER;
++
++typedef struct tdEFI_TCG2_EVENT {
++  grub_efi_uint32_t Size;
++  EFI_TCG2_EVENT_HEADER Header;
++  grub_efi_uint8_t Event[1];
++} GRUB_PACKED EFI_TCG2_EVENT;
++
++struct grub_efi_tpm2_protocol
++{
++  grub_efi_status_t (*get_capability) (struct grub_efi_tpm2_protocol *this,
++				       EFI_TCG2_BOOT_SERVICE_CAPABILITY *ProtocolCapability);
++  grub_efi_status_t (*get_event_log) (struct grub_efi_tpm2_protocol *this,
++				      EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat,
++				      grub_efi_physical_address_t *EventLogLocation,
++				      grub_efi_physical_address_t *EventLogLastEntry,
++				      grub_efi_boolean_t *EventLogTruncated);
++  grub_efi_status_t (*hash_log_extend_event) (struct grub_efi_tpm2_protocol *this,
++					      grub_efi_uint64_t Flags,
++					      grub_efi_physical_address_t *DataToHash,
++					      grub_efi_uint64_t DataToHashLen,
++					      EFI_TCG2_EVENT *EfiTcgEvent);
++  grub_efi_status_t (*submit_command) (struct grub_efi_tpm2_protocol *this,
++				       grub_efi_uint32_t InputParameterBlockSize,
++				       grub_efi_uint8_t *InputParameterBlock,
++				       grub_efi_uint32_t OutputParameterBlockSize,
++				       grub_efi_uint8_t *OutputParameterBlock);
++  grub_efi_status_t (*get_active_pcr_blanks) (struct grub_efi_tpm2_protocol *this,
++					      grub_efi_uint32_t *ActivePcrBanks);
++  grub_efi_status_t (*set_active_pcr_banks) (struct grub_efi_tpm2_protocol *this,
++					     grub_efi_uint32_t ActivePcrBanks);
++  grub_efi_status_t (*get_result_of_set_active_pcr_banks) (struct grub_efi_tpm2_protocol *this,
++							   grub_efi_uint32_t *OperationPresent,
++							   grub_efi_uint32_t *Response);
++};
++
++typedef struct grub_efi_tpm2_protocol grub_efi_tpm2_protocol_t;
++
++#define TCG_ALG_SHA 0x00000004
++
++#endif
+diff --git a/include/grub/tpm.h b/include/grub/tpm.h
+new file mode 100644
+index 00000000000..40d3cf65ba6
+--- /dev/null
++++ b/include/grub/tpm.h
+@@ -0,0 +1,91 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2015  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_TPM_HEADER
++#define GRUB_TPM_HEADER 1
++
++#define SHA1_DIGEST_SIZE 20
++
++#define TPM_BASE 0x0
++#define TPM_SUCCESS TPM_BASE
++#define TPM_AUTHFAIL (TPM_BASE + 0x1)
++#define TPM_BADINDEX (TPM_BASE + 0x2)
++
++#define GRUB_TPM_PCR 9
++#define GRUB_KERNEL_PCR 10
++#define GRUB_INITRD_PCR 11
++#define GRUB_CMDLINE_PCR 12
++
++#define TPM_TAG_RQU_COMMAND 0x00C1
++#define TPM_ORD_Extend 0x14
++
++#define EV_IPL 0x0d
++
++/* TCG_PassThroughToTPM Input Parameter Block */
++typedef struct {
++        grub_uint16_t IPBLength;
++        grub_uint16_t Reserved1;
++        grub_uint16_t OPBLength;
++        grub_uint16_t Reserved2;
++        grub_uint8_t TPMOperandIn[1];
++} GRUB_PACKED PassThroughToTPM_InputParamBlock;
++
++/* TCG_PassThroughToTPM Output Parameter Block */
++typedef struct {
++        grub_uint16_t OPBLength;
++        grub_uint16_t Reserved;
++        grub_uint8_t TPMOperandOut[1];
++} GRUB_PACKED PassThroughToTPM_OutputParamBlock;
++
++typedef struct {
++        grub_uint16_t tag;
++        grub_uint32_t paramSize;
++        grub_uint32_t ordinal;
++        grub_uint32_t pcrNum;
++        grub_uint8_t inDigest[SHA1_DIGEST_SIZE];                /* The 160 bit value representing the event to be recorded. */
++} GRUB_PACKED ExtendIncoming;
++
++/* TPM_Extend Outgoing Operand */
++typedef struct {
++        grub_uint16_t tag;
++        grub_uint32_t paramSize;
++        grub_uint32_t returnCode;
++        grub_uint8_t outDigest[SHA1_DIGEST_SIZE];               /* The PCR value after execution of the command. */
++} GRUB_PACKED ExtendOutgoing;
++
++grub_err_t EXPORT_FUNC(grub_tpm_measure) (unsigned char *buf, grub_size_t size,
++					  grub_uint8_t pcr,
++					  const char *description);
++#if defined (GRUB_MACHINE_EFI) || defined (GRUB_MACHINE_PCBIOS)
++grub_err_t grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
++			    PassThroughToTPM_OutputParamBlock *outbuf);
++grub_err_t grub_tpm_log_event(unsigned char *buf, grub_size_t size,
++			      grub_uint8_t pcr, const char *description);
++#else
++static inline grub_err_t grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
++					  PassThroughToTPM_OutputParamBlock *outbuf) { return 0; };
++static inline grub_err_t grub_tpm_log_event(unsigned char *buf,
++					    grub_size_t size,
++					    grub_uint8_t pcr,
++					    const char *description)
++{
++	return 0;
++};
++#endif
++
++#endif
+diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
+index f36200bd688..3781bb9cbb9 100644
+--- a/grub-core/Makefile.am
++++ b/grub-core/Makefile.am
+@@ -94,6 +94,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm_private.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/net.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/tpm.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/memory.h
+ 
+ if COND_i386_pc
diff --git a/SOURCES/0128-Measure-kernel-initrd.patch b/SOURCES/0128-Measure-kernel-initrd.patch
new file mode 100644
index 0000000..ff1f10b
--- /dev/null
+++ b/SOURCES/0128-Measure-kernel-initrd.patch
@@ -0,0 +1,39 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Thu, 16 Jul 2015 15:22:34 -0700
+Subject: [PATCH] Measure kernel + initrd
+
+Measure the kernel and initrd when loaded on UEFI systems
+---
+ grub-core/loader/i386/efi/linux.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 800c3e54022..d837249b4a1 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -27,6 +27,7 @@
+ #include <grub/lib/cmdline.h>
+ #include <grub/efi/efi.h>
+ #include <grub/efi/linux.h>
++#include <grub/tpm.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -131,6 +132,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+                         argv[i]);
+           goto fail;
+         }
++      grub_tpm_measure (ptr, cursize, GRUB_INITRD_PCR, "UEFI Linux initrd");
+       ptr += cursize;
+       grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
+       ptr += ALIGN_UP_OVERHEAD (cursize, 4);
+@@ -195,6 +197,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
++  grub_tpm_measure (kernel, filelen, GRUB_KERNEL_PCR, "UEFI Linux kernel");
++
+   rc = grub_linuxefi_secure_validate (kernel, filelen);
+   if (rc < 0)
+     {
diff --git a/SOURCES/0129-Add-BIOS-boot-measurement.patch b/SOURCES/0129-Add-BIOS-boot-measurement.patch
new file mode 100644
index 0000000..a428d32
--- /dev/null
+++ b/SOURCES/0129-Add-BIOS-boot-measurement.patch
@@ -0,0 +1,176 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Sun, 9 Aug 2015 15:48:51 -0700
+Subject: [PATCH] Add BIOS boot measurement
+
+Measure the on-disk grub core on BIOS systems - unlike UEFI, the firmware
+can't do this stage for us.
+---
+ grub-core/boot/i386/pc/boot.S     | 30 +++++++++++++++++++++++++-
+ grub-core/boot/i386/pc/diskboot.S | 44 +++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 73 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/boot/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S
+index ea167fe1206..c1df86dec0b 100644
+--- a/grub-core/boot/i386/pc/boot.S
++++ b/grub-core/boot/i386/pc/boot.S
+@@ -24,11 +24,14 @@
+  *  defines for the code go here
+  */
+ 
++#define TPM 1
++
+ 	/* Print message string */
+ #define MSG(x)	movw $x, %si; call LOCAL(message)
+ #define ERR(x)	movw $x, %si; jmp LOCAL(error_message)
+ 
+ 	.macro floppy
++#ifndef TPM
+ part_start:
+ 
+ LOCAL(probe_values):
+@@ -85,6 +88,7 @@ fd_probe_error_string:	.asciz "Floppy"
+ 	movb	MACRO_DOLLAR(79), %ch
+ 
+ 	jmp	LOCAL(final_init)
++#endif
+ 	.endm
+ 
+ 	.macro scratch
+@@ -252,6 +256,7 @@ real_start:
+ 	/* set %si to the disk address packet */
+ 	movw	$disk_address_packet, %si
+ 
++#ifndef TPM
+ 	/* check if LBA is supported */
+ 	movb	$0x41, %ah
+ 	movw	$0x55aa, %bx
+@@ -271,6 +276,7 @@ real_start:
+ 
+ 	andw	$1, %cx
+ 	jz	LOCAL(chs_mode)
++#endif
+ 
+ LOCAL(lba_mode):
+ 	xorw	%ax, %ax
+@@ -314,6 +320,9 @@ LOCAL(lba_mode):
+ 	jmp	LOCAL(copy_buffer)
+ 
+ LOCAL(chs_mode):
++#ifdef TPM
++	jmp	LOCAL(general_error)
++#else
+ 	/*
+ 	 *  Determine the hard disk geometry from the BIOS!
+ 	 *  We do this first, so that LS-120 IDE floppies work correctly.
+@@ -425,7 +434,7 @@ setup_sectors:
+ 	jc	LOCAL(read_error)
+ 
+ 	movw	%es, %bx
+-
++#endif /* TPM */
+ LOCAL(copy_buffer):
+ 	/*
+ 	 * We need to save %cx and %si because the startup code in
+@@ -448,6 +457,25 @@ LOCAL(copy_buffer):
+ 	popw	%ds
+ 	popa
+ 
++#ifdef TPM
++	pusha
++
++	movw	$0xBB00, %ax		/* TCG_StatusCheck */
++	int	$0x1A
++	test	%eax, %eax
++	jnz	boot			/* No TPM or TPM deactivated */
++
++	movw	$0xBB07, %ax		/* TCG_CompactHashLogExtendEvent */
++	movw	$GRUB_BOOT_MACHINE_KERNEL_ADDR, %di
++	xorl	%esi, %esi
++	movl	$0x41504354, %ebx	/* TCPA */
++	movl	$0x200, %ecx		/* Measure 512 bytes */
++	movl	$0x8, %edx		/* PCR 8 */
++	int	$0x1A
++
++	popa
++#endif
++boot:
+ 	/* boot kernel */
+ 	jmp	*(LOCAL(kernel_address))
+ 
+diff --git a/grub-core/boot/i386/pc/diskboot.S b/grub-core/boot/i386/pc/diskboot.S
+index 68d31de0c4c..f4744ec6fcb 100644
+--- a/grub-core/boot/i386/pc/diskboot.S
++++ b/grub-core/boot/i386/pc/diskboot.S
+@@ -19,6 +19,8 @@
+ #include <grub/symbol.h>
+ #include <grub/machine/boot.h>
+ 
++#define TPM 1
++
+ /*
+  *  defines for the code go here
+  */
+@@ -53,6 +55,21 @@ _start:
+ 	/* this sets up for the first run through "bootloop" */
+ 	movw	$LOCAL(firstlist), %di
+ 
++#ifdef TPM
++        /* clear EAX to remove potential garbage */
++	xorl    %eax, %eax
++	/* 8(%di) = number of sectors to read */
++	movw    8(%di), %ax
++
++	/* Multiply number of sectors to read with 512 bytes. EAX is 32bit
++	* which is large enough to hold values of up to 4GB. I doubt there
++	* will ever be a core.img larger than that. ;-) */
++	shll    $9, %eax
++
++	/* write result to bytes_to_measure var */
++	movl    %eax, bytes_to_measure
++#endif
++
+ 	/* save the sector number of the second sector in %ebp */
+ 	movl	(%di), %ebp
+ 
+@@ -290,6 +307,29 @@ LOCAL(copy_buffer):
+ /* END OF MAIN LOOP */
+ 
+ LOCAL(bootit):
++#ifdef TPM
++	pusha
++	movw	$0xBB07, %ax		/* TCG_CompactHashLogExtendEvent */
++
++	movw	$0x0, %bx
++	movw	%bx, %es
++
++	/* We've already measured the first 512 bytes, now measure the rest */
++	xorl	%edi, %edi
++	movw	$(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200), %di
++
++	movl	$0x41504354, %ebx	/* EBX = "TCPA" */
++
++	/* %ecx = The length, in bytes, of the buffer to measure  */
++	movl	$bytes_to_measure, %esi
++	movl	(%esi), %ecx
++	xorl	%esi, %esi
++	movl	$0x9, %edx		/* PCR 9 */
++
++	int	$0x1A
++
++	popa
++#endif
+ 	/* print a newline */
+ 	MSG(notification_done)
+ 	popw	%dx	/* this makes sure %dl is our "boot" drive */
+@@ -324,6 +364,10 @@ geometry_error_string:	.asciz "Geom"
+ read_error_string:	.asciz "Read"
+ general_error_string:	.asciz " Error"
+ 
++#ifdef TPM
++bytes_to_measure:	.long 0
++#endif
++
+ /*
+  * message: write the string pointed to by %si
+  *
diff --git a/SOURCES/0130-Measure-kernel-and-initrd-on-BIOS-systems.patch b/SOURCES/0130-Measure-kernel-and-initrd-on-BIOS-systems.patch
new file mode 100644
index 0000000..69d58fb
--- /dev/null
+++ b/SOURCES/0130-Measure-kernel-and-initrd-on-BIOS-systems.patch
@@ -0,0 +1,84 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Sun, 9 Aug 2015 16:28:29 -0700
+Subject: [PATCH] Measure kernel and initrd on BIOS systems
+
+Measure the kernel and initrd when loaded on BIOS systems
+---
+ grub-core/loader/i386/linux.c    | 5 +++++
+ grub-core/loader/i386/pc/linux.c | 3 +++
+ grub-core/loader/linux.c         | 2 ++
+ 3 files changed, 10 insertions(+)
+
+diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
+index c84747ea857..94526966e8a 100644
+--- a/grub-core/loader/i386/linux.c
++++ b/grub-core/loader/i386/linux.c
+@@ -36,6 +36,7 @@
+ #include <grub/lib/cmdline.h>
+ #include <grub/linux.h>
+ #include <grub/efi/sb.h>
++#include <grub/tpm.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -724,7 +725,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
++  grub_tpm_measure (kernel, len, GRUB_KERNEL_PCR, "Linux Kernel");
++
+   grub_memcpy (&lh, kernel, sizeof (lh));
++
+   kernel_offset = sizeof (lh);
+ 
+   if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
+@@ -1038,6 +1042,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   len = prot_file_size;
+   grub_memcpy (prot_mode_mem, kernel + kernel_offset, len);
++  kernel_offset += len;
+ 
+   if (grub_errno == GRUB_ERR_NONE)
+     {
+diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
+index 783a3cd93bc..15544230763 100644
+--- a/grub-core/loader/i386/pc/linux.c
++++ b/grub-core/loader/i386/pc/linux.c
+@@ -36,6 +36,7 @@
+ #include <grub/lib/cmdline.h>
+ #include <grub/linux.h>
+ #include <grub/efi/sb.h>
++#include <grub/tpm.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -161,6 +162,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
++  grub_tpm_measure (kernel, len, GRUB_KERNEL_PCR, "BIOS Linux Kernel");
++
+   grub_memcpy (&lh, kernel, sizeof (lh));
+   kernel_offset = sizeof (lh);
+ 
+diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c
+index be6fa0f4d45..3005c0d19c9 100644
+--- a/grub-core/loader/linux.c
++++ b/grub-core/loader/linux.c
+@@ -4,6 +4,7 @@
+ #include <grub/misc.h>
+ #include <grub/file.h>
+ #include <grub/mm.h>
++#include <grub/tpm.h>
+ 
+ struct newc_head
+ {
+@@ -288,6 +289,7 @@ grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
+ 	  grub_initrd_close (initrd_ctx);
+ 	  return grub_errno;
+ 	}
++      grub_tpm_measure (ptr, cursize, GRUB_INITRD_PCR, "Linux Initrd");
+       ptr += cursize;
+     }
+   if (newc)
diff --git a/SOURCES/0131-Measure-the-kernel-commandline.patch b/SOURCES/0131-Measure-the-kernel-commandline.patch
new file mode 100644
index 0000000..7fe2809
--- /dev/null
+++ b/SOURCES/0131-Measure-the-kernel-commandline.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Sun, 9 Aug 2015 16:32:29 -0700
+Subject: [PATCH] Measure the kernel commandline
+
+Measure the kernel commandline to ensure that it hasn't been modified
+---
+ grub-core/lib/cmdline.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c
+index 970ea868c14..6b56304d4a7 100644
+--- a/grub-core/lib/cmdline.c
++++ b/grub-core/lib/cmdline.c
+@@ -19,6 +19,7 @@
+ 
+ #include <grub/lib/cmdline.h>
+ #include <grub/misc.h>
++#include <grub/tpm.h>
+ 
+ static int
+ is_hex(char c)
+@@ -79,7 +80,7 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+ {
+   int i, space;
+   unsigned int arg_size;
+-  char *c;
++  char *c, *orig = buf;
+ 
+   for (i = 0; i < argc; i++)
+     {
+@@ -125,5 +126,8 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+ 
+   *buf = 0;
+ 
++  grub_tpm_measure ((void *)orig, grub_strlen (orig), GRUB_CMDLINE_PCR,
++		    "Kernel Commandline");
++
+   return i;
+ }
diff --git a/SOURCES/0132-Measure-commands.patch b/SOURCES/0132-Measure-commands.patch
new file mode 100644
index 0000000..bac4c8d
--- /dev/null
+++ b/SOURCES/0132-Measure-commands.patch
@@ -0,0 +1,73 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@srcf.ucam.org>
+Date: Mon, 10 Aug 2015 15:27:12 -0700
+Subject: [PATCH] Measure commands
+
+Measure each command executed by grub, which includes script execution.
+---
+ grub-core/script/execute.c | 25 +++++++++++++++++++++++--
+ include/grub/tpm.h         |  1 +
+ 2 files changed, 24 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
+index cf6cd6601d6..9ae04a05160 100644
+--- a/grub-core/script/execute.c
++++ b/grub-core/script/execute.c
+@@ -30,6 +30,7 @@
+ #ifdef GRUB_MACHINE_IEEE1275
+ #include <grub/ieee1275/ieee1275.h>
+ #endif
++#include <grub/tpm.h>
+ 
+ /* Max digits for a char is 3 (0xFF is 255), similarly for an int it
+    is sizeof (int) * 3, and one extra for a possible -ve sign.  */
+@@ -967,8 +968,9 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
+   grub_err_t ret = 0;
+   grub_script_function_t func = 0;
+   char errnobuf[18];
+-  char *cmdname;
+-  int argc;
++  char *cmdname, *cmdstring;
++  int argc, offset = 0, cmdlen = 0;
++  unsigned int i;
+   char **args;
+   int invert;
+   struct grub_script_argv argv = { 0, 0, 0 };
+@@ -977,6 +979,25 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
+   if (grub_script_arglist_to_argv (cmdline->arglist, &argv) || ! argv.args[0])
+     return grub_errno;
+ 
++  for (i = 0; i < argv.argc; i++) {
++	  cmdlen += grub_strlen (argv.args[i]) + 1;
++  }
++
++  cmdstring = grub_malloc (cmdlen);
++  if (!cmdstring)
++  {
++	  return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++			     N_("cannot allocate command buffer"));
++  }
++
++  for (i = 0; i < argv.argc; i++) {
++	  offset += grub_snprintf (cmdstring + offset, cmdlen - offset, "%s ",
++				   argv.args[i]);
++  }
++  cmdstring[cmdlen-1]= '\0';
++  grub_tpm_measure ((unsigned char *)cmdstring, cmdlen, GRUB_COMMAND_PCR,
++		    cmdstring);
++  grub_free(cmdstring);
+   invert = 0;
+   argc = argv.argc - 1;
+   args = argv.args + 1;
+diff --git a/include/grub/tpm.h b/include/grub/tpm.h
+index 40d3cf65ba6..7fc9d77d277 100644
+--- a/include/grub/tpm.h
++++ b/include/grub/tpm.h
+@@ -30,6 +30,7 @@
+ #define GRUB_KERNEL_PCR 10
+ #define GRUB_INITRD_PCR 11
+ #define GRUB_CMDLINE_PCR 12
++#define GRUB_COMMAND_PCR 13
+ 
+ #define TPM_TAG_RQU_COMMAND 0x00C1
+ #define TPM_ORD_Extend 0x14
diff --git a/SOURCES/0133-Measure-multiboot-images-and-modules.patch b/SOURCES/0133-Measure-multiboot-images-and-modules.patch
new file mode 100644
index 0000000..0c19d8d
--- /dev/null
+++ b/SOURCES/0133-Measure-multiboot-images-and-modules.patch
@@ -0,0 +1,75 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Tue, 1 Sep 2015 16:02:55 -0700
+Subject: [PATCH] Measure multiboot images and modules
+
+---
+ grub-core/loader/i386/multiboot_mbi.c | 3 +++
+ grub-core/loader/multiboot.c          | 2 ++
+ grub-core/loader/multiboot_mbi2.c     | 4 +++-
+ 3 files changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c
+index dc98dbcae25..1c5b0ac25ce 100644
+--- a/grub-core/loader/i386/multiboot_mbi.c
++++ b/grub-core/loader/i386/multiboot_mbi.c
+@@ -36,6 +36,7 @@
+ #include <grub/net.h>
+ #include <grub/i18n.h>
+ #include <grub/lib/cmdline.h>
++#include <grub/tpm.h>
+ 
+ #ifdef GRUB_MACHINE_EFI
+ #include <grub/efi/efi.h>
+@@ -173,6 +174,8 @@ grub_multiboot_load (grub_file_t file, const char *filename)
+       return grub_errno;
+     }
+ 
++  grub_tpm_measure((unsigned char*)buffer, len, GRUB_KERNEL_PCR, filename);
++
+   header = find_header (buffer, len);
+ 
+   if (header == 0)
+diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c
+index 26df46a4161..93e026c53db 100644
+--- a/grub-core/loader/multiboot.c
++++ b/grub-core/loader/multiboot.c
+@@ -51,6 +51,7 @@
+ #include <grub/memory.h>
+ #include <grub/i18n.h>
+ #include <grub/efi/sb.h>
++#include <grub/tpm.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -440,6 +441,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+     }
+ 
+   grub_file_close (file);
++  grub_tpm_measure (module, size, GRUB_KERNEL_PCR, argv[0]);
+   return GRUB_ERR_NONE;
+ }
+ 
+diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c
+index 4df6595954d..d5ad02a33a1 100644
+--- a/grub-core/loader/multiboot_mbi2.c
++++ b/grub-core/loader/multiboot_mbi2.c
+@@ -36,6 +36,7 @@
+ #include <grub/i18n.h>
+ #include <grub/net.h>
+ #include <grub/lib/cmdline.h>
++#include <grub/tpm.h>
+ 
+ #if defined (GRUB_MACHINE_EFI)
+ #include <grub/efi/efi.h>
+@@ -131,8 +132,9 @@ grub_multiboot2_load (grub_file_t file, const char *filename)
+ 
+   COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0);
+ 
++  grub_tpm_measure ((unsigned char *)buffer, len, GRUB_KERNEL_PCR, filename);
++
+   header = find_header (mld.buffer, len);
+-
+   if (header == 0)
+     {
+       grub_free (mld.buffer);
diff --git a/SOURCES/0134-Fix-boot-when-there-s-no-TPM.patch b/SOURCES/0134-Fix-boot-when-there-s-no-TPM.patch
new file mode 100644
index 0000000..60efb93
--- /dev/null
+++ b/SOURCES/0134-Fix-boot-when-there-s-no-TPM.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Wed, 23 Mar 2016 16:49:42 -0700
+Subject: [PATCH] Fix boot when there's no TPM
+
+If the firmware has TPM support but has no TPM, we're jumping to core.img
+without popping the registers back onto the stack. Fix that.
+
+(cherry picked from commit c2eee36ec08f8ed0cd25b8030276347680be4843)
+---
+ grub-core/boot/i386/pc/boot.S | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/boot/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S
+index c1df86dec0b..acab37369ae 100644
+--- a/grub-core/boot/i386/pc/boot.S
++++ b/grub-core/boot/i386/pc/boot.S
+@@ -473,9 +473,9 @@ LOCAL(copy_buffer):
+ 	movl	$0x8, %edx		/* PCR 8 */
+ 	int	$0x1A
+ 
+-	popa
+-#endif
+ boot:
++	popa
++#endif
+ 	/* boot kernel */
+ 	jmp	*(LOCAL(kernel_address))
+ 
diff --git a/SOURCES/0135-Rework-TPM-measurements.patch b/SOURCES/0135-Rework-TPM-measurements.patch
new file mode 100644
index 0000000..eb18094
--- /dev/null
+++ b/SOURCES/0135-Rework-TPM-measurements.patch
@@ -0,0 +1,216 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Wed, 23 Mar 2016 17:03:43 -0700
+Subject: [PATCH] Rework TPM measurements
+
+Rework TPM measurements to use fewer PCRs. After discussion with upstream,
+it's preferable to avoid using so many PCRs. Instead, measure into PCRs 8
+and 9 but use a prefix in the event log to indicate which subsystem carried
+out the measurements.
+
+(cherry picked from commit bb3473d7c8741ad5ef7cf8aafbbcf094df08bfc9)
+---
+ grub-core/kern/dl.c                   |  2 +-
+ grub-core/kern/tpm.c                  | 10 ++++++++--
+ grub-core/lib/cmdline.c               |  4 ++--
+ grub-core/loader/i386/efi/linux.c     |  4 ++--
+ grub-core/loader/i386/linux.c         |  2 +-
+ grub-core/loader/i386/multiboot_mbi.c |  2 +-
+ grub-core/loader/i386/pc/linux.c      |  2 +-
+ grub-core/loader/linux.c              |  2 +-
+ grub-core/loader/multiboot.c          |  2 +-
+ grub-core/loader/multiboot_mbi2.c     |  2 +-
+ grub-core/script/execute.c            |  4 ++--
+ include/grub/tpm.h                    |  9 +++------
+ 12 files changed, 24 insertions(+), 21 deletions(-)
+
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index 387d1e6446d..d0989573866 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -830,7 +830,7 @@ grub_dl_load_file (const char *filename)
+      opens of the same device.  */
+   grub_file_close (file);
+ 
+-  grub_tpm_measure(core, size, GRUB_TPM_PCR, filename);
++  grub_tpm_measure(core, size, GRUB_BINARY_PCR, "grub_module", filename);
+ 
+   mod = grub_dl_load_core (core, size);
+   grub_free (core);
+diff --git a/grub-core/kern/tpm.c b/grub-core/kern/tpm.c
+index 1a991876c83..cb5a812035d 100644
+--- a/grub-core/kern/tpm.c
++++ b/grub-core/kern/tpm.c
+@@ -7,7 +7,13 @@
+ 
+ grub_err_t
+ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
+-		  const char *description)
++		  const char *kind, const char *description)
+ {
+-  return grub_tpm_log_event(buf, size, pcr, description);
++  grub_err_t ret;
++  char *desc = grub_xasprintf("%s %s", kind, description);
++  if (!desc)
++    return GRUB_ERR_OUT_OF_MEMORY;
++  ret = grub_tpm_log_event(buf, size, pcr, description);
++  grub_free(desc);
++  return ret;
+ }
+diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c
+index 6b56304d4a7..178f7382f07 100644
+--- a/grub-core/lib/cmdline.c
++++ b/grub-core/lib/cmdline.c
+@@ -126,8 +126,8 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+ 
+   *buf = 0;
+ 
+-  grub_tpm_measure ((void *)orig, grub_strlen (orig), GRUB_CMDLINE_PCR,
+-		    "Kernel Commandline");
++  grub_tpm_measure ((void *)orig, grub_strlen (orig), GRUB_ASCII_PCR,
++		    "grub_kernel_cmdline", orig);
+ 
+   return i;
+ }
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index d837249b4a1..074dbd6513e 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -132,7 +132,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+                         argv[i]);
+           goto fail;
+         }
+-      grub_tpm_measure (ptr, cursize, GRUB_INITRD_PCR, "UEFI Linux initrd");
++      grub_tpm_measure (ptr, cursize, GRUB_BINARY_PCR, "grub_linuxefi", "Initrd");
+       ptr += cursize;
+       grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
+       ptr += ALIGN_UP_OVERHEAD (cursize, 4);
+@@ -197,7 +197,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  grub_tpm_measure (kernel, filelen, GRUB_KERNEL_PCR, "UEFI Linux kernel");
++  grub_tpm_measure (kernel, filelen, GRUB_BINARY_PCR, "grub_linuxefi", "Kernel");
+ 
+   rc = grub_linuxefi_secure_validate (kernel, filelen);
+   if (rc < 0)
+diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
+index 94526966e8a..273f48a6c88 100644
+--- a/grub-core/loader/i386/linux.c
++++ b/grub-core/loader/i386/linux.c
+@@ -725,7 +725,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  grub_tpm_measure (kernel, len, GRUB_KERNEL_PCR, "Linux Kernel");
++  grub_tpm_measure (kernel, len, GRUB_BINARY_PCR, "grub_linux", "Kernel");
+ 
+   grub_memcpy (&lh, kernel, sizeof (lh));
+ 
+diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c
+index 1c5b0ac25ce..2ce424a997b 100644
+--- a/grub-core/loader/i386/multiboot_mbi.c
++++ b/grub-core/loader/i386/multiboot_mbi.c
+@@ -174,7 +174,7 @@ grub_multiboot_load (grub_file_t file, const char *filename)
+       return grub_errno;
+     }
+ 
+-  grub_tpm_measure((unsigned char*)buffer, len, GRUB_KERNEL_PCR, filename);
++  grub_tpm_measure((unsigned char*)buffer, len, GRUB_BINARY_PCR, "grub_multiboot", filename);
+ 
+   header = find_header (buffer, len);
+ 
+diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
+index 15544230763..4f8c02288ec 100644
+--- a/grub-core/loader/i386/pc/linux.c
++++ b/grub-core/loader/i386/pc/linux.c
+@@ -162,7 +162,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  grub_tpm_measure (kernel, len, GRUB_KERNEL_PCR, "BIOS Linux Kernel");
++  grub_tpm_measure (kernel, len, GRUB_BINARY_PCR, "grub_linux16", "Kernel");
+ 
+   grub_memcpy (&lh, kernel, sizeof (lh));
+   kernel_offset = sizeof (lh);
+diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c
+index 3005c0d19c9..78c41e33416 100644
+--- a/grub-core/loader/linux.c
++++ b/grub-core/loader/linux.c
+@@ -289,7 +289,7 @@ grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
+ 	  grub_initrd_close (initrd_ctx);
+ 	  return grub_errno;
+ 	}
+-      grub_tpm_measure (ptr, cursize, GRUB_INITRD_PCR, "Linux Initrd");
++      grub_tpm_measure (ptr, cursize, GRUB_BINARY_PCR, "grub_initrd", "Initrd");
+       ptr += cursize;
+     }
+   if (newc)
+diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c
+index 93e026c53db..3b87dc4fab3 100644
+--- a/grub-core/loader/multiboot.c
++++ b/grub-core/loader/multiboot.c
+@@ -441,7 +441,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+     }
+ 
+   grub_file_close (file);
+-  grub_tpm_measure (module, size, GRUB_KERNEL_PCR, argv[0]);
++  grub_tpm_measure (module, size, GRUB_BINARY_PCR, "grub_multiboot", argv[0]);
+   return GRUB_ERR_NONE;
+ }
+ 
+diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c
+index d5ad02a33a1..60ae4606fda 100644
+--- a/grub-core/loader/multiboot_mbi2.c
++++ b/grub-core/loader/multiboot_mbi2.c
+@@ -132,7 +132,7 @@ grub_multiboot2_load (grub_file_t file, const char *filename)
+ 
+   COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0);
+ 
+-  grub_tpm_measure ((unsigned char *)buffer, len, GRUB_KERNEL_PCR, filename);
++  grub_tpm_measure ((unsigned char *)mld.buffer, len, GRUB_BINARY_PCR, "grub_multiboot", filename);
+ 
+   header = find_header (mld.buffer, len);
+   if (header == 0)
+diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
+index 9ae04a05160..976643c47b0 100644
+--- a/grub-core/script/execute.c
++++ b/grub-core/script/execute.c
+@@ -995,8 +995,8 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
+ 				   argv.args[i]);
+   }
+   cmdstring[cmdlen-1]= '\0';
+-  grub_tpm_measure ((unsigned char *)cmdstring, cmdlen, GRUB_COMMAND_PCR,
+-		    cmdstring);
++  grub_tpm_measure ((unsigned char *)cmdstring, cmdlen, GRUB_ASCII_PCR,
++		    "grub_cmd", cmdstring);
+   grub_free(cmdstring);
+   invert = 0;
+   argc = argv.argc - 1;
+diff --git a/include/grub/tpm.h b/include/grub/tpm.h
+index 7fc9d77d277..ecb2d09ff5d 100644
+--- a/include/grub/tpm.h
++++ b/include/grub/tpm.h
+@@ -26,11 +26,8 @@
+ #define TPM_AUTHFAIL (TPM_BASE + 0x1)
+ #define TPM_BADINDEX (TPM_BASE + 0x2)
+ 
+-#define GRUB_TPM_PCR 9
+-#define GRUB_KERNEL_PCR 10
+-#define GRUB_INITRD_PCR 11
+-#define GRUB_CMDLINE_PCR 12
+-#define GRUB_COMMAND_PCR 13
++#define GRUB_ASCII_PCR 8
++#define GRUB_BINARY_PCR 9
+ 
+ #define TPM_TAG_RQU_COMMAND 0x00C1
+ #define TPM_ORD_Extend 0x14
+@@ -70,7 +67,7 @@ typedef struct {
+ } GRUB_PACKED ExtendOutgoing;
+ 
+ grub_err_t EXPORT_FUNC(grub_tpm_measure) (unsigned char *buf, grub_size_t size,
+-					  grub_uint8_t pcr,
++					  grub_uint8_t pcr, const char *kind,
+ 					  const char *description);
+ #if defined (GRUB_MACHINE_EFI) || defined (GRUB_MACHINE_PCBIOS)
+ grub_err_t grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
diff --git a/SOURCES/0136-Fix-event-log-prefix.patch b/SOURCES/0136-Fix-event-log-prefix.patch
new file mode 100644
index 0000000..7b98f9a
--- /dev/null
+++ b/SOURCES/0136-Fix-event-log-prefix.patch
@@ -0,0 +1,26 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Tue, 29 Mar 2016 15:36:49 -0700
+Subject: [PATCH] Fix event log prefix
+
+We're not passing the prefixed version of the description to the event log.
+Fix that.
+
+(cherry picked from commit aab446306b8a78c741e229861c4988738cfc6426)
+---
+ grub-core/kern/tpm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/kern/tpm.c b/grub-core/kern/tpm.c
+index cb5a812035d..e5e8fced624 100644
+--- a/grub-core/kern/tpm.c
++++ b/grub-core/kern/tpm.c
+@@ -13,7 +13,7 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
+   char *desc = grub_xasprintf("%s %s", kind, description);
+   if (!desc)
+     return GRUB_ERR_OUT_OF_MEMORY;
+-  ret = grub_tpm_log_event(buf, size, pcr, description);
++  ret = grub_tpm_log_event(buf, size, pcr, desc);
+   grub_free(desc);
+   return ret;
+ }
diff --git a/SOURCES/0137-Set-the-first-boot-menu-entry-as-default-when-using-.patch b/SOURCES/0137-Set-the-first-boot-menu-entry-as-default-when-using-.patch
new file mode 100644
index 0000000..1e8e73f
--- /dev/null
+++ b/SOURCES/0137-Set-the-first-boot-menu-entry-as-default-when-using-.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 6 Apr 2018 14:08:36 +0200
+Subject: [PATCH] Set the first boot menu entry as default when using BLS
+ fragments
+
+When BootLoaderSpec configuration files are used, the default boot menu
+entry is always set to the first entry as sorted by the blscfg command.
+
+Suggested-by: Peter Jones <pjones@redhat.com>
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub.d/10_linux.in | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 839f1fdb655..89cd71d852d 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -144,6 +144,7 @@ if [ -s \$prefix/grubenv ]; then
+ fi
+ EOF
+ 
++    ${grub_editenv} - set saved_entry=0
+     ${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
+ 
+     exit 0
diff --git a/SOURCES/0138-tpm-fix-warnings-when-compiling-for-platforms-other-.patch b/SOURCES/0138-tpm-fix-warnings-when-compiling-for-platforms-other-.patch
new file mode 100644
index 0000000..9f9373f
--- /dev/null
+++ b/SOURCES/0138-tpm-fix-warnings-when-compiling-for-platforms-other-.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Marineau <michael.marineau@coreos.com>
+Date: Sun, 21 Aug 2016 18:24:58 -0700
+Subject: [PATCH] tpm: fix warnings when compiling for platforms other than pc
+ and efi
+
+---
+ include/grub/tpm.h | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/include/grub/tpm.h b/include/grub/tpm.h
+index ecb2d09ff5d..972a5edc836 100644
+--- a/include/grub/tpm.h
++++ b/include/grub/tpm.h
+@@ -75,12 +75,17 @@ grub_err_t grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
+ grub_err_t grub_tpm_log_event(unsigned char *buf, grub_size_t size,
+ 			      grub_uint8_t pcr, const char *description);
+ #else
+-static inline grub_err_t grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
+-					  PassThroughToTPM_OutputParamBlock *outbuf) { return 0; };
+-static inline grub_err_t grub_tpm_log_event(unsigned char *buf,
+-					    grub_size_t size,
+-					    grub_uint8_t pcr,
+-					    const char *description)
++static inline grub_err_t grub_tpm_execute(
++	PassThroughToTPM_InputParamBlock *inbuf __attribute__ ((unused)),
++	PassThroughToTPM_OutputParamBlock *outbuf __attribute__ ((unused)))
++{
++	return 0;
++};
++static inline grub_err_t grub_tpm_log_event(
++	unsigned char *buf __attribute__ ((unused)),
++	grub_size_t size __attribute__ ((unused)),
++	grub_uint8_t pcr __attribute__ ((unused)),
++	const char *description __attribute__ ((unused)))
+ {
+ 	return 0;
+ };
diff --git a/SOURCES/0139-Make-TPM-errors-less-fatal.patch b/SOURCES/0139-Make-TPM-errors-less-fatal.patch
new file mode 100644
index 0000000..bcee8a1
--- /dev/null
+++ b/SOURCES/0139-Make-TPM-errors-less-fatal.patch
@@ -0,0 +1,208 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@coreos.com>
+Date: Thu, 13 Oct 2016 13:55:26 -0700
+Subject: [PATCH] Make TPM errors less fatal
+
+Handle TPM errors, and stop trying to use the TPM once we hit one.
+---
+ grub-core/kern/dl.c                   |  1 +
+ grub-core/kern/i386/pc/tpm.c          | 21 +++++++++++++++++----
+ grub-core/lib/cmdline.c               |  1 +
+ grub-core/loader/i386/efi/linux.c     |  2 ++
+ grub-core/loader/i386/linux.c         |  1 +
+ grub-core/loader/i386/multiboot_mbi.c |  1 +
+ grub-core/loader/i386/pc/linux.c      |  1 +
+ grub-core/loader/linux.c              |  2 ++
+ grub-core/loader/multiboot.c          |  1 +
+ grub-core/loader/multiboot_mbi2.c     |  1 +
+ grub-core/script/execute.c            |  1 +
+ 11 files changed, 29 insertions(+), 4 deletions(-)
+
+diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
+index d0989573866..91105bc4677 100644
+--- a/grub-core/kern/dl.c
++++ b/grub-core/kern/dl.c
+@@ -831,6 +831,7 @@ grub_dl_load_file (const char *filename)
+   grub_file_close (file);
+ 
+   grub_tpm_measure(core, size, GRUB_BINARY_PCR, "grub_module", filename);
++  grub_print_error();
+ 
+   mod = grub_dl_load_core (core, size);
+   grub_free (core);
+diff --git a/grub-core/kern/i386/pc/tpm.c b/grub-core/kern/i386/pc/tpm.c
+index 8c6c1e6ece2..f6f264aff2e 100644
+--- a/grub-core/kern/i386/pc/tpm.c
++++ b/grub-core/kern/i386/pc/tpm.c
+@@ -7,21 +7,28 @@
+ 
+ #define TCPA_MAGIC 0x41504354
+ 
++static int tpm_presence = -1;
++
+ int tpm_present(void);
+ 
+ int tpm_present(void)
+ {
+   struct grub_bios_int_registers regs;
+ 
++  if (tpm_presence != -1)
++    return tpm_presence;
++
+   regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+   regs.eax = 0xbb00;
+   regs.ebx = TCPA_MAGIC;
+   grub_bios_interrupt (0x1a, &regs);
+ 
+   if (regs.eax == 0)
+-    return 1;
++    tpm_presence = 1;
++  else
++    tpm_presence = 0;
+ 
+-  return 0;
++  return tpm_presence;
+ }
+ 
+ grub_err_t
+@@ -49,7 +56,10 @@ grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
+   grub_bios_interrupt (0x1a, &regs);
+ 
+   if (regs.eax)
+-    return grub_error (GRUB_ERR_IO, N_("TPM error %x\n"), regs.eax);
++    {
++	tpm_presence = 0;
++	return grub_error (GRUB_ERR_IO, N_("TPM error %x, disabling TPM"), regs.eax);
++    }
+ 
+   return 0;
+ }
+@@ -126,7 +136,10 @@ grub_tpm_log_event(unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
+ 	grub_free(event);
+ 
+ 	if (regs.eax)
+-		return grub_error (GRUB_ERR_IO, N_("TPM error %x\n"), regs.eax);
++	  {
++		tpm_presence = 0;
++		return grub_error (GRUB_ERR_IO, N_("TPM error %x, disabling TPM"), regs.eax);
++	  }
+ 
+ 	return 0;
+ }
+diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c
+index 178f7382f07..d5c12957cad 100644
+--- a/grub-core/lib/cmdline.c
++++ b/grub-core/lib/cmdline.c
+@@ -128,6 +128,7 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+ 
+   grub_tpm_measure ((void *)orig, grub_strlen (orig), GRUB_ASCII_PCR,
+ 		    "grub_kernel_cmdline", orig);
++  grub_print_error();
+ 
+   return i;
+ }
+diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
+index 074dbd6513e..ea9f5134e67 100644
+--- a/grub-core/loader/i386/efi/linux.c
++++ b/grub-core/loader/i386/efi/linux.c
+@@ -133,6 +133,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+           goto fail;
+         }
+       grub_tpm_measure (ptr, cursize, GRUB_BINARY_PCR, "grub_linuxefi", "Initrd");
++      grub_print_error();
+       ptr += cursize;
+       grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
+       ptr += ALIGN_UP_OVERHEAD (cursize, 4);
+@@ -198,6 +199,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     }
+ 
+   grub_tpm_measure (kernel, filelen, GRUB_BINARY_PCR, "grub_linuxefi", "Kernel");
++  grub_print_error();
+ 
+   rc = grub_linuxefi_secure_validate (kernel, filelen);
+   if (rc < 0)
+diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
+index 273f48a6c88..76304f05700 100644
+--- a/grub-core/loader/i386/linux.c
++++ b/grub-core/loader/i386/linux.c
+@@ -726,6 +726,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     }
+ 
+   grub_tpm_measure (kernel, len, GRUB_BINARY_PCR, "grub_linux", "Kernel");
++  grub_print_error();
+ 
+   grub_memcpy (&lh, kernel, sizeof (lh));
+ 
+diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c
+index 2ce424a997b..ca85358f771 100644
+--- a/grub-core/loader/i386/multiboot_mbi.c
++++ b/grub-core/loader/i386/multiboot_mbi.c
+@@ -175,6 +175,7 @@ grub_multiboot_load (grub_file_t file, const char *filename)
+     }
+ 
+   grub_tpm_measure((unsigned char*)buffer, len, GRUB_BINARY_PCR, "grub_multiboot", filename);
++  grub_print_error();
+ 
+   header = find_header (buffer, len);
+ 
+diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
+index 4f8c02288ec..cfff25c21b5 100644
+--- a/grub-core/loader/i386/pc/linux.c
++++ b/grub-core/loader/i386/pc/linux.c
+@@ -163,6 +163,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     }
+ 
+   grub_tpm_measure (kernel, len, GRUB_BINARY_PCR, "grub_linux16", "Kernel");
++  grub_print_error();
+ 
+   grub_memcpy (&lh, kernel, sizeof (lh));
+   kernel_offset = sizeof (lh);
+diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c
+index 78c41e33416..c2c7cfcd0fd 100644
+--- a/grub-core/loader/linux.c
++++ b/grub-core/loader/linux.c
+@@ -290,6 +290,8 @@ grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
+ 	  return grub_errno;
+ 	}
+       grub_tpm_measure (ptr, cursize, GRUB_BINARY_PCR, "grub_initrd", "Initrd");
++      grub_print_error();
++
+       ptr += cursize;
+     }
+   if (newc)
+diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c
+index 3b87dc4fab3..9a8dae5565b 100644
+--- a/grub-core/loader/multiboot.c
++++ b/grub-core/loader/multiboot.c
+@@ -442,6 +442,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+ 
+   grub_file_close (file);
+   grub_tpm_measure (module, size, GRUB_BINARY_PCR, "grub_multiboot", argv[0]);
++  grub_print_error();
+   return GRUB_ERR_NONE;
+ }
+ 
+diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c
+index 60ae4606fda..54078455e2f 100644
+--- a/grub-core/loader/multiboot_mbi2.c
++++ b/grub-core/loader/multiboot_mbi2.c
+@@ -133,6 +133,7 @@ grub_multiboot2_load (grub_file_t file, const char *filename)
+   COMPILE_TIME_ASSERT (MULTIBOOT_HEADER_ALIGN % 4 == 0);
+ 
+   grub_tpm_measure ((unsigned char *)mld.buffer, len, GRUB_BINARY_PCR, "grub_multiboot", filename);
++  grub_print_error();
+ 
+   header = find_header (mld.buffer, len);
+   if (header == 0)
+diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
+index 976643c47b0..93965777138 100644
+--- a/grub-core/script/execute.c
++++ b/grub-core/script/execute.c
+@@ -997,6 +997,7 @@ grub_script_execute_cmdline (struct grub_script_cmd *cmd)
+   cmdstring[cmdlen-1]= '\0';
+   grub_tpm_measure ((unsigned char *)cmdstring, cmdlen, GRUB_ASCII_PCR,
+ 		    "grub_cmd", cmdstring);
++  grub_print_error();
+   grub_free(cmdstring);
+   invert = 0;
+   argc = argv.argc - 1;
diff --git a/SOURCES/0140-blscfg-handle-multiple-initramfs-images.patch b/SOURCES/0140-blscfg-handle-multiple-initramfs-images.patch
new file mode 100644
index 0000000..2050ffa
--- /dev/null
+++ b/SOURCES/0140-blscfg-handle-multiple-initramfs-images.patch
@@ -0,0 +1,104 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 11 Apr 2018 13:44:29 -0400
+Subject: [PATCH] blscfg: handle multiple initramfs images.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/commands/blscfg.c | 54 ++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 44 insertions(+), 10 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index e775c6b8794..6ab85df6b3a 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -587,6 +587,7 @@ static void create_entry (struct bls_entry *entry, const char *cfgfile)
+   char *title = NULL;
+   char *clinux = NULL;
+   char *options = NULL;
++  char **initrds = NULL;
+   char *initrd = NULL;
+   char *id = NULL;
+   char *hotkey = NULL;
+@@ -609,7 +610,7 @@ static void create_entry (struct bls_entry *entry, const char *cfgfile)
+ 
+   title = bls_get_val (entry, "title", NULL);
+   options = bls_get_val (entry, "options", NULL);
+-  initrd = bls_get_val (entry, "initrd", NULL);
++  initrds = bls_make_list (entry, "initrd", NULL);
+   id = bls_get_val (entry, "id", NULL);
+ 
+   hotkey = bls_get_val (entry, "grub_hotkey", NULL);
+@@ -624,30 +625,63 @@ static void create_entry (struct bls_entry *entry, const char *cfgfile)
+     argv[i] = args[i-1];
+   argv[argc] = NULL;
+ 
+-  grub_dprintf("blscfg", "adding menu entry for \"%s\"\n", title);
++  grub_dprintf ("blscfg", "adding menu entry for \"%s\"\n", title);
++  if (initrds)
++    {
++      int initrd_size = sizeof (GRUB_INITRD_CMD);
++      char *tmp;
++
++      for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
++	initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \
++		       + grub_strlen (initrds[i]) + 1;
++      initrd_size += 1;
++
++      initrd = grub_malloc (initrd_size);
++      if (!initrd)
++	{
++	  grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
++	  goto finish;
++	}
++
++
++      tmp = grub_stpcpy(initrd, GRUB_INITRD_CMD);
++      for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
++	{
++	  grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]);
++	  tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
++	  tmp = grub_stpcpy (tmp, initrds[i]);
++	}
++      tmp = grub_stpcpy (tmp, "\n");
++    }
++
+   src = grub_xasprintf ("load_video\n"
+ 			"set gfx_payload=keep\n"
+ 			"insmod gzio\n"
+ 			GRUB_LINUX_CMD " %s%s%s%s\n"
+-			"%s%s%s%s",
++			"%s",
+ 			GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "",
+-			initrd ? GRUB_INITRD_CMD " " : "", initrd ? GRUB_BOOT_DEVICE : "", initrd ? initrd : "", initrd ? "\n" : "");
++			initrd ? initrd : "");
+ 
+   grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0);
+ 
+ finish:
++  if (initrd)
++    grub_free (initrd);
++
++  if (initrds)
++    grub_free (initrds);
++
+   if (classes)
+-      grub_free (classes);
+-  grub_dprintf("blscfg", "%s got here\n", __func__);
++    grub_free (classes);
++
+   if (args)
+-      grub_free (args);
++    grub_free (args);
+ 
+   if (argv)
+-      grub_free (argv);
++    grub_free (argv);
+ 
+   if (src)
+-      grub_free (src);
+-  grub_dprintf("blscfg", "%s got here\n", __func__);
++    grub_free (src);
+ }
+ 
+ struct find_entry_info {
diff --git a/SOURCES/0141-BLS-Fix-grub2-switch-to-blscfg-on-non-EFI-machines.patch b/SOURCES/0141-BLS-Fix-grub2-switch-to-blscfg-on-non-EFI-machines.patch
new file mode 100644
index 0000000..a045646
--- /dev/null
+++ b/SOURCES/0141-BLS-Fix-grub2-switch-to-blscfg-on-non-EFI-machines.patch
@@ -0,0 +1,25 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jan Hlavac <jhlavac@redhat.com>
+Date: Tue, 10 Apr 2018 16:07:36 +0200
+Subject: [PATCH] BLS: Fix grub2-switch-to-blscfg on non-EFI machines
+
+On the non-EFI machines the grub2-switch-to-blscfg script places the BLS
+snippets into the /boot directory. But the right location is
+/boot/loader/entries.
+---
+ util/grub-switch-to-blscfg.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index 3ae5e4ea8d0..f740b8f4d03 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -44,7 +44,7 @@ if [ -d /sys/firmware/efi/efivars/ ]; then
+ else
+     startlink=/etc/grub2.cfg
+     grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
+-    blsdir=`echo "/@bootdirname@" | sed 's,//*,/,g'`
++    blsdir=`echo "/@bootdirname@/loader/entries" | sed 's,//*,/,g'`
+ fi
+ 
+ backupsuffix=.bak
diff --git a/SOURCES/0142-BLS-Use-etcdefaultgrub-instead-of-etc.patch b/SOURCES/0142-BLS-Use-etcdefaultgrub-instead-of-etc.patch
new file mode 100644
index 0000000..db97410
--- /dev/null
+++ b/SOURCES/0142-BLS-Use-etcdefaultgrub-instead-of-etc.patch
@@ -0,0 +1,24 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Jan Hlavac <jhlavac@redhat.com>
+Date: Tue, 10 Apr 2018 16:56:28 +0200
+Subject: [PATCH] BLS: Use ${etcdefaultgrub} instead of /etc/...
+
+Inside the grub-switch-to-blscfg script the ${etcdefaultgrub} variable
+is used. So replace the hardcoded /etc/default/grub with it.
+---
+ util/grub-switch-to-blscfg.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index f740b8f4d03..eae3c379e4a 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -252,7 +252,7 @@ if [[ "${GENERATE}" -eq 1 ]] ; then
+         cp -af "${GRUB_CONFIG_FILE}${backupsuffix}" "${GRUB_CONFIG_FILE}"
+         sed -i"${backupsuffix}" \
+             -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=false,' \
+-            /etc/default/grub
++            "${etcdefaultgrub}"
+         gettext_printf "Updating %s failed\n" "${GRUB_CONFIG_FILE}"
+         exit 1
+     fi
diff --git a/SOURCES/0143-Add-missing-options-to-grub2-switch-to-blscfg-man-pa.patch b/SOURCES/0143-Add-missing-options-to-grub2-switch-to-blscfg-man-pa.patch
new file mode 100644
index 0000000..16ab928
--- /dev/null
+++ b/SOURCES/0143-Add-missing-options-to-grub2-switch-to-blscfg-man-pa.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 11 Apr 2018 11:36:43 +0200
+Subject: [PATCH] Add missing options to grub2-switch-to-blscfg man page
+
+The script --bls-directory and --backup-suffix options were not documented
+in the man page, add them as well so users can know what these are about.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-switch-to-blscfg.8 | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/util/grub-switch-to-blscfg.8 b/util/grub-switch-to-blscfg.8
+index 134dfc62a7b..7d99de2d2f9 100644
+--- a/util/grub-switch-to-blscfg.8
++++ b/util/grub-switch-to-blscfg.8
+@@ -21,5 +21,13 @@ The grub config file to use.  The default value is \fI/etc/grub2-efi.cfg\fR on U
+ --grub-defaults=\fIFILE\fR
+ The defaults file for grub-mkconfig.  The default value is \fI/etc/default/grub\fR.
+ 
++.TP
++--bls-directory=\fIDIR\fR
++Create BootLoaderSpec fragments in \fIDIR\fR.  The default value is \fI/boot/loader/entries\fR on BIOS machines and \fI/boot/efi/EFI/\fBVENDOR\fI/loader/entries\fR on UEFI machines.
++
++.TP
++--backup-suffix=\fSUFFIX\fR
++The suffix to use for saved backup files.  The default value is \fI.bak\fR.
++
+ .SH SEE ALSO
+ .BR "info grub"
diff --git a/SOURCES/0144-Make-grub2-switch-to-blscfg-to-generate-debug-BLS-wh.patch b/SOURCES/0144-Make-grub2-switch-to-blscfg-to-generate-debug-BLS-wh.patch
new file mode 100644
index 0000000..5e47f2d
--- /dev/null
+++ b/SOURCES/0144-Make-grub2-switch-to-blscfg-to-generate-debug-BLS-wh.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 11 Apr 2018 11:49:24 +0200
+Subject: [PATCH] Make grub2-switch-to-blscfg to generate debug BLS when
+ MAKEDEBUG is set
+
+If MAKEDEBUG=yes in /etc/sysconfig/kernel, then a debug menu entry should
+be created. So for BLS, a debug configuration file has to be created that
+contains additional debug kernel command line parameters.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-switch-to-blscfg.in | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index eae3c379e4a..c59299ffa6a 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -21,6 +21,7 @@
+ # Initialize some variables.
+ prefix=@prefix@
+ exec_prefix=@exec_prefix@
++sbindir=@sbindir@
+ bindir=@bindir@
+ sysconfdir="@sysconfdir@"
+ PACKAGE_NAME=@PACKAGE_NAME@
+@@ -33,9 +34,12 @@ fi
+ 
+ self=`basename $0`
+ 
++grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@"
+ grub_editenv=${bindir}/@grub_editenv@
+ etcdefaultgrub=/etc/default/grub
+ 
++eval "$("${grub_get_kernel_settings}")" || true
++
+ EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/')
+ if [ -d /sys/firmware/efi/efivars/ ]; then
+     startlink=/etc/grub2-efi.cfg
+@@ -226,6 +230,17 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+             "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${kernel_dir}")")" \
+             >"${bls_target}"
+     fi
++
++    if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
++        arch="$(uname -m)"
++        bls_debug="$(echo ${bls_target} | sed -e "s/\.${arch}/-debug.${arch}/")"
++        cp -aT  "${bls_target}" "${bls_debug}"
++        title="$(grep '^title[ \t]' "${bls_debug}" | sed -e 's/^title[ \t]*//')"
++        blsid="$(grep '^id[ \t]' "${bls_debug}" | sed -e "s/\.${ARCH}/-debug.${arch}/")"
++        sed -i -e "s/^title.*/title ${title}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${bls_debug}"
++        sed -i -e "s/^id.*/${blsid}/" "${bls_debug}"
++        sed -i -e "s/^options.*/options \$kernelopts ${GRUB_CMDLINE_LINUX_DEBUG}/" "${bls_debug}"
++    fi
+ done
+ 
+ GENERATE=0
diff --git a/SOURCES/0145-Make-grub2-switch-to-blscfg-to-generate-BLS-fragment.patch b/SOURCES/0145-Make-grub2-switch-to-blscfg-to-generate-BLS-fragment.patch
new file mode 100644
index 0000000..eb1726b
--- /dev/null
+++ b/SOURCES/0145-Make-grub2-switch-to-blscfg-to-generate-BLS-fragment.patch
@@ -0,0 +1,28 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 11 Apr 2018 12:39:59 +0200
+Subject: [PATCH] Make grub2-switch-to-blscfg to generate BLS fragment for
+ rescue kernel
+
+If a rescue image is available, it should have a BootLoaderSpec fragment.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-switch-to-blscfg.in | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index c59299ffa6a..bc28053cd30 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -243,6 +243,10 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+     fi
+ done
+ 
++if [[ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]]; then
++    mkbls "0-rescue-${MACHINE_ID}" "0" >"${blsdir}/${MACHINE_ID}-0-rescue.conf"
++fi
++
+ GENERATE=0
+ if grep '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" \
+         | grep -vq '^GRUB_ENABLE_BLSCFG="*true"*\s*$' ; then
diff --git a/SOURCES/0146-Only-attempt-to-query-dev-mounted-in-boot-efi-as-boo.patch b/SOURCES/0146-Only-attempt-to-query-dev-mounted-in-boot-efi-as-boo.patch
new file mode 100644
index 0000000..84b0167
--- /dev/null
+++ b/SOURCES/0146-Only-attempt-to-query-dev-mounted-in-boot-efi-as-boo.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 24 Apr 2018 02:16:38 +0200
+Subject: [PATCH] Only attempt to query dev mounted in /boot/efi as boot dev on
+ EFI machines
+
+The 10_linux script calls grub2-probe to probe the information for the dev
+mounted in /boot/efi, but this directory may not exist on non-EFI machines
+which leads to the following error when generating the grub2 config file:
+
+/usr/sbin/grub2-probe: error: failed to get canonical path of `/boot/efi/'
+
+Instead query for the device mounted in /boot and use that as the boot dev
+for non-EFI machines.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub.d/10_linux.in | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 89cd71d852d..61d0664fb5c 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -133,8 +133,13 @@ linux_entry ()
+       fi
+     fi
+ 
+-    bootefi_device="`${grub_probe} --target=device /boot/efi/`"
+-    prepare_grub_to_access_device ${bootefi_device} boot
++    if [ -d /sys/firmware/efi ]; then
++        bootefi_device="`${grub_probe} --target=device /boot/efi/`"
++        prepare_grub_to_access_device ${bootefi_device} boot
++    else
++        boot_device="`${grub_probe} --target=device /boot/`"
++        prepare_grub_to_access_device ${boot_device} boot
++    fi
+ 
+     cat << EOF
+ insmod blscfg
diff --git a/SOURCES/0147-Include-OSTree-path-when-searching-kernels-images-if.patch b/SOURCES/0147-Include-OSTree-path-when-searching-kernels-images-if.patch
new file mode 100644
index 0000000..70b33b3
--- /dev/null
+++ b/SOURCES/0147-Include-OSTree-path-when-searching-kernels-images-if.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 24 Apr 2018 02:28:04 +0200
+Subject: [PATCH] Include OSTree path when searching kernels images if BLS
+ config is enabled
+
+The OSTree based distros (i.e: Fedora Atomic) don't install kernel images
+in the /boot directory, but in /boot/ostree. So the 10_linux script isn't
+able to include these kernels in its list, so the linux_entry() function
+is never called.
+
+This isn't a problem since the 10_linux script isn't used to populate the
+menu entries anyways, but instead a custom 15_ostree script is used. But
+for BLS we want the 10_linux script to generate the minimal grub.cfg that
+calls the blscfg command, so add the OSTree kernel images to the list.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub.d/10_linux.in | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 61d0664fb5c..9682e97b7f5 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -237,6 +237,12 @@ case "x$machine" in
+ 	done ;;
+ esac
+ 
++if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then
++    for i in /boot/ostree/*/vmlinuz-* ; do
++        if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi
++    done
++fi
++
+ case "$machine" in
+     i?86) GENKERNEL_ARCH="x86" ;;
+     mips|mips64) GENKERNEL_ARCH="mips" ;;
diff --git a/SOURCES/0148-Use-BLS-version-field-to-compare-entries-if-id-field.patch b/SOURCES/0148-Use-BLS-version-field-to-compare-entries-if-id-field.patch
new file mode 100644
index 0000000..0d76ad8
--- /dev/null
+++ b/SOURCES/0148-Use-BLS-version-field-to-compare-entries-if-id-field.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 27 Apr 2018 17:53:41 +0200
+Subject: [PATCH] Use BLS version field to compare entries if id field isn't
+ defined
+
+The BootLoaderSpec fragments generated by OSTree don't have the id field,
+so grub2 will attempt to sort the entries by using the title field which
+may not be correct. The entries do have a version field though so use it.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 6ab85df6b3a..c52d2b2e05a 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -418,6 +418,9 @@ static int bls_cmp(const void *p0, const void *p1, void *state UNUSED)
+ 
+   rc = bls_keyval_cmp (e0, e1, "id");
+ 
++  if (rc == 0)
++    rc = bls_keyval_cmp (e0, e1, "version");
++
+   if (rc == 0)
+     rc = bls_keyval_cmp (e0, e1, "title");
+ 
diff --git a/SOURCES/0149-Add-version-field-to-BLS-generated-by-grub2-switch-t.patch b/SOURCES/0149-Add-version-field-to-BLS-generated-by-grub2-switch-t.patch
new file mode 100644
index 0000000..27e0a17
--- /dev/null
+++ b/SOURCES/0149-Add-version-field-to-BLS-generated-by-grub2-switch-t.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Thu, 10 May 2018 10:52:11 +0200
+Subject: [PATCH] Add version field to BLS generated by grub2-switch-to-blscfg
+
+The version field is present in the BLS fragments that are shipped in the
+kernel packages, so add it to the BLS generated by grub2-switch-to-blscfg
+for consistency.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-switch-to-blscfg.in | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index bc28053cd30..89487ad611c 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -190,12 +190,14 @@ mkbls() {
+     local datetime=$1 && shift
+ 
+     local debugname=""
++    local debugid=""
+     local flavor=""
+ 
+     if [[ "$kernelver" == *\+* ]] ; then
+         local flavor=-"${kernelver##*+}"
+         if [[ "${flavor}" == "-debug" ]]; then
+             local debugname=" with debugging"
++            local debugid="-debug"
+         fi
+     fi
+     (
+@@ -203,6 +205,7 @@ mkbls() {
+ 
+         cat <<EOF
+ title ${NAME} (${kernelver}) ${VERSION}${debugname}
++version ${kernelver}${debugid}
+ linux /vmlinuz-${kernelver}
+ initrd /initramfs-${kernelver}.img
+ options \$kernelopts
diff --git a/SOURCES/0150-Fixup-for-newer-compiler.patch b/SOURCES/0150-Fixup-for-newer-compiler.patch
new file mode 100644
index 0000000..a63ca6b
--- /dev/null
+++ b/SOURCES/0150-Fixup-for-newer-compiler.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 10 May 2018 13:40:19 -0400
+Subject: [PATCH] Fixup for newer compiler
+
+---
+ grub-core/fs/btrfs.c         | 2 +-
+ include/grub/gpt_partition.h | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 7002ad81b7e..dac73b2fa8b 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -198,7 +198,7 @@ struct grub_btrfs_inode
+   grub_uint64_t size;
+   grub_uint8_t dummy2[0x70];
+   struct grub_btrfs_time mtime;
+-} GRUB_PACKED;
++} GRUB_PACKED  __attribute__ ((aligned(8)));
+ 
+ struct grub_btrfs_extent_data
+ {
+diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h
+index 7a93f43291c..8212697bf6b 100644
+--- a/include/grub/gpt_partition.h
++++ b/include/grub/gpt_partition.h
+@@ -76,7 +76,7 @@ struct grub_gpt_partentry
+   grub_uint64_t end;
+   grub_uint64_t attrib;
+   char name[72];
+-} GRUB_PACKED;
++} GRUB_PACKED  __attribute__ ((aligned(8)));
+ 
+ grub_err_t
+ grub_gpt_partition_map_iterate (grub_disk_t disk,
diff --git a/SOURCES/0151-Don-t-attempt-to-export-the-start-and-_start-symbols.patch b/SOURCES/0151-Don-t-attempt-to-export-the-start-and-_start-symbols.patch
new file mode 100644
index 0000000..33ceb3d
--- /dev/null
+++ b/SOURCES/0151-Don-t-attempt-to-export-the-start-and-_start-symbols.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Sat, 12 May 2018 11:29:07 +0200
+Subject: [PATCH] Don't attempt to export the start and _start symbols for
+ grub-emu
+
+Commit 318ee04aadc ("make better backtraces") reworked the backtrace logic
+but the changes lead to the following build error on the grub-emu platform:
+
+grub_emu_lite-symlist.o:(.data+0xf08): undefined reference to `start'
+collect2: error: ld returned 1 exit status
+make[3]: *** [Makefile:25959: grub-emu-lite] Error 1
+make[3]: *** Waiting for unfinished jobs....
+cat kernel_syms.input | grep -v '^#' | sed -n \
+  -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \
+  -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \
+  | sort -u >kernel_syms.lst
+
+The problem is that start and _start symbols are exported unconditionally,
+but these aren't defined for grub-emu since is an emultaed platform so it
+doesn't have a startup logic. Don't attempt to export those for grub-emu.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ include/grub/kernel.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/include/grub/kernel.h b/include/grub/kernel.h
+index ae69218af20..9548d552aad 100644
+--- a/include/grub/kernel.h
++++ b/include/grub/kernel.h
+@@ -108,8 +108,10 @@ grub_addr_t grub_modules_get_end (void);
+ 
+ #endif
+ 
++#if !defined(GRUB_MACHINE_EMU)
+ void EXPORT_FUNC(start) (void);
+ void EXPORT_FUNC(_start) (void);
++#endif
+ 
+ /* The start point of the C code.  */
+ void grub_main (void) __attribute__ ((noreturn));
diff --git a/SOURCES/0152-Simplify-BLS-entry-key-val-pairs-lookup.patch b/SOURCES/0152-Simplify-BLS-entry-key-val-pairs-lookup.patch
new file mode 100644
index 0000000..f3d2613
--- /dev/null
+++ b/SOURCES/0152-Simplify-BLS-entry-key-val-pairs-lookup.patch
@@ -0,0 +1,170 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 11 May 2018 23:47:31 +0200
+Subject: [PATCH] Simplify BLS entry key val pairs lookup
+
+The <key,value> pairs found in the BLS are being sorted but this isn't
+really needed and it makes the implementation complex and error prone.
+
+For example, the current implementation has the following issues:
+
+1) Fields not present in the grub2 menu entry
+
+  linux /linuz
+  initrd /foo
+  initrd /bar
+
+  load_video
+  set gfx_payload=keep
+  insmod gzio
+  linux /boot/linuz
+  initrd /boot/bar
+
+2) Fields present but in the wrong order
+
+  title Fedora (4.16.6-300.fc28.x86_64-tuned) 28 (Twenty Eight)
+  version 4.16.6-300.fc28.x86_64
+  linux /vmlinuz-4.16.6-300.fc28.x86_64
+  initrd /foo.img
+  initrd /bar.img
+  options $kernelopts
+  id fedora-20180430150025-4.16.6-300.fc28.x86_64
+
+  load_video
+  set gfx_payload=keep
+  insmod gzio
+  linux /boot/vmlinuz-4.16.6-300.fc28.x86_64 $kernelopts
+  initrd /boot/bar.img /boot/foo.img
+
+It's important to preserve the order in which fields have been defined
+in the BLS fragment since for some of the fields the order has meaning.
+For example, initramfs images have to be passed to the kernel in order
+that were defined in the BLS fragment.
+
+This patch simplifies the <key,value> pairs storage and lookup. Rather
+than sorting and attempt to later figure out what's the expected order,
+just store it in the same order as they were defined in the BLS config
+file and return in that same order to callers when these look them up.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c | 88 ++++++++++-----------------------------------
+ 1 file changed, 18 insertions(+), 70 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index c52d2b2e05a..fb08d8e4c12 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -169,84 +169,35 @@ static void bls_free_entry(struct bls_entry *entry)
+   grub_free (entry);
+ }
+ 
+-static int keyval_cmp (const void *p0, const void *p1,
+-		       void *state UNUSED)
+-{
+-  const struct keyval *kv0 = *(struct keyval * const *)p0;
+-  const struct keyval *kv1 = *(struct keyval * const *)p1;
+-  int rc;
+-
+-  rc = grub_strcmp(kv0->key, kv1->key);
+-
+-  return rc;
+-}
+-
+ /* Find they value of the key named by keyname.  If there are allowed to be
+  * more than one, pass a pointer to an int set to -1 the first time, and pass
+  * the same pointer through each time after, and it'll return them in sorted
+- * order. */
++ * order as defined in the BLS fragment file */
+ static char *bls_get_val(struct bls_entry *entry, const char *keyname, int *last)
+ {
+-  char *foo = (char *)"";
+-  struct keyval *kv = NULL, **kvp, key = {keyname, foo}, *keyp = &key;
++  int idx, start = 0;
++  struct keyval *kv = NULL;
+ 
+-  /* if we've already found an entry that matches, just iterate */
+-  if (last && *last >= 0)
+-    {
+-      int next = ++last[0];
++  if (last)
++    start = *last + 1;
+ 
+-      if (next == entry->nkeyvals)
+-	{
+-done:
+-	  *last = -1;
+-	  return NULL;
+-	}
++  for (idx = start; idx < entry->nkeyvals; idx++) {
++    kv = entry->keyvals[idx];
+ 
+-      kv = entry->keyvals[next];
+-      if (grub_strcmp (keyname, kv->key))
+-	goto done;
++    if (!grub_strcmp (keyname, kv->key))
++      break;
++  }
+ 
+-      return kv->val;
+-    }
++  if (idx == entry->nkeyvals) {
++    if (last)
++      *last = -1;
++    return NULL;
++  }
+ 
+-  kvp = grub_bsearch(&keyp, &entry->keyvals[0], entry->nkeyvals,
+-		    sizeof (struct keyval *), keyval_cmp, NULL);
+-  if (kvp)
+-    kv = *kvp;
++  if (last)
++    *last = idx;
+ 
+-  if (kv)
+-    {
+-      /* if we've got uninitialized but present state, track back until we find
+-       * the first match */
+-      if (last)
+-	{
+-	  grub_dprintf("blscfg", "%s trying to find another entry because last was set\n", __func__);
+-	  /* figure out the position of this entry in the array */
+-	  int idx;
+-	  for (idx = 0 ; idx < entry->nkeyvals; idx++)
+-	    if (entry->keyvals[idx] == kv)
+-	      break;
+-	  *last = idx;
+-
+-	  while (idx > 0)
+-	    {
+-	      struct keyval *kvtmp = entry->keyvals[idx-1];
+-	      if (idx == 0 || grub_strcmp (keyname, kvtmp->key))
+-		{
+-		  /* if we're at the start, or if the previous entry doesn't
+-		   * match, then we're done */
+-		  *last = idx;
+-		  break;
+-		}
+-	      else
+-		/* but if it does match, keep going backwards */
+-		idx--;
+-	    }
+-	}
+-
+-      return kv->val;
+-    }
+-  return NULL;
++  return kv->val;
+ }
+ 
+ #define goto_return(x) ({ ret = (x); goto finish; })
+@@ -503,9 +454,6 @@ static int read_entry (
+ 	break;
+     }
+ 
+-  grub_qsort(&entry->keyvals[0], entry->nkeyvals, sizeof (struct keyval *),
+-	     keyval_cmp, NULL);
+-
+ finish:
+   grub_free (p);
+ 
diff --git a/SOURCES/0153-Add-relative-path-to-the-kernel-and-initrds-BLS-fiel.patch b/SOURCES/0153-Add-relative-path-to-the-kernel-and-initrds-BLS-fiel.patch
new file mode 100644
index 0000000..5a5a77d
--- /dev/null
+++ b/SOURCES/0153-Add-relative-path-to-the-kernel-and-initrds-BLS-fiel.patch
@@ -0,0 +1,73 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Mon, 4 Jun 2018 16:10:22 +0200
+Subject: [PATCH] Add relative path to the kernel and initrds BLS fields if
+ needed
+
+The static BLS config file shipped with the kernel package assumes that
+the /boot directory is a mount point, and that the kernel and initramfs
+images relative path is to the root of a boot partition.
+
+But there are cases in which this isn't true, for example if a user has
+its /boot in a btrfs subvolume or if /boot isn't a mount point at all.
+
+So instead of always using the BLS fragment file as distributed by the
+package, check the relative path that GRUB 2 has to use for the images.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-switch-to-blscfg.in | 20 +++++++++++++++++---
+ 1 file changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index 89487ad611c..2482483a437 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -188,6 +188,7 @@ fi
+ mkbls() {
+     local kernelver=$1 && shift
+     local datetime=$1 && shift
++    local bootprefix=$1 && shift
+ 
+     local debugname=""
+     local debugid=""
+@@ -206,8 +207,8 @@ mkbls() {
+         cat <<EOF
+ title ${NAME} (${kernelver}) ${VERSION}${debugname}
+ version ${kernelver}${debugid}
+-linux /vmlinuz-${kernelver}
+-initrd /initramfs-${kernelver}.img
++linux ${bootprefix}/vmlinuz-${kernelver}
++initrd ${bootprefix}/initramfs-${kernelver}.img
+ options \$kernelopts
+ id ${ID}-${datetime}-${kernelver}
+ grub_users \$grub_users
+@@ -234,6 +235,16 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+             >"${bls_target}"
+     fi
+ 
++    linux="$(grep '^linux[ \t]' "${bls_target}" | sed -e 's,^linux[ \t]*,,')"
++    initrd="$(grep '^initrd[ \t]' "${bls_target}" | sed -e 's,^initrd[ \t]*,,')"
++    linux_relpath="$("${grub_mkrelpath}" /boot/$linux)"
++    initrd_relpath="$("${grub_mkrelpath}" /boot/$initrd)"
++
++    if [[ $linux != $linux_relpath ]]; then
++        sed -i -e "s,^linux.*,linux ${linux_relpath},g" "${bls_target}"
++        sed -i -e "s,^initrd.*,initrd ${initrd_relpath},g" "${bls_target}"
++    fi
++
+     if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
+         arch="$(uname -m)"
+         bls_debug="$(echo ${bls_target} | sed -e "s/\.${arch}/-debug.${arch}/")"
+@@ -247,7 +258,10 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+ done
+ 
+ if [[ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]]; then
+-    mkbls "0-rescue-${MACHINE_ID}" "0" >"${blsdir}/${MACHINE_ID}-0-rescue.conf"
++    if [[ $linux != $linux_relpath ]]; then
++        bootprefix="$(dirname ${linux_relpath})"
++    fi
++    mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf"
+ fi
+ 
+ GENERATE=0
diff --git a/SOURCES/0154-Skip-leading-spaces-on-BLS-field-values.patch b/SOURCES/0154-Skip-leading-spaces-on-BLS-field-values.patch
new file mode 100644
index 0000000..df80edf
--- /dev/null
+++ b/SOURCES/0154-Skip-leading-spaces-on-BLS-field-values.patch
@@ -0,0 +1,56 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Thu, 7 Jun 2018 00:44:51 +0200
+Subject: [PATCH] Skip leading spaces on BLS field values
+
+The GRUB 2 blscfg command doesn't parse correctly the BLS fields if these
+have extra spaces before the field values. For example, the following BLS
+fragment generates a wrong menu entry due using spaces to tabulate values:
+
+title      Fedora 28 (Twenty Eight)
+version    4.16.13-300.fc28.x86_64
+machine-id e5c131dfee3249cbb9891c2641d8e350
+linux      /vmlinuz-4.16.13-300.fc28.x86_64
+initrd     /initramfs-4.16.13-300.fc28.x86_64.img
+options    root=/dev/mapper/fedora-root ro
+
+Wrong generated menu entry:
+
+load_video
+set gfx_payload=keep
+insmod gzio
+linux  ($root)    /vmlinuz-4.16.13-300.fc28.x86_64    root=/dev/mapper/fedora-root ro
+initrd ($root)    /initramfs-4.16.13-300.fc28.x86_64.img
+
+Correct menu entry after the fix:
+
+load_video
+set gfx_payload=keep
+insmod gzio
+linux ($root)/vmlinuz-4.16.13-300.fc28.x86_64 root=/dev/mapper/fedora-root ro
+initrd ($root)/initramfs-4.16.13-300.fc28.x86_64.img
+
+Resolves: rhbz#1588184
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index fb08d8e4c12..831cdcaccdf 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -448,7 +448,11 @@ static int read_entry (
+ 
+       separator[0] = '\0';
+ 
+-      rc = bls_add_keyval (entry, buf, separator+1);
++      do {
++	separator++;
++      } while (*separator == ' ' || *separator == '\t');
++
++      rc = bls_add_keyval (entry, buf, separator);
+       grub_free (buf);
+       if (rc < 0)
+ 	break;
diff --git a/SOURCES/0155-Fixup-for-newer-compiler.patch b/SOURCES/0155-Fixup-for-newer-compiler.patch
new file mode 100644
index 0000000..e518af8
--- /dev/null
+++ b/SOURCES/0155-Fixup-for-newer-compiler.patch
@@ -0,0 +1,22 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 10 May 2018 13:40:19 -0400
+Subject: [PATCH] Fixup for newer compiler
+
+---
+ conf/Makefile.common | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/conf/Makefile.common b/conf/Makefile.common
+index 044ab3abe88..c75848f5c06 100644
+--- a/conf/Makefile.common
++++ b/conf/Makefile.common
+@@ -38,7 +38,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding
+ LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC)
+ CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1
+ CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
+-STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx
++STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes
+ 
+ CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding
+ LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
diff --git a/SOURCES/0156-TPM-Fix-hash_log_extend_event-function-prototype.patch b/SOURCES/0156-TPM-Fix-hash_log_extend_event-function-prototype.patch
new file mode 100644
index 0000000..56cd169
--- /dev/null
+++ b/SOURCES/0156-TPM-Fix-hash_log_extend_event-function-prototype.patch
@@ -0,0 +1,50 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 15 Jun 2018 09:25:00 +0200
+Subject: [PATCH] TPM: Fix hash_log_extend_event function prototype
+
+The DataToHash argument is a efi_physical_address, not a *pointer* to
+a efi_physical_address.
+
+This distinction is important for 32 bits builds, where the pointer is
+only 32 bits where as an efi_physical_address is 64 bits.
+
+Fixing this fixes the tpm code not working with 32 bits build and grub
+showing multiple:
+
+error: Invalid parameter
+
+Messages during boot, followed by a "press any key to continue" message.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ grub-core/kern/efi/tpm.c | 2 +-
+ include/grub/efi/tpm.h   | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/kern/efi/tpm.c b/grub-core/kern/efi/tpm.c
+index c9fb3c133f3..36e1f69df16 100644
+--- a/grub-core/kern/efi/tpm.c
++++ b/grub-core/kern/efi/tpm.c
+@@ -245,7 +245,7 @@ grub_tpm2_log_event(grub_efi_handle_t tpm_handle, unsigned char *buf,
+   event->Size = sizeof(*event) - sizeof(event->Event) + grub_strlen(description) + 1;
+   grub_memcpy(event->Event, description, grub_strlen(description) + 1);
+ 
+-  status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, buf,
++  status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, (unsigned long) buf,
+ 		       (grub_uint64_t) size, event);
+ 
+   switch (status) {
+diff --git a/include/grub/efi/tpm.h b/include/grub/efi/tpm.h
+index e2aff4a3c22..63d8a0fe714 100644
+--- a/include/grub/efi/tpm.h
++++ b/include/grub/efi/tpm.h
+@@ -129,7 +129,7 @@ struct grub_efi_tpm2_protocol
+ 				      grub_efi_boolean_t *EventLogTruncated);
+   grub_efi_status_t (*hash_log_extend_event) (struct grub_efi_tpm2_protocol *this,
+ 					      grub_efi_uint64_t Flags,
+-					      grub_efi_physical_address_t *DataToHash,
++					      grub_efi_physical_address_t DataToHash,
+ 					      grub_efi_uint64_t DataToHashLen,
+ 					      EFI_TCG2_EVENT *EfiTcgEvent);
+   grub_efi_status_t (*submit_command) (struct grub_efi_tpm2_protocol *this,
diff --git a/SOURCES/0157-TPM-Fix-compiler-warnings.patch b/SOURCES/0157-TPM-Fix-compiler-warnings.patch
new file mode 100644
index 0000000..b19d484
--- /dev/null
+++ b/SOURCES/0157-TPM-Fix-compiler-warnings.patch
@@ -0,0 +1,72 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 15 Jun 2018 09:58:50 +0200
+Subject: [PATCH] TPM: Fix compiler warnings
+
+Stop defining our own Event type in tpm.c instead use the one from
+the header, so that it matches the function prototype.
+Note this requires some further code changes to go from all lowercaps
+of the private Event type to the CamelCaps from the header.
+
+Also cast buf, which gets passed as a efi_physicall_address_t to an
+integer, to avoid the compiler complaining about passing a pointer as
+an integer.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ grub-core/kern/efi/tpm.c | 24 ++++++++----------------
+ 1 file changed, 8 insertions(+), 16 deletions(-)
+
+diff --git a/grub-core/kern/efi/tpm.c b/grub-core/kern/efi/tpm.c
+index 36e1f69df16..0d3ebe22e57 100644
+--- a/grub-core/kern/efi/tpm.c
++++ b/grub-core/kern/efi/tpm.c
+@@ -161,21 +161,12 @@ grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
+   }
+ }
+ 
+-typedef struct {
+-	grub_uint32_t pcrindex;
+-	grub_uint32_t eventtype;
+-	grub_uint8_t digest[20];
+-	grub_uint32_t eventsize;
+-	grub_uint8_t event[1];
+-} Event;
+-
+-
+ static grub_err_t
+ grub_tpm1_log_event(grub_efi_handle_t tpm_handle, unsigned char *buf,
+ 		    grub_size_t size, grub_uint8_t pcr,
+ 		    const char *description)
+ {
+-  Event *event;
++  TCG_PCR_EVENT *event;
+   grub_efi_status_t status;
+   grub_efi_tpm_protocol_t *tpm;
+   grub_efi_physical_address_t lastevent;
+@@ -188,18 +179,19 @@ grub_tpm1_log_event(grub_efi_handle_t tpm_handle, unsigned char *buf,
+   if (!grub_tpm_present(tpm))
+     return 0;
+ 
+-  event = grub_zalloc(sizeof (Event) + grub_strlen(description) + 1);
++  event = grub_zalloc(sizeof (TCG_PCR_EVENT) + grub_strlen(description) + 1);
+   if (!event)
+     return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ 		       N_("cannot allocate TPM event buffer"));
+ 
+-  event->pcrindex = pcr;
+-  event->eventtype = EV_IPL;
+-  event->eventsize = grub_strlen(description) + 1;
+-  grub_memcpy(event->event, description, event->eventsize);
++  event->PCRIndex = pcr;
++  event->EventType = EV_IPL;
++  event->EventSize = grub_strlen(description) + 1;
++  grub_memcpy(event->Event, description, event->EventSize);
+ 
+   algorithm = TCG_ALG_SHA;
+-  status = efi_call_7 (tpm->log_extend_event, tpm, buf, (grub_uint64_t) size,
++  status = efi_call_7 (tpm->log_extend_event, tpm,
++                       (unsigned long) buf, (grub_uint64_t) size,
+ 		       algorithm, event, &eventnum, &lastevent);
+ 
+   switch (status) {
diff --git a/SOURCES/0158-grub-switch-to-blscfg.in-get-rid-of-a-bunch-of-bashi.patch b/SOURCES/0158-grub-switch-to-blscfg.in-get-rid-of-a-bunch-of-bashi.patch
new file mode 100644
index 0000000..54c4322
--- /dev/null
+++ b/SOURCES/0158-grub-switch-to-blscfg.in-get-rid-of-a-bunch-of-bashi.patch
@@ -0,0 +1,113 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 22 Jun 2018 14:01:06 -0400
+Subject: [PATCH] grub-switch-to-blscfg.in: get rid of a bunch of bashisms
+
+Since this says /bin/sh at the top, it should work with dash.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-switch-to-blscfg.in | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index 2482483a437..dac41e73836 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -151,18 +151,18 @@ done
+ 
+ find_grub_cfg() {
+     local candidate=""
+-    while [[ -e "${candidate}" || $# -gt 0 ]]
++    while [ -e "${candidate}" -o $# -gt 0 ]
+     do
+-        if [[ ! -e "${candidate}" ]] ; then
++        if [ ! -e "${candidate}" ] ; then
+             candidate="$1"
+             shift
+         fi
+ 
+-        if [[ -L "${candidate}" ]]; then
++        if [ -L "${candidate}" ]; then
+             candidate="$(realpath "${candidate}")"
+         fi
+ 
+-        if [[ -f "${candidate}" ]]; then
++        if [ -f "${candidate}" ]; then
+             export GRUB_CONFIG_FILE="${candidate}"
+             return 0
+         fi
+@@ -175,11 +175,11 @@ if ! find_grub_cfg ${startlink} ${grubdir}/grub.cfg ; then
+   exit 1
+ fi
+ 
+-if [[ ! -d "${blsdir}" ]]; then
++if [ ! -d "${blsdir}" ]; then
+     install -m 700 -d "${blsdir}"
+ fi
+ 
+-if [[ -f /etc/machine-id ]]; then
++if [ -f /etc/machine-id ]; then
+     MACHINE_ID=$(cat /etc/machine-id)
+ else
+     MACHINE_ID=$(dmesg | sha256sum)
+@@ -194,9 +194,9 @@ mkbls() {
+     local debugid=""
+     local flavor=""
+ 
+-    if [[ "$kernelver" == *\+* ]] ; then
++    if [ "$kernelver" == *\+* ] ; then
+         local flavor=-"${kernelver##*+}"
+-        if [[ "${flavor}" == "-debug" ]]; then
++        if [ "${flavor}" == "-debug" ]; then
+             local debugname=" with debugging"
+             local debugid="-debug"
+         fi
+@@ -219,15 +219,15 @@ EOF
+ }
+ 
+ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+-    if [[ ! -d "/lib/modules/${kernelver}" ]] ; then
++    if [ ! -d "/lib/modules/${kernelver}" ] ; then
+         continue
+     fi
+-    if [[ ! -f "/boot/vmlinuz-${kernelver}" ]]; then
++    if [ ! -f "/boot/vmlinuz-${kernelver}" ]; then
+         continue
+     fi
+     bls_target="${blsdir}/${MACHINE_ID}-${kernelver}.conf"
+     kernel_dir="/lib/modules/${kernelver}"
+-    if [[ -f "${kernel_dir}/bls.conf" ]]; then
++    if [ -f "${kernel_dir}/bls.conf" ]; then
+         cp -af "${kernel_dir}/bls.conf" "${bls_target}"
+     else
+         mkbls "${kernelver}" \
+@@ -240,7 +240,7 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+     linux_relpath="$("${grub_mkrelpath}" /boot/$linux)"
+     initrd_relpath="$("${grub_mkrelpath}" /boot/$initrd)"
+ 
+-    if [[ $linux != $linux_relpath ]]; then
++    if [ $linux != $linux_relpath ] ; then
+         sed -i -e "s,^linux.*,linux ${linux_relpath},g" "${bls_target}"
+         sed -i -e "s,^initrd.*,initrd ${initrd_relpath},g" "${bls_target}"
+     fi
+@@ -257,8 +257,8 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+     fi
+ done
+ 
+-if [[ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]]; then
+-    if [[ $linux != $linux_relpath ]]; then
++if [ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then
++    if [ $linux != $linux_relpath ]; then
+         bootprefix="$(dirname ${linux_relpath})"
+     fi
+     mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf"
+@@ -282,7 +282,7 @@ elif ! grep -q '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" ; then
+     GENERATE=1
+ fi
+ 
+-if [[ "${GENERATE}" -eq 1 ]] ; then
++if [ "${GENERATE}" -eq 1 ] ; then
+     cp -af "${GRUB_CONFIG_FILE}" "${GRUB_CONFIG_FILE}${backupsuffix}"
+     if ! grub2-mkconfig -o "${GRUB_CONFIG_FILE}" ; then
+         cp -af "${GRUB_CONFIG_FILE}${backupsuffix}" "${GRUB_CONFIG_FILE}"
diff --git a/SOURCES/0159-grub-switch-to-blscfg.in-Better-boot-prefix-checking.patch b/SOURCES/0159-grub-switch-to-blscfg.in-Better-boot-prefix-checking.patch
new file mode 100644
index 0000000..8437c68
--- /dev/null
+++ b/SOURCES/0159-grub-switch-to-blscfg.in-Better-boot-prefix-checking.patch
@@ -0,0 +1,73 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 22 Jun 2018 14:04:28 -0400
+Subject: [PATCH] grub-switch-to-blscfg.in: Better boot prefix checking
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-switch-to-blscfg.in | 36 +++++++++++++++++-------------------
+ 1 file changed, 17 insertions(+), 19 deletions(-)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index dac41e73836..884cf45b1e1 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -219,30 +219,31 @@ EOF
+ }
+ 
+ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+-    if [ ! -d "/lib/modules/${kernelver}" ] ; then
+-        continue
+-    fi
+-    if [ ! -f "/boot/vmlinuz-${kernelver}" ]; then
+-        continue
+-    fi
+     bls_target="${blsdir}/${MACHINE_ID}-${kernelver}.conf"
++    linux="$(grep '^linux[ \t]' "${bls_target}" | sed -e 's,^linux[ \t]+,,')"
+     kernel_dir="/lib/modules/${kernelver}"
+-    if [ -f "${kernel_dir}/bls.conf" ]; then
++
++    if [ ! -d "${kernel_dir}" ] ; then
++        continue
++    fi
++    if [ ! -f "${linux_path}" ]; then
++        continue
++    fi
++
++    linux_relpath="$("${grub_mkrelpath}" "${linux}")"
++    bootprefix="${linux%%"${linux_relpath}"}"
++
++    if [ -f "${kernel_dir}/bls.conf" ] ; then
+         cp -af "${kernel_dir}/bls.conf" "${bls_target}"
+     else
+         mkbls "${kernelver}" \
+             "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${kernel_dir}")")" \
++            "${bootprefix}" \
+             >"${bls_target}"
+     fi
+ 
+-    linux="$(grep '^linux[ \t]' "${bls_target}" | sed -e 's,^linux[ \t]*,,')"
+-    initrd="$(grep '^initrd[ \t]' "${bls_target}" | sed -e 's,^initrd[ \t]*,,')"
+-    linux_relpath="$("${grub_mkrelpath}" /boot/$linux)"
+-    initrd_relpath="$("${grub_mkrelpath}" /boot/$initrd)"
+-
+-    if [ $linux != $linux_relpath ] ; then
+-        sed -i -e "s,^linux.*,linux ${linux_relpath},g" "${bls_target}"
+-        sed -i -e "s,^initrd.*,initrd ${initrd_relpath},g" "${bls_target}"
++    if [ -n "${bootprefix}" ]; then
++        sed -i -e "s,\([ \t]\)${bootprefix},\1,g" "${bls_target}"
+     fi
+ 
+     if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
+@@ -257,10 +258,7 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+     fi
+ done
+ 
+-if [ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then
+-    if [ $linux != $linux_relpath ]; then
+-        bootprefix="$(dirname ${linux_relpath})"
+-    fi
++if [ -n "${bootprefix}" -a -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then
+     mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf"
+ fi
+ 
diff --git a/SOURCES/0160-Use-boot-loader-entries-as-BLS-directory-path-also-o.patch b/SOURCES/0160-Use-boot-loader-entries-as-BLS-directory-path-also-o.patch
new file mode 100644
index 0000000..88b9bc2
--- /dev/null
+++ b/SOURCES/0160-Use-boot-loader-entries-as-BLS-directory-path-also-o.patch
@@ -0,0 +1,152 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Mon, 25 Jun 2018 11:45:33 +0200
+Subject: [PATCH] Use /boot/loader/entries as BLS directory path also on EFI
+ systems
+
+For EFI systems, the BLS fragments were stored in the EFI System Partition
+(ESP) while in non-EFI systems it was stored in /boot.
+
+For consistency, it's better to always store the BLS fragments in the same
+path regardless of the firmware interface used.
+
+Also change the grub2-switch-to-blscfg script default BLS directory.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c   | 48 ++++++++++++++++++++++++++++++++-----------
+ util/grub-switch-to-blscfg.in |  4 ++--
+ 2 files changed, 38 insertions(+), 14 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 831cdcaccdf..70939a81826 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -381,9 +381,14 @@ static int bls_cmp(const void *p0, const void *p1, void *state UNUSED)
+   return rc;
+ }
+ 
++struct read_entry_info {
++  const char *devid;
++  const char *dirname;
++};
++
+ static int read_entry (
+     const char *filename,
+-    const struct grub_dirhook_info *info UNUSED,
++    const struct grub_dirhook_info *dirhook_info UNUSED,
+     void *data)
+ {
+   grub_size_t n;
+@@ -391,8 +396,7 @@ static int read_entry (
+   grub_file_t f = NULL;
+   grub_off_t sz;
+   struct bls_entry *entry;
+-  const char *dirname= (const char *)data;
+-  const char *devid = grub_env_get ("boot");
++  struct read_entry_info *info = (struct read_entry_info *)data;
+ 
+   grub_dprintf ("blscfg", "filename: \"%s\"\n", filename);
+ 
+@@ -406,7 +410,7 @@ static int read_entry (
+   if (grub_strcmp (filename + n - 5, ".conf") != 0)
+     return 0;
+ 
+-  p = grub_xasprintf ("(%s)%s/%s", devid, dirname, filename);
++  p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
+ 
+   f = grub_file_open (p);
+   if (!f)
+@@ -655,10 +659,13 @@ static int find_entry (const char *filename,
+ 		       void *data)
+ {
+   struct find_entry_info *info = (struct find_entry_info *)data;
++  struct read_entry_info read_entry_info;
+   grub_file_t f = NULL;
+   char *grubenv_path = NULL;
+   grub_envblk_t env = NULL;
+   char *default_blsdir = NULL;
++  grub_fs_t blsdir_fs = NULL;
++  grub_device_t blsdir_dev = NULL;
+   const char *blsdir = NULL;
+   char *saved_env_buf = NULL;
+   int r = 0;
+@@ -678,9 +685,6 @@ static int find_entry (const char *filename,
+   if (info->platform == PLATFORM_EMU)
+     default_blsdir = grub_xasprintf ("%s%s", GRUB_BOOT_DEVICE,
+ 				     GRUB_BLS_CONFIG_PATH);
+-  else if (info->platform == PLATFORM_EFI)
+-    default_blsdir = grub_xasprintf ("/EFI/%s%s", filename,
+-				     GRUB_BLS_CONFIG_PATH);
+   else
+     default_blsdir = grub_xasprintf ("%s", GRUB_BLS_CONFIG_PATH);
+ 
+@@ -744,16 +748,33 @@ static int find_entry (const char *filename,
+     goto finish;
+ 
+   grub_dprintf ("blscfg", "blsdir: \"%s\"\n", blsdir);
+-  if (blsdir[0] != '/' && info->platform == PLATFORM_EFI)
+-    blsdir = grub_xasprintf ("/EFI/%s/%s/", filename, blsdir);
+-  else
+-    blsdir = grub_strdup (blsdir);
++  blsdir = grub_strdup (blsdir);
+ 
+   if (!blsdir)
+     goto finish;
+ 
+   grub_dprintf ("blscfg", "blsdir: \"%s\"\n", blsdir);
+-  r = info->fs->dir (info->dev, blsdir, read_entry, (char *)blsdir);
++  if (info->platform == PLATFORM_EFI) {
++    read_entry_info.devid = grub_env_get ("root");
++    if (!read_entry_info.devid)
++      goto finish;
++
++    blsdir_dev = grub_device_open (read_entry_info.devid);
++    if (!blsdir_dev)
++      goto finish;
++
++    blsdir_fs = grub_fs_probe (blsdir_dev);
++    if (!blsdir_fs)
++      goto finish;
++
++  } else {
++    read_entry_info.devid = devid;
++    blsdir_dev = info->dev;
++    blsdir_fs = info->fs;
++  }
++  read_entry_info.dirname = blsdir;
++
++  r = blsdir_fs->dir (blsdir_dev, blsdir, read_entry, &read_entry_info);
+   if (r != 0) {
+       grub_dprintf ("blscfg", "read_entry returned error\n");
+       grub_err_t e;
+@@ -773,6 +794,9 @@ static int find_entry (const char *filename,
+   for (r = 0; r < nentries; r++)
+       bls_free_entry (entries[r]);
+ finish:
++  if (info->platform == PLATFORM_EFI && blsdir_dev)
++    grub_device_close (blsdir_dev);
++
+   nentries = 0;
+ 
+   grub_free (entries);
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index 884cf45b1e1..2f37a1f740b 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -44,13 +44,13 @@ EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/')
+ if [ -d /sys/firmware/efi/efivars/ ]; then
+     startlink=/etc/grub2-efi.cfg
+     grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
+-    blsdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/loader/entries" | sed 's,//*,/,g'`
+ else
+     startlink=/etc/grub2.cfg
+     grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`
+-    blsdir=`echo "/@bootdirname@/loader/entries" | sed 's,//*,/,g'`
+ fi
+ 
++blsdir=`echo "/@bootdirname@/loader/entries" | sed 's,//*,/,g'`
++
+ backupsuffix=.bak
+ 
+ export TEXTDOMAIN=@PACKAGE@
diff --git a/SOURCES/0161-Use-BLS-fragment-filename-as-menu-entry-id-and-for-c.patch b/SOURCES/0161-Use-BLS-fragment-filename-as-menu-entry-id-and-for-c.patch
new file mode 100644
index 0000000..7f765e7
--- /dev/null
+++ b/SOURCES/0161-Use-BLS-fragment-filename-as-menu-entry-id-and-for-c.patch
@@ -0,0 +1,134 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 26 Jun 2018 14:01:26 +0200
+Subject: [PATCH] Use BLS fragment filename as menu entry id and for criteria
+ to sort
+
+The BLS config filenames are guaranteed to be unique, so they can be
+used as GRUB2 entry id and can also be used to sort the menu entries.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c | 62 +++++++++------------------------------------
+ 1 file changed, 12 insertions(+), 50 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 70939a81826..cd8659384e4 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -70,6 +70,7 @@ struct bls_entry
+ {
+   struct keyval **keyvals;
+   int nkeyvals;
++  char *filename;
+ };
+ 
+ static struct bls_entry **entries;
+@@ -166,6 +167,7 @@ static void bls_free_entry(struct bls_entry *entry)
+ 
+   grub_free (entry->keyvals);
+   grub_memset (entry, 0, sizeof (*entry));
++  grub_free (entry->filename);
+   grub_free (entry);
+ }
+ 
+@@ -327,58 +329,12 @@ finish:
+ 
+ typedef int (*void_cmp_t)(void *, void *);
+ 
+-static int nulcmp(char *s0, char *s1, void_cmp_t cmp)
+-{
+-  grub_dprintf("blscfg", "%s got here\n", __func__);
+-  if (s1 && !s0)
+-    return 1;
+-  if (s0 && !s1)
+-    return -1;
+-  if (!s0 && !s1)
+-    return 0;
+-  if (cmp)
+-    return cmp(s0, s1);
+-  return grub_strcmp(s0, s1);
+-}
+-
+-static int
+-bls_keyval_cmp(struct bls_entry *e0, struct bls_entry *e1, const char *keyname)
+-{
+-  char *val0, *val1;
+-
+-  val0 = bls_get_val (e0, keyname, NULL);
+-  val1 = bls_get_val (e1, keyname, NULL);
+-
+-  if (val1 && !val0)
+-    return 1;
+-
+-  if (val0 && !val1)
+-    return -1;
+-
+-  if (!val0 && !val1)
+-    return 0;
+-
+-  return nulcmp(val0, val1, (void_cmp_t)vercmp);
+-}
+-
+ static int bls_cmp(const void *p0, const void *p1, void *state UNUSED)
+ {
+   struct bls_entry * e0 = *(struct bls_entry **)p0;
+   struct bls_entry * e1 = *(struct bls_entry **)p1;
+-  int rc = 0;
+ 
+-  rc = bls_keyval_cmp (e0, e1, "id");
+-
+-  if (rc == 0)
+-    rc = bls_keyval_cmp (e0, e1, "version");
+-
+-  if (rc == 0)
+-    rc = bls_keyval_cmp (e0, e1, "title");
+-
+-  if (rc == 0)
+-    rc = bls_keyval_cmp (e0, e1, "linux");
+-
+-  return rc;
++  return vercmp(e0->filename, e1->filename);
+ }
+ 
+ struct read_entry_info {
+@@ -424,6 +380,12 @@ static int read_entry (
+   if (!entry)
+     goto finish;
+ 
++  entry->filename = grub_strndup(filename, n - 5);
++  if (!entry->filename)
++    goto finish;
++
++  entry->filename[n - 5] = '\0';
++
+   for (;;)
+     {
+       char *buf;
+@@ -548,7 +510,7 @@ static void create_entry (struct bls_entry *entry, const char *cfgfile)
+   char *options = NULL;
+   char **initrds = NULL;
+   char *initrd = NULL;
+-  char *id = NULL;
++  char *id = entry->filename;
+   char *hotkey = NULL;
+ 
+   char *users = NULL;
+@@ -570,7 +532,6 @@ static void create_entry (struct bls_entry *entry, const char *cfgfile)
+   title = bls_get_val (entry, "title", NULL);
+   options = bls_get_val (entry, "options", NULL);
+   initrds = bls_make_list (entry, "initrd", NULL);
+-  id = bls_get_val (entry, "id", NULL);
+ 
+   hotkey = bls_get_val (entry, "grub_hotkey", NULL);
+   users = bls_get_val (entry, "grub_users", NULL);
+@@ -584,7 +545,8 @@ static void create_entry (struct bls_entry *entry, const char *cfgfile)
+     argv[i] = args[i-1];
+   argv[argc] = NULL;
+ 
+-  grub_dprintf ("blscfg", "adding menu entry for \"%s\"\n", title);
++  grub_dprintf ("blscfg", "adding menu entry for \"%s\" with id \"%s\"\n",
++		title, id);
+   if (initrds)
+     {
+       int initrd_size = sizeof (GRUB_INITRD_CMD);
diff --git a/SOURCES/0162-Fix-grub-switch-to-blscfg-boot-prefix-handling.patch b/SOURCES/0162-Fix-grub-switch-to-blscfg-boot-prefix-handling.patch
new file mode 100644
index 0000000..be7d1a3
--- /dev/null
+++ b/SOURCES/0162-Fix-grub-switch-to-blscfg-boot-prefix-handling.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Mon, 9 Jul 2018 12:19:03 +0200
+Subject: [PATCH] Fix grub-switch-to-blscfg boot prefix handling
+
+Commit b3ac18e3265f ("grub-switch-to-blscfg.in: Better boot prefix checking")
+simplified the boot prefix checking, but unfortunately introduced a couple of
+regressions on the script. Fix them.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-switch-to-blscfg.in | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index 2f37a1f740b..40612e00686 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -220,7 +220,8 @@ EOF
+ 
+ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+     bls_target="${blsdir}/${MACHINE_ID}-${kernelver}.conf"
+-    linux="$(grep '^linux[ \t]' "${bls_target}" | sed -e 's,^linux[ \t]+,,')"
++    linux="/vmlinuz-${kernelver}"
++    linux_path="/boot${linux}"
+     kernel_dir="/lib/modules/${kernelver}"
+ 
+     if [ ! -d "${kernel_dir}" ] ; then
+@@ -230,8 +231,8 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+         continue
+     fi
+ 
+-    linux_relpath="$("${grub_mkrelpath}" "${linux}")"
+-    bootprefix="${linux%%"${linux_relpath}"}"
++    linux_relpath="$("${grub_mkrelpath}" "${linux_path}")"
++    bootprefix="${linux_relpath%%"${linux}"}"
+ 
+     if [ -f "${kernel_dir}/bls.conf" ] ; then
+         cp -af "${kernel_dir}/bls.conf" "${bls_target}"
+@@ -243,7 +244,8 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+     fi
+ 
+     if [ -n "${bootprefix}" ]; then
+-        sed -i -e "s,\([ \t]\)${bootprefix},\1,g" "${bls_target}"
++        sed -i -e "s,^\(linux[^ \t]*[ \t]\+\).*,\1${bootprefix}${linux},g" "${bls_target}"
++        sed -i -e "/^initrd/ s,\([ \t]\+\)\([^ \t]\+\),\1${bootprefix}\2,g" "${bls_target}"
+     fi
+ 
+     if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
+@@ -258,7 +260,7 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+     fi
+ done
+ 
+-if [ -n "${bootprefix}" -a -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then
++if [ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then
+     mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf"
+ fi
+ 
diff --git a/SOURCES/0163-Revert-trim-arp-packets-with-abnormal-size.patch b/SOURCES/0163-Revert-trim-arp-packets-with-abnormal-size.patch
new file mode 100644
index 0000000..5a169d7
--- /dev/null
+++ b/SOURCES/0163-Revert-trim-arp-packets-with-abnormal-size.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 18 May 2017 14:25:45 -0400
+Subject: [PATCH] Revert "trim arp packets with abnormal size"
+
+This reverts commit d11b2eb425d2125f67dd8d8e9b11d9be7d6f3f11.
+---
+ grub-core/net/arp.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c
+index d1c69ed2b55..54306e3b16d 100644
+--- a/grub-core/net/arp.c
++++ b/grub-core/net/arp.c
+@@ -150,12 +150,6 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
+     if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
+ 	&& arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
+       {
+-        if ((nb->tail - nb->data) > 50)
+-          {
+-            grub_dprintf ("net", "arp packet with abnormal size (%ld bytes).\n",
+-                         nb->tail - nb->data);
+-            nb->tail = nb->data + 50;
+-          }
+ 	grub_net_link_level_address_t target;
+ 	struct grub_net_buff nb_reply;
+ 	struct arppkt *arp_reply;
diff --git a/SOURCES/0164-Use-xid-to-match-DHCP-replies.patch b/SOURCES/0164-Use-xid-to-match-DHCP-replies.patch
new file mode 100644
index 0000000..657ebb7
--- /dev/null
+++ b/SOURCES/0164-Use-xid-to-match-DHCP-replies.patch
@@ -0,0 +1,65 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andrzej Kacprowski <andrzej.kacprowski@intel.com>
+Date: Fri, 21 Apr 2017 09:20:38 +0200
+Subject: [PATCH] Use xid to match DHCP replies
+
+Transaction identifier (xid) from DHCP request
+packet is stored in network level interface and used
+to match request with the responses it generates.
+
+Resolves: rhbz#1370642
+
+Signed-off-by: Andrzej Kacprowski <andrzej.kacprowski@intel.com>
+---
+ grub-core/net/bootp.c | 3 ++-
+ grub-core/net/ip.c    | 1 +
+ include/grub/net.h    | 3 ++-
+ 3 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index da3e454466b..2869482fe06 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -777,7 +777,8 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
+ 	      grub_errno = GRUB_ERR_NONE;
+ 	      t = 0;
+ 	    }
+-	  pack->ident = grub_cpu_to_be32 (t);
++	  pack->xid = grub_cpu_to_be32 (t);
++	  ifaces[j].dhcp_xid = pack->xid;
+ 	  pack->seconds = grub_cpu_to_be16 (t);
+ 
+ 	  grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6); 
+diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
+index 7c95cc7464a..8411e0ecca3 100644
+--- a/grub-core/net/ip.c
++++ b/grub-core/net/ip.c
+@@ -275,6 +275,7 @@ handle_dgram (struct grub_net_buff *nb,
+ 	FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
+ 	  if (inf->card == card
+ 	      && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
++	      && inf->dhcp_xid == bootp->xid
+ 	      && inf->hwaddress.type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
+ 	      && grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr,
+ 			      sizeof (inf->hwaddress.mac)) == 0)
+diff --git a/include/grub/net.h b/include/grub/net.h
+index f8f3ec13acc..de51894cbbf 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -292,6 +292,7 @@ struct grub_net_network_level_interface
+   struct grub_net_bootp_packet *dhcp_ack;
+   grub_size_t dhcp_acklen;
+   grub_uint16_t vlantag;
++  grub_uint32_t dhcp_xid;
+   void *data;
+ };
+ 
+@@ -429,7 +430,7 @@ struct grub_net_bootp_packet
+   grub_uint8_t hw_type;		/* hardware type.  */
+   grub_uint8_t hw_len;		/* hardware addr len.  */
+   grub_uint8_t gate_hops;	/* zero it.  */
+-  grub_uint32_t ident;		/* random number chosen by client.  */
++  grub_uint32_t xid;		/* transaction id chosen by client.  */
+   grub_uint16_t seconds;	/* seconds since did initial bootstrap.  */
+   grub_uint16_t flags;
+   grub_uint32_t	client_ip;
diff --git a/SOURCES/0165-Add-support-for-non-Ethernet-network-cards.patch b/SOURCES/0165-Add-support-for-non-Ethernet-network-cards.patch
new file mode 100644
index 0000000..ffd126c
--- /dev/null
+++ b/SOURCES/0165-Add-support-for-non-Ethernet-network-cards.patch
@@ -0,0 +1,764 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andrzej Kacprowski <andrzej.kacprowski@intel.com>
+Date: Fri, 21 Apr 2017 10:06:20 +0200
+Subject: [PATCH] Add support for non-Ethernet network cards
+
+This patch replaces fixed 6-byte link layer address with
+up to 32-byte variable sized address.
+This allows supporting Infiniband and Omni-Path fabric
+which use 20-byte address, but other network card types
+can also take advantage of this change.
+The network card driver is responsible for replacing L2
+header provided by grub2 if needed.
+This approach is compatible with UEFI network stack which
+also allows up to 32-byte variable size link address.
+
+The BOOTP/DHCP packet format is limited to 16 byte client
+hardware address, if link address is more that 16-bytes
+then chaddr field in BOOTP it will be set to 0 as per rfc4390.
+
+Resolves: rhbz#1370642
+
+Signed-off-by: Andrzej Kacprowski <andrzej.kacprowski@intel.com>
+
+Conflicts:
+	grub-core/net/ip.c
+---
+ grub-core/net/arp.c                    | 155 ++++++++++++++++++++++-----------
+ grub-core/net/bootp.c                  |  14 ++-
+ grub-core/net/drivers/efi/efinet.c     |   8 +-
+ grub-core/net/drivers/emu/emunet.c     |   1 +
+ grub-core/net/drivers/i386/pc/pxe.c    |  13 +--
+ grub-core/net/drivers/ieee1275/ofnet.c |   2 +
+ grub-core/net/drivers/uboot/ubootnet.c |   1 +
+ grub-core/net/ethernet.c               |  88 +++++++++----------
+ grub-core/net/icmp6.c                  |  15 ++--
+ grub-core/net/ip.c                     |   4 +-
+ grub-core/net/net.c                    |  48 +++++-----
+ include/grub/net.h                     |  19 ++--
+ 12 files changed, 216 insertions(+), 152 deletions(-)
+
+diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c
+index 54306e3b16d..67b409a8acc 100644
+--- a/grub-core/net/arp.c
++++ b/grub-core/net/arp.c
+@@ -31,22 +31,12 @@ enum
+     ARP_REPLY = 2
+   };
+ 
+-enum
+-  {
+-    /* IANA ARP constant to define hardware type as ethernet. */
+-    GRUB_NET_ARPHRD_ETHERNET = 1
+-  };
+-
+-struct arppkt {
++struct arphdr {
+   grub_uint16_t hrd;
+   grub_uint16_t pro;
+   grub_uint8_t hln;
+   grub_uint8_t pln;
+   grub_uint16_t op;
+-  grub_uint8_t sender_mac[6];
+-  grub_uint32_t sender_ip;
+-  grub_uint8_t recv_mac[6];
+-  grub_uint32_t recv_ip;
+ } GRUB_PACKED;
+ 
+ static int have_pending;
+@@ -57,12 +47,16 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
+ 			   const grub_net_network_level_address_t *proto_addr)
+ {
+   struct grub_net_buff nb;
+-  struct arppkt *arp_packet;
++  struct arphdr *arp_header;
+   grub_net_link_level_address_t target_mac_addr;
+   grub_err_t err;
+   int i;
+   grub_uint8_t *nbd;
+   grub_uint8_t arp_data[128];
++  grub_uint8_t hln;
++  grub_uint8_t pln;
++  grub_uint8_t arp_packet_len;
++  grub_uint8_t *tmp_ptr;
+ 
+   if (proto_addr->type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
+     return grub_error (GRUB_ERR_BUG, "unsupported address family");
+@@ -73,23 +67,39 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
+   grub_netbuff_clear (&nb);
+   grub_netbuff_reserve (&nb, 128);
+ 
+-  err = grub_netbuff_push (&nb, sizeof (*arp_packet));
++  hln = inf->card->default_address.len;
++  pln = sizeof (proto_addr->ipv4);
++  arp_packet_len = sizeof (*arp_header) + 2 * (hln + pln);
++
++  err = grub_netbuff_push (&nb, arp_packet_len);
+   if (err)
+     return err;
+ 
+-  arp_packet = (struct arppkt *) nb.data;
+-  arp_packet->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
+-  arp_packet->hln = 6;
+-  arp_packet->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
+-  arp_packet->pln = 4;
+-  arp_packet->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
+-  /* Sender hardware address.  */
+-  grub_memcpy (arp_packet->sender_mac, &inf->hwaddress.mac, 6);
+-  arp_packet->sender_ip = inf->address.ipv4;
+-  grub_memset (arp_packet->recv_mac, 0, 6);
+-  arp_packet->recv_ip = proto_addr->ipv4;
+-  /* Target protocol address */
+-  grub_memset (&target_mac_addr.mac, 0xff, 6);
++  arp_header = (struct arphdr *) nb.data;
++  arp_header->hrd = grub_cpu_to_be16 (inf->card->default_address.type);
++  arp_header->hln = hln;
++  arp_header->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
++  arp_header->pln = pln;
++  arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
++  tmp_ptr = nb.data + sizeof (*arp_header);
++
++  /* The source hardware address. */
++  grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln);
++  tmp_ptr += hln;
++
++  /* The source protocol address. */
++  grub_memcpy (tmp_ptr, &inf->address.ipv4, pln);
++  tmp_ptr += pln;
++
++  /* The target hardware address. */
++  grub_memset (tmp_ptr, 0, hln);
++  tmp_ptr += hln;
++
++  /* The target protocol address */
++  grub_memcpy (tmp_ptr, &proto_addr->ipv4, pln);
++  tmp_ptr += pln;
++
++  grub_memset (&target_mac_addr.mac, 0xff, hln);
+ 
+   nbd = nb.data;
+   send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP);
+@@ -114,28 +124,53 @@ grub_err_t
+ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
+                       grub_uint16_t *vlantag)
+ {
+-  struct arppkt *arp_packet = (struct arppkt *) nb->data;
++  struct arphdr *arp_header = (struct arphdr *) nb->data;
+   grub_net_network_level_address_t sender_addr, target_addr;
+   grub_net_link_level_address_t sender_mac_addr;
+   struct grub_net_network_level_interface *inf;
++  grub_uint16_t hw_type;
++  grub_uint8_t hln;
++  grub_uint8_t pln;
++  grub_uint8_t arp_packet_len;
++  grub_uint8_t *tmp_ptr;
+ 
+-  if (arp_packet->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP)
+-      || arp_packet->pln != 4 || arp_packet->hln != 6
+-      || nb->tail - nb->data < (int) sizeof (*arp_packet))
++  hw_type = card->default_address.type;
++  hln = card->default_address.len;
++  pln = sizeof(sender_addr.ipv4);
++  arp_packet_len = sizeof (*arp_header) + 2 * (pln + hln);
++
++  if (arp_header->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP)
++      || arp_header->hrd != grub_cpu_to_be16 (hw_type)
++      || arp_header->hln != hln || arp_header->pln != pln
++      || nb->tail - nb->data < (int) arp_packet_len) {
+     return GRUB_ERR_NONE;
++  }
+ 
++  tmp_ptr =  nb->data + sizeof (*arp_header);
++
++  /* The source hardware address. */
++  sender_mac_addr.type = hw_type;
++  sender_mac_addr.len = hln;
++  grub_memcpy (sender_mac_addr.mac, tmp_ptr, hln);
++  tmp_ptr += hln;
++
++  /* The source protocol address. */
+   sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
++  grub_memcpy(&sender_addr.ipv4, tmp_ptr, pln);
++  tmp_ptr += pln;
++
++  grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1);
++
++  /* The target hardware address. */
++  tmp_ptr += hln;
++
++  /* The target protocol address. */
+   target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
+-  sender_addr.ipv4 = arp_packet->sender_ip;
+-  target_addr.ipv4 = arp_packet->recv_ip;
+-  if (arp_packet->sender_ip == pending_req)
++  grub_memcpy(&target_addr.ipv4, tmp_ptr, pln);
++
++  if (sender_addr.ipv4 == pending_req)
+     have_pending = 1;
+ 
+-  sender_mac_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-  grub_memcpy (sender_mac_addr.mac, arp_packet->sender_mac,
+-	       sizeof (sender_mac_addr.mac));
+-  grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1);
+-
+   FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
+   {
+     /* Verify vlantag id */
+@@ -148,11 +183,11 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
+ 
+     /* Am I the protocol address target? */
+     if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
+-	&& arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
++	&& arp_header->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
+       {
+ 	grub_net_link_level_address_t target;
+ 	struct grub_net_buff nb_reply;
+-	struct arppkt *arp_reply;
++	struct arphdr *arp_reply;
+ 	grub_uint8_t arp_data[128];
+ 	grub_err_t err;
+ 
+@@ -161,25 +196,39 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
+ 	grub_netbuff_clear (&nb_reply);
+ 	grub_netbuff_reserve (&nb_reply, 128);
+ 
+-	err = grub_netbuff_push (&nb_reply, sizeof (*arp_packet));
++	err = grub_netbuff_push (&nb_reply, arp_packet_len);
+ 	if (err)
+ 	  return err;
+ 
+-	arp_reply = (struct arppkt *) nb_reply.data;
++	arp_reply = (struct arphdr *) nb_reply.data;
+ 
+-	arp_reply->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
++	arp_reply->hrd = grub_cpu_to_be16 (hw_type);
+ 	arp_reply->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
+-	arp_reply->pln = 4;
+-	arp_reply->hln = 6;
++	arp_reply->pln = pln;
++	arp_reply->hln = hln;
+ 	arp_reply->op = grub_cpu_to_be16_compile_time (ARP_REPLY);
+-	arp_reply->sender_ip = arp_packet->recv_ip;
+-	arp_reply->recv_ip = arp_packet->sender_ip;
+-	arp_reply->hln = 6;
+-
+-	target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-	grub_memcpy (target.mac, arp_packet->sender_mac, 6);
+-	grub_memcpy (arp_reply->sender_mac, inf->hwaddress.mac, 6);
+-	grub_memcpy (arp_reply->recv_mac, arp_packet->sender_mac, 6);
++
++	tmp_ptr = nb_reply.data + sizeof (*arp_reply);
++
++	/* The source hardware address. */
++	grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln);
++	tmp_ptr += hln;
++
++	/* The source protocol address. */
++	grub_memcpy (tmp_ptr, &target_addr.ipv4, pln);
++	tmp_ptr += pln;
++
++	/* The target hardware address. */
++	grub_memcpy (tmp_ptr, sender_mac_addr.mac, hln);
++	tmp_ptr += hln;
++
++	/* The target protocol address */
++	grub_memcpy (tmp_ptr, &sender_addr.ipv4, pln);
++	tmp_ptr += pln;
++
++	target.type = hw_type;
++	target.len = hln;
++	grub_memcpy (target.mac, sender_mac_addr.mac, hln);
+ 
+ 	/* Change operation to REPLY and send packet */
+ 	send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP);
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index 2869482fe06..4e55adc557b 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -219,7 +219,6 @@ grub_net_configure_by_dhcp_ack (const char *name,
+ 				int is_def, char **device, char **path)
+ {
+   grub_net_network_level_address_t addr;
+-  grub_net_link_level_address_t hwaddr;
+   struct grub_net_network_level_interface *inter;
+   int mask = -1;
+   char server_ip[sizeof ("xxx.xxx.xxx.xxx")];
+@@ -232,12 +231,8 @@ grub_net_configure_by_dhcp_ack (const char *name,
+   if (path)
+     *path = 0;
+ 
+-  grub_memcpy (hwaddr.mac, bp->mac_addr,
+-	       bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len
+-	       : sizeof (hwaddr.mac));
+-  hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-
+-  inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags);
++  grub_dprintf("dhcp", "configuring dhcp for %s\n", name);
++  inter = grub_net_add_addr (name, card, &addr, &card->default_address, flags);
+   if (!inter)
+     return 0;
+ 
+@@ -770,7 +765,8 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
+ 	  grub_memset (pack, 0, sizeof (*pack) + 64);
+ 	  pack->opcode = 1;
+ 	  pack->hw_type = 1;
+-	  pack->hw_len = 6;
++	  pack->hw_len = ifaces[j].hwaddress.len > 16 ? 0
++						      : ifaces[j].hwaddress.len;
+ 	  err = grub_get_datetime (&date);
+ 	  if (err || !grub_datetime2unixtime (&date, &t))
+ 	    {
+@@ -781,7 +777,7 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
+ 	  ifaces[j].dhcp_xid = pack->xid;
+ 	  pack->seconds = grub_cpu_to_be16 (t);
+ 
+-	  grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6); 
++	  grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, pack->hw_len);
+ 
+ 	  grub_netbuff_push (nb, sizeof (*udph));
+ 
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index a4daaa460bd..cd6dba79f63 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -280,6 +280,9 @@ grub_efinet_findcards (void)
+ 	/* This should not happen... Why?  */
+ 	continue;
+ 
++      if (net->mode->hwaddr_size > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
++	continue;
++
+       if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
+ 	  && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
+ 	continue;
+@@ -316,10 +319,11 @@ grub_efinet_findcards (void)
+       card->name = grub_xasprintf ("efinet%d", i++);
+       card->driver = &efidriver;
+       card->flags = 0;
+-      card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++      card->default_address.type = net->mode->if_type;
++      card->default_address.len = net->mode->hwaddr_size;
+       grub_memcpy (card->default_address.mac,
+ 		   net->mode->current_address,
+-		   sizeof (card->default_address.mac));
++		   net->mode->hwaddr_size);
+       card->efi_net = net;
+       card->efi_handle = *handle;
+ 
+diff --git a/grub-core/net/drivers/emu/emunet.c b/grub-core/net/drivers/emu/emunet.c
+index b194920861f..5b6c5e16a6d 100644
+--- a/grub-core/net/drivers/emu/emunet.c
++++ b/grub-core/net/drivers/emu/emunet.c
+@@ -46,6 +46,7 @@ static struct grub_net_card emucard =
+     .mtu = 1500,
+     .default_address = {
+ 			 .type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET,
++			 . len = 6,
+ 			 {.mac = {0, 1, 2, 3, 4, 5}}
+ 		       },
+     .flags = 0
+diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c
+index 3f4152d036c..9f8fb4b6d2b 100644
+--- a/grub-core/net/drivers/i386/pc/pxe.c
++++ b/grub-core/net/drivers/i386/pc/pxe.c
+@@ -386,20 +386,21 @@ GRUB_MOD_INIT(pxe)
+   grub_memset (ui, 0, sizeof (*ui));
+   grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry);
+ 
++  grub_pxe_card.default_address.len = 6;
+   grub_memcpy (grub_pxe_card.default_address.mac, ui->current_addr,
+-	       sizeof (grub_pxe_card.default_address.mac));
+-  for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++)
++	       grub_pxe_card.default_address.len);
++  for (i = 0; i < grub_pxe_card.default_address.len; i++)
+     if (grub_pxe_card.default_address.mac[i] != 0)
+       break;
+-  if (i != sizeof (grub_pxe_card.default_address.mac))
++  if (i != grub_pxe_card.default_address.len)
+     {
+-      for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++)
++      for (i = 0; i < grub_pxe_card.default_address.len; i++)
+ 	if (grub_pxe_card.default_address.mac[i] != 0xff)
+ 	  break;
+     }
+-  if (i == sizeof (grub_pxe_card.default_address.mac))
++  if (i == grub_pxe_card.default_address.len)
+     grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr,
+-		 sizeof (grub_pxe_card.default_address.mac));
++		 grub_pxe_card.default_address.len);
+   grub_pxe_card.mtu = ui->mtu;
+ 
+   grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
+index 3df75357a70..ba50415f5f6 100644
+--- a/grub-core/net/drivers/ieee1275/ofnet.c
++++ b/grub-core/net/drivers/ieee1275/ofnet.c
+@@ -160,6 +160,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath,
+   grub_uint16_t vlantag = 0;
+ 
+   hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++  hw_addr.len = 6;
+ 
+   args = bootpath + grub_strlen (devpath) + 1;
+   do
+@@ -503,6 +504,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
+     grub_memcpy (&lla.mac, pprop, 6);
+ 
+   lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++  lla.len = 6;
+   card->default_address = lla;
+ 
+   card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
+diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c
+index 056052e40d5..22ebcbf211e 100644
+--- a/grub-core/net/drivers/uboot/ubootnet.c
++++ b/grub-core/net/drivers/uboot/ubootnet.c
+@@ -131,6 +131,7 @@ GRUB_MOD_INIT (ubootnet)
+ 
+       grub_memcpy (&(card->default_address.mac), &devinfo->di_net.hwaddr, 6);
+       card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++      card->default_address.len = 6;
+ 
+       card->txbufsize = ALIGN_UP (card->mtu, 64) + 256;
+       card->txbuf = grub_zalloc (card->txbufsize);
+diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c
+index 4d7ceed6f93..9aae83a5eb4 100644
+--- a/grub-core/net/ethernet.c
++++ b/grub-core/net/ethernet.c
+@@ -29,13 +29,6 @@
+ 
+ #define LLCADDRMASK 0x7f
+ 
+-struct etherhdr
+-{
+-  grub_uint8_t dst[6];
+-  grub_uint8_t src[6];
+-  grub_uint16_t type;
+-} GRUB_PACKED;
+-
+ struct llchdr
+ {
+   grub_uint8_t dsap;
+@@ -55,13 +48,15 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
+ 		      grub_net_link_level_address_t target_addr,
+ 		      grub_net_ethertype_t ethertype)
+ {
+-  struct etherhdr *eth;
++  grub_uint8_t *eth;
+   grub_err_t err;
+-  grub_uint8_t etherhdr_size;
+-  grub_uint16_t vlantag_id = VLANTAG_IDENTIFIER;
++  grub_uint32_t vlantag = 0;
++  grub_uint8_t hw_addr_len = inf->card->default_address.len;
++  grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2;
+ 
+-  etherhdr_size = sizeof (*eth);
+-  COMPILE_TIME_ASSERT (sizeof (*eth) + 4 < GRUB_NET_MAX_LINK_HEADER_SIZE);
++  /* Source and destination link addresses + ethertype + vlan tag */
++  COMPILE_TIME_ASSERT ((GRUB_NET_MAX_LINK_ADDRESS_SIZE * 2 + 2 + 4) <
++		       GRUB_NET_MAX_LINK_HEADER_SIZE);
+ 
+   /* Increase ethernet header in case of vlantag */
+   if (inf->vlantag != 0)
+@@ -70,11 +65,22 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
+   err = grub_netbuff_push (nb, etherhdr_size);
+   if (err)
+     return err;
+-  eth = (struct etherhdr *) nb->data;
+-  grub_memcpy (eth->dst, target_addr.mac, 6);
+-  grub_memcpy (eth->src, inf->hwaddress.mac, 6);
++  eth = nb->data;
++  grub_memcpy (eth, target_addr.mac, hw_addr_len);
++  eth += hw_addr_len;
++  grub_memcpy (eth, inf->hwaddress.mac, hw_addr_len);
++  eth += hw_addr_len;
++
++  /* Check if a vlan-tag is present. */
++  if (vlantag != 0)
++    {
++      *((grub_uint32_t *)eth) = grub_cpu_to_be32 (vlantag);
++      eth += sizeof (vlantag);
++    }
++
++  /* Write ethertype */
++  *((grub_uint16_t*) eth) = grub_cpu_to_be16 (ethertype);
+ 
+-  eth->type = grub_cpu_to_be16 (ethertype);
+   if (!inf->card->opened)
+     {
+       err = GRUB_ERR_NONE;
+@@ -85,18 +91,6 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
+       inf->card->opened = 1;
+     }
+ 
+-  /* Check and add a vlan-tag if needed. */
+-  if (inf->vlantag != 0)
+-    {
+-      /* Move eth type to the right */
+-      grub_memcpy ((char *) nb->data + etherhdr_size - 2,
+-                   (char *) nb->data + etherhdr_size - 6, 2);
+-
+-      /* Add the tag in the middle */
+-      grub_memcpy ((char *) nb->data + etherhdr_size - 6, &vlantag_id, 2);
+-      grub_memcpy ((char *) nb->data + etherhdr_size - 4, (char *) &(inf->vlantag), 2);
+-    }
+-
+   return inf->card->driver->send (inf->card, nb);
+ }
+ 
+@@ -104,31 +98,40 @@ grub_err_t
+ grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
+ 			       struct grub_net_card *card)
+ {
+-  struct etherhdr *eth;
++  grub_uint8_t *eth;
+   struct llchdr *llch;
+   struct snaphdr *snaph;
+   grub_net_ethertype_t type;
+   grub_net_link_level_address_t hwaddress;
+   grub_net_link_level_address_t src_hwaddress;
+   grub_err_t err;
+-  grub_uint8_t etherhdr_size = sizeof (*eth);
++  grub_uint8_t hw_addr_len = card->default_address.len;
++  grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2;
+   grub_uint16_t vlantag = 0;
+ 
++  eth = nb->data;
+ 
+-  /* Check if a vlan-tag is present. If so, the ethernet header is 4 bytes */
+-  /* longer than the original one. The vlantag id is extracted and the header */
+-  /* is reseted to the original size. */
+-  if (grub_get_unaligned16 (nb->data + etherhdr_size - 2) == VLANTAG_IDENTIFIER)
++  hwaddress.type = card->default_address.type;
++  hwaddress.len = hw_addr_len;
++  grub_memcpy (hwaddress.mac, eth, hw_addr_len);
++  eth += hw_addr_len;
++
++  src_hwaddress.type = card->default_address.type;
++  src_hwaddress.len = hw_addr_len;
++  grub_memcpy (src_hwaddress.mac, eth, hw_addr_len);
++  eth += hw_addr_len;
++
++  type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
++  if (type == VLANTAG_IDENTIFIER)
+     {
+-      vlantag = grub_get_unaligned16 (nb->data + etherhdr_size);
++      /* Skip vlan tag */
++      eth += 2;
++      vlantag = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
+       etherhdr_size += 4;
+-      /* Move eth type to the original position */
+-      grub_memcpy((char *) nb->data + etherhdr_size - 6,
+-                  (char *) nb->data + etherhdr_size - 2, 2);
++      eth += 2;
++      type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth));
+     }
+ 
+-  eth = (struct etherhdr *) nb->data;
+-  type = grub_be_to_cpu16 (eth->type);
+   err = grub_netbuff_pull (nb, etherhdr_size);
+   if (err)
+     return err;
+@@ -148,11 +151,6 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
+ 	}
+     }
+ 
+-  hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-  grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac));
+-  src_hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-  grub_memcpy (src_hwaddress.mac, eth->src, sizeof (src_hwaddress.mac));
+-
+   switch (type)
+     {
+       /* ARP packet. */
+diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c
+index 2cbd95dce25..56a3ec5c8e8 100644
+--- a/grub-core/net/icmp6.c
++++ b/grub-core/net/icmp6.c
+@@ -231,8 +231,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
+ 		&& ohdr->len == 1)
+ 	      {
+ 		grub_net_link_level_address_t ll_address;
+-		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
++		ll_address.type = card->default_address.type;
++		ll_address.len = card->default_address.len;
++		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
+ 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
+ 	      }
+ 	  }
+@@ -335,8 +336,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
+ 		&& ohdr->len == 1)
+ 	      {
+ 		grub_net_link_level_address_t ll_address;
+-		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
++		ll_address.type = card->default_address.type;
++		ll_address.len = card->default_address.len;
++		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
+ 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
+ 	      }
+ 	  }
+@@ -384,8 +386,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
+ 		&& ohdr->len == 1)
+ 	      {
+ 		grub_net_link_level_address_t ll_address;
+-		ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-		grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
++		ll_address.type = card->default_address.type;
++		ll_address.len = card->default_address.len;
++		grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len);
+ 		grub_net_link_layer_add_address (card, source, &ll_address, 0);
+ 	      }
+ 	    if (ohdr->type == OPTION_PREFIX && ohdr->len == 4)
+diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
+index 8411e0ecca3..b2ca74b6eb1 100644
+--- a/grub-core/net/ip.c
++++ b/grub-core/net/ip.c
+@@ -277,8 +277,8 @@ handle_dgram (struct grub_net_buff *nb,
+ 	      && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
+ 	      && inf->dhcp_xid == bootp->xid
+ 	      && inf->hwaddress.type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
+-	      && grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr,
+-			      sizeof (inf->hwaddress.mac)) == 0)
++	      && (grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr,
++			       bootp->hw_len) == 0 || bootp->hw_len == 0))
+ 	    {
+ 	      grub_net_process_dhcp (nb, inf->card);
+ 	      grub_netbuff_free (nb);
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index fa3e2912643..9b8944292c7 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -128,8 +128,9 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf,
+ 								   << 48)
+ 	  && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1))))
+     {
+-      hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-      grub_memset (hw_addr->mac, -1, 6);
++      hw_addr->type = inf->card->default_address.type;
++      hw_addr->len = inf->card->default_address.len;
++      grub_memset (hw_addr->mac, -1, hw_addr->len);
+       return GRUB_ERR_NONE;
+     }
+ 
+@@ -137,6 +138,7 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf,
+       && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff))
+     {
+       hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
++      hw_addr->len = inf->card->default_address.len;
+       hw_addr->mac[0] = 0x33;
+       hw_addr->mac[1] = 0x33;
+       hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff);
+@@ -757,23 +759,21 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf)
+ void
+ grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
+ {
+-  str[0] = 0;
+-  switch (addr->type)
++  char *ptr;
++  unsigned i;
++
++  if (addr->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
+     {
+-    case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET:
+-      {
+-	char *ptr;
+-	unsigned i;
+-	for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++)
+-	  {
+-	    grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str),
+-			   "%02x:", addr->mac[i] & 0xff);
+-	    ptr += (sizeof ("XX:") - 1);
+-	  }
+-      return;
+-      }
++       str[0] = 0;
++       grub_printf (_("Unsupported hw address type %d len %d\n"),
++		    addr->type, addr->len);
++       return;
++    }
++  for (ptr = str, i = 0; i < addr->len; i++)
++    {
++      ptr += grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str),
++		     "%02x:", addr->mac[i] & 0xff);
+     }
+-  grub_printf (_("Unsupported hw address type %d\n"), addr->type);
+ }
+ 
+ int
+@@ -784,13 +784,17 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
+     return -1;
+   if (a->type > b->type)
+     return +1;
+-  switch (a->type)
++  if (a->len < b->len)
++    return -1;
++  if (a->len > b->len)
++    return +1;
++  if (a->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
+     {
+-    case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET:
+-      return grub_memcmp (a->mac, b->mac, sizeof (a->mac));
++      grub_printf (_("Unsupported hw address type %d len %d\n"),
++		   a->type, a->len);
++      return + 1;
+     }
+-  grub_printf (_("Unsupported hw address type %d\n"), a->type);
+-  return 1;
++  return grub_memcmp (a->mac, b->mac, a->len);
+ }
+ 
+ int
+diff --git a/include/grub/net.h b/include/grub/net.h
+index de51894cbbf..e9ebc6a1b4f 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -29,7 +29,8 @@
+ 
+ enum
+   {
+-    GRUB_NET_MAX_LINK_HEADER_SIZE = 64,
++    GRUB_NET_MAX_LINK_HEADER_SIZE = 96,
++    GRUB_NET_MAX_LINK_ADDRESS_SIZE = 32,
+     GRUB_NET_UDP_HEADER_SIZE = 8,
+     GRUB_NET_TCP_HEADER_SIZE = 20,
+     GRUB_NET_OUR_IPV4_HEADER_SIZE = 20,
+@@ -42,15 +43,17 @@ enum
+ 
+ typedef enum grub_link_level_protocol_id 
+ {
+-  GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
++  /* IANA ARP constant to define hardware type. */
++  GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET = 1,
+ } grub_link_level_protocol_id_t;
+ 
+ typedef struct grub_net_link_level_address
+ {
+   grub_link_level_protocol_id_t type;
++  grub_uint8_t len;
+   union
+   {
+-    grub_uint8_t mac[6];
++    grub_uint8_t mac[GRUB_NET_MAX_LINK_ADDRESS_SIZE];
+   };
+ } grub_net_link_level_address_t;
+ 
+@@ -555,11 +558,13 @@ grub_net_addr_cmp (const grub_net_network_level_address_t *a,
+ #define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")
+ 
+ /*
+-  Currently suppoerted adresses:
+-  ethernet:   XX:XX:XX:XX:XX:XX
++  Up to 32 byte hardware address supported, see GRUB_NET_MAX_LINK_ADDRESS_SIZE
+  */
+-
+-#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX"))
++#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof (\
++	"XX:XX:XX:XX:XX:XX:XX:XX:"\
++	"XX:XX:XX:XX:XX:XX:XX:XX:"\
++	"XX:XX:XX:XX:XX:XX:XX:XX:"\
++	"XX:XX:XX:XX:XX:XX:XX:XX"))
+ 
+ void
+ grub_net_addr_to_str (const grub_net_network_level_address_t *target,
diff --git a/SOURCES/0166-misc-fix-invalid-character-recongition-in-strto-l.patch b/SOURCES/0166-misc-fix-invalid-character-recongition-in-strto-l.patch
new file mode 100644
index 0000000..4006028
--- /dev/null
+++ b/SOURCES/0166-misc-fix-invalid-character-recongition-in-strto-l.patch
@@ -0,0 +1,37 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aaron Miller <aaronmiller@fb.com>
+Date: Fri, 29 Jul 2016 17:41:27 +0800
+Subject: [PATCH] misc: fix invalid character recongition in strto*l
+
+Would previously allow digits larger than the base and didn't check that
+subtracting the difference from 0-9 to lowercase letters for characters
+larger than 9 didn't result in a value lower than 9, which allowed the
+parses: ` = 9, _ = 8, ^ = 7, ] = 6, \ = 5, and [ = 4
+---
+ grub-core/kern/misc.c | 13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 0e89c483d5e..5c3899f0e5b 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -434,11 +434,14 @@ grub_strtoull (const char *str, char **end, int base)
+       unsigned long digit;
+ 
+       digit = grub_tolower (*str) - '0';
+-      if (digit >= 'a' - '0')
+-	digit += '0' - 'a' + 10;
+-      else if (digit > 9)
+-	break;
+-
++      if (digit > 9)
++	{
++	  digit += '0' - 'a' + 10;
++	  /* digit <= 9 check is needed to keep chars larger than
++	     '9' but less than 'a' from being read as numbers */
++	  if (digit >= (unsigned long) base || digit <= 9)
++	    break;
++	}
+       if (digit >= (unsigned long) base)
+ 	break;
+ 
diff --git a/SOURCES/0167-net-read-bracketed-ipv6-addrs-and-port-numbers.patch b/SOURCES/0167-net-read-bracketed-ipv6-addrs-and-port-numbers.patch
new file mode 100644
index 0000000..4f68187
--- /dev/null
+++ b/SOURCES/0167-net-read-bracketed-ipv6-addrs-and-port-numbers.patch
@@ -0,0 +1,229 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aaron Miller <aaronmiller@fb.com>
+Date: Fri, 29 Jul 2016 17:41:38 +0800
+Subject: [PATCH] net: read bracketed ipv6 addrs and port numbers
+
+Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses
+to be recognized with brackets around them, which is required to specify a port
+number
+---
+ grub-core/net/http.c | 21 +++++++++++---
+ grub-core/net/net.c  | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ grub-core/net/tftp.c |  8 ++++--
+ include/grub/net.h   |  1 +
+ 4 files changed, 101 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index 5aa4ad3befc..f182d7b871d 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -312,12 +312,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
+   int i;
+   struct grub_net_buff *nb;
+   grub_err_t err;
++  char* server = file->device->net->server;
++  int port = file->device->net->port;
+ 
+   nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE
+ 			   + sizeof ("GET ") - 1
+ 			   + grub_strlen (data->filename)
+ 			   + sizeof (" HTTP/1.1\r\nHost: ") - 1
+-			   + grub_strlen (file->device->net->server)
++			   + grub_strlen (server) + sizeof (":XXXXXXXXXX")
+ 			   + sizeof ("\r\nUser-Agent: " PACKAGE_STRING
+ 				     "\r\n") - 1
+ 			   + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX"
+@@ -356,7 +358,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
+ 	       sizeof (" HTTP/1.1\r\nHost: ") - 1);
+ 
+   ptr = nb->tail;
+-  err = grub_netbuff_put (nb, grub_strlen (file->device->net->server));
++  err = grub_netbuff_put (nb, grub_strlen (server));
+   if (err)
+     {
+       grub_netbuff_free (nb);
+@@ -365,6 +367,15 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
+   grub_memcpy (ptr, file->device->net->server,
+ 	       grub_strlen (file->device->net->server));
+ 
++  if (port)
++    {
++      ptr = nb->tail;
++      grub_snprintf ((char *) ptr,
++	  sizeof (":XXXXXXXXXX"),
++	  ":%d",
++	  port);
++    }
++
+   ptr = nb->tail;
+   err = grub_netbuff_put (nb, 
+ 			  sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n")
+@@ -390,8 +401,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
+   grub_netbuff_put (nb, 2);
+   grub_memcpy (ptr, "\r\n", 2);
+ 
+-  data->sock = grub_net_tcp_open (file->device->net->server,
+-				  HTTP_PORT, http_receive,
++  grub_dprintf ("http", "opening path %s on host %s TCP port %d\n",
++		data->filename, server, port ? port : HTTP_PORT);
++  data->sock = grub_net_tcp_open (server,
++				  port ? port : HTTP_PORT, http_receive,
+ 				  http_err, http_err,
+ 				  file);
+   if (!data->sock)
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 9b8944292c7..1f887d44b32 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -439,6 +439,12 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
+   grub_uint16_t newip[8];
+   const char *ptr = val;
+   int word, quaddot = -1;
++  int bracketed = 0;
++
++  if (ptr[0] == '[') {
++    bracketed = 1;
++    ptr++;
++  }
+ 
+   if (ptr[0] == ':' && ptr[1] != ':')
+     return 0;
+@@ -477,6 +483,9 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
+       grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
+     }
+   grub_memcpy (ip, newip, 16);
++  if (bracketed && *ptr == ']') {
++    ptr++;
++  }
+   if (rest)
+     *rest = ptr;
+   return 1;
+@@ -1336,8 +1345,10 @@ grub_net_open_real (const char *name)
+ {
+   grub_net_app_level_t proto;
+   const char *protname, *server;
++  char *host;
+   grub_size_t protnamelen;
+   int try;
++  int port = 0;
+ 
+   if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
+     {
+@@ -1375,6 +1386,72 @@ grub_net_open_real (const char *name)
+       return NULL;
+     }  
+ 
++  char* port_start;
++  /* ipv6 or port specified? */
++  if ((port_start = grub_strchr (server, ':')))
++  {
++      char* ipv6_begin;
++      if((ipv6_begin = grub_strchr (server, '[')))
++	{
++	  char* ipv6_end = grub_strchr (server, ']');
++	  if(!ipv6_end)
++	    {
++	      grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++		      N_("mismatched [ in address"));
++	      return NULL;
++	    }
++	  /* port number after bracketed ipv6 addr */
++	  if(ipv6_end[1] == ':')
++	    {
++	      port = grub_strtoul (ipv6_end + 2, NULL, 10);
++	      if(port > 65535)
++		{
++		  grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++			  N_("bad port number"));
++		  return NULL;
++		}
++	    }
++	  host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1);
++	}
++      else
++	{
++	  if (grub_strchr (port_start + 1, ':'))
++	    {
++	      int iplen = grub_strlen (server);
++	      /* bracket bare ipv6 addrs */
++	      host = grub_malloc (iplen + 3);
++	      if(!host)
++		{
++		  return NULL;
++		}
++	      host[0] = '[';
++	      grub_memcpy (host + 1, server, iplen);
++	      host[iplen + 1] = ']';
++	      host[iplen + 2] = '\0';
++	    }
++	  else
++	    {
++	      /* hostname:port or ipv4:port */
++	      port = grub_strtol (port_start + 1, NULL, 10);
++	      if(port > 65535)
++		{
++		  grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++			  N_("bad port number"));
++		  return NULL;
++		}
++	      host = grub_strndup (server, port_start - server);
++	    }
++	}
++    }
++  else
++    {
++      host = grub_strdup (server);
++    }
++  if (!host)
++    {
++      return NULL;
++    }
++
+   for (try = 0; try < 2; try++)
+     {
+       FOR_NET_APP_LEVEL (proto)
+diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
+index f90071353ad..e267af354f4 100644
+--- a/grub-core/net/tftp.c
++++ b/grub-core/net/tftp.c
+@@ -333,6 +333,7 @@ tftp_open (struct grub_file *file, const char *filename)
+   grub_err_t err;
+   grub_uint8_t *nbd;
+   grub_net_network_level_address_t addr;
++  int port = file->device->net->port;
+ 
+   data = grub_zalloc (sizeof (*data));
+   if (!data)
+@@ -405,7 +406,10 @@ tftp_open (struct grub_file *file, const char *filename)
+   err = grub_net_resolve_address (file->device->net->server, &addr);
+   if (err)
+     {
+-      grub_dprintf("tftp", "Address resolution failed: %d\n", err);
++      grub_dprintf ("tftp", "Address resolution failed: %d\n", err);
++      grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n",
++		    (unsigned long long)data->file_size,
++		    (unsigned long long)data->block_size);
+       destroy_pq (data);
+       grub_free (data);
+       return err;
+@@ -413,7 +417,7 @@ tftp_open (struct grub_file *file, const char *filename)
+ 
+   grub_dprintf("tftp", "opening connection\n");
+   data->sock = grub_net_udp_open (addr,
+-				  TFTP_SERVER_PORT, tftp_receive,
++				  port ? port : TFTP_SERVER_PORT, tftp_receive,
+ 				  file);
+   if (!data->sock)
+     {
+diff --git a/include/grub/net.h b/include/grub/net.h
+index e9ebc6a1b4f..f4cd86e582f 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -273,6 +273,7 @@ typedef struct grub_net
+ {
+   char *server;
+   char *name;
++  int port;
+   grub_net_app_level_t protocol;
+   grub_net_packets_t packs;
+   grub_off_t offset;
diff --git a/SOURCES/0168-net-read-bracketed-ipv6-addrs-and-port-numbers-pjone.patch b/SOURCES/0168-net-read-bracketed-ipv6-addrs-and-port-numbers-pjone.patch
new file mode 100644
index 0000000..a0f3859
--- /dev/null
+++ b/SOURCES/0168-net-read-bracketed-ipv6-addrs-and-port-numbers-pjone.patch
@@ -0,0 +1,105 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Aaron Miller <aaronmiller@fb.com>
+Date: Fri, 29 Jul 2016 17:41:38 +0800
+Subject: [PATCH] net: read bracketed ipv6 addrs and port numbers (pjones
+ fixup)
+
+Various bug fixes related to previous patch.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/http.c |  6 ++++--
+ grub-core/net/net.c  | 24 ++++++++++++------------
+ 2 files changed, 16 insertions(+), 14 deletions(-)
+
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index f182d7b871d..00737c52750 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -289,7 +289,9 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
+ 	  nb2 = grub_netbuff_alloc (data->chunk_rem);
+ 	  if (!nb2)
+ 	    return grub_errno;
+-	  grub_netbuff_put (nb2, data->chunk_rem);
++	  err = grub_netbuff_put (nb2, data->chunk_rem);
++	  if (err)
++	    return grub_errno;
+ 	  grub_memcpy (nb2->data, nb->data, data->chunk_rem);
+ 	  if (file->device->net->packs.count >= 20)
+ 	    {
+@@ -405,7 +407,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
+ 		data->filename, server, port ? port : HTTP_PORT);
+   data->sock = grub_net_tcp_open (server,
+ 				  port ? port : HTTP_PORT, http_receive,
+-				  http_err, http_err,
++				  http_err, NULL,
+ 				  file);
+   if (!data->sock)
+     {
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 1f887d44b32..a0f4d00f0be 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -441,10 +441,11 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
+   int word, quaddot = -1;
+   int bracketed = 0;
+ 
+-  if (ptr[0] == '[') {
+-    bracketed = 1;
+-    ptr++;
+-  }
++  if (ptr[0] == '[')
++    {
++      bracketed = 1;
++      ptr++;
++    }
+ 
+   if (ptr[0] == ':' && ptr[1] != ':')
+     return 0;
+@@ -483,9 +484,8 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
+       grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
+     }
+   grub_memcpy (ip, newip, 16);
+-  if (bracketed && *ptr == ']') {
++  if (bracketed && *ptr == ']')
+     ptr++;
+-  }
+   if (rest)
+     *rest = ptr;
+   return 1;
+@@ -1389,7 +1389,7 @@ grub_net_open_real (const char *name)
+   char* port_start;
+   /* ipv6 or port specified? */
+   if ((port_start = grub_strchr (server, ':')))
+-  {
++    {
+       char* ipv6_begin;
+       if((ipv6_begin = grub_strchr (server, '[')))
+ 	{
+@@ -1461,14 +1461,13 @@ grub_net_open_real (const char *name)
+ 	  {
+ 	    grub_net_t ret = grub_zalloc (sizeof (*ret));
+ 	    if (!ret)
+-	      return NULL;
+-	    ret->protocol = proto;
+-	    ret->server = grub_strdup (server);
+-	    if (!ret->server)
+ 	      {
+-		grub_free (ret);
++		grub_free (host);
+ 		return NULL;
+ 	      }
++	    ret->protocol = proto;
++	    ret->port = port;
++	    ret->server = host;
+ 	    ret->fs = &grub_net_fs;
+ 	    return ret;
+ 	  }
+@@ -1543,6 +1542,7 @@ grub_net_open_real (const char *name)
+   grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
+ 	      name);
+ 
++  grub_free (host);
+   return NULL;
+ }
+ 
diff --git a/SOURCES/0169-bootp-New-net_bootp6-command.patch b/SOURCES/0169-bootp-New-net_bootp6-command.patch
new file mode 100644
index 0000000..9e2a5d3
--- /dev/null
+++ b/SOURCES/0169-bootp-New-net_bootp6-command.patch
@@ -0,0 +1,1357 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Sun, 10 Jul 2016 23:46:06 +0800
+Subject: [PATCH] bootp: New net_bootp6 command
+
+Implement new net_bootp6 command for IPv6 network auto configuration via the
+DHCPv6 protocol (RFC3315).
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+---
+ grub-core/net/bootp.c              | 1048 ++++++++++++++++++++++++++++++------
+ grub-core/net/drivers/efi/efinet.c |   20 +-
+ grub-core/net/ip.c                 |   39 ++
+ include/grub/efi/api.h             |    2 +-
+ include/grub/net.h                 |   91 ++--
+ 5 files changed, 994 insertions(+), 206 deletions(-)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index 4e55adc557b..ff1d7776e7f 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -25,6 +25,98 @@
+ #include <grub/net/udp.h>
+ #include <grub/net/url.h>
+ #include <grub/datetime.h>
++#include <grub/time.h>
++#include <grub/list.h>
++
++static int
++dissect_url (const char *url, char **proto, char **host, char **path)
++{
++  const char *p, *ps;
++  grub_size_t l;
++
++  *proto = *host = *path = NULL;
++  ps = p = url;
++
++  while ((p = grub_strchr (p, ':')))
++    {
++      if (grub_strlen (p) < sizeof ("://") - 1)
++	break;
++      if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0)
++	{
++	  l = p - ps;
++	  *proto = grub_malloc (l + 1);
++	  if (!*proto)
++	    {
++	      grub_print_error ();
++	      return 0;
++	    }
++
++	  grub_memcpy (*proto, ps, l);
++	  (*proto)[l] = '\0';
++	  p +=  sizeof ("://") - 1;
++	  break;
++	}
++      ++p;
++    }
++
++  if (!*proto)
++    {
++      grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url);
++      return 0;
++    }
++
++  ps = p;
++  p = grub_strchr (p, '/');
++
++  if (!p)
++    {
++      grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url);
++      grub_free (*proto);
++      *proto = NULL;
++      return 0;
++    }
++
++  l = p - ps;
++
++  if (l > 2 && ps[0] == '[' && ps[l - 1] == ']')
++    {
++      *host = grub_malloc (l - 1);
++      if (!*host)
++	{
++	  grub_print_error ();
++	  grub_free (*proto);
++	  *proto = NULL;
++	  return 0;
++	}
++      grub_memcpy (*host, ps + 1, l - 2);
++      (*host)[l - 2] = 0;
++    }
++  else
++    {
++      *host = grub_malloc (l + 1);
++      if (!*host)
++	{
++	  grub_print_error ();
++	  grub_free (*proto);
++	  *proto = NULL;
++	  return 0;
++	}
++      grub_memcpy (*host, ps, l);
++      (*host)[l] = 0;
++    }
++
++  *path = grub_strdup (p);
++  if (!*path)
++    {
++      grub_print_error ();
++      grub_free (*host);
++      grub_free (*proto);
++      *host = NULL;
++      *proto = NULL;
++      return 0;
++    }
++  return 1;
++}
+ 
+ static char *
+ grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
+@@ -345,178 +437,578 @@ grub_net_configure_by_dhcp_ack (const char *name,
+   return inter;
+ }
+ 
+-struct grub_net_network_level_interface *
+-grub_net_configure_by_dhcpv6_ack (const char *name,
+-				  struct grub_net_card *card,
+-				  grub_net_interface_flags_t flags
+-				    __attribute__((__unused__)),
+-				  const grub_net_link_level_address_t *hwaddr,
+-				  const struct grub_net_dhcpv6_packet *packet,
+-				  int is_def, char **device, char **path)
+-{
+-  struct grub_net_network_level_interface *inter = NULL;
+-  struct grub_net_network_level_address addr;
+-  int mask = -1;
+-
+-  if (!device || !path)
++/* The default netbuff size for sending DHCPv6 packets which should be
++   large enough to hold the information */
++#define GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE 512
++
++struct grub_dhcp6_options
++{
++  grub_uint8_t *client_duid;
++  grub_uint16_t client_duid_len;
++  grub_uint8_t *server_duid;
++  grub_uint16_t server_duid_len;
++  grub_uint32_t iaid;
++  grub_uint32_t t1;
++  grub_uint32_t t2;
++  grub_net_network_level_address_t *ia_addr;
++  grub_uint32_t preferred_lifetime;
++  grub_uint32_t valid_lifetime;
++  grub_net_network_level_address_t *dns_server_addrs;
++  grub_uint16_t num_dns_server;
++  char *boot_file_proto;
++  char *boot_file_server_ip;
++  char *boot_file_path;
++};
++
++typedef struct grub_dhcp6_options *grub_dhcp6_options_t;
++
++struct grub_dhcp6_session
++{
++  struct grub_dhcp6_session *next;
++  struct grub_dhcp6_session **prev;
++  grub_uint32_t iaid;
++  grub_uint32_t transaction_id:24;
++  grub_uint64_t start_time;
++  struct grub_net_dhcp6_option_duid_ll duid;
++  struct grub_net_network_level_interface *iface;
++
++  /* The associated dhcpv6 options */
++  grub_dhcp6_options_t adv;
++  grub_dhcp6_options_t reply;
++};
++
++typedef struct grub_dhcp6_session *grub_dhcp6_session_t;
++
++typedef void (*dhcp6_option_hook_fn) (const struct grub_net_dhcp6_option *opt, void *data);
++
++static void
++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size,
++		      dhcp6_option_hook_fn hook, void *hook_data);
++
++static void
++parse_dhcp6_iaaddr (const struct grub_net_dhcp6_option *opt, void *data)
++{
++  grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t )data;
++
++  grub_uint16_t code = grub_be_to_cpu16 (opt->code);
++  grub_uint16_t len = grub_be_to_cpu16 (opt->len);
++
++  if (code == GRUB_NET_DHCP6_OPTION_IAADDR)
++    {
++      const struct grub_net_dhcp6_option_iaaddr *iaaddr;
++      iaaddr = (const struct grub_net_dhcp6_option_iaaddr *)opt->data;
++
++      if (len < sizeof (*iaaddr))
++	{
++	  grub_dprintf ("bootp", "DHCPv6: code %u with insufficient length %u\n", code, len);
++	  return;
++	}
++      if (!dhcp6->ia_addr)
++	{
++	  dhcp6->ia_addr = grub_malloc (sizeof(*dhcp6->ia_addr));
++	  dhcp6->ia_addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++	  dhcp6->ia_addr->ipv6[0] = grub_get_unaligned64 (iaaddr->addr);
++	  dhcp6->ia_addr->ipv6[1] = grub_get_unaligned64 (iaaddr->addr + 8);
++	  dhcp6->preferred_lifetime = grub_be_to_cpu32 (iaaddr->preferred_lifetime);
++	  dhcp6->valid_lifetime = grub_be_to_cpu32 (iaaddr->valid_lifetime);
++	}
++    }
++}
++
++static void
++parse_dhcp6_option (const struct grub_net_dhcp6_option *opt, void *data)
++{
++  grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t)data;
++  grub_uint16_t code = grub_be_to_cpu16 (opt->code);
++  grub_uint16_t len = grub_be_to_cpu16 (opt->len);
++
++  switch (code)
++    {
++      case GRUB_NET_DHCP6_OPTION_CLIENTID:
++
++	if (dhcp6->client_duid || !len)
++	  {
++	    grub_dprintf ("bootp", "Skipped DHCPv6 CLIENTID with length %u\n", len);
++	    break;
++	  }
++	dhcp6->client_duid = grub_malloc (len);
++	grub_memcpy (dhcp6->client_duid, opt->data, len);
++	dhcp6->client_duid_len = len;
++	break;
++
++      case GRUB_NET_DHCP6_OPTION_SERVERID:
++
++	if (dhcp6->server_duid || !len)
++	  {
++	    grub_dprintf ("bootp", "Skipped DHCPv6 SERVERID with length %u\n", len);
++	    break;
++	  }
++	dhcp6->server_duid = grub_malloc (len);
++	grub_memcpy (dhcp6->server_duid, opt->data, len);
++	dhcp6->server_duid_len = len;
++	break;
++
++      case GRUB_NET_DHCP6_OPTION_IA_NA:
++	{
++	  const struct grub_net_dhcp6_option_iana *ia_na;
++	  grub_uint16_t data_len;
++
++	  if (dhcp6->iaid || len < sizeof (*ia_na))
++	    {
++	      grub_dprintf ("bootp", "Skipped DHCPv6 IA_NA with length %u\n", len);
++	      break;
++	    }
++	  ia_na = (const struct grub_net_dhcp6_option_iana *)opt->data;
++	  dhcp6->iaid = grub_be_to_cpu32 (ia_na->iaid);
++	  dhcp6->t1 = grub_be_to_cpu32 (ia_na->t1);
++	  dhcp6->t2 = grub_be_to_cpu32 (ia_na->t2);
++
++	  data_len = len - sizeof (*ia_na);
++	  if (data_len)
++	    foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)ia_na->data, data_len, parse_dhcp6_iaaddr, dhcp6);
++	}
++	break;
++
++      case GRUB_NET_DHCP6_OPTION_DNS_SERVERS:
++	{
++	  const grub_uint8_t *po;
++	  grub_uint16_t ln;
++	  grub_net_network_level_address_t *la;
++
++	  if (!len || len & 0xf)
++	    {
++	      grub_dprintf ("bootp", "Skip invalid length DHCPv6 DNS_SERVERS \n");
++	      break;
++	    }
++	  dhcp6->num_dns_server = ln = len >> 4;
++	  dhcp6->dns_server_addrs = la = grub_zalloc (ln * sizeof (*la));
++
++	  for (po = opt->data; ln > 0; po += 0x10, la++, ln--)
++	    {
++	      la->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++	      la->ipv6[0] = grub_get_unaligned64 (po);
++	      la->ipv6[1] = grub_get_unaligned64 (po + 8);
++	      la->option = DNS_OPTION_PREFER_IPV6;
++	    }
++	}
++	break;
++
++      case GRUB_NET_DHCP6_OPTION_BOOTFILE_URL:
++	dissect_url ((const char *)opt->data,
++		      &dhcp6->boot_file_proto,
++		      &dhcp6->boot_file_server_ip,
++		      &dhcp6->boot_file_path);
++	break;
++
++      default:
++	break;
++    }
++}
++
++static void
++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, dhcp6_option_hook_fn hook, void *hook_data)
++{
++  while (size)
++    {
++      grub_uint16_t code, len;
++
++      if (size < sizeof (*opt))
++	{
++	  grub_dprintf ("bootp", "DHCPv6: Options stopped with remaining size %" PRIxGRUB_SIZE "\n", size);
++	  break;
++	}
++      size -= sizeof (*opt);
++      len = grub_be_to_cpu16 (opt->len);
++      code = grub_be_to_cpu16 (opt->code);
++      if (size < len)
++	{
++	  grub_dprintf ("bootp", "DHCPv6: Options stopped at out of bound length %u for option %u\n", len, code);
++	  break;
++	}
++      if (!len)
++	{
++	  grub_dprintf ("bootp", "DHCPv6: Options stopped at zero length option %u\n", code);
++	  break;
++	}
++      else
++	{
++	  if (hook)
++	    hook (opt, hook_data);
++	  size -= len;
++	  opt = (const struct grub_net_dhcp6_option *)((grub_uint8_t *)opt + len + sizeof (*opt));
++	}
++    }
++}
++
++static grub_dhcp6_options_t
++grub_dhcp6_options_get (const struct grub_net_dhcp6_packet *v6h,
++			grub_size_t size)
++{
++  grub_dhcp6_options_t options;
++
++  if (size < sizeof (*v6h))
++    {
++      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small"));
++      return NULL;
++    }
++
++  options = grub_zalloc (sizeof(*options));
++  if (!options)
+     return NULL;
+ 
+-  *device = 0;
+-  *path = 0;
+-
+-  grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n",
+-		hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2],
+-		hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]);
+-
+-  if (is_def)
+-    grub_net_default_server = 0;
+-
+-  if (is_def && !grub_net_default_server && packet)
++  foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)v6h->dhcp_options,
++		       size - sizeof (*v6h), parse_dhcp6_option, options);
++
++  return options;
++}
++
++static void
++grub_dhcp6_options_free (grub_dhcp6_options_t options)
++{
++  if (options->client_duid)
++    grub_free (options->client_duid);
++  if (options->server_duid)
++    grub_free (options->server_duid);
++  if (options->ia_addr)
++    grub_free (options->ia_addr);
++  if (options->dns_server_addrs)
++    grub_free (options->dns_server_addrs);
++  if (options->boot_file_proto)
++    grub_free (options->boot_file_proto);
++  if (options->boot_file_server_ip)
++    grub_free (options->boot_file_server_ip);
++  if (options->boot_file_path)
++    grub_free (options->boot_file_path);
++
++  grub_free (options);
++}
++
++static grub_dhcp6_session_t grub_dhcp6_sessions;
++#define FOR_DHCP6_SESSIONS_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE (var, next, grub_dhcp6_sessions)
++#define FOR_DHCP6_SESSIONS(var) FOR_LIST_ELEMENTS (var, grub_dhcp6_sessions)
++
++static void
++grub_net_configure_by_dhcp6_info (const char *name,
++	  struct grub_net_card *card,
++	  grub_dhcp6_options_t dhcp6,
++	  int is_def,
++	  int flags,
++	  struct grub_net_network_level_interface **ret_inf)
++{
++  grub_net_network_level_netaddress_t netaddr;
++  struct grub_net_network_level_interface *inf;
++
++  if (dhcp6->ia_addr)
+     {
+-      const grub_uint8_t *options = packet->dhcp_options;
+-      unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet);
+-      unsigned int i;
+-
+-      for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); )
+-	{
+-	  grub_uint16_t num, len;
+-	  grub_net_dhcpv6_option_t *opt =
+-	    (grub_net_dhcpv6_option_t *)(options + i);
+-
+-	  num = grub_be_to_cpu16(opt->option_num);
+-	  len = grub_be_to_cpu16(opt->option_len);
+-
+-	  grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len);
+-
+-	  if (len == 0)
+-	    break;
+-
+-	  if (len + i > 1024)
+-	    break;
+-
+-	  if (num == GRUB_NET_DHCP6_BOOTFILE_URL)
+-	    {
+-	      char *scheme, *userinfo, *host, *file;
+-	      char *tmp;
+-	      int hostlen;
+-	      int port;
+-	      int rc = extract_url_info ((const char *)opt->option_data,
+-					 (grub_size_t)len,
+-					 &scheme, &userinfo, &host, &port,
+-					 &file);
+-	      if (rc < 0)
+-		continue;
+-
+-	      /* right now this only handles tftp. */
+-	      if (grub_strcmp("tftp", scheme))
+-		{
+-		  grub_free (scheme);
+-		  grub_free (userinfo);
+-		  grub_free (host);
+-		  grub_free (file);
+-		  continue;
+-		}
+-	      grub_free (userinfo);
+-
+-	      hostlen = grub_strlen (host);
+-	      if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']')
+-		{
+-		  tmp = host+1;
+-		  host[hostlen-1] = '\0';
+-		}
+-	      else
+-		tmp = host;
++      inf = grub_net_add_addr (name, card, dhcp6->ia_addr, &card->default_address, flags);
+ 
+-	      *device = grub_xasprintf ("%s,%s", scheme, tmp);
+-	      grub_free (scheme);
+-	      grub_free (host);
++      netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++      netaddr.ipv6.base[0] = dhcp6->ia_addr->ipv6[0];
++      netaddr.ipv6.base[1] = 0;
++      netaddr.ipv6.masksize = 64;
++      grub_net_add_route (name, netaddr, inf);
+ 
+-	      if (file && *file)
+-		{
+-		  tmp = grub_strrchr (file, '/');
+-		  if (tmp)
+-		    *(tmp+1) = '\0';
+-		  else
+-		    file[0] = '\0';
+-		}
+-	      else if (!file)
+-		file = grub_strdup ("");
+-
+-	      if (file[0] == '/')
+-		{
+-		  *path = grub_strdup (file+1);
+-		  grub_free (file);
+-		}
+-	      else
+-		*path = file;
+-	    }
+-	  else if (num == GRUB_NET_DHCP6_IA_NA)
+-	    {
+-	      const grub_net_dhcpv6_option_t *ia_na_opt;
+-	      const grub_net_dhcpv6_opt_ia_na_t *ia_na =
+-		(const grub_net_dhcpv6_opt_ia_na_t *)opt;
+-	      unsigned int left = len - OFFSET_OF (options, ia_na);
+-	      unsigned int j;
+-
+-	      if ((grub_uint8_t *)ia_na + left >
+-		  (grub_uint8_t *)options + option_max)
+-		left -= ((grub_uint8_t *)ia_na + left)
+-		        - ((grub_uint8_t *)options + option_max);
+-
+-	      if (len < OFFSET_OF (option_data, opt)
+-			+ sizeof (grub_net_dhcpv6_option_t))
+-		{
+-		  grub_dprintf ("net",
+-				"found dhcpv6 ia_na option with no address\n");
+-		  continue;
+-		}
+-
+-	      for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); )
+-		{
+-		  ia_na_opt = (const grub_net_dhcpv6_option_t *)
+-			       (ia_na->options + j);
+-		  grub_uint16_t ia_na_opt_num, ia_na_opt_len;
+-
+-		  ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num);
+-		  ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len);
+-		  if (ia_na_opt_len == 0)
+-		    break;
+-		  if (j + ia_na_opt_len > left)
+-		    break;
+-		  if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS)
+-		    {
+-		      const grub_net_dhcpv6_opt_ia_address_t *ia_addr;
+-
+-		      ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *)
+-				 ia_na_opt;
+-		      addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+-		      grub_memcpy(addr.ipv6, ia_addr->ipv6_address,
+-				  sizeof (ia_addr->ipv6_address));
+-		      inter = grub_net_add_addr (name, card, &addr, hwaddr, 0);
+-		    }
+-
+-		  j += ia_na_opt_len;
+-		  left -= ia_na_opt_len;
+-		}
+-	    }
++      if (ret_inf)
++	*ret_inf = inf;
++    }
+ 
+-	  i += len + 4;
+-	}
++  if (dhcp6->dns_server_addrs)
++    {
++      grub_uint16_t i;
+ 
+-      grub_print_error ();
++      for (i = 0; i < dhcp6->num_dns_server; ++i)
++	grub_net_add_dns_server (dhcp6->dns_server_addrs + i);
+     }
+ 
+-  if (is_def)
++  if (dhcp6->boot_file_path)
++    grub_env_set_net_property (name, "boot_file", dhcp6->boot_file_path,
++			  grub_strlen (dhcp6->boot_file_path));
++
++  if (is_def && dhcp6->boot_file_server_ip)
+     {
++      grub_net_default_server = grub_strdup (dhcp6->boot_file_server_ip);
+       grub_env_set ("net_default_interface", name);
+       grub_env_export ("net_default_interface");
+     }
++}
++
++static void
++grub_dhcp6_session_add (struct grub_net_network_level_interface *iface,
++			grub_uint32_t iaid)
++{
++  grub_dhcp6_session_t se;
++  struct grub_datetime date;
++  grub_err_t err;
++  grub_int32_t t = 0;
++
++  se = grub_malloc (sizeof (*se));
++
++  err = grub_get_datetime (&date);
++  if (err || !grub_datetime2unixtime (&date, &t))
++    {
++      grub_errno = GRUB_ERR_NONE;
++      t = 0;
++    }
++
++  se->iface = iface;
++  se->iaid = iaid;
++  se->transaction_id = t;
++  se->start_time = grub_get_time_ms ();
++  se->duid.type = grub_cpu_to_be16_compile_time (3) ;
++  se->duid.hw_type = grub_cpu_to_be16_compile_time (1);
++  grub_memcpy (&se->duid.hwaddr, &iface->hwaddress.mac, sizeof (se->duid.hwaddr));
++  se->adv = NULL;
++  se->reply = NULL;
++  grub_list_push (GRUB_AS_LIST_P (&grub_dhcp6_sessions), GRUB_AS_LIST (se));
++}
++
++static void
++grub_dhcp6_session_remove (grub_dhcp6_session_t se)
++{
++  grub_list_remove (GRUB_AS_LIST (se));
++  if (se->adv)
++    grub_dhcp6_options_free (se->adv);
++  if (se->reply)
++    grub_dhcp6_options_free (se->reply);
++  grub_free (se);
++}
++
++static void
++grub_dhcp6_session_remove_all (void)
++{
++  grub_dhcp6_session_t se, next;
++
++  FOR_DHCP6_SESSIONS_SAFE (se, next)
++    {
++      grub_dhcp6_session_remove (se);
++    }
++  grub_dhcp6_sessions = NULL;
++}
++
++static grub_err_t
++grub_dhcp6_session_configure_network (grub_dhcp6_session_t se)
++{
++  char *name;
+ 
+-    if (inter)
+-      grub_net_add_ipv6_local (inter, mask);
+-    return inter;
++  name = grub_xasprintf ("%s:dhcp6", se->iface->card->name);
++  if (!name)
++    return grub_errno;
++
++  grub_net_configure_by_dhcp6_info (name, se->iface->card, se->reply, 1, 0, 0);
++  grub_free (name);
++
++  return GRUB_ERR_NONE;
+ }
+ 
++static grub_err_t
++grub_dhcp6_session_send_request (grub_dhcp6_session_t se)
++{
++  struct grub_net_buff *nb;
++  struct grub_net_dhcp6_option *opt;
++  struct grub_net_dhcp6_packet *v6h;
++  struct grub_net_dhcp6_option_iana *ia_na;
++  struct grub_net_dhcp6_option_iaaddr *iaaddr;
++  struct udphdr *udph;
++  grub_net_network_level_address_t multicast;
++  grub_net_link_level_address_t ll_multicast;
++  grub_uint64_t elapsed;
++  struct grub_net_network_level_interface *inf = se->iface;
++  grub_dhcp6_options_t dhcp6 = se->adv;
++  grub_err_t err = GRUB_ERR_NONE;
++
++  multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++  multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48);
++  multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL);
++
++  err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast);
++  if (err)
++    return err;
++
++  nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++
++  if (!nb)
++    return grub_errno;
++
++  err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++
++  err = grub_netbuff_push (nb, dhcp6->client_duid_len + sizeof (*opt));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++  opt = (struct grub_net_dhcp6_option *)nb->data;
++  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID);
++  opt->len = grub_cpu_to_be16 (dhcp6->client_duid_len);
++  grub_memcpy (opt->data, dhcp6->client_duid , dhcp6->client_duid_len);
++
++  err = grub_netbuff_push (nb, dhcp6->server_duid_len + sizeof (*opt));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++  opt = (struct grub_net_dhcp6_option *)nb->data;
++  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_SERVERID);
++  opt->len = grub_cpu_to_be16 (dhcp6->server_duid_len);
++  grub_memcpy (opt->data, dhcp6->server_duid , dhcp6->server_duid_len);
++
++  err = grub_netbuff_push (nb, sizeof (*ia_na) + sizeof (*opt));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++
++  if (dhcp6->ia_addr)
++    {
++      err = grub_netbuff_push (nb, sizeof(*iaaddr) + sizeof (*opt));
++      if (err)
++	{
++	  grub_netbuff_free (nb);
++	  return err;
++	}
++    }
++  opt = (struct grub_net_dhcp6_option *)nb->data;
++  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
++  opt->len = grub_cpu_to_be16 (sizeof (*ia_na));
++  if (dhcp6->ia_addr)
++    opt->len += grub_cpu_to_be16 (sizeof(*iaaddr) + sizeof (*opt));
++
++  ia_na = (struct grub_net_dhcp6_option_iana *)opt->data;
++  ia_na->iaid = grub_cpu_to_be32 (dhcp6->iaid);
++
++  ia_na->t1 = grub_cpu_to_be32 (dhcp6->t1);
++  ia_na->t2 = grub_cpu_to_be32 (dhcp6->t2);
++
++  if (dhcp6->ia_addr)
++    {
++      opt = (struct grub_net_dhcp6_option *)ia_na->data;
++      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR);
++      opt->len = grub_cpu_to_be16 (sizeof (*iaaddr));
++      iaaddr = (struct grub_net_dhcp6_option_iaaddr *)opt->data;
++      grub_set_unaligned64 (iaaddr->addr, dhcp6->ia_addr->ipv6[0]);
++      grub_set_unaligned64 (iaaddr->addr + 8, dhcp6->ia_addr->ipv6[1]);
++
++      iaaddr->preferred_lifetime = grub_cpu_to_be32 (dhcp6->preferred_lifetime);
++      iaaddr->valid_lifetime = grub_cpu_to_be32 (dhcp6->valid_lifetime);
++    }
++
++  err = grub_netbuff_push (nb, sizeof (*opt) + 2 * sizeof (grub_uint16_t));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++
++  opt = (struct grub_net_dhcp6_option*) nb->data;
++  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ORO);
++  opt->len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_uint16_t));
++  grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL));
++  grub_set_unaligned16 (opt->data + 2, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS));
++
++  err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++  opt = (struct grub_net_dhcp6_option*) nb->data;
++  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME);
++  opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t));
++
++  /* the time is expressed in hundredths of a second */
++  elapsed = grub_divmod64 (grub_get_time_ms () - se->start_time, 10, 0);
++
++  if (elapsed > 0xffff)
++    elapsed = 0xffff;
++
++  grub_set_unaligned16 (opt->data,  grub_cpu_to_be16 ((grub_uint16_t)elapsed));
++
++  err = grub_netbuff_push (nb, sizeof (*v6h));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++
++  v6h = (struct grub_net_dhcp6_packet *) nb->data;
++  v6h->message_type = GRUB_NET_DHCP6_REQUEST;
++  v6h->transaction_id = se->transaction_id;
++
++  err = grub_netbuff_push (nb, sizeof (*udph));
++  if (err)
++    {
++      grub_netbuff_free (nb);
++      return err;
++    }
++
++  udph = (struct udphdr *) nb->data;
++  udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT);
++  udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT);
++  udph->chksum = 0;
++  udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
++
++  udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
++						 &inf->address,
++						 &multicast);
++  err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb,
++				 GRUB_NET_IP_UDP);
++
++  grub_netbuff_free (nb);
++
++  return err;
++}
++
++struct grub_net_network_level_interface *
++grub_net_configure_by_dhcpv6_reply (const char *name,
++	struct grub_net_card *card,
++	grub_net_interface_flags_t flags,
++	const struct grub_net_dhcp6_packet *v6h,
++	grub_size_t size,
++	int is_def,
++	char **device, char **path)
++{
++  struct grub_net_network_level_interface *inf;
++  grub_dhcp6_options_t dhcp6;
++
++  dhcp6 = grub_dhcp6_options_get (v6h, size);
++  if (!dhcp6)
++    {
++      grub_print_error ();
++      return NULL;
++    }
++
++  grub_net_configure_by_dhcp6_info (name, card, dhcp6, is_def, flags, &inf);
++
++  if (device && dhcp6->boot_file_proto && dhcp6->boot_file_server_ip)
++    {
++      *device = grub_xasprintf ("%s,%s", dhcp6->boot_file_proto, dhcp6->boot_file_server_ip);
++      grub_print_error ();
++    }
++  if (path && dhcp6->boot_file_path)
++    {
++      *path = grub_strdup (dhcp6->boot_file_path);
++      grub_print_error ();
++      if (*path)
++	{
++	  char *slash;
++	  slash = grub_strrchr (*path, '/');
++	  if (slash)
++	    *slash = 0;
++	  else
++	    **path = 0;
++	}
++    }
++
++  grub_dhcp6_options_free (dhcp6);
++  return inf;
++}
+ 
+ void
+ grub_net_process_dhcp (struct grub_net_buff *nb,
+@@ -550,6 +1042,77 @@ grub_net_process_dhcp (struct grub_net_buff *nb,
+     }
+ }
+ 
++grub_err_t
++grub_net_process_dhcp6 (struct grub_net_buff *nb,
++			struct grub_net_card *card __attribute__ ((unused)))
++{
++  const struct grub_net_dhcp6_packet *v6h;
++  grub_dhcp6_session_t se;
++  grub_size_t size;
++  grub_dhcp6_options_t options;
++
++  v6h = (const struct grub_net_dhcp6_packet *) nb->data;
++  size = nb->tail - nb->data;
++
++  options = grub_dhcp6_options_get (v6h, size);
++  if (!options)
++    return grub_errno;
++
++  if (!options->client_duid || !options->server_duid || !options->ia_addr)
++    {
++      grub_dhcp6_options_free (options);
++      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Bad DHCPv6 Packet");
++    }
++
++  FOR_DHCP6_SESSIONS (se)
++    {
++      if (se->transaction_id == v6h->transaction_id &&
++	  grub_memcmp (options->client_duid, &se->duid, sizeof (se->duid)) == 0 &&
++	  se->iaid == options->iaid)
++	break;
++    }
++
++  if (!se)
++    {
++      grub_dprintf ("bootp", "DHCPv6 session not found\n");
++      grub_dhcp6_options_free (options);
++      return GRUB_ERR_NONE;
++    }
++
++  if (v6h->message_type == GRUB_NET_DHCP6_ADVERTISE)
++    {
++      if (se->adv)
++	{
++	  grub_dprintf ("bootp", "Skipped DHCPv6 Advertised .. \n");
++	  grub_dhcp6_options_free (options);
++	  return GRUB_ERR_NONE;
++	}
++
++      se->adv = options;
++      return grub_dhcp6_session_send_request (se);
++    }
++  else if (v6h->message_type == GRUB_NET_DHCP6_REPLY)
++    {
++      if (!se->adv)
++	{
++	  grub_dprintf ("bootp", "Skipped DHCPv6 Reply .. \n");
++	  grub_dhcp6_options_free (options);
++	  return GRUB_ERR_NONE;
++	}
++
++      se->reply = options;
++      grub_dhcp6_session_configure_network (se);
++      grub_dhcp6_session_remove (se);
++      return GRUB_ERR_NONE;
++    }
++  else
++    {
++      grub_dhcp6_options_free (options);
++    }
++
++  return GRUB_ERR_NONE;
++}
++
+ static grub_err_t
+ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
+ 		  int argc, char **args)
+@@ -824,7 +1387,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
+   return err;
+ }
+ 
+-static grub_command_t cmd_getdhcp, cmd_bootp;
++static grub_err_t
++grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
++		  int argc, char **args)
++{
++  struct grub_net_card *card;
++  grub_uint32_t iaid = 0;
++  int interval;
++  grub_err_t err;
++  grub_dhcp6_session_t se;
++
++  err = GRUB_ERR_NONE;
++
++  FOR_NET_CARDS (card)
++  {
++    struct grub_net_network_level_interface *iface;
++
++    if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
++      continue;
++
++    iface = grub_net_ipv6_get_link_local (card, &card->default_address);
++    if (!iface)
++      {
++	grub_dhcp6_session_remove_all ();
++	return grub_errno;
++      }
++
++    grub_dhcp6_session_add (iface, iaid++);
++  }
++
++  for (interval = 200; interval < 10000; interval *= 2)
++    {
++      int done = 1;
++
++      FOR_DHCP6_SESSIONS (se)
++	{
++	  struct grub_net_buff *nb;
++	  struct grub_net_dhcp6_option *opt;
++	  struct grub_net_dhcp6_packet *v6h;
++	  struct grub_net_dhcp6_option_duid_ll *duid;
++	  struct grub_net_dhcp6_option_iana *ia_na;
++	  grub_net_network_level_address_t multicast;
++	  grub_net_link_level_address_t ll_multicast;
++	  struct udphdr *udph;
++
++	  multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
++	  multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48);
++	  multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL);
++
++	  err = grub_net_link_layer_resolve (se->iface,
++		    &multicast, &ll_multicast);
++	  if (err)
++	    {
++	      grub_dhcp6_session_remove_all ();
++	      return err;
++	    }
++
++	  nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++
++	  if (!nb)
++	    {
++	      grub_dhcp6_session_remove_all ();
++	      return grub_errno;
++	    }
++
++	  err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
++	  if (err)
++	    {
++	      grub_dhcp6_session_remove_all ();
++	      grub_netbuff_free (nb);
++	      return err;
++	    }
++
++	  err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t));
++	  if (err)
++	    {
++	      grub_dhcp6_session_remove_all ();
++	      grub_netbuff_free (nb);
++	      return err;
++	    }
++
++	  opt = (struct grub_net_dhcp6_option *)nb->data;
++	  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME);
++	  opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t));
++	  grub_set_unaligned16 (opt->data, 0);
++
++	  err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*duid));
++	  if (err)
++	    {
++	      grub_dhcp6_session_remove_all ();
++	      grub_netbuff_free (nb);
++	      return err;
++	    }
++
++	  opt = (struct grub_net_dhcp6_option *)nb->data;
++	  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID);
++	  opt->len = grub_cpu_to_be16 (sizeof (*duid));
++
++	  duid = (struct grub_net_dhcp6_option_duid_ll *) opt->data;
++	  grub_memcpy (duid, &se->duid, sizeof (*duid));
++
++	  err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*ia_na));
++	  if (err)
++	    {
++	      grub_dhcp6_session_remove_all ();
++	      grub_netbuff_free (nb);
++	      return err;
++	    }
++
++	  opt = (struct grub_net_dhcp6_option *)nb->data;
++	  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
++	  opt->len = grub_cpu_to_be16 (sizeof (*ia_na));
++	  ia_na = (struct grub_net_dhcp6_option_iana *)opt->data;
++	  ia_na->iaid = grub_cpu_to_be32 (se->iaid);
++	  ia_na->t1 = 0;
++	  ia_na->t2 = 0;
++
++	  err = grub_netbuff_push (nb, sizeof (*v6h));
++	  if (err)
++	    {
++	      grub_dhcp6_session_remove_all ();
++	      grub_netbuff_free (nb);
++	      return err;
++	    }
++
++	  v6h = (struct grub_net_dhcp6_packet *)nb->data;
++	  v6h->message_type = GRUB_NET_DHCP6_SOLICIT;
++	  v6h->transaction_id = se->transaction_id;
++
++	  grub_netbuff_push (nb, sizeof (*udph));
++
++	  udph = (struct udphdr *) nb->data;
++	  udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT);
++	  udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT);
++	  udph->chksum = 0;
++	  udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
++
++	  udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
++			    &se->iface->address, &multicast);
++
++	  err = grub_net_send_ip_packet (se->iface, &multicast,
++		    &ll_multicast, nb, GRUB_NET_IP_UDP);
++	  done = 0;
++	  grub_netbuff_free (nb);
++
++	  if (err)
++	    {
++	      grub_dhcp6_session_remove_all ();
++	      return err;
++	    }
++	}
++      if (!done)
++	grub_net_poll_cards (interval, 0);
++    }
++
++  FOR_DHCP6_SESSIONS (se)
++    {
++      grub_error_push ();
++      err = grub_error (GRUB_ERR_FILE_NOT_FOUND,
++			N_("couldn't autoconfigure %s"),
++			se->iface->card->name);
++    }
++
++  grub_dhcp6_session_remove_all ();
++
++  return err;
++}
++
++static grub_command_t cmd_getdhcp, cmd_bootp, cmd_bootp6;
+ 
+ void
+ grub_bootp_init (void)
+@@ -835,6 +1565,9 @@ grub_bootp_init (void)
+   cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
+ 				       N_("VAR INTERFACE NUMBER DESCRIPTION"),
+ 				       N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
++  cmd_bootp6 = grub_register_command ("net_bootp6", grub_cmd_bootp6,
++				     N_("[CARD]"),
++				     N_("perform a DHCPv6 autoconfiguration"));
+ }
+ 
+ void
+@@ -842,4 +1575,5 @@ grub_bootp_fini (void)
+ {
+   grub_unregister_command (cmd_getdhcp);
+   grub_unregister_command (cmd_bootp);
++  grub_unregister_command (cmd_bootp6);
+ }
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index cd6dba79f63..6fd0a4f4998 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -393,9 +393,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+     pxe_mode = pxe->mode;
+     if (pxe_mode->using_ipv6)
+       {
+-	grub_net_link_level_address_t hwaddr;
+-	struct grub_net_network_level_interface *intf;
+-
+ 	grub_dprintf ("efinet", "using ipv6 and dhcpv6\n");
+ 	grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
+ 		      pxe_mode->dhcp_ack_received ? "yes" : "no",
+@@ -403,15 +400,14 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	if (!pxe_mode->dhcp_ack_received)
+ 	  continue;
+ 
+-	hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+-	grub_memcpy (hwaddr.mac,
+-		     card->efi_net->mode->current_address,
+-		     sizeof (hwaddr.mac));
+-
+-	intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr,
+-	      (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6,
+-	      1, device, path);
+-	if (intf && device && path)
++	grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
++					    (struct grub_net_dhcp6_packet *)
++					    &pxe_mode->dhcp_ack,
++					    sizeof (pxe_mode->dhcp_ack),
++					    1, device, path);
++	if (grub_errno)
++	  grub_print_error ();
++	if (device && path)
+ 	  grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
+       }
+     else
+diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
+index b2ca74b6eb1..9a4e589aa39 100644
+--- a/grub-core/net/ip.c
++++ b/grub-core/net/ip.c
+@@ -239,6 +239,45 @@ handle_dgram (struct grub_net_buff *nb,
+   {
+     struct udphdr *udph;
+     udph = (struct udphdr *) nb->data;
++
++    if (proto == GRUB_NET_IP_UDP && udph->dst == grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT))
++      {
++	if (udph->chksum)
++	  {
++	    grub_uint16_t chk, expected;
++	    chk = udph->chksum;
++	    udph->chksum = 0;
++	    expected = grub_net_ip_transport_checksum (nb,
++						       GRUB_NET_IP_UDP,
++						       source,
++						       dest);
++	    if (expected != chk)
++	      {
++		grub_dprintf ("net", "Invalid UDP checksum. "
++			      "Expected %x, got %x\n",
++			      grub_be_to_cpu16 (expected),
++			      grub_be_to_cpu16 (chk));
++		grub_netbuff_free (nb);
++		return GRUB_ERR_NONE;
++	      }
++	    udph->chksum = chk;
++	  }
++
++	err = grub_netbuff_pull (nb, sizeof (*udph));
++	if (err)
++	  {
++	    grub_netbuff_free (nb);
++	    return err;
++	  }
++
++	err = grub_net_process_dhcp6 (nb, card);
++	if (err)
++	  grub_print_error ();
++
++	grub_netbuff_free (nb);
++	return GRUB_ERR_NONE;
++      }
++
+     if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68)
+       {
+ 	const struct grub_net_bootp_packet *bootp;
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index e5b521bd9be..1250d493e25 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -1507,7 +1507,7 @@ typedef struct grub_efi_pxe_ip_filter
+ {
+   grub_efi_uint8_t filters;
+   grub_efi_uint8_t ip_count;
+-  grub_efi_uint8_t reserved;
++  grub_efi_uint16_t reserved;
+   grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT];
+ } grub_efi_pxe_ip_filter_t;
+ 
+diff --git a/include/grub/net.h b/include/grub/net.h
+index f4cd86e582f..5f78b22e109 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -447,50 +447,65 @@ struct grub_net_bootp_packet
+   grub_uint8_t vendor[0];
+ } GRUB_PACKED;
+ 
+-enum
+-  {
+-    GRUB_NET_DHCP6_IA_NA = 3,
+-    GRUB_NET_DHCP6_IA_ADDRESS = 5,
+-    GRUB_NET_DHCP6_BOOTFILE_URL = 59,
+-  };
+-
+-struct grub_net_dhcpv6_option
++struct grub_net_dhcp6_packet
+ {
+-  grub_uint16_t option_num;
+-  grub_uint16_t option_len;
+-  grub_uint8_t option_data[];
++  grub_uint32_t message_type:8;
++  grub_uint32_t transaction_id:24;
++  grub_uint8_t dhcp_options[0];
+ } GRUB_PACKED;
+-typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t;
+ 
+-struct grub_net_dhcpv6_opt_ia_na
+-{
+-  grub_uint16_t option_num;
+-  grub_uint16_t option_len;
++struct grub_net_dhcp6_option {
++  grub_uint16_t code;
++  grub_uint16_t len;
++  grub_uint8_t data[0];
++} GRUB_PACKED;
++
++struct grub_net_dhcp6_option_iana {
+   grub_uint32_t iaid;
+   grub_uint32_t t1;
+   grub_uint32_t t2;
+-  grub_uint8_t options[];
++  grub_uint8_t data[0];
+ } GRUB_PACKED;
+-typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t;
+ 
+-struct grub_net_dhcpv6_opt_ia_address
+-{
+-  grub_uint16_t option_num;
+-  grub_uint16_t option_len;
+-  grub_uint64_t ipv6_address[2];
++struct grub_net_dhcp6_option_iaaddr {
++  grub_uint8_t addr[16];
+   grub_uint32_t preferred_lifetime;
+   grub_uint32_t valid_lifetime;
+-  grub_uint8_t options[];
++  grub_uint8_t data[0];
+ } GRUB_PACKED;
+-typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t;
+ 
+-struct grub_net_dhcpv6_packet
++struct grub_net_dhcp6_option_duid_ll
+ {
+-  grub_uint32_t message_type:8;
+-  grub_uint32_t transaction_id:24;
+-  grub_uint8_t dhcp_options[1024];
++  grub_uint16_t type;
++  grub_uint16_t hw_type;
++  grub_uint8_t hwaddr[6];
+ } GRUB_PACKED;
+-typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t;
++
++enum
++  {
++    GRUB_NET_DHCP6_SOLICIT = 1,
++    GRUB_NET_DHCP6_ADVERTISE = 2,
++    GRUB_NET_DHCP6_REQUEST = 3,
++    GRUB_NET_DHCP6_REPLY = 7
++  };
++
++enum
++  {
++    DHCP6_CLIENT_PORT = 546,
++    DHCP6_SERVER_PORT = 547
++  };
++
++enum
++  {
++    GRUB_NET_DHCP6_OPTION_CLIENTID = 1,
++    GRUB_NET_DHCP6_OPTION_SERVERID = 2,
++    GRUB_NET_DHCP6_OPTION_IA_NA = 3,
++    GRUB_NET_DHCP6_OPTION_IAADDR = 5,
++    GRUB_NET_DHCP6_OPTION_ORO = 6,
++    GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8,
++    GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23,
++    GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59
++  };
+ 
+ #define	GRUB_NET_BOOTP_RFC1048_MAGIC_0	0x63
+ #define	GRUB_NET_BOOTP_RFC1048_MAGIC_1	0x82
+@@ -521,12 +536,12 @@ grub_net_configure_by_dhcp_ack (const char *name,
+ 				int is_def, char **device, char **path);
+ 
+ struct grub_net_network_level_interface *
+-grub_net_configure_by_dhcpv6_ack (const char *name,
+-				 struct grub_net_card *card,
+-				 grub_net_interface_flags_t flags,
+-				 const grub_net_link_level_address_t *hwaddr,
+-				 const struct grub_net_dhcpv6_packet *packet,
+-				 int is_def, char **device, char **path);
++grub_net_configure_by_dhcpv6_reply (const char *name,
++				    struct grub_net_card *card,
++				    grub_net_interface_flags_t flags,
++				    const struct grub_net_dhcp6_packet *v6,
++				    grub_size_t size,
++				    int is_def, char **device, char **path);
+ 
+ int
+ grub_ipv6_get_masksize(grub_uint16_t *mask);
+@@ -543,6 +558,10 @@ void
+ grub_net_process_dhcp (struct grub_net_buff *nb,
+ 		       struct grub_net_card *card);
+ 
++grub_err_t
++grub_net_process_dhcp6 (struct grub_net_buff *nb,
++			struct grub_net_card *card);
++
+ int
+ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
+ 		     const grub_net_link_level_address_t *b);
diff --git a/SOURCES/0170-Put-back-our-code-to-add-a-local-route.patch b/SOURCES/0170-Put-back-our-code-to-add-a-local-route.patch
new file mode 100644
index 0000000..e8da589
--- /dev/null
+++ b/SOURCES/0170-Put-back-our-code-to-add-a-local-route.patch
@@ -0,0 +1,35 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 21 Jun 2018 18:32:26 -0400
+Subject: [PATCH] Put back our code to add a local route.
+
+This was removed by the previous patch.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/bootp.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index ff1d7776e7f..242cd1f4cbd 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -976,6 +976,7 @@ grub_net_configure_by_dhcpv6_reply (const char *name,
+ {
+   struct grub_net_network_level_interface *inf;
+   grub_dhcp6_options_t dhcp6;
++  int mask = -1;
+ 
+   dhcp6 = grub_dhcp6_options_get (v6h, size);
+   if (!dhcp6)
+@@ -1007,6 +1008,10 @@ grub_net_configure_by_dhcpv6_reply (const char *name,
+     }
+ 
+   grub_dhcp6_options_free (dhcp6);
++
++  if (inf)
++    grub_net_add_ipv6_local (inf, mask);
++
+   return inf;
+ }
+ 
diff --git a/SOURCES/0171-efinet-UEFI-IPv6-PXE-support.patch b/SOURCES/0171-efinet-UEFI-IPv6-PXE-support.patch
new file mode 100644
index 0000000..a16b276
--- /dev/null
+++ b/SOURCES/0171-efinet-UEFI-IPv6-PXE-support.patch
@@ -0,0 +1,126 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Wed, 15 Apr 2015 14:48:30 +0800
+Subject: [PATCH] efinet: UEFI IPv6 PXE support
+
+When grub2 image is booted from UEFI IPv6 PXE, the DHCPv6 Reply packet is
+cached in firmware buffer which can be obtained by PXE Base Code protocol. The
+network interface can be setup through the parameters in that obtained packet.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+---
+ grub-core/net/drivers/efi/efinet.c |  2 ++
+ include/grub/efi/api.h             | 71 +++++++++++++++++++++++---------------
+ 2 files changed, 46 insertions(+), 27 deletions(-)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 6fd0a4f4998..712b4f85962 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -409,6 +409,8 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	  grub_print_error ();
+ 	if (device && path)
+ 	  grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
++	if (grub_errno)
++	  grub_print_error ();
+       }
+     else
+       {
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 1250d493e25..2f164d4209c 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -1499,31 +1499,6 @@ typedef union
+   grub_efi_pxe_dhcpv6_packet_t dhcpv6;
+ } grub_efi_pxe_packet_t;
+ 
+-#define GRUB_EFI_PXE_MAX_IPCNT 8
+-#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8
+-#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8
+-
+-typedef struct grub_efi_pxe_ip_filter
+-{
+-  grub_efi_uint8_t filters;
+-  grub_efi_uint8_t ip_count;
+-  grub_efi_uint16_t reserved;
+-  grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT];
+-} grub_efi_pxe_ip_filter_t;
+-
+-typedef struct grub_efi_pxe_arp_entry
+-{
+-  grub_efi_ip_address_t ip_addr;
+-  grub_efi_mac_address_t mac_addr;
+-} grub_efi_pxe_arp_entry_t;
+-
+-typedef struct grub_efi_pxe_route_entry
+-{
+-  grub_efi_ip_address_t ip_addr;
+-  grub_efi_ip_address_t subnet_mask;
+-  grub_efi_ip_address_t gateway_addr;
+-} grub_efi_pxe_route_entry_t;
+-
+ typedef struct grub_efi_pxe_icmp_error
+ {
+   grub_efi_uint8_t type;
+@@ -1549,6 +1524,48 @@ typedef struct grub_efi_pxe_tftp_error
+   grub_efi_char8_t error_string[127];
+ } grub_efi_pxe_tftp_error_t;
+ 
++typedef struct {
++  grub_uint8_t addr[4];
++} grub_efi_pxe_ipv4_address_t;
++
++typedef struct {
++  grub_uint8_t addr[16];
++} grub_efi_pxe_ipv6_address_t;
++
++typedef struct {
++  grub_uint8_t addr[32];
++} grub_efi_pxe_mac_address_t;
++
++typedef union {
++  grub_uint32_t addr[4];
++  grub_efi_pxe_ipv4_address_t v4;
++  grub_efi_pxe_ipv6_address_t v6;
++} grub_efi_pxe_ip_address_t;
++
++#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8
++typedef struct grub_efi_pxe_ip_filter
++{
++  grub_efi_uint8_t filters;
++  grub_efi_uint8_t ip_count;
++  grub_efi_uint16_t reserved;
++  grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT];
++} grub_efi_pxe_ip_filter_t;
++
++typedef struct {
++  grub_efi_pxe_ip_address_t ip_addr;
++  grub_efi_pxe_mac_address_t mac_addr;
++} grub_efi_pxe_arp_entry_t;
++
++typedef struct {
++  grub_efi_pxe_ip_address_t ip_addr;
++  grub_efi_pxe_ip_address_t subnet_mask;
++  grub_efi_pxe_ip_address_t gw_addr;
++} grub_efi_pxe_route_entry_t;
++
++
++#define GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8
++#define GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8
++
+ typedef struct grub_efi_pxe_mode
+ {
+   grub_efi_boolean_t started;
+@@ -1580,9 +1597,9 @@ typedef struct grub_efi_pxe_mode
+   grub_efi_pxe_packet_t pxe_bis_reply;
+   grub_efi_pxe_ip_filter_t ip_filter;
+   grub_efi_uint32_t arp_cache_entries;
+-  grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES];
++  grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES];
+   grub_efi_uint32_t route_table_entries;
+-  grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES];
++  grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES];
+   grub_efi_pxe_icmp_error_t icmp_error;
+   grub_efi_pxe_tftp_error_t tftp_error;
+ } grub_efi_pxe_mode_t;
diff --git a/SOURCES/0172-grub.texi-Add-net_bootp6-doument.patch b/SOURCES/0172-grub.texi-Add-net_bootp6-doument.patch
new file mode 100644
index 0000000..b66a80c
--- /dev/null
+++ b/SOURCES/0172-grub.texi-Add-net_bootp6-doument.patch
@@ -0,0 +1,48 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Tue, 5 May 2015 14:19:24 +0800
+Subject: [PATCH] grub.texi: Add net_bootp6 doument
+
+Update grub documentation for net_bootp6 command.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+---
+ docs/grub.texi | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 2b7b7faf847..c54bee31679 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -5303,6 +5303,7 @@ This command is only available on AArch64 systems.
+ * net_add_dns::                 Add a DNS server
+ * net_add_route::               Add routing entry
+ * net_bootp::                   Perform a bootp autoconfiguration
++* net_bootp6::                  Perform a DHCPv6 autoconfiguration
+ * net_del_addr::                Remove IP address from interface
+ * net_del_dns::                 Remove a DNS server
+ * net_del_route::               Remove a route entry
+@@ -5384,6 +5385,22 @@ Sets environment variable @samp{net_}@var{<card>}@samp{_dhcp_extensionspath}
+ 
+ @end deffn
+ 
++@node net_bootp6
++@subsection net_bootp6
++
++@deffn Command net_bootp6 [@var{card}]
++Perform configuration of @var{card} using DHCPv6 protocol. If no card name is
++specified, try to configure all existing cards. If configuration was
++successful, interface with name @var{card}@samp{:dhcp6} and configured address
++is added to @var{card}.
++
++@table @samp
++@item 1 (Domain Name Server)
++Adds all servers from option value to the list of servers used during name
++resolution.
++@end table
++
++@end deffn
+ 
+ @node net_del_addr
+ @subsection net_del_addr
diff --git a/SOURCES/0173-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch b/SOURCES/0173-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch
new file mode 100644
index 0000000..1874107
--- /dev/null
+++ b/SOURCES/0173-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch
@@ -0,0 +1,135 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 14 Jul 2016 18:45:14 +0800
+Subject: [PATCH] bootp: Add processing DHCPACK packet from HTTP Boot
+
+The vendor class identifier with the string "HTTPClient" is used to denote the
+packet as responding to HTTP boot request. In DHCP4 config, the filename for
+HTTP boot is the URL of the boot file while for PXE boot it is the path to the
+boot file. As a consequence, the next-server becomes obseleted because the HTTP
+URL already contains the server address for the boot file. For DHCP6 config,
+there's no difference definition in existing config as dhcp6.bootfile-url can
+be used to specify URL for both HTTP and PXE boot file.
+
+This patch adds processing for "HTTPClient" vendor class identifier in DHCPACK
+packet by treating it as HTTP format, not as the PXE format.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+---
+ grub-core/net/bootp.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++--
+ include/grub/net.h    |  1 +
+ 2 files changed, 67 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
+index 242cd1f4cbd..8b6fc9f2411 100644
+--- a/grub-core/net/bootp.c
++++ b/grub-core/net/bootp.c
+@@ -20,6 +20,7 @@
+ #include <grub/env.h>
+ #include <grub/i18n.h>
+ #include <grub/command.h>
++#include <grub/net.h>
+ #include <grub/net/ip.h>
+ #include <grub/net/netbuff.h>
+ #include <grub/net/udp.h>
+@@ -254,6 +255,11 @@ parse_dhcp_vendor (const char *name, const void *vend, int limit, int *mask)
+                                      taglength);
+           break;
+ 
++        case GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER:
++          grub_env_set_net_property (name, "vendor_class_identifier", (const char *) ptr,
++                                     taglength);
++	  break;
++
+ 	case GRUB_NET_BOOTP_EXTENSIONS_PATH:
+           grub_env_set_net_property (name, "extensionspath", (const char *) ptr,
+                                      taglength);
+@@ -357,6 +363,66 @@ grub_net_configure_by_dhcp_ack (const char *name,
+     }
+ #endif
+ 
++  if (size > OFFSET_OF (vendor, bp))
++    {
++      char *cidvar;
++      const char *cid;
++
++      parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp), &mask);
++      cidvar = grub_xasprintf ("net_%s_%s", name, "vendor_class_identifier");
++      cid = grub_env_get (cidvar);
++      grub_free (cidvar);
++
++      if (cid && grub_strcmp (cid, "HTTPClient") == 0)
++	{
++	  char *proto, *ip, *pa;
++
++	  if (!dissect_url (bp->boot_file, &proto, &ip, &pa))
++	    return inter;
++
++	  grub_env_set_net_property (name, "boot_file", pa, grub_strlen (pa));
++	  if (is_def)
++	    {
++	      grub_net_default_server = grub_strdup (ip);
++	      grub_env_set ("net_default_interface", name);
++	      grub_env_export ("net_default_interface");
++	    }
++	  if (device && !*device)
++	    {
++	      *device = grub_xasprintf ("%s,%s", proto, ip);
++	      grub_print_error ();
++	    }
++	  if (path)
++	    {
++	      *path = grub_strdup (pa);
++	      grub_print_error ();
++	      if (*path)
++		{
++		  char *slash;
++		  slash = grub_strrchr (*path, '/');
++		  if (slash)
++		    *slash = 0;
++		  else
++		    **path = 0;
++		}
++	    }
++	  grub_net_add_ipv4_local (inter, mask);
++	  inter->dhcp_ack = grub_malloc (size);
++	  if (inter->dhcp_ack)
++	    {
++	      grub_memcpy (inter->dhcp_ack, bp, size);
++	      inter->dhcp_acklen = size;
++	    }
++	  else
++	    grub_errno = GRUB_ERR_NONE;
++
++	  grub_free (proto);
++	  grub_free (ip);
++	  grub_free (pa);
++	  return inter;
++	}
++    }
++
+   if (size > OFFSET_OF (boot_file, bp))
+     grub_env_set_net_property (name, "boot_file", bp->boot_file,
+                                sizeof (bp->boot_file));
+@@ -421,8 +487,6 @@ grub_net_configure_by_dhcp_ack (const char *name,
+ 	    **path = 0;
+ 	}
+     }
+-  if (size > OFFSET_OF (vendor, bp))
+-    parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp), &mask);
+   grub_net_add_ipv4_local (inter, mask);
+   
+   inter->dhcp_ack = grub_malloc (size);
+diff --git a/include/grub/net.h b/include/grub/net.h
+index 5f78b22e109..9cf6da68973 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -522,6 +522,7 @@ enum
+     GRUB_NET_BOOTP_DOMAIN = 0x0f,
+     GRUB_NET_BOOTP_ROOT_PATH = 0x11,
+     GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12,
++    GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 0x3C,
+     GRUB_NET_BOOTP_CLIENT_ID = 0x3d,
+     GRUB_NET_BOOTP_CLIENT_UUID = 0x61,
+     GRUB_NET_BOOTP_END = 0xff
diff --git a/SOURCES/0174-efinet-Setting-network-from-UEFI-device-path.patch b/SOURCES/0174-efinet-Setting-network-from-UEFI-device-path.patch
new file mode 100644
index 0000000..9c7b469
--- /dev/null
+++ b/SOURCES/0174-efinet-Setting-network-from-UEFI-device-path.patch
@@ -0,0 +1,405 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Sun, 10 Jul 2016 23:46:31 +0800
+Subject: [PATCH] efinet: Setting network from UEFI device path
+
+The PXE Base Code protocol used to obtain cached PXE DHCPACK packet is no
+longer provided for HTTP Boot. Instead, we have to get the HTTP boot
+information from the device path nodes defined in following UEFI Specification
+sections.
+
+ 9.3.5.12 IPv4 Device Path
+ 9.3.5.13 IPv6 Device Path
+ 9.3.5.23 Uniform Resource Identifiers (URI) Device Path
+
+This patch basically does:
+
+include/grub/efi/api.h:
+Add new structure of Uniform Resource Identifiers (URI) Device Path
+
+grub-core/net/drivers/efi/efinet.c:
+Check if PXE Base Code is available, if not it will try to obtain the netboot
+information from the device path where the image booted from. The DHCPACK
+packet is recoverd from the information in device patch and feed into the same
+DHCP packet processing functions to ensure the network interface is setting up
+the same way it used to be.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+---
+ grub-core/net/drivers/efi/efinet.c | 284 +++++++++++++++++++++++++++++++++++--
+ include/grub/efi/api.h             |  11 ++
+ 2 files changed, 280 insertions(+), 15 deletions(-)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 712b4f85962..3e51e106473 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -27,6 +27,7 @@
+ #include <grub/i18n.h>
+ #include <grub/lib/hexdump.h>
+ #include <grub/types.h>
++#include <grub/net/netbuff.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -332,6 +333,227 @@ grub_efinet_findcards (void)
+   grub_free (handles);
+ }
+ 
++static struct grub_net_buff *
++grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
++{
++  grub_efi_uint16_t uri_len;
++  grub_efi_device_path_t *ldp, *ddp;
++  grub_efi_uri_device_path_t *uri_dp;
++  struct grub_net_buff *nb;
++  grub_err_t err;
++
++  ddp = grub_efi_duplicate_device_path (dp);
++  if (!ddp)
++    return NULL;
++
++  ldp = grub_efi_find_last_device_path (ddp);
++
++  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++      || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
++    {
++      grub_free (ddp);
++      return NULL;
++    }
++
++  uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4  : 0;
++
++  if (!uri_len)
++    {
++      grub_free (ddp);
++      return NULL;
++    }
++
++  uri_dp = (grub_efi_uri_device_path_t *) ldp;
++
++  ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++  ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++  ldp->length = sizeof (*ldp);
++
++  ldp = grub_efi_find_last_device_path (ddp);
++
++  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++      || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
++          && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
++    {
++      grub_free (ddp);
++      return NULL;
++    }
++
++  nb = grub_netbuff_alloc (512);
++  if (!nb)
++    {
++      grub_free (ddp);
++      return NULL;
++    }
++
++  if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
++    {
++      grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp;
++      struct grub_net_bootp_packet *bp;
++      grub_uint8_t *ptr;
++
++      bp = (struct grub_net_bootp_packet *) nb->tail;
++      err = grub_netbuff_put (nb, sizeof (*bp) + 4);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++
++      if (sizeof(bp->boot_file) < uri_len)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      grub_memcpy (bp->boot_file, uri_dp->uri, uri_len);
++      grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip));
++      grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip));
++
++      bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0;
++      bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1;
++      bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2;
++      bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3;
++
++      ptr = nb->tail;
++      err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      *ptr++ = GRUB_NET_BOOTP_NETMASK;
++      *ptr++ = sizeof (ipv4->subnet_mask);
++      grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask));
++
++      ptr = nb->tail;
++      err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      *ptr++ = GRUB_NET_BOOTP_ROUTER;
++      *ptr++ = sizeof (ipv4->gateway_ip_address);
++      grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address));
++
++      ptr = nb->tail;
++      err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER;
++      *ptr++ = sizeof ("HTTPClient") - 1;
++      grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1);
++
++      ptr = nb->tail;
++      err = grub_netbuff_put (nb, 1);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      *ptr = GRUB_NET_BOOTP_END;
++      *use_ipv6 = 0;
++
++      ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++      ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++      ldp->length = sizeof (*ldp);
++      ldp = grub_efi_find_last_device_path (ddp);
++
++      if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) ==  GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)
++	{
++	  grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp;
++	  bp->hw_type = mac->if_type;
++	  bp->hw_len = sizeof (bp->mac_addr);
++	  grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len);
++	}
++    }
++  else
++    {
++      grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp;
++
++      struct grub_net_dhcp6_packet *d6p;
++      struct grub_net_dhcp6_option *opt;
++      struct grub_net_dhcp6_option_iana *iana;
++      struct grub_net_dhcp6_option_iaaddr *iaaddr;
++
++      d6p = (struct grub_net_dhcp6_packet *)nb->tail;
++      err = grub_netbuff_put (nb, sizeof(*d6p));
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      d6p->message_type = GRUB_NET_DHCP6_REPLY;
++
++      opt = (struct grub_net_dhcp6_option *)nb->tail;
++      err = grub_netbuff_put (nb, sizeof(*opt));
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
++      opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr));
++
++      err = grub_netbuff_put (nb, sizeof(*iana));
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++
++      opt = (struct grub_net_dhcp6_option *)nb->tail;
++      err = grub_netbuff_put (nb, sizeof(*opt));
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR);
++      opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr));
++
++      iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail;
++      err = grub_netbuff_put (nb, sizeof(*iaaddr));
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address));
++
++      opt = (struct grub_net_dhcp6_option *)nb->tail;
++      err = grub_netbuff_put (nb, sizeof(*opt) + uri_len);
++      if (err)
++	{
++	  grub_free (ddp);
++	  grub_netbuff_free (nb);
++	  return NULL;
++	}
++      opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL);
++      opt->len = grub_cpu_to_be16 (uri_len);
++      grub_memcpy (opt->data, uri_dp->uri, uri_len);
++
++      *use_ipv6 = 1;
++    }
++
++  grub_free (ddp);
++  return nb;
++}
++
+ static void
+ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 			  char **path)
+@@ -347,7 +569,11 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+   {
+     grub_efi_device_path_t *cdp;
+     struct grub_efi_pxe *pxe;
+-    struct grub_efi_pxe_mode *pxe_mode;
++    struct grub_efi_pxe_mode *pxe_mode = NULL;
++    grub_uint8_t *packet_buf;
++    grub_size_t packet_bufsz ;
++    int ipv6;
++    struct grub_net_buff *nb = NULL;
+ 
+     if (card->driver != &efidriver)
+       continue;
+@@ -370,11 +596,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+          */
+ 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+-		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
++		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
++		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
+ 	  continue;
+ 	dup_dp = grub_efi_duplicate_device_path (dp);
+ 	if (!dup_dp)
+ 	  continue;
++
++	if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
++	  {
++	    dup_ldp = grub_efi_find_last_device_path (dup_dp);
++	    dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++	    dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++	    dup_ldp->length = sizeof (*dup_ldp);
++	  }
++
+ 	dup_ldp = grub_efi_find_last_device_path (dup_dp);
+ 	dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ 	dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+@@ -387,23 +623,37 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 
+     pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
+ 				  GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+-    if (! pxe)
+-      continue;
++    if (!pxe)
++      {
++	nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6);
++	if (!nb)
++	  {
++	    grub_print_error ();
++	    continue;
++	  }
++	packet_buf = nb->head;
++	packet_bufsz = nb->tail - nb->head;
++      }
++    else
++      {
++	pxe_mode = pxe->mode;
++	packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack;
++	packet_bufsz = sizeof (pxe_mode->dhcp_ack);
++	ipv6 = pxe_mode->using_ipv6;
++      }
+ 
+-    pxe_mode = pxe->mode;
+-    if (pxe_mode->using_ipv6)
++    if (ipv6)
+       {
+ 	grub_dprintf ("efinet", "using ipv6 and dhcpv6\n");
+-	grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
+-		      pxe_mode->dhcp_ack_received ? "yes" : "no",
+-		      pxe_mode->dhcp_ack_received ? "" : " cannot continue");
+-	if (!pxe_mode->dhcp_ack_received)
+-	  continue;
++	if (pxe_mode)
++	  grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n",
++			pxe_mode->dhcp_ack_received ? "yes" : "no",
++			pxe_mode->dhcp_ack_received ? "" : " cannot continue");
+ 
+ 	grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
+ 					    (struct grub_net_dhcp6_packet *)
+-					    &pxe_mode->dhcp_ack,
+-					    sizeof (pxe_mode->dhcp_ack),
++					    packet_buf,
++					    packet_bufsz,
+ 					    1, device, path);
+ 	if (grub_errno)
+ 	  grub_print_error ();
+@@ -417,11 +667,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	grub_dprintf ("efinet", "using ipv4 and dhcp\n");
+ 	grub_net_configure_by_dhcp_ack (card->name, card, 0,
+ 					(struct grub_net_bootp_packet *)
+-					&pxe_mode->dhcp_ack,
+-					sizeof (pxe_mode->dhcp_ack),
++					packet_buf,
++					packet_bufsz,
+ 					1, device, path);
+ 	grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path);
+       }
++
++    if (nb)
++      grub_netbuff_free (nb);
++
+     return;
+   }
+ }
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index 2f164d4209c..eb6bb50857c 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -839,6 +839,8 @@ struct grub_efi_ipv4_device_path
+   grub_efi_uint16_t remote_port;
+   grub_efi_uint16_t protocol;
+   grub_efi_uint8_t static_ip_address;
++  grub_efi_ipv4_address_t gateway_ip_address;
++  grub_efi_ipv4_address_t subnet_mask;
+ } GRUB_PACKED;
+ typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t;
+ 
+@@ -893,6 +895,15 @@ struct grub_efi_sata_device_path
+ } GRUB_PACKED;
+ typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t;
+ 
++#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE		24
++
++struct grub_efi_uri_device_path
++{
++  grub_efi_device_path_t header;
++  grub_efi_uint8_t uri[0];
++} GRUB_PACKED;
++typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t;
++
+ #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE	10
+ 
+ /* Media Device Path.  */
diff --git a/SOURCES/0175-efinet-Setting-DNS-server-from-UEFI-protocol.patch b/SOURCES/0175-efinet-Setting-DNS-server-from-UEFI-protocol.patch
new file mode 100644
index 0000000..47cee2f
--- /dev/null
+++ b/SOURCES/0175-efinet-Setting-DNS-server-from-UEFI-protocol.patch
@@ -0,0 +1,337 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Thu, 14 Jul 2016 17:48:45 +0800
+Subject: [PATCH] efinet: Setting DNS server from UEFI protocol
+
+In the URI device path node, any name rahter than address can be used for
+looking up the resources so that DNS service become needed to get answer of the
+name's address. Unfortunately the DNS is not defined in any of the device path
+nodes so that we use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL
+to obtain it.
+
+These two protcols are defined the sections of UEFI specification.
+
+ 27.5 EFI IPv4 Configuration II Protocol
+ 27.7 EFI IPv6 Configuration Protocol
+
+include/grub/efi/api.h:
+Add new structure and protocol UUID of EFI_IP4_CONFIG2_PROTOCOL and
+EFI_IP6_CONFIG_PROTOCOL.
+
+grub-core/net/drivers/efi/efinet.c:
+Use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL to obtain the list
+of DNS server address for IPv4 and IPv6 respectively. The address of DNS
+servers is structured into DHCPACK packet and feed into the same DHCP packet
+processing functions to ensure the network interface is setting up the same way
+it used to be.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+Signed-off-by: Ken Lin <ken.lin@hpe.com>
+---
+ grub-core/net/drivers/efi/efinet.c | 163 +++++++++++++++++++++++++++++++++++++
+ include/grub/efi/api.h             |  76 +++++++++++++++++
+ 2 files changed, 239 insertions(+)
+
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 3e51e106473..3d775074705 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -34,6 +34,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ /* GUID.  */
+ static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID;
+ static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID;
++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID;
+ 
+ static grub_err_t
+ send_card_buffer (struct grub_net_card *dev,
+@@ -333,6 +335,125 @@ grub_efinet_findcards (void)
+   grub_free (handles);
+ }
+ 
++static grub_efi_handle_t
++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path,
++			    grub_efi_device_path_t **r_device_path)
++{
++  grub_efi_handle_t handle;
++  grub_efi_status_t status;
++
++  status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path,
++		      protocol, &device_path, &handle);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++
++  if (r_device_path)
++    *r_device_path = device_path;
++
++  return handle;
++}
++
++static grub_efi_ipv4_address_t *
++grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
++{
++  grub_efi_handle_t hnd;
++  grub_efi_status_t status;
++  grub_efi_ip4_config2_protocol_t *conf;
++  grub_efi_ipv4_address_t *addrs;
++  grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t);
++
++  hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL);
++
++  if (!hnd)
++    return 0;
++
++  conf = grub_efi_open_protocol (hnd, &ip4_config_guid,
++				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++  if (!conf)
++    return 0;
++
++  addrs  = grub_malloc (data_size);
++  if (!addrs)
++    return 0;
++
++  status = efi_call_4 (conf->get_data, conf,
++		      GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
++		      &data_size, addrs);
++
++  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++    {
++      grub_free (addrs);
++      addrs  = grub_malloc (data_size);
++      if (!addrs)
++	return 0;
++
++      status = efi_call_4 (conf->get_data,  conf,
++			  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
++			  &data_size, addrs);
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (addrs);
++      return 0;
++    }
++
++  *num_dns = data_size / sizeof (grub_efi_ipv4_address_t);
++  return addrs;
++}
++
++static grub_efi_ipv6_address_t *
++grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
++{
++  grub_efi_handle_t hnd;
++  grub_efi_status_t status;
++  grub_efi_ip6_config_protocol_t *conf;
++  grub_efi_ipv6_address_t *addrs;
++  grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t);
++
++  hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL);
++
++  if (!hnd)
++    return 0;
++
++  conf = grub_efi_open_protocol (hnd, &ip6_config_guid,
++				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++  if (!conf)
++    return 0;
++
++  addrs  = grub_malloc (data_size);
++  if (!addrs)
++    return 0;
++
++  status = efi_call_4 (conf->get_data, conf,
++		      GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
++		      &data_size, addrs);
++
++  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++    {
++      grub_free (addrs);
++      addrs  = grub_malloc (data_size);
++      if (!addrs)
++	return 0;
++
++      status = efi_call_4 (conf->get_data,  conf,
++			  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
++			  &data_size, addrs);
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (addrs);
++      return 0;
++    }
++
++  *num_dns = data_size / sizeof (grub_efi_ipv6_address_t);
++  return addrs;
++}
++
+ static struct grub_net_buff *
+ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
+ {
+@@ -391,6 +512,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
+       grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp;
+       struct grub_net_bootp_packet *bp;
+       grub_uint8_t *ptr;
++      grub_efi_ipv4_address_t *dns;
++      grub_efi_uintn_t num_dns;
+ 
+       bp = (struct grub_net_bootp_packet *) nb->tail;
+       err = grub_netbuff_put (nb, sizeof (*bp) + 4);
+@@ -452,6 +575,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
+       *ptr++ = sizeof ("HTTPClient") - 1;
+       grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1);
+ 
++      dns = grub_dns_server_ip4_address (dp, &num_dns);
++      if (dns)
++	{
++	  grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns;
++
++	  ptr = nb->tail;
++	  err = grub_netbuff_put (nb, size_dns + 2);
++	  if (err)
++	    {
++	      grub_free (ddp);
++	      grub_netbuff_free (nb);
++	      return NULL;
++	    }
++	  *ptr++ = GRUB_NET_BOOTP_DNS;
++	  *ptr++ = size_dns;
++	  grub_memcpy (ptr, dns, size_dns);
++	  grub_free (dns);
++	}
++
+       ptr = nb->tail;
+       err = grub_netbuff_put (nb, 1);
+       if (err)
+@@ -484,6 +626,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
+       struct grub_net_dhcp6_option *opt;
+       struct grub_net_dhcp6_option_iana *iana;
+       struct grub_net_dhcp6_option_iaaddr *iaaddr;
++      grub_efi_ipv6_address_t *dns;
++      grub_efi_uintn_t num_dns;
+ 
+       d6p = (struct grub_net_dhcp6_packet *)nb->tail;
+       err = grub_netbuff_put (nb, sizeof(*d6p));
+@@ -547,6 +691,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
+       opt->len = grub_cpu_to_be16 (uri_len);
+       grub_memcpy (opt->data, uri_dp->uri, uri_len);
+ 
++      dns = grub_dns_server_ip6_address (dp, &num_dns);
++      if (dns)
++	{
++	  grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns;
++
++	  opt = (struct grub_net_dhcp6_option *)nb->tail;
++	  err = grub_netbuff_put (nb, sizeof(*opt) + size_dns);
++	  if (err)
++	  {
++	    grub_free (ddp);
++	    grub_netbuff_free (nb);
++	    return NULL;
++	  }
++	  opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS);
++	  opt->len = grub_cpu_to_be16 (size_dns);
++	  grub_memcpy (opt->data, dns, size_dns);
++	  grub_free (dns);
++	}
++
+       *use_ipv6 = 1;
+     }
+ 
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index eb6bb50857c..dd3b07eac97 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -334,6 +334,16 @@
+       { 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7 } \
+   }
+ 
++#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \
++  { 0x5b446ed1, 0xe30b, 0x4faa, \
++      { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \
++  }
++
++#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \
++  { 0x937fe521, 0x95ae, 0x4d1a, \
++      { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \
++  }
++
+ struct grub_efi_sal_system_table
+ {
+   grub_uint32_t signature;
+@@ -1838,6 +1848,72 @@ struct grub_efi_block_io
+ };
+ typedef struct grub_efi_block_io grub_efi_block_io_t;
+ 
++enum grub_efi_ip4_config2_data_type {
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
++  GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM
++};
++typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t;
++
++struct grub_efi_ip4_config2_protocol
++{
++  grub_efi_status_t (*set_data) (struct grub_efi_ip4_config2_protocol *this,
++				 grub_efi_ip4_config2_data_type_t data_type,
++				 grub_efi_uintn_t data_size,
++				 void *data);
++
++  grub_efi_status_t (*get_data) (struct grub_efi_ip4_config2_protocol *this,
++				 grub_efi_ip4_config2_data_type_t data_type,
++				 grub_efi_uintn_t *data_size,
++				 void *data);
++
++  grub_efi_status_t (*register_data_notify) (struct grub_efi_ip4_config2_protocol *this,
++					     grub_efi_ip4_config2_data_type_t data_type,
++					     grub_efi_event_t event);
++
++  grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this,
++					     grub_efi_ip4_config2_data_type_t data_type,
++					     grub_efi_event_t event);
++};
++typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t;
++
++enum grub_efi_ip6_config_data_type {
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
++  GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM
++};
++typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t;
++
++struct grub_efi_ip6_config_protocol
++{
++  grub_efi_status_t (*set_data) (struct grub_efi_ip6_config_protocol *this,
++				 grub_efi_ip6_config_data_type_t data_type,
++				 grub_efi_uintn_t data_size,
++				 void *data);
++
++  grub_efi_status_t (*get_data) (struct grub_efi_ip6_config_protocol *this,
++				 grub_efi_ip6_config_data_type_t data_type,
++				 grub_efi_uintn_t *data_size,
++				 void *data);
++
++  grub_efi_status_t (*register_data_notify) (struct grub_efi_ip6_config_protocol *this,
++					     grub_efi_ip6_config_data_type_t data_type,
++					     grub_efi_event_t event);
++
++  grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip6_config_protocol *this,
++					     grub_efi_ip6_config_data_type_t data_type,
++					     grub_efi_event_t event);
++};
++typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t;
++
+ #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
+   || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__)
+ 
diff --git a/SOURCES/0176-Fix-one-more-coverity-complaint.patch b/SOURCES/0176-Fix-one-more-coverity-complaint.patch
new file mode 100644
index 0000000..ba00fbd
--- /dev/null
+++ b/SOURCES/0176-Fix-one-more-coverity-complaint.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 25 May 2017 11:27:40 -0400
+Subject: [PATCH] Fix one more coverity complaint
+
+No idea why covscan thinks this is an "added" bug, since the file hasn't
+changed in 3 years, but... yeah.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/normal/completion.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/normal/completion.c b/grub-core/normal/completion.c
+index 2c9b9e9312a..93aa0d8eda8 100644
+--- a/grub-core/normal/completion.c
++++ b/grub-core/normal/completion.c
+@@ -284,7 +284,8 @@ complete_file (void)
+ 
+       /* Cut away the filename part.  */
+       dirfile = grub_strrchr (dir, '/');
+-      dirfile[1] = '\0';
++      if (dirfile)
++	dirfile[1] = '\0';
+ 
+       /* Iterate the directory.  */
+       (fs->dir) (dev, dir, iterate_dir, NULL);
diff --git a/SOURCES/0177-Fix-grub_net_hwaddr_to_str.patch b/SOURCES/0177-Fix-grub_net_hwaddr_to_str.patch
new file mode 100644
index 0000000..6c17a32
--- /dev/null
+++ b/SOURCES/0177-Fix-grub_net_hwaddr_to_str.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Mark Salter <msalter@redhat.com>
+Date: Tue, 22 Aug 2017 12:21:12 -0400
+Subject: [PATCH] Fix grub_net_hwaddr_to_str
+
+commit 5c3b78c92f8 introduced support for larger network hw addresses.
+However, grub_net_hwaddr_to_str() relies on GRUB_NET_MAX_STR_ADDRESS_SIZE
+to prevent a spurious ':' at the end of the string. So now, if actual
+hwaddr size is less than max, an extra ':' appears at the end of the
+string. So calculate max string size based on actual hwaddr length to
+fix the problem.
+
+Signed-off-by: Mark Salter <msalter@redhat.com>
+---
+ grub-core/net/net.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index a0f4d00f0be..191e8e41bd6 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -770,6 +770,7 @@ grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
+ {
+   char *ptr;
+   unsigned i;
++  int maxstr;
+ 
+   if (addr->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE)
+     {
+@@ -778,9 +779,10 @@ grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
+ 		    addr->type, addr->len);
+        return;
+     }
++  maxstr = addr->len * grub_strlen ("XX:");
+   for (ptr = str, i = 0; i < addr->len; i++)
+     {
+-      ptr += grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str),
++      ptr += grub_snprintf (ptr, maxstr - (ptr - str),
+ 		     "%02x:", addr->mac[i] & 0xff);
+     }
+ }
diff --git a/SOURCES/0178-Support-UEFI-networking-protocols.patch b/SOURCES/0178-Support-UEFI-networking-protocols.patch
new file mode 100644
index 0000000..2a4d586
--- /dev/null
+++ b/SOURCES/0178-Support-UEFI-networking-protocols.patch
@@ -0,0 +1,5055 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Michael Chang <mchang@suse.com>
+Date: Wed, 22 Feb 2017 14:27:50 +0800
+Subject: [PATCH] Support UEFI networking protocols
+
+References: fate#320130, bsc#1015589, bsc#1076132
+Patch-Mainline: no
+
+V1:
+  * Add preliminary support of UEFI networking protocols
+  * Support UEFI HTTPS Boot
+
+V2:
+  * Workaround http data access in firmware
+  * Fix DNS device path parsing for efinet device
+  * Relaxed UEFI Protocol requirement
+  * Support Intel OPA (Omni-Path Architecture) PXE Boot
+
+V3:
+  * Fix bufio in calculating address of next_buf
+  * Check HTTP respond code
+  * Use HEAD request method to test before GET
+  * Finish HTTP transaction in one go
+  * Fix bsc#1076132
+---
+ grub-core/Makefile.core.def        |   18 +
+ grub-core/io/bufio.c               |    2 +-
+ grub-core/kern/efi/efi.c           |   96 ++-
+ grub-core/net/drivers/efi/efinet.c |   27 +
+ grub-core/net/efi/dhcp.c           |  397 ++++++++++
+ grub-core/net/efi/efi_netfs.c      |   57 ++
+ grub-core/net/efi/http.c           |  419 +++++++++++
+ grub-core/net/efi/ip4_config.c     |  398 ++++++++++
+ grub-core/net/efi/ip6_config.c     |  422 +++++++++++
+ grub-core/net/efi/net.c            | 1428 ++++++++++++++++++++++++++++++++++++
+ grub-core/net/efi/pxe.c            |  424 +++++++++++
+ grub-core/net/net.c                |   74 ++
+ util/grub-mknetdir.c               |   23 +-
+ include/grub/efi/api.h             |  180 ++++-
+ include/grub/efi/dhcp.h            |  343 +++++++++
+ include/grub/efi/http.h            |  215 ++++++
+ include/grub/net/efi.h             |  144 ++++
+ 17 files changed, 4626 insertions(+), 41 deletions(-)
+ create mode 100644 grub-core/net/efi/dhcp.c
+ create mode 100644 grub-core/net/efi/efi_netfs.c
+ create mode 100644 grub-core/net/efi/http.c
+ create mode 100644 grub-core/net/efi/ip4_config.c
+ create mode 100644 grub-core/net/efi/ip6_config.c
+ create mode 100644 grub-core/net/efi/net.c
+ create mode 100644 grub-core/net/efi/pxe.c
+ create mode 100644 include/grub/efi/dhcp.h
+ create mode 100644 include/grub/efi/http.h
+ create mode 100644 include/grub/net/efi.h
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 420831bc89e..2851437e098 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2181,6 +2181,18 @@ module = {
+   common = hook/datehook.c;
+ };
+ 
++module = {
++  name = efi_netfs;
++  common = net/efi/efi_netfs.c;
++  common = net/efi/net.c;
++  common = net/efi/http.c;
++  common = net/efi/pxe.c;
++  common = net/efi/ip4_config.c;
++  common = net/efi/ip6_config.c;
++  common = net/efi/dhcp.c;
++  enable = efi;
++};
++
+ module = {
+   name = net;
+   common = net/net.c;
+@@ -2195,6 +2207,12 @@ module = {
+   common = net/arp.c;
+   common = net/netbuff.c;
+   common = net/url.c;
++  efi = net/efi/net.c;
++  efi = net/efi/http.c;
++  efi = net/efi/pxe.c;
++  efi = net/efi/ip4_config.c;
++  efi = net/efi/ip6_config.c;
++  efi = net/efi/dhcp.c;
+ };
+ 
+ module = {
+diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c
+index dbed6474431..6118bade50d 100644
+--- a/grub-core/io/bufio.c
++++ b/grub-core/io/bufio.c
+@@ -139,7 +139,7 @@ grub_bufio_read (grub_file_t file, char *buf, grub_size_t len)
+     return res;
+ 
+   /* Need to read some more.  */
+-  next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1);
++  next_buf = (grub_divmod64 (file->offset + res + len - 1, bufio->block_size, NULL)) * bufio->block_size;
+   /* Now read between file->offset + res and bufio->buffer_at.  */
+   if (file->offset + res < next_buf)
+     {
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index a2a732ffc0d..4d36fe31177 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -696,7 +696,7 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
+ 	      {
+ 		grub_efi_ipv4_device_path_t *ipv4
+ 		  = (grub_efi_ipv4_device_path_t *) dp;
+-		grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)",
++		grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x",
+ 			     (unsigned) ipv4->local_ip_address[0],
+ 			     (unsigned) ipv4->local_ip_address[1],
+ 			     (unsigned) ipv4->local_ip_address[2],
+@@ -709,33 +709,60 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
+ 			     (unsigned) ipv4->remote_port,
+ 			     (unsigned) ipv4->protocol,
+ 			     (unsigned) ipv4->static_ip_address);
++		if (len == sizeof (*ipv4))
++		  {
++		    grub_printf (",%u.%u.%u.%u,%u.%u.%u.%u",
++			(unsigned) ipv4->gateway_ip_address[0],
++			(unsigned) ipv4->gateway_ip_address[1],
++			(unsigned) ipv4->gateway_ip_address[2],
++			(unsigned) ipv4->gateway_ip_address[3],
++			(unsigned) ipv4->subnet_mask[0],
++			(unsigned) ipv4->subnet_mask[1],
++			(unsigned) ipv4->subnet_mask[2],
++			(unsigned) ipv4->subnet_mask[3]);
++		  }
++		grub_printf (")");
+ 	      }
+ 	      break;
+ 	    case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE:
+ 	      {
+ 		grub_efi_ipv6_device_path_t *ipv6
+ 		  = (grub_efi_ipv6_device_path_t *) dp;
+-		grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)",
+-			     (unsigned) ipv6->local_ip_address[0],
+-			     (unsigned) ipv6->local_ip_address[1],
+-			     (unsigned) ipv6->local_ip_address[2],
+-			     (unsigned) ipv6->local_ip_address[3],
+-			     (unsigned) ipv6->local_ip_address[4],
+-			     (unsigned) ipv6->local_ip_address[5],
+-			     (unsigned) ipv6->local_ip_address[6],
+-			     (unsigned) ipv6->local_ip_address[7],
+-			     (unsigned) ipv6->remote_ip_address[0],
+-			     (unsigned) ipv6->remote_ip_address[1],
+-			     (unsigned) ipv6->remote_ip_address[2],
+-			     (unsigned) ipv6->remote_ip_address[3],
+-			     (unsigned) ipv6->remote_ip_address[4],
+-			     (unsigned) ipv6->remote_ip_address[5],
+-			     (unsigned) ipv6->remote_ip_address[6],
+-			     (unsigned) ipv6->remote_ip_address[7],
++		grub_printf ("/IPv6(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%u,%u,%x,%x",
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[0]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[1]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[2]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[3]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[4]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[5]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[6]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[7]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[0]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[1]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[2]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[3]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[4]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[5]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[6]),
++			     (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[7]),
+ 			     (unsigned) ipv6->local_port,
+ 			     (unsigned) ipv6->remote_port,
+ 			     (unsigned) ipv6->protocol,
+ 			     (unsigned) ipv6->static_ip_address);
++		if (len == sizeof (*ipv6))
++		  {
++		    grub_printf (",%u,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
++			(unsigned) ipv6->prefix_length,
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[0]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[1]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[2]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[3]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[4]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[5]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[6]),
++			(unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[7]));
++		  }
++		grub_printf (")");
+ 	      }
+ 	      break;
+ 	    case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE:
+@@ -775,6 +802,39 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp)
+ 	      dump_vendor_path ("Messaging",
+ 				(grub_efi_vendor_device_path_t *) dp);
+ 	      break;
++	    case GRUB_EFI_URI_DEVICE_PATH_SUBTYPE:
++	      {
++		grub_efi_uri_device_path_t *uri
++		  = (grub_efi_uri_device_path_t *) dp;
++		grub_printf ("/URI(%s)", uri->uri);
++	      }
++	      break;
++	    case GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE:
++	      {
++		grub_efi_dns_device_path_t *dns
++		  = (grub_efi_dns_device_path_t *) dp;
++		if (dns->is_ipv6)
++		  {
++		    grub_printf ("/DNS(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)",
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0]) >> 16),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0])),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1]) >> 16),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1])),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2]) >> 16),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2])),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]) >> 16),
++			    (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3])));
++		  }
++		else
++		  {
++		    grub_printf ("/DNS(%d.%d.%d.%d)",
++			  dns->dns_server_ip[0].v4.addr[0],
++			  dns->dns_server_ip[0].v4.addr[1],
++			  dns->dns_server_ip[0].v4.addr[2],
++			  dns->dns_server_ip[0].v4.addr[3]);
++		  }
++	      }
++	      break;
+ 	    default:
+ 	      grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype);
+ 	      break;
+diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
+index 3d775074705..df7760ad203 100644
+--- a/grub-core/net/drivers/efi/efinet.c
++++ b/grub-core/net/drivers/efi/efinet.c
+@@ -28,6 +28,7 @@
+ #include <grub/lib/hexdump.h>
+ #include <grub/types.h>
+ #include <grub/net/netbuff.h>
++#include <grub/env.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -492,6 +493,17 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
+ 
+   ldp = grub_efi_find_last_device_path (ddp);
+ 
++  /* Skip the DNS Device */
++  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++      && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE)
++    {
++      ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++      ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++      ldp->length = sizeof (*ldp);
++
++      ldp = grub_efi_find_last_device_path (ddp);
++    }
++
+   if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+       || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+           && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
+@@ -760,6 +772,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ 	    || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+ 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
++		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE
+ 		&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
+ 	  continue;
+ 	dup_dp = grub_efi_duplicate_device_path (dp);
+@@ -774,6 +787,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 	    dup_ldp->length = sizeof (*dup_ldp);
+ 	  }
+ 
++	dup_ldp = grub_efi_find_last_device_path (dup_dp);
++	if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE)
++	  {
++	    dup_ldp = grub_efi_find_last_device_path (dup_dp);
++	    dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++	    dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++	    dup_ldp->length = sizeof (*dup_ldp);
++	  }
++
+ 	dup_ldp = grub_efi_find_last_device_path (dup_dp);
+ 	dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ 	dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+@@ -845,6 +867,9 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
+ 
+ GRUB_MOD_INIT(efinet)
+ {
++  if (grub_efi_net_config)
++    return;
++
+   grub_efinet_findcards ();
+   grub_efi_net_config = grub_efi_net_config_real;
+ }
+@@ -856,5 +881,7 @@ GRUB_MOD_FINI(efinet)
+   FOR_NET_CARDS_SAFE (card, next) 
+     if (card->driver == &efidriver)
+       grub_net_card_unregister (card);
++
++  grub_efi_net_config = NULL;
+ }
+ 
+diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c
+new file mode 100644
+index 00000000000..dbef63d8c08
+--- /dev/null
++++ b/grub-core/net/efi/dhcp.c
+@@ -0,0 +1,397 @@
++#include <grub/mm.h>
++#include <grub/command.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/misc.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++#ifdef GRUB_EFI_NET_DEBUG
++static void
++dhcp4_mode_print (grub_efi_dhcp4_mode_data_t *mode)
++{
++    switch (mode->state)
++      {
++	case GRUB_EFI_DHCP4_STOPPED:
++	  grub_printf ("STATE: STOPPED\n");
++	  break;
++	case GRUB_EFI_DHCP4_INIT:
++	  grub_printf ("STATE: INIT\n");
++	  break;
++	case GRUB_EFI_DHCP4_SELECTING:
++	  grub_printf ("STATE: SELECTING\n");
++	  break;
++	case GRUB_EFI_DHCP4_REQUESTING:
++	  grub_printf ("STATE: REQUESTING\n");
++	  break;
++	case GRUB_EFI_DHCP4_BOUND:
++	  grub_printf ("STATE: BOUND\n");
++	  break;
++	case GRUB_EFI_DHCP4_RENEWING:
++	  grub_printf ("STATE: RENEWING\n");
++	  break;
++	case GRUB_EFI_DHCP4_REBINDING:
++	  grub_printf ("STATE: REBINDING\n");
++	  break;
++	case GRUB_EFI_DHCP4_INIT_REBOOT:
++	  grub_printf ("STATE: INIT_REBOOT\n");
++	  break;
++	case GRUB_EFI_DHCP4_REBOOTING:
++	  grub_printf ("STATE: REBOOTING\n");
++	  break;
++	default:
++	  grub_printf ("STATE: UNKNOWN\n");
++	  break;
++      }
++
++    grub_printf ("CLIENT_ADDRESS: %u.%u.%u.%u\n",
++      mode->client_address[0],
++      mode->client_address[1],
++      mode->client_address[2],
++      mode->client_address[3]);
++    grub_printf ("SERVER_ADDRESS: %u.%u.%u.%u\n",
++      mode->server_address[0],
++      mode->server_address[1],
++      mode->server_address[2],
++      mode->server_address[3]);
++    grub_printf ("SUBNET_MASK: %u.%u.%u.%u\n",
++      mode->subnet_mask[0],
++      mode->subnet_mask[1],
++      mode->subnet_mask[2],
++      mode->subnet_mask[3]);
++    grub_printf ("ROUTER_ADDRESS: %u.%u.%u.%u\n",
++      mode->router_address[0],
++      mode->router_address[1],
++      mode->router_address[2],
++      mode->router_address[3]);
++}
++#endif
++
++static grub_efi_ipv4_address_t *
++grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packet_t *reply_packet)
++{
++  grub_efi_dhcp4_packet_option_t **option_list;
++  grub_efi_status_t status;
++  grub_efi_uint32_t option_count = 0;
++  grub_efi_uint32_t i;
++
++  status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, NULL);
++
++  if (status != GRUB_EFI_BUFFER_TOO_SMALL)
++    return NULL;
++
++  option_list = grub_malloc (option_count * sizeof(*option_list));
++  if (!option_list)
++    return NULL;
++
++  status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, option_list);
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (option_list);
++      return NULL;
++    }
++
++  for (i = 0; i < option_count; ++i)
++    {
++      if (option_list[i]->op_code == 6)
++	{
++	  grub_efi_ipv4_address_t *dns_address;
++
++	  if (((option_list[i]->length & 0x3) != 0) || (option_list[i]->length == 0))
++	    continue;
++
++	  /* We only contact primary dns */
++	  dns_address = grub_malloc (sizeof (*dns_address));
++	  if (!dns_address)
++	    {
++	      grub_free (option_list);
++	      return NULL;
++	    }
++	  grub_memcpy (dns_address, option_list[i]->data, sizeof (dns_address));
++	  grub_free (option_list);
++	  return dns_address;
++	}
++    }
++
++  grub_free (option_list);
++  return NULL;
++}
++
++#if 0
++/* Somehow this doesn't work ... */
++static grub_err_t
++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)),
++		    int argc __attribute__ ((unused)),
++		    char **args __attribute__ ((unused)))
++{
++  struct grub_efi_net_device *dev;
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      grub_efi_pxe_t *pxe = dev->ip4_pxe;
++      grub_efi_pxe_mode_t *mode = pxe->mode;
++      grub_efi_status_t status;
++
++      if (!mode->started)
++	{
++	  status = efi_call_2 (pxe->start, pxe, 0);
++
++	  if (status != GRUB_EFI_SUCCESS)
++	      grub_printf ("Couldn't start PXE\n");
++	}
++
++      status = efi_call_2 (pxe->dhcp, pxe, 0);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp4 configure failed, %d\n", (int)status);
++	  continue;
++	}
++
++      dev->prefer_ip6 = 0;
++    }
++
++  return GRUB_ERR_NONE;
++}
++#endif
++
++static grub_err_t
++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)),
++		    int argc,
++		    char **args)
++{
++  struct grub_efi_net_device *netdev;
++
++  for (netdev = net_devices; netdev; netdev = netdev->next)
++    {
++      grub_efi_status_t status;
++      grub_efi_dhcp4_mode_data_t mode;
++      grub_efi_dhcp4_config_data_t config;
++      grub_efi_dhcp4_packet_option_t *options;
++      grub_efi_ipv4_address_t *dns_address;
++      grub_efi_net_ip_manual_address_t net_ip;
++      grub_efi_net_ip_address_t ip_addr;
++      grub_efi_net_interface_t *inf = NULL;
++
++      if (argc > 0 && grub_strcmp (netdev->card_name, args[0]) != 0)
++	continue;
++
++      grub_memset (&config, 0, sizeof(config));
++
++      config.option_count = 1;
++      options = grub_malloc (sizeof(*options) + 2);
++      /* Parameter request list */
++      options->op_code = 55;
++      options->length = 3;
++      /* subnet mask */
++      options->data[0] = 1;
++      /* router */
++      options->data[1] = 3;
++      /* DNS */
++      options->data[2] = 6;
++      config.option_list = &options;
++
++      /* FIXME: What if the dhcp has bounded */
++      status = efi_call_2 (netdev->dhcp4->configure, netdev->dhcp4, &config);
++      grub_free (options);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp4 configure failed, %d\n", (int)status);
++	  continue;
++	}
++
++      status = efi_call_2 (netdev->dhcp4->start, netdev->dhcp4, NULL);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp4 start failed, %d\n", (int)status);
++	  continue;
++	}
++
++      status = efi_call_2 (netdev->dhcp4->get_mode_data, netdev->dhcp4, &mode);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp4 get mode failed, %d\n", (int)status);
++	  continue;
++	}
++
++#ifdef GRUB_EFI_NET_DEBUG
++      dhcp4_mode_print (&mode);
++#endif
++
++      for (inf = netdev->net_interfaces; inf; inf = inf->next)
++	if (inf->prefer_ip6 == 0)
++	  break;
++
++      grub_memcpy (net_ip.ip4.address, mode.client_address, sizeof (net_ip.ip4.address));
++      grub_memcpy (net_ip.ip4.subnet_mask, mode.subnet_mask, sizeof (net_ip.ip4.subnet_mask));
++
++      if (!inf)
++	{
++	  char *name = grub_xasprintf ("%s:dhcp", netdev->card_name);
++
++	  net_ip.is_ip6 = 0;
++	  inf = grub_efi_net_create_interface (netdev,
++		    name,
++		    &net_ip,
++		    1);
++	  grub_free (name);
++	}
++      else
++	{
++	  efi_net_interface_set_address (inf, &net_ip, 1);
++	}
++
++      grub_memcpy (ip_addr.ip4, mode.router_address, sizeof (ip_addr.ip4));
++      efi_net_interface_set_gateway (inf, &ip_addr);
++
++      dns_address = grub_efi_dhcp4_parse_dns (netdev->dhcp4, mode.reply_packet);
++      if (dns_address)
++	efi_net_interface_set_dns (inf, (grub_efi_net_ip_address_t *)&dns_address);
++
++    }
++
++  return GRUB_ERR_NONE;
++}
++
++
++static grub_err_t
++grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
++		    int argc,
++		    char **args)
++{
++  struct grub_efi_net_device *dev;
++  grub_efi_uint32_t ia_id;
++
++  for (dev = net_devices, ia_id = 0; dev; dev = dev->next, ia_id++)
++    {
++      grub_efi_dhcp6_config_data_t config;
++      grub_efi_dhcp6_packet_option_t *option_list[1];
++      grub_efi_dhcp6_packet_option_t *opt;
++      grub_efi_status_t status;
++      grub_efi_dhcp6_mode_data_t mode;
++      grub_efi_dhcp6_retransmission_t retrans;
++      grub_efi_net_ip_manual_address_t net_ip;
++      grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
++      grub_efi_net_interface_t *inf = NULL;
++
++      if (argc > 0 && grub_strcmp (dev->card_name, args[0]) != 0)
++	continue;
++
++      opt = grub_malloc (sizeof(*opt) + 2 * sizeof (grub_efi_uint16_t));
++
++#define GRUB_EFI_DHCP6_OPT_ORO 6
++
++      opt->op_code = grub_cpu_to_be16_compile_time (GRUB_EFI_DHCP6_OPT_ORO);
++      opt->op_len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_efi_uint16_t));
++
++#define GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL 59
++#define GRUB_EFI_DHCP6_OPT_DNS_SERVERS 23
++
++      grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL));
++      grub_set_unaligned16 (opt->data + 1 * sizeof (grub_efi_uint16_t),
++	      grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS));
++
++      option_list[0] = opt;
++      retrans.irt = 4;
++      retrans.mrc = 4;
++      retrans.mrt = 32;
++      retrans.mrd = 60;
++
++      config.dhcp6_callback = NULL;
++      config.callback_context = NULL;
++      config.option_count = 1;
++      config.option_list = option_list;
++      config.ia_descriptor.ia_id = ia_id;
++      config.ia_descriptor.type = GRUB_EFI_DHCP6_IA_TYPE_NA;
++      config.ia_info_event = NULL;
++      config.reconfigure_accept = 0;
++      config.rapid_commit = 0;
++      config.solicit_retransmission = &retrans;
++
++      status = efi_call_2 (dev->dhcp6->configure, dev->dhcp6, &config);
++      grub_free (opt);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp6 configure failed, %d\n", (int)status);
++	  continue;
++	}
++      status = efi_call_1 (dev->dhcp6->start, dev->dhcp6);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp6 start failed, %d\n", (int)status);
++	  continue;
++	}
++
++      status = efi_call_3 (dev->dhcp6->get_mode_data, dev->dhcp6, &mode, NULL);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("dhcp4 get mode failed, %d\n", (int)status);
++	  continue;
++	}
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	if (inf->prefer_ip6 == 1)
++	  break;
++
++      grub_memcpy (net_ip.ip6.address, mode.ia->ia_address[0].ip_address, sizeof (net_ip.ip6.address));
++      net_ip.ip6.prefix_length = 64;
++      net_ip.ip6.is_anycast = 0;
++      net_ip.is_ip6 = 1;
++
++      if (!inf)
++	{
++	  char *name = grub_xasprintf ("%s:dhcp", dev->card_name);
++
++	  inf = grub_efi_net_create_interface (dev,
++		    name,
++		    &net_ip,
++		    1);
++	  grub_free (name);
++	}
++      else
++	{
++	  efi_net_interface_set_address (inf, &net_ip, 1);
++	}
++
++      {
++	grub_efi_uint32_t count = 0;
++	grub_efi_dhcp6_packet_option_t **options = NULL;
++	grub_efi_uint32_t i;
++
++	status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, NULL);
++
++	if (status == GRUB_EFI_BUFFER_TOO_SMALL && count)
++	  {
++	    options = grub_malloc (count * sizeof(*options));
++	    status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options);
++	  }
++
++	if (status != GRUB_EFI_SUCCESS)
++	  {
++	    if (options)
++	      grub_free (options);
++	    continue;
++	  }
++
++	for (i = 0; i < count; ++i)
++	  {
++	    if (options[i]->op_code == grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS))
++	      {
++		grub_efi_net_ip_address_t dns;
++		grub_memcpy (dns.ip6, options[i]->data, sizeof(net_ip.ip6));
++		efi_net_interface_set_dns (inf, &dns);
++		break;
++	      }
++	  }
++
++	if (options)
++	  grub_free (options);
++      }
++
++      efi_call_1 (b->free_pool, mode.client_id);
++      efi_call_1 (b->free_pool, mode.ia);
++    }
++
++  return GRUB_ERR_NONE;
++}
++
++grub_command_func_t grub_efi_net_bootp = grub_cmd_efi_bootp;
++grub_command_func_t grub_efi_net_bootp6 = grub_cmd_efi_bootp6;
+diff --git a/grub-core/net/efi/efi_netfs.c b/grub-core/net/efi/efi_netfs.c
+new file mode 100644
+index 00000000000..ef371d885ea
+--- /dev/null
++++ b/grub-core/net/efi/efi_netfs.c
+@@ -0,0 +1,57 @@
++#include <grub/dl.h>
++#include <grub/env.h>
++#define EFI_NET_CMD_PREFIX "net_efi"
++#include <grub/net/efi.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++static grub_command_t cmd_efi_lsroutes;
++static grub_command_t cmd_efi_lscards;
++static grub_command_t cmd_efi_lsaddrs;
++static grub_command_t cmd_efi_addaddr;
++static grub_command_t cmd_efi_bootp;
++static grub_command_t cmd_efi_bootp6;
++
++static int initialized;
++
++GRUB_MOD_INIT(efi_netfs)
++{
++  if (grub_net_open)
++    return;
++
++  if (grub_efi_net_fs_init ())
++    {
++      cmd_efi_lsroutes = grub_register_command ("net_efi_ls_routes", grub_efi_net_list_routes,
++					    "", N_("list network routes"));
++      cmd_efi_lscards = grub_register_command ("net_efi_ls_cards", grub_efi_net_list_cards,
++					   "", N_("list network cards"));
++      cmd_efi_lsaddrs = grub_register_command ("net_efi_ls_addr", grub_efi_net_list_addrs,
++					  "", N_("list network addresses"));
++      cmd_efi_addaddr = grub_register_command ("net_efi_add_addr", grub_efi_net_add_addr,
++					  N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
++					  N_("Add a network address."));
++      cmd_efi_bootp = grub_register_command ("net_efi_bootp", grub_efi_net_bootp,
++					 N_("[CARD]"),
++					 N_("perform a bootp autoconfiguration"));
++      cmd_efi_bootp6 = grub_register_command ("net_efi_bootp6", grub_efi_net_bootp6,
++					 N_("[CARD]"),
++					 N_("perform a bootp autoconfiguration"));
++      initialized = 1;
++    }
++}
++
++GRUB_MOD_FINI(efi_netfs)
++{
++  if (initialized)
++    {
++      grub_unregister_command (cmd_efi_lsroutes);
++      grub_unregister_command (cmd_efi_lscards);
++      grub_unregister_command (cmd_efi_lsaddrs);
++      grub_unregister_command (cmd_efi_addaddr);
++      grub_unregister_command (cmd_efi_bootp);
++      grub_unregister_command (cmd_efi_bootp6);
++      grub_efi_net_fs_fini ();
++      initialized = 0;
++      return;
++    }
++}
+diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
+new file mode 100644
+index 00000000000..3f61fd2fa5b
+--- /dev/null
++++ b/grub-core/net/efi/http.c
+@@ -0,0 +1,419 @@
++
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/misc.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++static void
++http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
++{
++  grub_efi_http_config_data_t http_config;
++  grub_efi_httpv4_access_point_t httpv4_node;
++  grub_efi_httpv6_access_point_t httpv6_node;
++  grub_efi_status_t status;
++
++  grub_efi_http_t *http = dev->http;
++
++  grub_memset (&http_config, 0, sizeof(http_config));
++  http_config.http_version = GRUB_EFI_HTTPVERSION11;
++  http_config.timeout_millisec = 5000;
++
++  if (prefer_ip6)
++    {
++      grub_efi_uintn_t sz;
++      grub_efi_ip6_config_manual_address_t manual_address;
++
++      http_config.local_address_is_ipv6 = 1;
++      sz = sizeof (manual_address);
++      status = efi_call_4 (dev->ip6_config->get_data, dev->ip6_config,
++			GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
++			&sz, &manual_address);
++
++      if (status == GRUB_EFI_NOT_FOUND)
++	{
++	  grub_printf ("The MANUAL ADDRESS is not found\n");
++	}
++
++      /* FIXME: The manual interface would return BUFFER TOO SMALL !!! */
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  grub_printf ("??? %d\n",(int) status);
++	  return;
++	}
++
++      grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address));
++      httpv6_node.local_port = 0;
++      http_config.access_point.ipv6_node = &httpv6_node;
++    }
++  else
++    {
++      http_config.local_address_is_ipv6 = 0;
++      grub_memset (&httpv4_node, 0, sizeof(httpv4_node));
++      httpv4_node.use_default_address = 1;
++
++      /* Use random port here */
++      /* See TcpBind() in edk2/NetworkPkg/TcpDxe/TcpDispatcher.c */
++      httpv4_node.local_port = 0;
++      http_config.access_point.ipv4_node = &httpv4_node;
++    }
++
++  status = efi_call_2 (http->configure, http, &http_config);
++
++  if (status == GRUB_EFI_ALREADY_STARTED)
++    {
++      /* XXX: This hangs HTTPS boot */
++#if 0
++      if (efi_call_2 (http->configure, http, NULL) != GRUB_EFI_SUCCESS)
++	{
++	  grub_error (GRUB_ERR_IO, N_("couldn't reset http instance"));
++	  grub_print_error ();
++	  return;
++	}
++      status = efi_call_2 (http->configure, http, &http_config);
++#endif
++      return;
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_error (GRUB_ERR_IO, N_("couldn't configure http protocol, reason: %d"), (int)status);
++      grub_print_error ();
++      return ;
++    }
++}
++
++static grub_efi_boolean_t request_callback_done;
++static grub_efi_boolean_t response_callback_done;
++
++static void
++grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)),
++				void *context __attribute__ ((unused)))
++{
++  request_callback_done = 1;
++}
++
++static void
++grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)),
++				void *context __attribute__ ((unused)))
++{
++  response_callback_done = 1;
++}
++
++static grub_err_t
++efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size)
++{
++  grub_efi_http_request_data_t request_data;
++  grub_efi_http_message_t request_message;
++  grub_efi_http_token_t request_token;
++  grub_efi_http_response_data_t response_data;
++  grub_efi_http_message_t response_message;
++  grub_efi_http_token_t response_token;
++  grub_efi_http_header_t request_headers[3];
++
++  grub_efi_status_t status;
++  grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
++  char *url = NULL;
++
++  request_headers[0].field_name = (grub_efi_char8_t *)"Host";
++  request_headers[0].field_value = (grub_efi_char8_t *)server;
++  request_headers[1].field_name = (grub_efi_char8_t *)"Accept";
++  request_headers[1].field_value = (grub_efi_char8_t *)"*/*";
++  request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent";
++  request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0";
++
++  {
++    grub_efi_ipv6_address_t address;
++    const char *rest;
++    grub_efi_char16_t *ucs2_url;
++    grub_size_t url_len, ucs2_url_len;
++    const char *protocol = (use_https == 1) ? "https" : "http";
++
++    if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0)
++      url = grub_xasprintf ("%s://[%s]%s", protocol, server, name);
++    else
++      url = grub_xasprintf ("%s://%s%s", protocol, server, name);
++
++    if (!url)
++      {
++	return grub_errno;
++      }
++
++    url_len = grub_strlen (url);
++    ucs2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8;
++    ucs2_url = grub_malloc ((ucs2_url_len + 1) * sizeof (ucs2_url[0]));
++
++    if (!ucs2_url)
++      {
++	grub_free (url);
++	return grub_errno;
++      }
++
++    ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */
++    ucs2_url[ucs2_url_len] = 0;
++    grub_free (url);
++    request_data.url = ucs2_url;
++  }
++
++  request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET;
++
++  request_message.data.request = &request_data;
++  request_message.header_count = 3;
++  request_message.headers = request_headers;
++  request_message.body_length = 0;
++  request_message.body = NULL;
++
++  /* request token */
++  request_token.event = NULL;
++  request_token.status = GRUB_EFI_NOT_READY;
++  request_token.message = &request_message;
++
++  request_callback_done = 0;
++  status = efi_call_5 (b->create_event,
++                       GRUB_EFI_EVT_NOTIFY_SIGNAL,
++                       GRUB_EFI_TPL_CALLBACK,
++                       grub_efi_http_request_callback,
++                       NULL,
++                       &request_token.event);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (request_data.url);
++      return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status);
++    }
++
++  status = efi_call_2 (http->request, http, &request_token);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      efi_call_1 (b->close_event, request_token.event);
++      grub_free (request_data.url);
++      return grub_error (GRUB_ERR_IO, "Fail to send a request! status=0x%x\n", status);
++    }
++  /* TODO: Add Timeout */
++  while (!request_callback_done)
++    efi_call_1(http->poll, http);
++
++  response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS;
++  response_message.data.response = &response_data;
++  /* herader_count will be updated by the HTTP driver on response */
++  response_message.header_count = 0;
++  /* headers will be populated by the driver on response */
++  response_message.headers = NULL;
++  /* use zero BodyLength to only receive the response headers */
++  response_message.body_length = 0;
++  response_message.body = NULL;
++  response_token.event = NULL;
++
++  status = efi_call_5 (b->create_event,
++              GRUB_EFI_EVT_NOTIFY_SIGNAL,
++              GRUB_EFI_TPL_CALLBACK,
++              grub_efi_http_response_callback,
++              NULL,
++              &response_token.event);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      efi_call_1 (b->close_event, request_token.event);
++      grub_free (request_data.url);
++      return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status);
++    }
++
++  response_token.status = GRUB_EFI_SUCCESS;
++  response_token.message = &response_message;
++
++  /* wait for HTTP response */
++  response_callback_done = 0;
++  status = efi_call_2 (http->response, http, &response_token);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      efi_call_1 (b->close_event, response_token.event);
++      efi_call_1 (b->close_event, request_token.event);
++      grub_free (request_data.url);
++      return grub_error (GRUB_ERR_IO, "Fail to receive a response! status=%d\n", (int)status);
++    }
++
++  /* TODO: Add Timeout */
++  while (!response_callback_done)
++    efi_call_1 (http->poll, http);
++
++  if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK)
++    {
++      grub_efi_http_status_code_t status_code = response_message.data.response->status_code;
++
++      if (response_message.headers)
++	efi_call_1 (b->free_pool, response_message.headers);
++      efi_call_1 (b->close_event, response_token.event);
++      efi_call_1 (b->close_event, request_token.event);
++      grub_free (request_data.url);
++      if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND)
++	{
++	  return grub_error (GRUB_ERR_FILE_NOT_FOUND, _("file `%s' not found"), name);
++	}
++      else
++	{
++	  return grub_error (GRUB_ERR_NET_UNKNOWN_ERROR,
++		  _("unsupported uefi http status code 0x%x"), status_code);
++	}
++    }
++
++  if (file_size)
++    {
++      int i;
++      /* parse the length of the file from the ContentLength header */
++      for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i)
++	{
++	  if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length"))
++	    {
++	      *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10);
++	      break;
++	    }
++	}
++    }
++
++  if (response_message.headers)
++    efi_call_1 (b->free_pool, response_message.headers);
++  efi_call_1 (b->close_event, response_token.event);
++  efi_call_1 (b->close_event, request_token.event);
++  grub_free (request_data.url);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_ssize_t
++efihttp_read (struct grub_efi_net_device *dev,
++		  char *buf,
++		  grub_size_t len)
++{
++  grub_efi_http_message_t response_message;
++  grub_efi_http_token_t response_token;
++
++  grub_efi_status_t status;
++  grub_size_t sum = 0;
++  grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
++  grub_efi_http_t *http = dev->http;
++
++  if (!len)
++    {
++      grub_error (GRUB_ERR_BUG, "Invalid arguments to EFI HTTP Read");
++      return -1;
++    }
++
++  efi_call_5 (b->create_event,
++              GRUB_EFI_EVT_NOTIFY_SIGNAL,
++              GRUB_EFI_TPL_CALLBACK,
++              grub_efi_http_response_callback,
++              NULL,
++              &response_token.event);
++
++  while (len)
++    {
++      response_message.data.response = NULL;
++      response_message.header_count = 0;
++      response_message.headers = NULL;
++      response_message.body_length = len;
++      response_message.body = buf;
++
++      response_token.message = &response_message;
++      response_token.status = GRUB_EFI_NOT_READY;
++
++      response_callback_done = 0;
++
++      status = efi_call_2 (http->response, http, &response_token);
++      if (status != GRUB_EFI_SUCCESS)
++	{
++	  efi_call_1 (b->close_event, response_token.event);
++	  grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status);
++	  return -1;
++	}
++
++      while (!response_callback_done)
++	efi_call_1(http->poll, http);
++
++      sum += response_message.body_length;
++      buf += response_message.body_length;
++      len -= response_message.body_length;
++    }
++
++  efi_call_1 (b->close_event, response_token.event);
++
++  return sum;
++}
++
++static grub_err_t
++grub_efihttp_open (struct grub_efi_net_device *dev,
++		  int prefer_ip6 __attribute__ ((unused)),
++		  grub_file_t file,
++		  const char *filename __attribute__ ((unused)),
++		  int type)
++{
++  grub_err_t err;
++  grub_off_t size;
++  char *buf;
++
++  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0);
++  if (err != GRUB_ERR_NONE)
++    return err;
++
++  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size);
++  if (err != GRUB_ERR_NONE)
++    return err;
++
++  buf = grub_malloc (size);
++  efihttp_read (dev, buf, size);
++
++  file->size = size;
++  file->data = buf;
++  file->not_easily_seekable = 0;
++  file->device->net->offset = 0;
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_efihttp_close (struct grub_efi_net_device *dev __attribute__ ((unused)),
++		    int prefer_ip6 __attribute__ ((unused)),
++		    grub_file_t file)
++{
++  if (file->data)
++    grub_free (file->data);
++
++  file->data = 0;
++  file->offset = 0;
++  file->size = 0;
++  file->device->net->offset = 0;
++  return GRUB_ERR_NONE;
++}
++
++static grub_ssize_t
++grub_efihttp_read (struct grub_efi_net_device *dev __attribute__((unused)),
++		  int prefer_ip6 __attribute__((unused)),
++		  grub_file_t file,
++		  char *buf,
++		  grub_size_t len)
++{
++  grub_size_t r = len;
++
++  if (!file->data || !buf || !len)
++    return 0;
++
++  if ((file->device->net->offset + len) > file->size)
++    r = file->size - file->device->net->offset;
++
++  if (r)
++    {
++      grub_memcpy (buf, (char *)file->data + file->device->net->offset, r);
++      file->device->net->offset += r;
++    }
++
++  return r;
++}
++
++struct grub_efi_net_io io_http =
++  {
++    .configure = http_configure,
++    .open = grub_efihttp_open,
++    .read = grub_efihttp_read,
++    .close = grub_efihttp_close
++  };
+diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
+new file mode 100644
+index 00000000000..b711a5d9457
+--- /dev/null
++++ b/grub-core/net/efi/ip4_config.c
+@@ -0,0 +1,398 @@
++
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/misc.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++char *
++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address)
++{
++  char *hw_addr, *p;
++  int sz, s;
++  int i;
++
++  sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1;
++
++  hw_addr = grub_malloc (sz);
++  if (!hw_addr)
++    return NULL;
++
++  p = hw_addr;
++  s = sz;
++  for (i = 0; i < (int)hw_address_size; i++)
++    {
++      grub_snprintf (p, sz, "%02x:", hw_address[i]);
++      p +=  sizeof ("XX:") - 1;
++      s -=  sizeof ("XX:") - 1;
++    }
++
++  hw_addr[sz - 2] = '\0';
++  return hw_addr;
++}
++
++char *
++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address)
++{
++  char *addr;
++
++  addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX"));
++  if (!addr)
++      return NULL;
++
++  /* FIXME: Use grub_xasprintf ? */
++  grub_snprintf (addr,
++	  sizeof ("XXX.XXX.XXX.XXX"),
++	  "%u.%u.%u.%u",
++	  (*address)[0],
++	  (*address)[1],
++	  (*address)[2],
++	  (*address)[3]);
++
++  return addr;
++}
++
++int
++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest)
++{
++  grub_uint32_t newip = 0;
++  int i;
++  const char *ptr = val;
++
++  for (i = 0; i < 4; i++)
++    {
++      unsigned long t;
++      t = grub_strtoul (ptr, (char **) &ptr, 0);
++      if (grub_errno)
++	{
++	  grub_errno = GRUB_ERR_NONE;
++	  return 0;
++	}
++      if (*ptr != '.' && i == 0)
++	{
++	  /* XXX: t is in host byte order */
++	  newip = t;
++	  break;
++	}
++      if (t & ~0xff)
++	return 0;
++      newip <<= 8;
++      newip |= t;
++      if (i != 3 && *ptr != '.')
++	return 0;
++      ptr++;
++    }
++
++  newip =  grub_cpu_to_be32 (newip);
++
++  grub_memcpy (address, &newip, sizeof(*address));
++
++  if (rest)
++    *rest = (ptr - 1);
++  return 1;
++}
++
++static grub_efi_ip4_config2_interface_info_t *
++efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip4_config2_interface_info_t *interface_info;
++
++  sz = sizeof (*interface_info) + sizeof (*interface_info->route_table);
++  interface_info = grub_malloc (sz);
++  if (!interface_info)
++    return NULL;
++
++  status = efi_call_4 (ip4_config->get_data, ip4_config,
++		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
++		&sz, interface_info);
++
++  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++    {
++      grub_free (interface_info);
++      interface_info = grub_malloc (sz);
++      status = efi_call_4 (ip4_config->get_data, ip4_config,
++		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
++		    &sz, interface_info);
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (interface_info);
++      return NULL;
++    }
++
++  return interface_info;
++}
++
++static grub_efi_ip4_config2_manual_address_t *
++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip4_config2_manual_address_t *manual_address;
++
++  sz = sizeof (*manual_address);
++  manual_address = grub_malloc (sz);
++  if (!manual_address)
++    return NULL;
++
++  status = efi_call_4 (ip4_config->get_data, ip4_config,
++		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
++		    &sz, manual_address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (manual_address);
++      return NULL;
++    }
++
++  return manual_address;
++}
++
++char *
++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip4_config2_interface_info_t *interface_info;
++  char *name;
++
++  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
++
++  if (!interface_info)
++    return NULL;
++
++  name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE
++		      * GRUB_MAX_UTF8_PER_UTF16 + 1);
++  *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name,
++		      GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0;
++  grub_free (interface_info);
++  return name;
++}
++
++static char *
++grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip4_config2_interface_info_t *interface_info;
++  char *hw_addr;
++
++  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
++
++  if (!interface_info)
++    return NULL;
++
++  hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address);
++  grub_free (interface_info);
++
++  return hw_addr;
++}
++
++static char *
++grub_efi_ip4_interface_address (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip4_config2_manual_address_t *manual_address;
++  char *addr;
++
++  manual_address = efi_ip4_config_manual_address (dev->ip4_config);
++
++  if (!manual_address)
++    return NULL;
++
++  addr = grub_efi_ip4_address_to_string (&manual_address->address);
++  grub_free (manual_address);
++  return addr;
++}
++
++
++static int
++address_mask_size (grub_efi_ipv4_address_t *address)
++{
++  grub_uint8_t i;
++  grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address));
++
++  if (u32_addr == 0)
++    return 0;
++
++  for (i = 0; i < 32 ; ++i)
++    {
++      if (u32_addr == ((0xffffffff >> i) << i))
++	return (32 - i);
++    }
++
++  return -1;
++}
++
++static char **
++grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip4_config2_interface_info_t *interface_info;
++  char **ret;
++  int i, id;
++
++  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
++  if (!interface_info)
++    return NULL;
++
++  ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1));
++
++  if (!ret)
++    {
++      grub_free (interface_info);
++      return NULL;
++    }
++
++  id = 0;
++  for (i = 0; i < (int)interface_info->route_table_size; i++)
++    {
++      char *subnet, *gateway, *mask;
++      grub_uint32_t u32_subnet, u32_gateway;
++      int mask_size;
++      grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i;
++      grub_efi_net_interface_t *inf;
++      char *interface_name = NULL;
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	if (!inf->prefer_ip6)
++	  interface_name = inf->name;
++
++      u32_gateway = grub_get_unaligned32 (&route_table->gateway_address);
++      gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address);
++      u32_subnet = grub_get_unaligned32 (&route_table->subnet_address);
++      subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address);
++      mask_size = address_mask_size (&route_table->subnet_mask);
++      mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask);
++      if (u32_subnet && !u32_gateway && interface_name)
++	ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name);
++      else if (u32_subnet && u32_gateway)
++	ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway);
++      else if (!u32_subnet && u32_gateway)
++	ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway);
++      grub_free (subnet);
++      grub_free (gateway);
++      grub_free (mask);
++    }
++
++  ret[id] = NULL;
++  grub_free (interface_info);
++  return ret;
++}
++
++static grub_efi_net_interface_t *
++grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address)
++{
++  grub_efi_ip4_config2_interface_info_t *interface_info;
++  grub_efi_net_interface_t *inf;
++  int i;
++  grub_efi_ipv4_address_t *address = &ip_address->ip4;
++
++  interface_info = efi_ip4_config_interface_info (dev->ip4_config);
++  if (!interface_info)
++    return NULL;
++
++  for (i = 0; i < (int)interface_info->route_table_size; i++)
++    {
++      grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i;
++      grub_uint32_t u32_address, u32_mask, u32_subnet;
++
++      u32_address = grub_get_unaligned32 (address);
++      u32_subnet = grub_get_unaligned32 (route_table->subnet_address);
++      u32_mask = grub_get_unaligned32 (route_table->subnet_mask);
++
++      /* SKIP Default GATEWAY */
++      if (!u32_subnet && !u32_mask)
++	continue;
++
++      if ((u32_address & u32_mask) == u32_subnet)
++	{
++	  for (inf = dev->net_interfaces; inf; inf = inf->next)
++	    if (!inf->prefer_ip6)
++	      {
++		grub_free (interface_info);
++		return inf;
++	      }
++	}
++    }
++
++  grub_free (interface_info);
++  return NULL;
++}
++
++static int
++grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev,
++	    grub_efi_net_ip_manual_address_t *net_ip,
++	    int with_subnet)
++{
++  grub_efi_status_t status;
++  grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4;
++
++  if (!with_subnet)
++    {
++      grub_efi_ip4_config2_manual_address_t *manual_address =
++      efi_ip4_config_manual_address (dev->ip4_config);
++
++      if (manual_address)
++	{
++	  grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask));
++	  grub_free (manual_address);
++	}
++      else
++	{
++	  /* XXX: */
++	  address->subnet_mask[0] = 0xff;
++	  address->subnet_mask[1] = 0xff;
++	  address->subnet_mask[2] = 0xff;
++	  address->subnet_mask[3] = 0;
++	}
++    }
++
++  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
++		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
++		    sizeof(*address), address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++
++  return 1;
++}
++
++static int
++grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev,
++	      grub_efi_net_ip_address_t *address)
++{
++  grub_efi_status_t status;
++
++  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
++		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
++		sizeof (address->ip4), &address->ip4);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++  return 1;
++}
++
++/* FIXME: Multiple DNS */
++static int
++grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev,
++	      grub_efi_net_ip_address_t *address)
++{
++  grub_efi_status_t status;
++
++  status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
++		GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
++		sizeof (address->ip4), &address->ip4);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++  return 1;
++}
++
++grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t)
++  {
++    .get_hw_address = grub_efi_ip4_interface_hw_address,
++    .get_address = grub_efi_ip4_interface_address,
++    .get_route_table = grub_efi_ip4_interface_route_table,
++    .best_interface = grub_efi_ip4_interface_match,
++    .set_address = grub_efi_ip4_interface_set_manual_address,
++    .set_gateway = grub_efi_ip4_interface_set_gateway,
++    .set_dns = grub_efi_ip4_interface_set_dns
++  };
+diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c
+new file mode 100644
+index 00000000000..017c4d05bc7
+--- /dev/null
++++ b/grub-core/net/efi/ip6_config.c
+@@ -0,0 +1,422 @@
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/misc.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++char *
++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address)
++{
++  char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX"));
++  char *p;
++  int i;
++  int squash;
++
++  if (!str)
++    return NULL;
++
++  p = str;
++  squash = 0;
++  for (i = 0; i < 8; ++i)
++    {
++      grub_uint16_t addr;
++
++      if (i == 7)
++	squash = 2;
++
++      addr = grub_get_unaligned16 (address->addr + i * 2);
++
++      if (grub_be_to_cpu16 (addr))
++	{
++	  char buf[sizeof ("XXXX")];
++	  if (i > 0)
++	    *p++ = ':';
++	  grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr));
++	  grub_strcpy (p, buf);
++	  p += grub_strlen (buf);
++
++	  if (squash == 1)
++	    squash = 2;
++	}
++      else
++	{
++	  if (squash == 0)
++	    {
++	      *p++ = ':';
++	      squash = 1;
++	    }
++	  else if (squash == 2)
++	    {
++	      *p++ = ':';
++	      *p++ = '0';
++	    }
++	}
++    }
++  *p = '\0';
++  return str;
++}
++
++int
++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest)
++{
++  grub_uint16_t newip[8];
++  const char *ptr = val;
++  int word, quaddot = -1;
++  int bracketed = 0;
++
++  if (ptr[0] == '[') {
++    bracketed = 1;
++    ptr++;
++  }
++
++  if (ptr[0] == ':' && ptr[1] != ':')
++    return 0;
++  if (ptr[0] == ':')
++    ptr++;
++
++  for (word = 0; word < 8; word++)
++    {
++      unsigned long t;
++      if (*ptr == ':')
++	{
++	  quaddot = word;
++	  word--;
++	  ptr++;
++	  continue;
++	}
++      t = grub_strtoul (ptr, (char **) &ptr, 16);
++      if (grub_errno)
++	{
++	  grub_errno = GRUB_ERR_NONE;
++	  break;
++	}
++      if (t & ~0xffff)
++	return 0;
++      newip[word] = grub_cpu_to_be16 (t);
++      if (*ptr != ':')
++	break;
++      ptr++;
++    }
++  if (quaddot == -1 && word < 7)
++    return 0;
++  if (quaddot != -1)
++    {
++      grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
++		    (word - quaddot + 1) * sizeof (newip[0]));
++      grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
++    }
++  grub_memcpy (address, newip, 16);
++  if (bracketed && *ptr == ']') {
++    ptr++;
++  }
++  if (rest)
++    *rest = ptr;
++  return 1;
++}
++
++static grub_efi_ip6_config_interface_info_t *
++efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip6_config_interface_info_t *interface_info;
++
++  sz = sizeof (*interface_info) + sizeof (*interface_info->route_table);
++  interface_info = grub_malloc (sz);
++
++  status = efi_call_4 (ip6_config->get_data, ip6_config,
++		GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
++		&sz, interface_info);
++
++  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++    {
++      grub_free (interface_info);
++      interface_info = grub_malloc (sz);
++      status = efi_call_4 (ip6_config->get_data, ip6_config,
++		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
++		    &sz, interface_info);
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (interface_info);
++      return NULL;
++    }
++
++  return interface_info;
++}
++
++static grub_efi_ip6_config_manual_address_t *
++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip6_config_manual_address_t *manual_address;
++
++  sz = sizeof (*manual_address);
++  manual_address = grub_malloc (sz);
++  if (!manual_address)
++    return NULL;
++
++  status = efi_call_4 (ip6_config->get_data, ip6_config,
++		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
++		    &sz, manual_address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (manual_address);
++      return NULL;
++    }
++
++  return manual_address;
++}
++
++char *
++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip6_config_interface_info_t *interface_info;
++  char *name;
++
++  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
++
++  if (!interface_info)
++    return NULL;
++
++  name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE
++		      * GRUB_MAX_UTF8_PER_UTF16 + 1);
++  *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name,
++		      GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0;
++  grub_free (interface_info);
++  return name;
++}
++
++static char *
++grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip6_config_interface_info_t *interface_info;
++  char *hw_addr;
++
++  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
++
++  if (!interface_info)
++    return NULL;
++
++  hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address);
++  grub_free (interface_info);
++
++  return hw_addr;
++}
++
++static char *
++grub_efi_ip6_interface_address (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip6_config_manual_address_t *manual_address;
++  char *addr;
++
++  manual_address = efi_ip6_config_manual_address (dev->ip6_config);
++
++  if (!manual_address)
++    return NULL;
++
++  addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address);
++  grub_free (manual_address);
++  return addr;
++}
++
++static char **
++grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev)
++{
++  grub_efi_ip6_config_interface_info_t *interface_info;
++  char **ret;
++  int i, id;
++
++  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
++  if (!interface_info)
++    return NULL;
++
++  ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1));
++
++  if (!ret)
++    {
++      grub_free (interface_info);
++      return NULL;
++    }
++
++  id = 0;
++  for (i = 0; i < (int)interface_info->route_count ; i++)
++    {
++      char *gateway, *destination;
++      grub_uint64_t u64_gateway[2];
++      grub_uint64_t u64_destination[2];
++      grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i;
++      grub_efi_net_interface_t *inf;
++      char *interface_name = NULL;
++
++      gateway = grub_efi_ip6_address_to_string (&route_table->gateway);
++      destination = grub_efi_ip6_address_to_string (&route_table->destination);
++
++      u64_gateway[0] = grub_get_unaligned64 (route_table->gateway.addr);
++      u64_gateway[1] = grub_get_unaligned64 (route_table->gateway.addr + 8);
++      u64_destination[0] = grub_get_unaligned64 (route_table->destination.addr);
++      u64_destination[1] = grub_get_unaligned64 (route_table->destination.addr + 8);
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	if (inf->prefer_ip6)
++	  interface_name = inf->name;
++
++      if ((!u64_gateway[0] && !u64_gateway[1])
++	  && (u64_destination[0] || u64_destination[1]))
++	{
++	  if (interface_name)
++	    {
++	      if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL)
++	      && (!u64_destination[1])
++	      && (route_table->prefix_length == 64))
++		ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name);
++	      else
++		ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name);
++	    }
++	}
++      else if ((u64_gateway[0] || u64_gateway[1])
++	  && (u64_destination[0] || u64_destination[1]))
++	ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway);
++      else if ((u64_gateway[0] || u64_gateway[1])
++	  && (!u64_destination[0] && !u64_destination[1]))
++	ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway);
++
++      grub_free (gateway);
++      grub_free (destination);
++    }
++
++  ret[id] = NULL;
++  grub_free (interface_info);
++  return ret;
++}
++
++static grub_efi_net_interface_t *
++grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address)
++{
++  grub_efi_ip6_config_interface_info_t *interface_info;
++  grub_efi_net_interface_t *inf;
++  int i;
++  grub_efi_ipv6_address_t *address = &ip_address->ip6;
++
++  interface_info = efi_ip6_config_interface_info (dev->ip6_config);
++  if (!interface_info)
++    return NULL;
++
++  for (i = 0; i < (int)interface_info->route_count ; i++)
++    {
++      grub_uint64_t u64_addr[2];
++      grub_uint64_t u64_subnet[2];
++      grub_uint64_t u64_mask[2];
++
++      grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i;
++
++      /* SKIP Default GATEWAY */
++      if (route_table->prefix_length == 0)
++	continue;
++
++      u64_addr[0] = grub_get_unaligned64 (address);
++      u64_addr[1] = grub_get_unaligned64 (address + 4);
++      u64_subnet[0] = grub_get_unaligned64 (route_table->destination.addr);
++      u64_subnet[1] = grub_get_unaligned64 (route_table->destination.addr + 8);
++      u64_mask[0] = (route_table->prefix_length <= 64) ?
++	    0xffffffffffffffffULL << (64 - route_table->prefix_length) :
++	    0xffffffffffffffffULL;
++      u64_mask[1] = (route_table->prefix_length <= 64) ?
++	    0 :
++	    0xffffffffffffffffULL << (128 - route_table->prefix_length);
++
++      if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0])
++	  && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1]))
++	{
++	  for (inf = dev->net_interfaces; inf; inf = inf->next)
++	    if (inf->prefer_ip6)
++	      {
++		grub_free (interface_info);
++		return inf;
++	      }
++	}
++    }
++
++  grub_free (interface_info);
++  return NULL;
++}
++
++static int
++grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev,
++	    grub_efi_net_ip_manual_address_t *net_ip,
++	    int with_subnet)
++{
++  grub_efi_status_t status;
++  grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6;
++
++  if (!with_subnet)
++    {
++      grub_efi_ip6_config_manual_address_t *manual_address =
++      efi_ip6_config_manual_address (dev->ip6_config);
++
++      if (manual_address)
++	{
++	  address->prefix_length = manual_address->prefix_length;
++	  grub_free (manual_address);
++	}
++      else
++	{
++	  /* XXX: */
++	  address->prefix_length = 64;
++	}
++    }
++
++  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
++		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
++		    sizeof(*address), address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++
++  return 1;
++}
++
++static int
++grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev,
++	      grub_efi_net_ip_address_t *address)
++{
++  grub_efi_status_t status;
++
++  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
++		GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY,
++		sizeof (address->ip6), &address->ip6);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++  return 1;
++}
++
++static int
++grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev,
++	      grub_efi_net_ip_address_t *address)
++{
++
++  grub_efi_status_t status;
++
++  status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
++		GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
++		sizeof (address->ip6), &address->ip6);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++  return 1;
++}
++
++grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t)
++  {
++    .get_hw_address = grub_efi_ip6_interface_hw_address,
++    .get_address = grub_efi_ip6_interface_address,
++    .get_route_table = grub_efi_ip6_interface_route_table,
++    .best_interface = grub_efi_ip6_interface_match,
++    .set_address = grub_efi_ip6_interface_set_manual_address,
++    .set_gateway = grub_efi_ip6_interface_set_gateway,
++    .set_dns = grub_efi_ip6_interface_set_dns
++  };
+diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
+new file mode 100644
+index 00000000000..9e0078ac1c6
+--- /dev/null
++++ b/grub-core/net/efi/net.c
+@@ -0,0 +1,1428 @@
++#include <grub/net.h>
++#include <grub/env.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/dl.h>
++#include <grub/command.h>
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/i18n.h>
++#include <grub/bufio.h>
++#include <grub/efi/http.h>
++#include <grub/efi/dhcp.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++#define GRUB_EFI_IP6_PREFIX_LENGTH 64
++
++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID;
++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID;
++static grub_efi_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;
++static grub_efi_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID;
++static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
++static grub_efi_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID;
++static grub_efi_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID;
++static grub_efi_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID;
++static grub_efi_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID;
++
++struct grub_efi_net_device *net_devices;
++
++static char *default_server;
++static grub_efi_net_interface_t *net_interface;
++static grub_efi_net_interface_t *net_default_interface;
++
++#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6)
++#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type)
++#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz)
++#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file)
++#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__)
++
++static grub_efi_handle_t
++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path,
++                            grub_efi_device_path_t **r_device_path)
++{
++  grub_efi_handle_t handle;
++  grub_efi_status_t status;
++
++  status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path,
++                      protocol, &device_path, &handle);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return 0;
++
++  if (r_device_path)
++    *r_device_path = device_path;
++
++  return handle;
++}
++
++static int
++url_parse_fields (const char *url, char **proto, char **host, char **path)
++{
++  const char *p, *ps;
++  grub_size_t l;
++
++  *proto = *host = *path = NULL;
++  ps = p = url;
++
++  while ((p = grub_strchr (p, ':')))
++    {
++      if (grub_strlen (p) < sizeof ("://") - 1)
++	break;
++      if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0)
++	{
++	  l = p - ps;
++	  *proto = grub_malloc (l + 1);
++	  if (!*proto)
++	    {
++	      grub_print_error ();
++	      return 0;
++	    }
++
++	  grub_memcpy (*proto, ps, l);
++	  (*proto)[l] = '\0';
++	  p +=  sizeof ("://") - 1;
++	  break;
++	}
++      ++p;
++    }
++
++  if (!*proto)
++    {
++      grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url);
++      return 0;
++    }
++
++  ps = p;
++  p = grub_strchr (p, '/');
++
++  if (!p)
++    {
++      grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url);
++      grub_free (*proto);
++      *proto = NULL;
++      return 0;
++    }
++
++  l = p - ps;
++
++  if (l > 2 && ps[0] == '[' && ps[l - 1] == ']')
++    {
++      *host = grub_malloc (l - 1);
++      if (!*host)
++	{
++	  grub_print_error ();
++	  grub_free (*proto);
++	  *proto = NULL;
++	  return 0;
++	}
++      grub_memcpy (*host, ps + 1, l - 2);
++      (*host)[l - 2] = 0;
++    }
++  else
++    {
++      *host = grub_malloc (l + 1);
++      if (!*host)
++	{
++	  grub_print_error ();
++	  grub_free (*proto);
++	  *proto = NULL;
++	  return 0;
++	}
++      grub_memcpy (*host, ps, l);
++      (*host)[l] = 0;
++    }
++
++  *path = grub_strdup (p);
++  if (!*path)
++    {
++      grub_print_error ();
++      grub_free (*host);
++      grub_free (*proto);
++      *host = NULL;
++      *proto = NULL;
++      return 0;
++    }
++  return 1;
++}
++
++static void
++url_get_boot_location (const char *url, char **device, char **path, int is_default)
++{
++  char *protocol, *server, *file;
++  char *slash;
++
++  if (!url_parse_fields (url, &protocol, &server, &file))
++    return;
++
++  if ((slash = grub_strrchr (file, '/')))
++    *slash = 0;
++  else
++    *file = 0;
++
++  *device = grub_xasprintf ("%s,%s", protocol, server);
++  *path = grub_strdup(file);
++
++  if (is_default)
++    default_server = server;
++  else
++    grub_free (server);
++
++  grub_free (protocol);
++  grub_free (file);
++}
++
++static void
++pxe_get_boot_location (const struct grub_net_bootp_packet *bp,
++		  char **device,
++		  char **path,
++		  int is_default)
++{
++  char *server = grub_xasprintf ("%d.%d.%d.%d",
++	     ((grub_uint8_t *) &bp->server_ip)[0],
++	     ((grub_uint8_t *) &bp->server_ip)[1],
++	     ((grub_uint8_t *) &bp->server_ip)[2],
++	     ((grub_uint8_t *) &bp->server_ip)[3]);
++
++  *device = grub_xasprintf ("tftp,%s", server);
++
++  *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file));
++
++  if (*path)
++    {
++      char *slash;
++      slash = grub_strrchr (*path, '/');
++      if (slash)
++	*slash = 0;
++      else
++	**path = 0;
++    }
++
++  if (is_default)
++    default_server = server;
++  else
++    grub_free (server);
++}
++
++static void
++pxe_get_boot_location_v6 (const struct grub_net_dhcp6_packet *dp,
++		  grub_size_t dhcp_size,
++		  char **device,
++		  char **path)
++{
++
++  struct grub_net_dhcp6_option *dhcp_opt;
++  grub_size_t dhcp_remain_size;
++  *device = *path = 0;
++
++  if (dhcp_size < sizeof (*dp))
++    {
++      grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small"));
++      return;
++    }
++
++  dhcp_remain_size = dhcp_size - sizeof (*dp);
++  dhcp_opt = (struct grub_net_dhcp6_option *)dp->dhcp_options;
++
++  while (dhcp_remain_size)
++    {
++      grub_uint16_t code = grub_be_to_cpu16 (dhcp_opt->code);
++      grub_uint16_t len = grub_be_to_cpu16 (dhcp_opt->len);
++      grub_uint16_t option_size = sizeof (*dhcp_opt) + len;
++
++      if (dhcp_remain_size < option_size || code == 0)
++	break;
++
++      if (code == GRUB_NET_DHCP6_OPTION_BOOTFILE_URL)
++	{
++	  char *url = grub_malloc (len + 1);
++
++	  grub_memcpy (url, dhcp_opt->data, len);
++	  url[len] = 0;
++
++	  url_get_boot_location ((const char *)url, device, path, 1);
++	  grub_free (url);
++	  break;
++	}
++
++      dhcp_remain_size -= option_size;
++      dhcp_opt = (struct grub_net_dhcp6_option *)((grub_uint8_t *)dhcp_opt + option_size);
++    }
++}
++
++static grub_efi_net_interface_t *
++grub_efi_net_config_from_device_path (grub_efi_device_path_t *dp,
++		  struct grub_efi_net_device *netdev,
++		  char **device,
++		  char **path)
++{
++  grub_efi_net_interface_t *inf = NULL;
++
++  while (1)
++    {
++      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
++      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
++      grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
++
++      if (type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
++	{
++	  if (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
++	    {
++	      grub_efi_uri_device_path_t *uri_dp;
++	      uri_dp = (grub_efi_uri_device_path_t *) dp;
++	      /* Beware that uri_dp->uri may not be null terminated */
++	      url_get_boot_location ((const char *)uri_dp->uri, device, path, 1);
++	    }
++	  else if (subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
++	    {
++	      grub_efi_net_ip_manual_address_t net_ip;
++	      grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) dp;
++
++	      if (inf)
++		continue;
++	      grub_memcpy (net_ip.ip4.address, ipv4->local_ip_address, sizeof (net_ip.ip4.address));
++	      grub_memcpy (net_ip.ip4.subnet_mask, ipv4->subnet_mask, sizeof (net_ip.ip4.subnet_mask));
++	      net_ip.is_ip6 = 0;
++	      inf = grub_efi_net_create_interface (netdev,
++			    netdev->card_name,
++			    &net_ip,
++			    1);
++	    }
++	  else if (subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
++	    {
++	      grub_efi_net_ip_manual_address_t net_ip;
++	      grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) dp;
++
++	      if (inf)
++		continue;
++	      grub_memcpy (net_ip.ip6.address, ipv6->local_ip_address, sizeof (net_ip.ip6.address));
++	      net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH;
++	      net_ip.ip6.is_anycast = 0;
++	      net_ip.is_ip6 = 1;
++	      inf = grub_efi_net_create_interface (netdev,
++			    netdev->card_name,
++			    &net_ip,
++			    1);
++	    }
++	}
++
++      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
++        break;
++      dp = (grub_efi_device_path_t *) ((char *) dp + len);
++    }
++
++  return inf;
++}
++
++static grub_efi_net_interface_t *
++grub_efi_net_config_from_handle (grub_efi_handle_t *hnd,
++		  struct grub_efi_net_device *netdev,
++		  char **device,
++		  char **path)
++{
++  grub_efi_pxe_t *pxe = NULL;
++
++  if (hnd == netdev->ip4_pxe_handle)
++    pxe = netdev->ip4_pxe;
++  else if (hnd == netdev->ip6_pxe_handle)
++    pxe = netdev->ip6_pxe;
++
++  if (!pxe)
++    return (grub_efi_net_config_from_device_path (
++		grub_efi_get_device_path (hnd),
++		netdev,
++		device,
++		path));
++
++  if (pxe->mode->using_ipv6)
++    {
++      grub_efi_net_ip_manual_address_t net_ip;
++
++      pxe_get_boot_location_v6 (
++	    (const struct grub_net_dhcp6_packet *) &pxe->mode->dhcp_ack,
++	    sizeof (pxe->mode->dhcp_ack),
++	    device,
++	    path);
++
++      grub_memcpy (net_ip.ip6.address, pxe->mode->station_ip.v6, sizeof(net_ip.ip6.address));
++      net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH;
++      net_ip.ip6.is_anycast = 0;
++      net_ip.is_ip6 = 1;
++      return (grub_efi_net_create_interface (netdev,
++		    netdev->card_name,
++		    &net_ip,
++		    1));
++    }
++  else
++    {
++      grub_efi_net_ip_manual_address_t net_ip;
++
++      pxe_get_boot_location (
++		(const struct grub_net_bootp_packet *) &pxe->mode->dhcp_ack,
++		device,
++		path,
++		1);
++
++      grub_memcpy (net_ip.ip4.address, pxe->mode->station_ip.v4, sizeof (net_ip.ip4.address));
++      grub_memcpy (net_ip.ip4.subnet_mask, pxe->mode->subnet_mask.v4, sizeof (net_ip.ip4.subnet_mask));
++      net_ip.is_ip6 = 0;
++      return (grub_efi_net_create_interface (netdev,
++		    netdev->card_name,
++		    &net_ip,
++		    1));
++    }
++}
++
++static const char *
++grub_efi_net_var_get_address (struct grub_env_var *var,
++                   const char *val __attribute__ ((unused)))
++{
++  struct grub_efi_net_device *dev;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      grub_efi_net_interface_t *inf;
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	{
++	  char *var_name;
++
++	  var_name = grub_xasprintf ("net_%s_ip", inf->name);
++	  if (grub_strcmp (var_name, var->name) == 0)
++	    return efi_net_interface_get_address (inf);
++	  grub_free (var_name);
++	  var_name = grub_xasprintf ("net_%s_mac", inf->name);
++	  if (grub_strcmp (var_name, var->name) == 0)
++	    return efi_net_interface_get_hw_address (inf);
++	  grub_free (var_name);
++	}
++    }
++
++  return NULL;
++}
++
++static char *
++grub_efi_net_var_set_interface (struct grub_env_var *var __attribute__ ((unused)),
++		   const char *val)
++{
++  struct grub_efi_net_device *dev;
++  grub_efi_net_interface_t *inf;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    for (inf = dev->net_interfaces; inf; inf = inf->next)
++      if (grub_strcmp (inf->name, val) == 0)
++	{
++	  net_default_interface = inf;
++	  return grub_strdup (val);
++	}
++
++  return NULL;
++}
++
++static char *
++grub_efi_net_var_set_server (struct grub_env_var *var __attribute__ ((unused)),
++		   const char *val)
++{
++  grub_free (default_server);
++  default_server = grub_strdup (val);
++  return grub_strdup (val);
++}
++
++static const char *
++grub_efi_net_var_get_server (struct grub_env_var *var __attribute__ ((unused)),
++		   const char *val __attribute__ ((unused)))
++{
++  return default_server ? : "";
++}
++
++static const char *
++grub_efi_net_var_get_ip (struct grub_env_var *var __attribute__ ((unused)),
++	       const char *val __attribute__ ((unused)))
++{
++  const char *intf = grub_env_get ("net_default_interface");
++  const char *ret = NULL;
++  if (intf)
++    {
++      char *buf = grub_xasprintf ("net_%s_ip", intf);
++      if (buf)
++	ret = grub_env_get (buf);
++      grub_free (buf);
++    }
++  return ret;
++}
++
++static const char *
++grub_efi_net_var_get_mac (struct grub_env_var *var __attribute__ ((unused)),
++	       const char *val __attribute__ ((unused)))
++{
++  const char *intf = grub_env_get ("net_default_interface");
++  const char *ret = NULL;
++  if (intf)
++    {
++      char *buf = grub_xasprintf ("net_%s_mac", intf);
++      if (buf)
++	ret = grub_env_get (buf);
++      grub_free (buf);
++    }
++  return ret;
++}
++
++static void
++grub_efi_net_export_interface_vars (void)
++{
++  struct grub_efi_net_device *dev;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      grub_efi_net_interface_t *inf;
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	{
++	  char *var;
++
++	  var = grub_xasprintf ("net_%s_ip", inf->name);
++	  grub_register_variable_hook (var, grub_efi_net_var_get_address, 0);
++	  grub_env_export (var);
++	  grub_free (var);
++	  var = grub_xasprintf ("net_%s_mac", inf->name);
++	  grub_register_variable_hook (var, grub_efi_net_var_get_address, 0);
++	  grub_env_export (var);
++	  grub_free (var);
++	}
++    }
++}
++
++static void
++grub_efi_net_unset_interface_vars (void)
++{
++  struct grub_efi_net_device *dev;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      grub_efi_net_interface_t *inf;
++
++      for (inf = dev->net_interfaces; inf; inf = inf->next)
++	{
++	  char *var;
++
++	  var = grub_xasprintf ("net_%s_ip", inf->name);
++	  grub_register_variable_hook (var, 0, 0);
++	  grub_env_unset (var);
++	  grub_free (var);
++	  var = grub_xasprintf ("net_%s_mac", inf->name);
++	  grub_register_variable_hook (var, 0, 0);
++	  grub_env_unset (var);
++	  grub_free (var);
++	}
++    }
++}
++
++grub_efi_net_interface_t *
++grub_efi_net_create_interface (struct grub_efi_net_device *dev,
++		const char *interface_name,
++		grub_efi_net_ip_manual_address_t *net_ip,
++		int has_subnet)
++{
++  grub_efi_net_interface_t *inf;
++
++  for (inf = dev->net_interfaces; inf; inf = inf->next)
++    {
++      if (inf->prefer_ip6 == net_ip->is_ip6)
++	break;
++    }
++
++  if (!inf)
++    {
++      inf = grub_malloc (sizeof(*inf));
++      inf->name = grub_strdup (interface_name);
++      inf->prefer_ip6 = net_ip->is_ip6;
++      inf->dev = dev;
++      inf->next = dev->net_interfaces;
++      inf->ip_config = (net_ip->is_ip6) ? efi_net_ip6_config : efi_net_ip4_config ;
++      dev->net_interfaces = inf;
++    }
++  else
++    {
++      grub_free (inf->name);
++      inf->name = grub_strdup (interface_name);
++    }
++
++  if (!efi_net_interface_set_address (inf, net_ip, has_subnet))
++    {
++      grub_error (GRUB_ERR_BUG, N_("Set Address Failed"));
++      return NULL;
++    }
++
++  return inf;
++}
++
++static void
++grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
++			  char **path)
++{
++  grub_efi_handle_t config_hnd;
++
++  struct grub_efi_net_device *netdev;
++  grub_efi_net_interface_t *inf;
++
++  config_hnd = grub_efi_locate_device_path (&ip4_config_guid, grub_efi_get_device_path (hnd), NULL);
++
++  if (!config_hnd)
++    return;
++
++  for (netdev = net_devices; netdev; netdev = netdev->next)
++    if (netdev->handle == config_hnd)
++      break;
++
++  if (!netdev)
++    return;
++
++  if (!(inf = grub_efi_net_config_from_handle (hnd, netdev, device, path)))
++    return;
++
++  grub_env_set ("net_default_interface", inf->name);
++  grub_efi_net_export_interface_vars ();
++}
++
++static grub_err_t
++grub_efi_netfs_dir (grub_device_t device, const char *path __attribute__ ((unused)),
++		 grub_fs_dir_hook_t hook __attribute__ ((unused)),
++		 void *hook_data __attribute__ ((unused)))
++{
++  if (!device->net)
++    return grub_error (GRUB_ERR_BUG, "invalid net device");
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_efi_netfs_open (struct grub_file *file_out __attribute__ ((unused)),
++		  const char *name __attribute__ ((unused)))
++{
++  struct grub_file *file, *bufio;
++
++  file = grub_malloc (sizeof (*file));
++  if (!file)
++    return grub_errno;
++
++  grub_memcpy (file, file_out, sizeof (struct grub_file));
++  file->device->net->name = grub_strdup (name);
++
++  if (!file->device->net->name)
++    {
++      grub_free (file);
++      return grub_errno;
++    }
++
++  efi_net_interface(open, file, name);
++  grub_print_error ();
++
++  bufio = grub_bufio_open (file, 32768);
++  if (!bufio)
++    {
++      grub_free (file->device->net->name);
++      grub_free (file);
++      return grub_errno;
++    }
++  grub_memcpy (file_out, bufio, sizeof (struct grub_file));
++  grub_free (bufio);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_ssize_t
++grub_efihttp_chunk_read (grub_file_t file, char *buf,
++			grub_size_t len, grub_size_t chunk_size)
++{
++  char *chunk = grub_malloc (chunk_size);
++  grub_size_t sum = 0;
++
++  while (len)
++    {
++      grub_ssize_t rd;
++      grub_size_t sz = (len > chunk_size) ? chunk_size : len;
++
++      rd = efi_net_interface (read, file, chunk, sz);
++
++      if (rd <= 0)
++	return rd;
++
++      if (buf)
++	{
++	  grub_memcpy (buf, chunk, rd);
++	  buf += rd;
++	}
++      sum += rd;
++      len -= rd;
++    }
++
++  grub_free (chunk);
++  return sum;
++}
++
++static grub_ssize_t
++grub_efi_netfs_read (grub_file_t file __attribute__ ((unused)),
++		  char *buf __attribute__ ((unused)), grub_size_t len __attribute__ ((unused)))
++{
++  if (file->offset > file->device->net->offset)
++    {
++      grub_efihttp_chunk_read (file, NULL, file->offset - file->device->net->offset, 10240);
++    }
++  else if (file->offset < file->device->net->offset)
++    {
++      efi_net_interface (close, file);
++      efi_net_interface (open, file, file->device->net->name);
++      if (file->offset)
++	grub_efihttp_chunk_read (file, NULL, file->offset, 10240);
++    }
++
++  return efi_net_interface (read, file, buf, len);
++}
++
++static grub_err_t
++grub_efi_netfs_close (grub_file_t file)
++{
++  efi_net_interface (close, file);
++  return GRUB_ERR_NONE;
++}
++
++static grub_efi_handle_t
++grub_efi_service_binding (grub_efi_handle_t dev, grub_efi_guid_t *service_binding_guid)
++{
++  grub_efi_service_binding_t *service;
++  grub_efi_status_t status;
++  grub_efi_handle_t child_dev = NULL;
++
++  service = grub_efi_open_protocol (dev, service_binding_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++  if (!service)
++    {
++      grub_error (GRUB_ERR_IO, N_("couldn't open efi service binding protocol"));
++      return NULL;
++    }
++
++  status = efi_call_2 (service->create_child, service, &child_dev);
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_error (GRUB_ERR_IO, N_("Failed to create child device of http service %x"), status);
++      return NULL;
++    }
++
++  return child_dev;
++}
++
++static grub_err_t
++grub_efi_net_parse_address (const char *address,
++    grub_efi_ip4_config2_manual_address_t *ip4,
++    grub_efi_ip6_config_manual_address_t *ip6,
++    int *is_ip6,
++    int *has_cidr)
++{
++  const char *rest;
++
++  if (grub_efi_string_to_ip4_address (address, &ip4->address, &rest))
++    {
++      *is_ip6 = 0;
++      if (*rest == '/')
++	{
++	  grub_uint32_t subnet_mask_size;
++
++	  subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0);
++
++	  if (!grub_errno && subnet_mask_size <= 32 && *rest == 0)
++	    {
++	      grub_uint32_t subnet_mask;
++
++	      subnet_mask = grub_cpu_to_be32 ((0xffffffffU << (32 - subnet_mask_size)));
++	      grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask));
++	      if (has_cidr)
++		*has_cidr = 1;
++	      return GRUB_ERR_NONE;
++	    }
++	}
++      else if (*rest == 0)
++	{
++	  grub_uint32_t subnet_mask = 0xffffffffU;
++	  grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask));
++	  if (has_cidr)
++	    *has_cidr = 0;
++	  return GRUB_ERR_NONE;
++	}
++    }
++  else if (grub_efi_string_to_ip6_address (address, &ip6->address, &rest))
++    {
++      *is_ip6 = 1;
++      if (*rest == '/')
++	{
++	  grub_efi_uint8_t prefix_length;
++
++	  prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0);
++	  if (!grub_errno && prefix_length <= 128 && *rest == 0)
++	    {
++	      ip6->prefix_length = prefix_length;
++	      ip6->is_anycast = 0;
++	      if (has_cidr)
++		*has_cidr = 1;
++	      return GRUB_ERR_NONE;
++	    }
++	}
++      else if (*rest == 0)
++	{
++	  ip6->prefix_length = 128;
++	  ip6->is_anycast = 0;
++	  if (has_cidr)
++	    *has_cidr = 0;
++	  return GRUB_ERR_NONE;
++	}
++    }
++
++  return grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++		   N_("unrecognised network address `%s'"),
++		   address);
++}
++
++static grub_efi_net_interface_t *
++match_route (const char *server)
++{
++  grub_err_t err;
++  grub_efi_ip4_config2_manual_address_t ip4;
++  grub_efi_ip6_config_manual_address_t ip6;
++  grub_efi_net_interface_t *inf;
++  int is_ip6 = 0;
++
++  err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0);
++
++  if (err)
++    {
++      grub_print_error ();
++      return NULL;
++    }
++
++  if (is_ip6)
++    {
++      struct grub_efi_net_device *dev;
++      grub_efi_net_ip_address_t addr;
++
++      grub_memcpy (addr.ip6, ip6.address, sizeof(ip6.address));
++
++      for (dev = net_devices; dev; dev = dev->next)
++	  if ((inf = efi_net_ip6_config->best_interface (dev, &addr)))
++	    return inf;
++    }
++  else
++    {
++      struct grub_efi_net_device *dev;
++      grub_efi_net_ip_address_t addr;
++
++      grub_memcpy (addr.ip4, ip4.address, sizeof(ip4.address));
++
++      for (dev = net_devices; dev; dev = dev->next)
++	  if ((inf = efi_net_ip4_config->best_interface (dev, &addr)))
++	    return inf;
++    }
++
++  return 0;
++}
++
++static void
++grub_efi_net_add_pxebc_to_cards (void)
++{
++  grub_efi_uintn_t num_handles;
++  grub_efi_handle_t *handles;
++  grub_efi_handle_t *handle;
++
++  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &pxe_io_guid,
++				    0, &num_handles);
++  if (!handles)
++    return;
++
++  for (handle = handles; num_handles--; handle++)
++    {
++      grub_efi_device_path_t *dp, *ddp, *ldp;
++      grub_efi_pxe_t *pxe;
++      struct grub_efi_net_device *d;
++      int is_ip6 = 0;
++
++      dp = grub_efi_get_device_path (*handle);
++      if (!dp)
++	continue;
++
++      ddp = grub_efi_duplicate_device_path (dp);
++      ldp = grub_efi_find_last_device_path (ddp);
++
++      if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++	  && ldp->subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
++	{
++	  ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++	  ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++	  ldp->length = sizeof (*ldp);
++	}
++      else if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
++	  && ldp->subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
++	{
++	  is_ip6 = 1;
++	  ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
++	  ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
++	  ldp->length = sizeof (*ldp);
++	}
++
++      for (d = net_devices; d; d = d->next)
++	if (grub_efi_compare_device_paths (ddp, grub_efi_get_device_path (d->handle)) == 0)
++	  break;
++
++      if (!d)
++	{
++	  grub_free (ddp);
++	  continue;
++	}
++
++      pxe = grub_efi_open_protocol (*handle, &pxe_io_guid,
++				GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++      if (!pxe)
++	{
++	  grub_free (ddp);
++	  continue;
++	}
++
++      if (is_ip6)
++	{
++	  d->ip6_pxe_handle = *handle;
++	  d->ip6_pxe = pxe;
++	}
++      else
++	{
++	  d->ip4_pxe_handle = *handle;
++	  d->ip4_pxe = pxe;
++	}
++
++      grub_free (ddp);
++    }
++
++  grub_free (handles);
++}
++
++static void
++set_ip_policy_to_static (void)
++{
++  struct grub_efi_net_device *dev;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      grub_efi_ip4_config2_policy_t ip4_policy = GRUB_EFI_IP4_CONFIG2_POLICY_STATIC;
++
++      if (efi_call_4 (dev->ip4_config->set_data, dev->ip4_config,
++		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
++		    sizeof (ip4_policy), &ip4_policy) != GRUB_EFI_SUCCESS)
++	grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP4_CONFIG2_POLICY_STATIC on dev `%s'", dev->card_name);
++
++      if (dev->ip6_config)
++	{
++	  grub_efi_ip6_config_policy_t ip6_policy = GRUB_EFI_IP6_CONFIG_POLICY_MANUAL;
++
++	  if (efi_call_4 (dev->ip6_config->set_data, dev->ip6_config,
++		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY,
++		    sizeof (ip6_policy), &ip6_policy) != GRUB_EFI_SUCCESS)
++	    grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP6_CONFIG_POLICY_MANUAL on dev `%s'", dev->card_name);
++	}
++    }
++}
++
++/* FIXME: Do not fail if the card did not support any of the protocol (Eg http) */
++static void
++grub_efi_net_find_cards (void)
++{
++  grub_efi_uintn_t num_handles;
++  grub_efi_handle_t *handles;
++  grub_efi_handle_t *handle;
++  int id;
++
++  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &ip4_config_guid,
++				    0, &num_handles);
++  if (!handles)
++    return;
++
++  for (id = 0, handle = handles; num_handles--; handle++, id++)
++    {
++      grub_efi_device_path_t *dp;
++      grub_efi_ip4_config2_protocol_t *ip4_config;
++      grub_efi_ip6_config_protocol_t *ip6_config;
++      grub_efi_handle_t http_handle;
++      grub_efi_http_t *http;
++      grub_efi_handle_t dhcp4_handle;
++      grub_efi_dhcp4_protocol_t *dhcp4;
++      grub_efi_handle_t dhcp6_handle;
++      grub_efi_dhcp6_protocol_t *dhcp6;
++
++      struct grub_efi_net_device *d;
++
++      dp = grub_efi_get_device_path (*handle);
++      if (!dp)
++	continue;
++
++      ip4_config = grub_efi_open_protocol (*handle, &ip4_config_guid,
++				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++      if (!ip4_config)
++	continue;
++
++      ip6_config = grub_efi_open_protocol (*handle, &ip6_config_guid,
++				    GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
++
++      http_handle = grub_efi_service_binding (*handle, &http_service_binding_guid);
++      grub_errno = GRUB_ERR_NONE;
++      http = (http_handle)
++	? grub_efi_open_protocol (http_handle, &http_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
++	: NULL;
++
++      dhcp4_handle = grub_efi_service_binding (*handle, &dhcp4_service_binding_guid);
++      grub_errno = GRUB_ERR_NONE;
++      dhcp4 = (dhcp4_handle)
++	? grub_efi_open_protocol (dhcp4_handle, &dhcp4_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
++	: NULL;
++
++
++      dhcp6_handle = grub_efi_service_binding (*handle, &dhcp6_service_binding_guid);
++      grub_errno = GRUB_ERR_NONE;
++      dhcp6 = (dhcp6_handle)
++	? grub_efi_open_protocol (dhcp6_handle, &dhcp6_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL)
++	: NULL;
++
++      d = grub_malloc (sizeof (*d));
++      if (!d)
++	{
++	  grub_free (handles);
++	  while (net_devices)
++	    {
++	      d = net_devices->next;
++	      grub_free (net_devices);
++	      net_devices = d;
++	    }
++	  return;
++	}
++      d->handle = *handle;
++      d->ip4_config = ip4_config;
++      d->ip6_config = ip6_config;
++      d->http_handle = http_handle;
++      d->http = http;
++      d->dhcp4_handle = dhcp4_handle;
++      d->dhcp4 = dhcp4;
++      d->dhcp6_handle = dhcp6_handle;
++      d->dhcp6 = dhcp6;
++      d->next = net_devices;
++      d->card_name = grub_xasprintf ("efinet%d", id);
++      d->net_interfaces = NULL;
++      net_devices = d;
++    }
++
++  grub_efi_net_add_pxebc_to_cards ();
++  grub_free (handles);
++  set_ip_policy_to_static ();
++}
++
++static void
++listroutes_ip4 (struct grub_efi_net_device *netdev)
++{
++  char **routes;
++
++  routes = NULL;
++
++  if ((routes = efi_net_ip4_config->get_route_table (netdev)))
++    {
++      char **r;
++
++      for (r = routes; *r; ++r)
++	grub_printf ("%s\n", *r);
++    }
++
++  if (routes)
++    {
++      char **r;
++
++      for (r = routes; *r; ++r)
++	grub_free (*r);
++      grub_free (routes);
++    }
++}
++
++static void
++listroutes_ip6 (struct grub_efi_net_device *netdev)
++{
++  char **routes;
++
++  routes = NULL;
++
++  if ((routes = efi_net_ip6_config->get_route_table (netdev)))
++    {
++      char **r;
++
++      for (r = routes; *r; ++r)
++	grub_printf ("%s\n", *r);
++    }
++
++  if (routes)
++    {
++      char **r;
++
++      for (r = routes; *r; ++r)
++	grub_free (*r);
++      grub_free (routes);
++    }
++}
++
++static grub_err_t
++grub_cmd_efi_listroutes (struct grub_command *cmd __attribute__ ((unused)),
++		     int argc __attribute__ ((unused)),
++		     char **args __attribute__ ((unused)))
++{
++  struct grub_efi_net_device *netdev;
++
++  for (netdev = net_devices; netdev; netdev = netdev->next)
++    {
++      listroutes_ip4 (netdev);
++      listroutes_ip6 (netdev);
++    }
++
++  return GRUB_ERR_NONE;
++}
++static grub_err_t
++grub_cmd_efi_listcards (struct grub_command *cmd __attribute__ ((unused)),
++		    int argc __attribute__ ((unused)),
++		    char **args __attribute__ ((unused)))
++{
++  struct grub_efi_net_device *dev;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      char *hw_addr;
++
++      hw_addr = efi_net_ip4_config->get_hw_address (dev);
++
++      if (hw_addr)
++	{
++	  grub_printf ("%s %s\n", dev->card_name, hw_addr);
++	  grub_free (hw_addr);
++	}
++    }
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_cmd_efi_listaddrs (struct grub_command *cmd __attribute__ ((unused)),
++		    int argc __attribute__ ((unused)),
++		    char **args __attribute__ ((unused)))
++{
++  struct grub_efi_net_device *dev;
++  grub_efi_net_interface_t *inf;
++
++  for (dev = net_devices; dev; dev = dev->next)
++    for (inf = dev->net_interfaces; inf; inf = inf->next)
++      {
++	char *hw_addr = NULL;
++	char *addr = NULL;
++
++	if ((hw_addr = efi_net_interface_get_hw_address (inf))
++	    && (addr = efi_net_interface_get_address (inf)))
++	  grub_printf ("%s %s %s\n", inf->name, hw_addr, addr);
++
++	if (hw_addr)
++	  grub_free (hw_addr);
++	if (addr)
++	  grub_free (addr);
++      }
++
++  return GRUB_ERR_NONE;
++}
++
++/* FIXME: support MAC specifying.  */
++static grub_err_t
++grub_cmd_efi_addaddr (struct grub_command *cmd __attribute__ ((unused)),
++                  int argc, char **args)
++{
++  struct grub_efi_net_device *dev;
++  grub_err_t err;
++  grub_efi_ip4_config2_manual_address_t ip4;
++  grub_efi_ip6_config_manual_address_t ip6;
++  grub_efi_net_ip_manual_address_t net_ip;
++  int is_ip6 = 0;
++  int cidr = 0;
++
++  if (argc != 3)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected"));
++
++  for (dev = net_devices; dev; dev = dev->next)
++    {
++      if (grub_strcmp (dev->card_name, args[1]) == 0)
++	break;
++    }
++
++  if (!dev)
++    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found"));
++
++  err = grub_efi_net_parse_address (args[2], &ip4, &ip6, &is_ip6, &cidr);
++
++  if (err)
++    return err;
++
++  net_ip.is_ip6 = is_ip6;
++  if (is_ip6)
++    grub_memcpy (&net_ip.ip6, &ip6, sizeof(net_ip.ip6));
++  else
++    grub_memcpy (&net_ip.ip4, &ip4, sizeof(net_ip.ip4));
++
++  if (!grub_efi_net_create_interface (dev,
++		args[0],
++		&net_ip,
++		cidr))
++    return grub_errno;
++
++  return GRUB_ERR_NONE;
++}
++
++static struct grub_fs grub_efi_netfs;
++
++static grub_net_t
++grub_net_open_real (const char *name __attribute__ ((unused)))
++{
++  grub_size_t protnamelen;
++  const char *protname, *server;
++  grub_net_t ret;
++
++  net_interface = NULL;
++
++  if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
++    {
++      protname = "tftp";
++      protnamelen = sizeof ("tftp") - 1;
++      server = name + sizeof ("pxe:") - 1;
++    }
++  else if (grub_strcmp (name, "pxe") == 0)
++    {
++      protname = "tftp";
++      protnamelen = sizeof ("tftp") - 1;
++      server = default_server;
++    }
++  else
++    {
++      const char *comma;
++
++      comma = grub_strchr (name, ',');
++      if (comma)
++	{
++	  protnamelen = comma - name;
++	  server = comma + 1;
++	  protname = name;
++	}
++      else
++	{
++	  protnamelen = grub_strlen (name);
++	  server = default_server;
++	  protname = name;
++	}
++    }
++
++  if (!server)
++    {
++      grub_error (GRUB_ERR_NET_BAD_ADDRESS,
++		  N_("no server is specified"));
++      return NULL;
++    }
++
++  /*FIXME: Use DNS translate name to address */
++  net_interface = match_route (server);
++
++  /*XXX: should we check device with default gateway ? */
++  if (!net_interface && !(net_interface = net_default_interface))
++    {
++      grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"),
++		  name);
++      return NULL;
++    }
++
++  if ((protnamelen == (sizeof ("https") - 1)
++	&& grub_memcmp ("https", protname, protnamelen) == 0))
++    {
++      net_interface->io = &io_http;
++      net_interface->io_type = 1;
++    }
++  else if ((protnamelen == (sizeof ("http") - 1)
++	&& grub_memcmp ("http", protname, protnamelen) == 0))
++    {
++      net_interface->io = &io_http;
++      net_interface->io_type = 0;
++    }
++  else if (protnamelen == (sizeof ("tftp") - 1)
++	&& grub_memcmp ("tftp", protname, protnamelen) == 0)
++    {
++      net_interface->io = &io_pxe;
++      net_interface->io_type = 0;
++    }
++  else
++    {
++      grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"),
++		  name);
++      return NULL;
++    }
++
++  /*XXX: Should we try to avoid doing excess "reconfigure" here ??? */
++  efi_net_interface (configure);
++
++  ret = grub_zalloc (sizeof (*ret));
++  if (!ret)
++    return NULL;
++
++  ret->server = grub_strdup (server);
++  if (!ret->server)
++    {
++      grub_free (ret);
++      return NULL;
++    }
++
++  ret->fs = &grub_efi_netfs;
++  return ret;
++}
++#if 0
++static grub_command_t cmd_efi_lsaddr;
++static grub_command_t cmd_efi_lscards;
++static grub_command_t cmd_efi_lsroutes;
++static grub_command_t cmd_efi_addaddr;
++#endif
++
++static struct grub_fs grub_efi_netfs =
++  {
++    .name = "efi netfs",
++    .dir = grub_efi_netfs_dir,
++    .open = grub_efi_netfs_open,
++    .read = grub_efi_netfs_read,
++    .close = grub_efi_netfs_close,
++    .label = NULL,
++    .uuid = NULL,
++    .mtime = NULL,
++  };
++
++int
++grub_efi_net_boot_from_https (void)
++{
++  grub_efi_loaded_image_t *image = NULL;
++  grub_efi_device_path_t *dp;
++
++  image = grub_efi_get_loaded_image (grub_efi_image_handle);
++  if (!image)
++    return 0;
++
++  dp = grub_efi_get_device_path (image->device_handle);
++
++  while (1)
++    {
++      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
++      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
++      grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
++
++      if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
++	  && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
++	{
++	  grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp;
++	  return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0;
++	}
++
++      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
++        break;
++      dp = (grub_efi_device_path_t *) ((char *) dp + len);
++    }
++
++  return 0;
++}
++
++int
++grub_efi_net_boot_from_opa (void)
++{
++  grub_efi_loaded_image_t *image = NULL;
++  grub_efi_device_path_t *dp;
++
++  image = grub_efi_get_loaded_image (grub_efi_image_handle);
++  if (!image)
++    return 0;
++
++  dp = grub_efi_get_device_path (image->device_handle);
++
++  while (1)
++    {
++      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
++      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
++      grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp);
++
++      if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE)
++	  && (subtype == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE))
++	{
++	  grub_efi_mac_address_device_path_t *mac_dp  = (grub_efi_mac_address_device_path_t *)dp;
++	  return (mac_dp->if_type == 0xC7) ? 1 : 0;
++	}
++
++      if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
++        break;
++      dp = (grub_efi_device_path_t *) ((char *) dp + len);
++    }
++
++  return 0;
++}
++
++static char *
++grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
++			 const char *val __attribute__ ((unused)))
++{
++  return NULL;
++}
++
++grub_command_func_t grub_efi_net_list_routes = grub_cmd_efi_listroutes;
++grub_command_func_t grub_efi_net_list_cards = grub_cmd_efi_listcards;
++grub_command_func_t grub_efi_net_list_addrs = grub_cmd_efi_listaddrs;
++grub_command_func_t grub_efi_net_add_addr = grub_cmd_efi_addaddr;
++
++int
++grub_efi_net_fs_init ()
++{
++  grub_efi_net_find_cards ();
++  grub_efi_net_config = grub_efi_net_config_real;
++  grub_net_open = grub_net_open_real;
++  grub_register_variable_hook ("net_default_server", grub_efi_net_var_get_server,
++			       grub_efi_net_var_set_server);
++  grub_env_export ("net_default_server");
++  grub_register_variable_hook ("pxe_default_server", grub_efi_net_var_get_server,
++			       grub_efi_net_var_set_server);
++  grub_env_export ("pxe_default_server");
++  grub_register_variable_hook ("net_default_interface", 0,
++			       grub_efi_net_var_set_interface);
++  grub_env_export ("net_default_interface");
++  grub_register_variable_hook ("net_default_ip", grub_efi_net_var_get_ip,
++			       0);
++  grub_env_export ("net_default_ip");
++  grub_register_variable_hook ("net_default_mac", grub_efi_net_var_get_mac,
++			       0);
++  grub_env_export ("net_default_mac");
++
++  grub_env_set ("grub_netfs_type", "efi");
++  grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly);
++  grub_env_export ("grub_netfs_type");
++
++  return 1;
++}
++
++void
++grub_efi_net_fs_fini (void)
++{
++  grub_env_unset ("grub_netfs_type");
++  grub_efi_net_unset_interface_vars ();
++  grub_register_variable_hook ("net_default_server", 0, 0);
++  grub_env_unset ("net_default_server");
++  grub_register_variable_hook ("net_default_interface", 0, 0);
++  grub_env_unset ("net_default_interface");
++  grub_register_variable_hook ("pxe_default_server", 0, 0);
++  grub_env_unset ("pxe_default_server");
++  grub_register_variable_hook ("net_default_ip", 0, 0);
++  grub_env_unset ("net_default_ip");
++  grub_register_variable_hook ("net_default_mac", 0, 0);
++  grub_env_unset ("net_default_mac");
++  grub_efi_net_config = NULL;
++  grub_net_open = NULL;
++  grub_fs_unregister (&grub_efi_netfs);
++}
+diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c
+new file mode 100644
+index 00000000000..531949cba5c
+--- /dev/null
++++ b/grub-core/net/efi/pxe.c
+@@ -0,0 +1,424 @@
++
++#include <grub/efi/api.h>
++#include <grub/efi/efi.h>
++#include <grub/misc.h>
++#include <grub/net/efi.h>
++#include <grub/charset.h>
++
++static grub_efi_ip6_config_manual_address_t *
++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip6_config_manual_address_t *manual_address;
++
++  sz = sizeof (*manual_address);
++  manual_address = grub_malloc (sz);
++  if (!manual_address)
++    return NULL;
++
++  status = efi_call_4 (ip6_config->get_data, ip6_config,
++		    GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
++		    &sz, manual_address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (manual_address);
++      return NULL;
++    }
++
++  return manual_address;
++}
++
++static grub_efi_ip4_config2_manual_address_t *
++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config)
++{
++  grub_efi_uintn_t sz;
++  grub_efi_status_t status;
++  grub_efi_ip4_config2_manual_address_t *manual_address;
++
++  sz = sizeof (*manual_address);
++  manual_address = grub_malloc (sz);
++  if (!manual_address)
++    return NULL;
++
++  status = efi_call_4 (ip4_config->get_data, ip4_config,
++		    GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
++		    &sz, manual_address);
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      grub_free (manual_address);
++      return NULL;
++    }
++
++  return manual_address;
++}
++
++static void
++pxe_configure (struct grub_efi_net_device *dev, int prefer_ip6)
++{
++  grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
++
++  grub_efi_pxe_mode_t *mode = pxe->mode;
++
++  if (!mode->started)
++    {
++      grub_efi_status_t status;
++      status = efi_call_2 (pxe->start, pxe, prefer_ip6);
++
++      if (status != GRUB_EFI_SUCCESS)
++	  grub_printf ("Couldn't start PXE\n");
++    }
++
++#if 0
++  grub_printf ("PXE STARTED: %u\n", mode->started);
++  grub_printf ("PXE USING IPV6: %u\n", mode->using_ipv6);
++#endif
++
++  if (mode->using_ipv6)
++    {
++      grub_efi_ip6_config_manual_address_t *manual_address;
++      manual_address = efi_ip6_config_manual_address (dev->ip6_config);
++
++      if (manual_address &&
++	  grub_memcmp (manual_address->address, mode->station_ip.v6, sizeof (manual_address->address)) != 0)
++	{
++	  grub_efi_status_t status;
++	  grub_efi_pxe_ip_address_t station_ip;
++
++	  grub_memcpy (station_ip.v6.addr, manual_address->address, sizeof (station_ip.v6.addr));
++	  status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, NULL);
++
++	  if (status != GRUB_EFI_SUCCESS)
++	      grub_printf ("Couldn't set station ip\n");
++
++	  grub_free (manual_address);
++	}
++    }
++  else
++    {
++      grub_efi_ip4_config2_manual_address_t *manual_address;
++      manual_address = efi_ip4_config_manual_address (dev->ip4_config);
++
++      if (manual_address &&
++	  grub_memcmp (manual_address->address, mode->station_ip.v4, sizeof (manual_address->address)) != 0)
++	{
++	  grub_efi_status_t status;
++	  grub_efi_pxe_ip_address_t station_ip;
++	  grub_efi_pxe_ip_address_t subnet_mask;
++
++	  grub_memcpy (station_ip.v4.addr, manual_address->address, sizeof (station_ip.v4.addr));
++	  grub_memcpy (subnet_mask.v4.addr, manual_address->subnet_mask, sizeof (subnet_mask.v4.addr));
++
++	  status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, &subnet_mask);
++
++	  if (status != GRUB_EFI_SUCCESS)
++	      grub_printf ("Couldn't set station ip\n");
++
++	  grub_free (manual_address);
++	}
++    }
++
++#if 0
++  if (mode->using_ipv6)
++    {
++      grub_printf ("PXE STATION IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
++	mode->station_ip.v6.addr[0],
++	mode->station_ip.v6.addr[1],
++	mode->station_ip.v6.addr[2],
++	mode->station_ip.v6.addr[3],
++	mode->station_ip.v6.addr[4],
++	mode->station_ip.v6.addr[5],
++	mode->station_ip.v6.addr[6],
++	mode->station_ip.v6.addr[7],
++	mode->station_ip.v6.addr[8],
++	mode->station_ip.v6.addr[9],
++	mode->station_ip.v6.addr[10],
++	mode->station_ip.v6.addr[11],
++	mode->station_ip.v6.addr[12],
++	mode->station_ip.v6.addr[13],
++	mode->station_ip.v6.addr[14],
++	mode->station_ip.v6.addr[15]);
++    }
++  else
++    {
++      grub_printf ("PXE STATION IP: %d.%d.%d.%d\n",
++	mode->station_ip.v4.addr[0],
++	mode->station_ip.v4.addr[1],
++	mode->station_ip.v4.addr[2],
++	mode->station_ip.v4.addr[3]);
++      grub_printf ("PXE SUBNET MASK: %d.%d.%d.%d\n",
++	mode->subnet_mask.v4.addr[0],
++	mode->subnet_mask.v4.addr[1],
++	mode->subnet_mask.v4.addr[2],
++	mode->subnet_mask.v4.addr[3]);
++    }
++#endif
++
++  /* TODO: Set The Station IP to the IP2 Config */
++}
++
++static int
++parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
++{
++  grub_uint16_t newip[8];
++  const char *ptr = val;
++  int word, quaddot = -1;
++  int bracketed = 0;
++
++  if (ptr[0] == '[') {
++    bracketed = 1;
++    ptr++;
++  }
++
++  if (ptr[0] == ':' && ptr[1] != ':')
++    return 0;
++  if (ptr[0] == ':')
++    ptr++;
++
++  for (word = 0; word < 8; word++)
++    {
++      unsigned long t;
++      if (*ptr == ':')
++	{
++	  quaddot = word;
++	  word--;
++	  ptr++;
++	  continue;
++	}
++      t = grub_strtoul (ptr, (char **) &ptr, 16);
++      if (grub_errno)
++	{
++	  grub_errno = GRUB_ERR_NONE;
++	  break;
++	}
++      if (t & ~0xffff)
++	return 0;
++      newip[word] = grub_cpu_to_be16 (t);
++      if (*ptr != ':')
++	break;
++      ptr++;
++    }
++  if (quaddot == -1 && word < 7)
++    return 0;
++  if (quaddot != -1)
++    {
++      grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
++		    (word - quaddot + 1) * sizeof (newip[0]));
++      grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
++    }
++  grub_memcpy (ip, newip, 16);
++  if (bracketed && *ptr == ']') {
++    ptr++;
++  }
++  if (rest)
++    *rest = ptr;
++  return 1;
++}
++
++static grub_err_t
++pxe_open (struct grub_efi_net_device *dev,
++	  int prefer_ip6,
++	  grub_file_t file,
++	  const char *filename,
++	  int type __attribute__((unused)))
++{
++  int i;
++  char *p;
++  grub_efi_status_t status;
++  grub_efi_pxe_ip_address_t server_ip;
++  grub_efi_uint64_t file_size = 0;
++  grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
++
++  if (pxe->mode->using_ipv6)
++    {
++      const char *rest;
++      grub_uint64_t ip6[2];
++      if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0)
++	grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr));
++      /* TODO: ERROR Handling Here */
++#if 0
++      grub_printf ("PXE SERVER IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n",
++	server_ip.v6.addr[0],
++	server_ip.v6.addr[1],
++	server_ip.v6.addr[2],
++	server_ip.v6.addr[3],
++	server_ip.v6.addr[4],
++	server_ip.v6.addr[5],
++	server_ip.v6.addr[6],
++	server_ip.v6.addr[7],
++	server_ip.v6.addr[8],
++	server_ip.v6.addr[9],
++	server_ip.v6.addr[10],
++	server_ip.v6.addr[11],
++	server_ip.v6.addr[12],
++	server_ip.v6.addr[13],
++	server_ip.v6.addr[14],
++	server_ip.v6.addr[15]);
++#endif
++    }
++  else
++    {
++      for (i = 0, p = file->device->net->server; i < 4; ++i, ++p)
++	server_ip.v4.addr[i] = grub_strtoul (p, &p, 10);
++    }
++
++  status = efi_call_10 (pxe->mtftp,
++	    pxe,
++	    GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
++	    NULL,
++	    0,
++	    &file_size,
++	    NULL,
++	    &server_ip,
++	    (grub_efi_char8_t *)filename,
++	    NULL,
++	    0);
++
++  if (status != GRUB_EFI_SUCCESS)
++    return grub_error (GRUB_ERR_IO, "Couldn't get file size");
++
++  file->size = (grub_off_t)file_size;
++  file->not_easily_seekable = 0;
++  file->data = 0;
++  file->device->net->offset = 0;
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++pxe_close (struct grub_efi_net_device *dev __attribute__((unused)),
++	  int prefer_ip6 __attribute__((unused)),
++	  grub_file_t file __attribute__((unused)))
++{
++  file->offset = 0;
++  file->size = 0;
++  file->device->net->offset = 0;
++
++  if (file->data)
++    {
++      grub_free (file->data);
++      file->data = NULL;
++    }
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_ssize_t
++pxe_read (struct grub_efi_net_device *dev,
++	  int prefer_ip6,
++	  grub_file_t file,
++	  char *buf,
++	  grub_size_t len)
++{
++  int i;
++  char *p;
++  grub_efi_status_t status;
++  grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
++  grub_efi_uint64_t bufsz = len;
++  grub_efi_pxe_ip_address_t server_ip;
++  char *buf2 = NULL;
++
++  if (file->data)
++    {
++      /* TODO: RANGE Check for offset and file size */
++      grub_memcpy (buf, (char*)file->data + file->device->net->offset, len);
++      file->device->net->offset += len;
++      return len;
++    }
++
++  if (file->device->net->offset)
++    {
++      grub_error (GRUB_ERR_BUG, "No Offet Read Possible");
++      grub_print_error ();
++      return 0;
++    }
++
++  if (pxe->mode->using_ipv6)
++    {
++      const char *rest;
++      grub_uint64_t ip6[2];
++      if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0)
++	grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr));
++      /* TODO: ERROR Handling Here */
++    }
++  else
++    {
++      for (i = 0, p = file->device->net->server; i < 4; ++i, ++p)
++	server_ip.v4.addr[i] = grub_strtoul (p, &p, 10);
++    }
++
++  status = efi_call_10 (pxe->mtftp,
++	    pxe,
++	    GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
++	    buf,
++	    0,
++	    &bufsz,
++	    NULL,
++	    &server_ip,
++	    (grub_efi_char8_t *)file->device->net->name,
++	    NULL,
++	    0);
++
++  if (bufsz != file->size)
++    {
++      grub_error (GRUB_ERR_BUG, "Short read should not happen here");
++      grub_print_error ();
++      return 0;
++    }
++
++  if (status == GRUB_EFI_BUFFER_TOO_SMALL)
++    {
++
++      buf2 = grub_malloc (bufsz);
++
++      if (!buf2)
++	{
++	  grub_error (GRUB_ERR_OUT_OF_MEMORY, "ERROR OUT OF MEMORY");
++	  grub_print_error ();
++	  return 0;
++	}
++
++      status = efi_call_10 (pxe->mtftp,
++		pxe,
++		GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
++		buf2,
++		0,
++		&bufsz,
++		NULL,
++		&server_ip,
++		(grub_efi_char8_t *)file->device->net->name,
++		NULL,
++		0);
++    }
++
++  if (status != GRUB_EFI_SUCCESS)
++    {
++      if (buf2)
++	grub_free (buf2);
++
++      grub_error (GRUB_ERR_IO, "Failed to Read File");
++      grub_print_error ();
++      return 0;
++    }
++
++  if (buf2)
++    grub_memcpy (buf, buf2, len);
++
++  file->device->net->offset = len;
++
++  if (buf2)
++    file->data = buf2;
++
++  return len;
++}
++
++struct grub_efi_net_io io_pxe =
++  {
++    .configure = pxe_configure,
++    .open = pxe_open,
++    .read = pxe_read,
++    .close = pxe_close
++  };
++
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index 191e8e41bd6..a571ee92efa 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -32,6 +32,9 @@
+ #include <grub/loader.h>
+ #include <grub/bufio.h>
+ #include <grub/kernel.h>
++#ifdef GRUB_MACHINE_EFI
++#include <grub/net/efi.h>
++#endif
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -2025,8 +2028,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
+ static grub_command_t cmd_lsroutes, cmd_lscards;
+ static grub_command_t cmd_lsaddr, cmd_slaac;
+ 
++#ifdef GRUB_MACHINE_EFI
++
++static enum {
++  INIT_MODE_NONE,
++  INIT_MODE_GRUB,
++  INIT_MODE_EFI
++} init_mode;
++
++static grub_command_t cmd_bootp, cmd_bootp6;
++
++#endif
++
+ GRUB_MOD_INIT(net)
+ {
++#ifdef GRUB_MACHINE_EFI
++  if (grub_net_open)
++    return;
++
++  if ((grub_efi_net_boot_from_https () || grub_efi_net_boot_from_opa ())
++      && grub_efi_net_fs_init ())
++    {
++      cmd_lsroutes = grub_register_command ("net_ls_routes", grub_efi_net_list_routes,
++					    "", N_("list network routes"));
++      cmd_lscards = grub_register_command ("net_ls_cards", grub_efi_net_list_cards,
++					   "", N_("list network cards"));
++      cmd_lsaddr = grub_register_command ("net_ls_addr", grub_efi_net_list_addrs,
++					  "", N_("list network addresses"));
++      cmd_addaddr = grub_register_command ("net_add_addr", grub_efi_net_add_addr,
++					    /* TRANSLATORS: HWADDRESS stands for
++					       "hardware address".  */
++					  N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
++					  N_("Add a network address."));
++      cmd_bootp = grub_register_command ("net_bootp", grub_efi_net_bootp,
++					 N_("[CARD]"),
++					 N_("perform a bootp autoconfiguration"));
++      cmd_bootp6 = grub_register_command ("net_bootp6", grub_efi_net_bootp6,
++					 N_("[CARD]"),
++					 N_("perform a bootp autoconfiguration"));
++      init_mode = INIT_MODE_EFI;
++      return;
++    }
++#endif
++
+   grub_register_variable_hook ("net_default_server", defserver_get_env,
+ 			       defserver_set_env);
+   grub_env_export ("net_default_server");
+@@ -2074,10 +2118,37 @@ GRUB_MOD_INIT(net)
+ 						grub_net_restore_hw,
+ 						GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
+   grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
++
++#ifdef GRUB_MACHINE_EFI
++  grub_env_set ("grub_netfs_type", "grub");
++  grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly);
++  grub_env_export ("grub_netfs_type");
++  init_mode = INIT_MODE_GRUB;
++#endif
++
+ }
+ 
+ GRUB_MOD_FINI(net)
+ {
++
++#ifdef GRUB_MACHINE_EFI
++  if (init_mode == INIT_MODE_NONE)
++    return;
++
++  if (init_mode == INIT_MODE_EFI)
++    {
++      grub_unregister_command (cmd_lsroutes);
++      grub_unregister_command (cmd_lscards);
++      grub_unregister_command (cmd_lsaddr);
++      grub_unregister_command (cmd_addaddr);
++      grub_unregister_command (cmd_bootp);
++      grub_unregister_command (cmd_bootp6);
++      grub_efi_net_fs_fini ();
++      init_mode = INIT_MODE_NONE;
++      return;
++    }
++#endif
++
+   grub_register_variable_hook ("net_default_server", 0, 0);
+   grub_register_variable_hook ("pxe_default_server", 0, 0);
+ 
+@@ -2096,4 +2167,7 @@ GRUB_MOD_FINI(net)
+   grub_net_fini_hw (0);
+   grub_loader_unregister_preboot_hook (fini_hnd);
+   grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
++#ifdef GRUB_MACHINE_EFI
++  init_mode = INIT_MODE_NONE;
++#endif
+ }
+diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c
+index 82073d5cc94..ae31271bbc0 100644
+--- a/util/grub-mknetdir.c
++++ b/util/grub-mknetdir.c
+@@ -32,13 +32,15 @@
+ 
+ static char *rootdir = NULL, *subdir = NULL;
+ static char *debug_image = NULL;
++static char efi_netfs = 0;
+ 
+ enum
+   {
+     OPTION_NET_DIRECTORY = 0x301,
+     OPTION_SUBDIR,
+     OPTION_DEBUG,
+-    OPTION_DEBUG_IMAGE
++    OPTION_DEBUG_IMAGE,
++    OPTION_DEBUG_EFI_NETFS
+   };
+ 
+ static struct argp_option options[] = {
+@@ -49,6 +51,7 @@ static struct argp_option options[] = {
+    0, N_("relative subdirectory on network server"), 2},
+   {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2},
+   {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2},
++  {"debug-efi-netfs", OPTION_DEBUG_EFI_NETFS, 0, OPTION_HIDDEN, 0, 2},
+   {0, 0, 0, 0, 0, 0}
+ };
+ 
+@@ -67,6 +70,9 @@ argp_parser (int key, char *arg, struct argp_state *state)
+       free (subdir);
+       subdir = xstrdup (arg);
+       return 0;
++    case OPTION_DEBUG_EFI_NETFS:
++      efi_netfs = 1;
++      return 0;
+       /* This is an undocumented feature...  */
+     case OPTION_DEBUG:
+       verbosity++;
+@@ -82,7 +88,6 @@ argp_parser (int key, char *arg, struct argp_state *state)
+     }
+ }
+ 
+-
+ struct argp argp = {
+   options, argp_parser, NULL,
+   "\v"N_("Prepares GRUB network boot images at net_directory/subdir "
+@@ -92,7 +97,7 @@ struct argp argp = {
+ 
+ static char *base;
+ 
+-static const struct
++static struct
+ {
+   const char *mkimage_target;
+   const char *netmodule;
+@@ -154,6 +159,7 @@ process_input_dir (const char *input_dir, enum grub_install_plat platform)
+   grub_install_push_module (targets[platform].netmodule);
+ 
+   output = grub_util_path_concat_ext (2, grubdir, "core", targets[platform].ext);
++
+   grub_install_make_image_wrap (input_dir, prefix, output,
+ 				0, load_cfg,
+ 				targets[platform].mkimage_target, 0);
+@@ -190,7 +196,16 @@ main (int argc, char *argv[])
+ 
+   grub_install_mkdir_p (base);
+ 
+-  grub_install_push_module ("tftp");
++  if (!efi_netfs)
++    {
++      grub_install_push_module ("tftp");
++      grub_install_push_module ("http");
++    }
++  else
++    {
++      targets[GRUB_INSTALL_PLATFORM_I386_EFI].netmodule = "efi_netfs";
++      targets[GRUB_INSTALL_PLATFORM_X86_64_EFI].netmodule = "efi_netfs";
++    }
+ 
+   if (!grub_install_source_directory)
+     {
+diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
+index dd3b07eac97..b337e1a193d 100644
+--- a/include/grub/efi/api.h
++++ b/include/grub/efi/api.h
+@@ -602,6 +602,23 @@ typedef union
+ 
+ typedef grub_efi_uint64_t grub_efi_physical_address_t;
+ typedef grub_efi_uint64_t grub_efi_virtual_address_t;
++typedef struct {
++  grub_uint8_t addr[4];
++} grub_efi_pxe_ipv4_address_t;
++
++typedef struct {
++  grub_uint8_t addr[16];
++} grub_efi_pxe_ipv6_address_t;
++
++typedef struct {
++  grub_uint8_t addr[32];
++} grub_efi_pxe_mac_address_t;
++
++typedef union {
++    grub_uint32_t addr[4];
++    grub_efi_pxe_ipv4_address_t v4;
++    grub_efi_pxe_ipv6_address_t v6;
++} grub_efi_pxe_ip_address_t;
+ 
+ struct grub_efi_guid
+ {
+@@ -865,6 +882,8 @@ struct grub_efi_ipv6_device_path
+   grub_efi_uint16_t remote_port;
+   grub_efi_uint16_t protocol;
+   grub_efi_uint8_t static_ip_address;
++  grub_efi_uint8_t prefix_length;
++  grub_efi_ipv6_address_t gateway_ip_address;
+ } GRUB_PACKED;
+ typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t;
+ 
+@@ -914,6 +933,15 @@ struct grub_efi_uri_device_path
+ } GRUB_PACKED;
+ typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t;
+ 
++#define GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE                31
++struct grub_efi_dns_device_path
++{
++  grub_efi_device_path_t header;
++  grub_efi_uint8_t is_ipv6;
++  grub_efi_pxe_ip_address_t dns_server_ip[0];
++} GRUB_PACKED;
++typedef struct grub_efi_dns_device_path grub_efi_dns_device_path_t;
++
+ #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE	10
+ 
+ /* Media Device Path.  */
+@@ -996,6 +1024,23 @@ struct grub_efi_bios_device_path
+ } GRUB_PACKED;
+ typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t;
+ 
++/* Service Binding definitions */
++struct grub_efi_service_binding;
++
++typedef grub_efi_status_t
++(*grub_efi_service_binding_create_child) (struct grub_efi_service_binding *this,
++                                          grub_efi_handle_t *child_handle);
++
++typedef grub_efi_status_t
++(*grub_efi_service_binding_destroy_child) (struct grub_efi_service_binding *this,
++                                           grub_efi_handle_t *child_handle);
++
++typedef struct grub_efi_service_binding
++{
++  grub_efi_service_binding_create_child create_child;
++  grub_efi_service_binding_destroy_child destroy_child;
++} grub_efi_service_binding_t;
++
+ struct grub_efi_open_protocol_information_entry
+ {
+   grub_efi_handle_t agent_handle;
+@@ -1545,23 +1590,27 @@ typedef struct grub_efi_pxe_tftp_error
+   grub_efi_char8_t error_string[127];
+ } grub_efi_pxe_tftp_error_t;
+ 
+-typedef struct {
+-  grub_uint8_t addr[4];
+-} grub_efi_pxe_ipv4_address_t;
++typedef grub_efi_uint16_t grub_efi_pxe_base_code_udp_port_t;
+ 
+-typedef struct {
+-  grub_uint8_t addr[16];
+-} grub_efi_pxe_ipv6_address_t;
++typedef enum {
++  GRUB_EFI_PXE_BASE_CODE_TFTP_FIRST,
++  GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
++  GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE,
++  GRUB_EFI_PXE_BASE_CODE_TFTP_WRITE_FILE,
++  GRUB_EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY,
++  GRUB_EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE,
++  GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_FILE,
++  GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY,
++  GRUB_EFI_PXE_BASE_CODE_MTFTP_LAST
++} grub_efi_pxe_base_code_tftp_opcode_t;
+ 
+ typedef struct {
+-  grub_uint8_t addr[32];
+-} grub_efi_pxe_mac_address_t;
+-
+-typedef union {
+-  grub_uint32_t addr[4];
+-  grub_efi_pxe_ipv4_address_t v4;
+-  grub_efi_pxe_ipv6_address_t v6;
+-} grub_efi_pxe_ip_address_t;
++  grub_efi_ip_address_t mcast_ip;
++  grub_efi_pxe_base_code_udp_port_t c_port;
++  grub_efi_pxe_base_code_udp_port_t s_port;
++  grub_efi_uint16_t listen_timeout;
++  grub_efi_uint16_t transmit_timeout;
++} grub_efi_pxe_base_code_mtftp_info_t;
+ 
+ #define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8
+ typedef struct grub_efi_pxe_ip_filter
+@@ -1628,17 +1677,31 @@ typedef struct grub_efi_pxe_mode
+ typedef struct grub_efi_pxe
+ {
+   grub_uint64_t rev;
+-  void (*start) (void);
++  grub_efi_status_t (*start) (struct grub_efi_pxe *this, grub_efi_boolean_t use_ipv6);
+   void (*stop) (void);
+-  void (*dhcp) (void);
++  grub_efi_status_t (*dhcp) (struct grub_efi_pxe *this,
++			    grub_efi_boolean_t sort_offers);
+   void (*discover) (void);
+-  void (*mftp) (void);
++  grub_efi_status_t (*mtftp) (struct grub_efi_pxe *this,
++			    grub_efi_pxe_base_code_tftp_opcode_t operation,
++			    void *buffer_ptr,
++			    grub_efi_boolean_t overwrite,
++			    grub_efi_uint64_t *buffer_size,
++			    grub_efi_uintn_t *block_size,
++			    grub_efi_pxe_ip_address_t *server_ip,
++			    //grub_efi_ip_address_t *server_ip,
++			    grub_efi_char8_t *filename,
++			    grub_efi_pxe_base_code_mtftp_info_t *info,
++			    grub_efi_boolean_t dont_use_buffer);
+   void (*udpwrite) (void);
+   void (*udpread) (void);
+   void (*setipfilter) (void);
+   void (*arp) (void);
+   void (*setparams) (void);
+-  void (*setstationip) (void);
++  grub_efi_status_t (*set_station_ip) (struct grub_efi_pxe *this,
++			    grub_efi_pxe_ip_address_t *new_station_ip,
++			    grub_efi_pxe_ip_address_t *new_subnet_mask);
++  //void (*setstationip) (void);
+   void (*setpackets) (void);
+   struct grub_efi_pxe_mode *mode;
+ } grub_efi_pxe_t;
+@@ -1880,6 +1943,44 @@ struct grub_efi_ip4_config2_protocol
+ };
+ typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t;
+ 
++struct grub_efi_ip4_route_table {
++  grub_efi_ipv4_address_t subnet_address;
++  grub_efi_ipv4_address_t subnet_mask;
++  grub_efi_ipv4_address_t gateway_address;
++};
++
++typedef struct grub_efi_ip4_route_table grub_efi_ip4_route_table_t;
++
++#define GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32
++
++struct grub_efi_ip4_config2_interface_info {
++  grub_efi_char16_t name[GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE];
++  grub_efi_uint8_t if_type;
++  grub_efi_uint32_t hw_address_size;
++  grub_efi_mac_address_t hw_address;
++  grub_efi_ipv4_address_t station_address;
++  grub_efi_ipv4_address_t subnet_mask;
++  grub_efi_uint32_t route_table_size;
++  grub_efi_ip4_route_table_t *route_table;
++};
++
++typedef struct grub_efi_ip4_config2_interface_info grub_efi_ip4_config2_interface_info_t;
++
++enum grub_efi_ip4_config2_policy {
++  GRUB_EFI_IP4_CONFIG2_POLICY_STATIC,
++  GRUB_EFI_IP4_CONFIG2_POLICY_DHCP,
++  GRUB_EFI_IP4_CONFIG2_POLICY_MAX
++};
++
++typedef enum grub_efi_ip4_config2_policy grub_efi_ip4_config2_policy_t;
++
++struct grub_efi_ip4_config2_manual_address {
++  grub_efi_ipv4_address_t address;
++  grub_efi_ipv4_address_t subnet_mask;
++};
++
++typedef struct grub_efi_ip4_config2_manual_address grub_efi_ip4_config2_manual_address_t;
++
+ enum grub_efi_ip6_config_data_type {
+   GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
+   GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID,
+@@ -1914,6 +2015,49 @@ struct grub_efi_ip6_config_protocol
+ };
+ typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t;
+ 
++enum grub_efi_ip6_config_policy {
++  GRUB_EFI_IP6_CONFIG_POLICY_MANUAL,
++  GRUB_EFI_IP6_CONFIG_POLICY_AUTOMATIC
++};
++typedef enum grub_efi_ip6_config_policy grub_efi_ip6_config_policy_t;
++
++struct grub_efi_ip6_address_info {
++  grub_efi_ipv6_address_t address;
++  grub_efi_uint8_t prefix_length;
++};
++typedef struct grub_efi_ip6_address_info grub_efi_ip6_address_info_t;
++
++struct grub_efi_ip6_route_table {
++  grub_efi_pxe_ipv6_address_t gateway;
++  grub_efi_pxe_ipv6_address_t destination;
++  grub_efi_uint8_t prefix_length;
++};
++typedef struct grub_efi_ip6_route_table grub_efi_ip6_route_table_t;
++
++struct grub_efi_ip6_config_interface_info {
++  grub_efi_char16_t name[32];
++  grub_efi_uint8_t if_type;
++  grub_efi_uint32_t hw_address_size;
++  grub_efi_mac_address_t hw_address;
++  grub_efi_uint32_t address_info_count;
++  grub_efi_ip6_address_info_t *address_info;
++  grub_efi_uint32_t route_count;
++  grub_efi_ip6_route_table_t *route_table;
++};
++typedef struct grub_efi_ip6_config_interface_info grub_efi_ip6_config_interface_info_t;
++
++struct grub_efi_ip6_config_dup_addr_detect_transmits {
++  grub_efi_uint32_t dup_addr_detect_transmits;
++};
++typedef struct grub_efi_ip6_config_dup_addr_detect_transmits grub_efi_ip6_config_dup_addr_detect_transmits_t;
++
++struct grub_efi_ip6_config_manual_address {
++  grub_efi_ipv6_address_t address;
++  grub_efi_boolean_t is_anycast;
++  grub_efi_uint8_t prefix_length;
++};
++typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t;
++
+ #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
+   || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__)
+ 
+diff --git a/include/grub/efi/dhcp.h b/include/grub/efi/dhcp.h
+new file mode 100644
+index 00000000000..fdb88eb810e
+--- /dev/null
++++ b/include/grub/efi/dhcp.h
+@@ -0,0 +1,343 @@
++#ifndef GRUB_EFI_DHCP_HEADER
++#define GRUB_EFI_DHCP_HEADER	1
++
++#define GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \
++  { 0x9d9a39d8, 0xbd42, 0x4a73, \
++    { 0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80 } \
++  }
++
++#define GRUB_EFI_DHCP4_PROTOCOL_GUID \
++  { 0x8a219718, 0x4ef5, 0x4761, \
++    { 0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56 } \
++  }
++
++#define GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \
++  { 0x9fb9a8a1, 0x2f4a, 0x43a6, \
++    { 0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4 ,0x7a, 0xd5 } \
++  }
++
++#define GRUB_EFI_DHCP6_PROTOCOL_GUID \
++  { 0x87c8bad7, 0x595, 0x4053, \
++    { 0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \
++  }
++
++typedef struct grub_efi_dhcp4_protocol grub_efi_dhcp4_protocol_t;
++
++enum grub_efi_dhcp4_state {
++  GRUB_EFI_DHCP4_STOPPED,
++  GRUB_EFI_DHCP4_INIT,
++  GRUB_EFI_DHCP4_SELECTING,
++  GRUB_EFI_DHCP4_REQUESTING,
++  GRUB_EFI_DHCP4_BOUND,
++  GRUB_EFI_DHCP4_RENEWING,
++  GRUB_EFI_DHCP4_REBINDING,
++  GRUB_EFI_DHCP4_INIT_REBOOT,
++  GRUB_EFI_DHCP4_REBOOTING
++};
++
++typedef enum grub_efi_dhcp4_state grub_efi_dhcp4_state_t;
++
++struct grub_efi_dhcp4_header {
++  grub_efi_uint8_t op_code;
++  grub_efi_uint8_t hw_type;
++  grub_efi_uint8_t hw_addr_len;
++  grub_efi_uint8_t hops;
++  grub_efi_uint32_t xid;
++  grub_efi_uint16_t seconds;
++  grub_efi_uint16_t reserved;
++  grub_efi_ipv4_address_t client_addr;
++  grub_efi_ipv4_address_t your_addr;
++  grub_efi_ipv4_address_t server_addr;
++  grub_efi_ipv4_address_t gateway_addr;
++  grub_efi_uint8_t client_hw_addr[16];
++  grub_efi_char8_t server_name[64];
++  grub_efi_char8_t boot_file_name[128];
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp4_header grub_efi_dhcp4_header_t;
++
++struct grub_efi_dhcp4_packet {
++  grub_efi_uint32_t size;
++  grub_efi_uint32_t length;
++  struct {
++    grub_efi_dhcp4_header_t header;
++    grub_efi_uint32_t magik;
++    grub_efi_uint8_t option[1];
++  } dhcp4;
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp4_packet grub_efi_dhcp4_packet_t;
++
++struct grub_efi_dhcp4_listen_point {
++  grub_efi_ipv4_address_t listen_address;
++  grub_efi_ipv4_address_t subnet_mask;
++  grub_efi_uint16_t listen_port;
++};
++
++typedef struct grub_efi_dhcp4_listen_point grub_efi_dhcp4_listen_point_t;
++
++struct grub_efi_dhcp4_transmit_receive_token {
++  grub_efi_status_t status;
++  grub_efi_event_t completion_event;
++  grub_efi_ipv4_address_t remote_address;
++  grub_efi_uint16_t remote_port;
++  grub_efi_ipv4_address_t gateway_address;
++  grub_efi_uint32_t listen_point_count;
++  grub_efi_dhcp4_listen_point_t *listen_points;
++  grub_efi_uint32_t timeout_value;
++  grub_efi_dhcp4_packet_t *packet;
++  grub_efi_uint32_t response_count;
++  grub_efi_dhcp4_packet_t *response_list;
++};
++
++typedef struct grub_efi_dhcp4_transmit_receive_token grub_efi_dhcp4_transmit_receive_token_t;
++
++enum grub_efi_dhcp4_event {
++  GRUB_EFI_DHCP4_SEND_DISCOVER = 0X01,
++  GRUB_EFI_DHCP4_RCVD_OFFER,
++  GRUB_EFI_DHCP4_SELECT_OFFER,
++  GRUB_EFI_DHCP4_SEND_REQUEST,
++  GRUB_EFI_DHCP4_RCVD_ACK,
++  GRUB_EFI_DHCP4_RCVD_NAK,
++  GRUB_EFI_DHCP4_SEND_DECLINE,
++  GRUB_EFI_DHCP4_BOUND_COMPLETED,
++  GRUB_EFI_DHCP4_ENTER_RENEWING,
++  GRUB_EFI_DHCP4_ENTER_REBINDING,
++  GRUB_EFI_DHCP4_ADDRESS_LOST,
++  GRUB_EFI_DHCP4_FAIL
++};
++
++typedef enum grub_efi_dhcp4_event grub_efi_dhcp4_event_t;
++
++struct grub_efi_dhcp4_packet_option {
++  grub_efi_uint8_t op_code;
++  grub_efi_uint8_t length;
++  grub_efi_uint8_t data[1];
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp4_packet_option grub_efi_dhcp4_packet_option_t;
++
++struct grub_efi_dhcp4_config_data {
++  grub_efi_uint32_t discover_try_count;
++  grub_efi_uint32_t *discover_timeout;
++  grub_efi_uint32_t request_try_count;
++  grub_efi_uint32_t *request_timeout;
++  grub_efi_ipv4_address_t client_address;
++  grub_efi_status_t (*dhcp4_callback) (
++    grub_efi_dhcp4_protocol_t *this,
++    void *context,
++    grub_efi_dhcp4_state_t current_state,
++    grub_efi_dhcp4_event_t dhcp4_event,
++    grub_efi_dhcp4_packet_t *packet,
++    grub_efi_dhcp4_packet_t **new_packet
++  );
++  void *callback_context;
++  grub_efi_uint32_t option_count;
++  grub_efi_dhcp4_packet_option_t **option_list;
++};
++
++typedef struct grub_efi_dhcp4_config_data grub_efi_dhcp4_config_data_t;
++
++struct grub_efi_dhcp4_mode_data {
++  grub_efi_dhcp4_state_t state;
++  grub_efi_dhcp4_config_data_t config_data;
++  grub_efi_ipv4_address_t client_address;
++  grub_efi_mac_address_t client_mac_address;
++  grub_efi_ipv4_address_t server_address;
++  grub_efi_ipv4_address_t router_address;
++  grub_efi_ipv4_address_t subnet_mask;
++  grub_efi_uint32_t lease_time;
++  grub_efi_dhcp4_packet_t *reply_packet;
++};
++
++typedef struct grub_efi_dhcp4_mode_data grub_efi_dhcp4_mode_data_t;
++
++struct grub_efi_dhcp4_protocol {
++  grub_efi_status_t (*get_mode_data) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_dhcp4_mode_data_t *dhcp4_mode_data);
++  grub_efi_status_t (*configure) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_dhcp4_config_data_t *dhcp4_cfg_data);
++  grub_efi_status_t (*start) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_event_t completion_event);
++  grub_efi_status_t (*renew_rebind) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_boolean_t rebind_request,
++	      grub_efi_event_t completion_event);
++  grub_efi_status_t (*release) (grub_efi_dhcp4_protocol_t *this);
++  grub_efi_status_t (*stop) (grub_efi_dhcp4_protocol_t *this);
++  grub_efi_status_t (*build) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_dhcp4_packet_t *seed_packet,
++	      grub_efi_uint32_t delete_count,
++	      grub_efi_uint8_t *delete_list,
++	      grub_efi_uint32_t append_count,
++	      grub_efi_dhcp4_packet_option_t *append_list[],
++	      grub_efi_dhcp4_packet_t **new_packet);
++  grub_efi_status_t (*transmit_receive) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_dhcp4_transmit_receive_token_t *token);
++  grub_efi_status_t (*parse) (grub_efi_dhcp4_protocol_t *this,
++	      grub_efi_dhcp4_packet_t *packet,
++	      grub_efi_uint32_t *option_count,
++	      grub_efi_dhcp4_packet_option_t *packet_option_list[]);
++};
++
++typedef struct grub_efi_dhcp6_protocol grub_efi_dhcp6_protocol_t;
++
++struct grub_efi_dhcp6_retransmission {
++  grub_efi_uint32_t irt;
++  grub_efi_uint32_t mrc;
++  grub_efi_uint32_t mrt;
++  grub_efi_uint32_t mrd;
++};
++
++typedef struct grub_efi_dhcp6_retransmission grub_efi_dhcp6_retransmission_t;
++
++enum grub_efi_dhcp6_event {
++  GRUB_EFI_DHCP6_SEND_SOLICIT,
++  GRUB_EFI_DHCP6_RCVD_ADVERTISE,
++  GRUB_EFI_DHCP6_SELECT_ADVERTISE,
++  GRUB_EFI_DHCP6_SEND_REQUEST,
++  GRUB_EFI_DHCP6_RCVD_REPLY,
++  GRUB_EFI_DHCP6_RCVD_RECONFIGURE,
++  GRUB_EFI_DHCP6_SEND_DECLINE,
++  GRUB_EFI_DHCP6_SEND_CONFIRM,
++  GRUB_EFI_DHCP6_SEND_RELEASE,
++  GRUB_EFI_DHCP6_SEND_RENEW,
++  GRUB_EFI_DHCP6_SEND_REBIND
++};
++
++typedef enum grub_efi_dhcp6_event grub_efi_dhcp6_event_t;
++
++struct grub_efi_dhcp6_packet_option {
++  grub_efi_uint16_t op_code;
++  grub_efi_uint16_t op_len;
++  grub_efi_uint8_t data[1];
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp6_packet_option grub_efi_dhcp6_packet_option_t;
++
++struct grub_efi_dhcp6_header {
++  grub_efi_uint32_t transaction_id:24;
++  grub_efi_uint32_t message_type:8;
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp6_header grub_efi_dhcp6_header_t;
++
++struct grub_efi_dhcp6_packet {
++  grub_efi_uint32_t size;
++  grub_efi_uint32_t length;
++  struct {
++    grub_efi_dhcp6_header_t header;
++    grub_efi_uint8_t option[1];
++  } dhcp6;
++} GRUB_PACKED;
++
++typedef struct grub_efi_dhcp6_packet grub_efi_dhcp6_packet_t;
++
++struct grub_efi_dhcp6_ia_address {
++  grub_efi_ipv6_address_t ip_address;
++  grub_efi_uint32_t preferred_lifetime;
++  grub_efi_uint32_t valid_lifetime;
++};
++
++typedef struct grub_efi_dhcp6_ia_address grub_efi_dhcp6_ia_address_t;
++
++enum grub_efi_dhcp6_state {
++  GRUB_EFI_DHCP6_INIT,
++  GRUB_EFI_DHCP6_SELECTING,
++  GRUB_EFI_DHCP6_REQUESTING,
++  GRUB_EFI_DHCP6_DECLINING,
++  GRUB_EFI_DHCP6_CONFIRMING,
++  GRUB_EFI_DHCP6_RELEASING,
++  GRUB_EFI_DHCP6_BOUND,
++  GRUB_EFI_DHCP6_RENEWING,
++  GRUB_EFI_DHCP6_REBINDING
++};
++
++typedef enum grub_efi_dhcp6_state grub_efi_dhcp6_state_t;
++
++#define GRUB_EFI_DHCP6_IA_TYPE_NA 3
++#define GRUB_EFI_DHCP6_IA_TYPE_TA 4
++
++struct grub_efi_dhcp6_ia_descriptor {
++  grub_efi_uint16_t type;
++  grub_efi_uint32_t ia_id;
++};
++
++typedef struct grub_efi_dhcp6_ia_descriptor grub_efi_dhcp6_ia_descriptor_t;
++
++struct grub_efi_dhcp6_ia {
++  grub_efi_dhcp6_ia_descriptor_t descriptor;
++  grub_efi_dhcp6_state_t state;
++  grub_efi_dhcp6_packet_t *reply_packet;
++  grub_efi_uint32_t ia_address_count;
++  grub_efi_dhcp6_ia_address_t ia_address[1];
++};
++
++typedef struct grub_efi_dhcp6_ia grub_efi_dhcp6_ia_t;
++
++struct grub_efi_dhcp6_duid {
++  grub_efi_uint16_t length;
++  grub_efi_uint8_t duid[1];
++};
++
++typedef struct grub_efi_dhcp6_duid grub_efi_dhcp6_duid_t;
++
++struct grub_efi_dhcp6_mode_data {
++  grub_efi_dhcp6_duid_t *client_id;
++  grub_efi_dhcp6_ia_t *ia;
++};
++
++typedef struct grub_efi_dhcp6_mode_data grub_efi_dhcp6_mode_data_t;
++
++struct grub_efi_dhcp6_config_data {
++  grub_efi_status_t (*dhcp6_callback) (grub_efi_dhcp6_protocol_t this,
++		void *context,
++		grub_efi_dhcp6_state_t current_state,
++		grub_efi_dhcp6_event_t dhcp6_event,
++		grub_efi_dhcp6_packet_t *packet,
++		grub_efi_dhcp6_packet_t **new_packet);
++  void *callback_context;
++  grub_efi_uint32_t option_count;
++  grub_efi_dhcp6_packet_option_t **option_list;
++  grub_efi_dhcp6_ia_descriptor_t ia_descriptor;
++  grub_efi_event_t ia_info_event;
++  grub_efi_boolean_t reconfigure_accept;
++  grub_efi_boolean_t rapid_commit;
++  grub_efi_dhcp6_retransmission_t *solicit_retransmission;
++};
++
++typedef struct grub_efi_dhcp6_config_data grub_efi_dhcp6_config_data_t;
++
++struct grub_efi_dhcp6_protocol {
++  grub_efi_status_t (*get_mode_data) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_dhcp6_mode_data_t *dhcp6_mode_data,
++	    grub_efi_dhcp6_config_data_t *dhcp6_config_data);
++  grub_efi_status_t (*configure) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_dhcp6_config_data_t *dhcp6_cfg_data);
++  grub_efi_status_t (*start) (grub_efi_dhcp6_protocol_t *this);
++  grub_efi_status_t (*info_request) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_boolean_t send_client_id,
++	    grub_efi_dhcp6_packet_option_t *option_request,
++	    grub_efi_uint32_t option_count,
++	    grub_efi_dhcp6_packet_option_t *option_list[],
++	    grub_efi_dhcp6_retransmission_t *retransmission,
++	    grub_efi_event_t timeout_event,
++	    grub_efi_status_t (*reply_callback) (grub_efi_dhcp6_protocol_t *this,
++		    void *context,
++		    grub_efi_dhcp6_packet_t *packet),
++	    void *callback_context);
++  grub_efi_status_t (*renew_rebind) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_boolean_t rebind_request);
++  grub_efi_status_t (*decline) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_uint32_t address_count,
++	    grub_efi_ipv6_address_t *addresses);
++  grub_efi_status_t (*release) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_uint32_t address_count,
++	    grub_efi_ipv6_address_t *addresses);
++  grub_efi_status_t (*stop) (grub_efi_dhcp6_protocol_t *this);
++  grub_efi_status_t (*parse) (grub_efi_dhcp6_protocol_t *this,
++	    grub_efi_dhcp6_packet_t *packet,
++	    grub_efi_uint32_t *option_count,
++	    grub_efi_dhcp6_packet_option_t *packet_option_list[]);
++};
++
++#endif /* ! GRUB_EFI_DHCP_HEADER */
+diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h
+new file mode 100644
+index 00000000000..c5e9a89f505
+--- /dev/null
++++ b/include/grub/efi/http.h
+@@ -0,0 +1,215 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2006,2007,2008  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_EFI_HTTP_HEADER
++#define GRUB_EFI_HTTP_HEADER	1
++
++#include <grub/symbol.h>
++#include <grub/net.h>
++#include <grub/efi/api.h>
++
++#define GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \
++  { 0xbdc8e6af, 0xd9bc, 0x4379, \
++      { 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \
++  }
++
++#define GRUB_EFI_HTTP_PROTOCOL_GUID \
++  { 0x7A59B29B, 0x910B, 0x4171, \
++      { 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B } \
++  }
++
++#define EFIHTTP_WAIT_TIME 10000 // 10000ms = 10s
++#define EFIHTTP_RX_BUF_LEN 10240
++
++//******************************************
++// Protocol Interface Structure
++//******************************************
++struct grub_efi_http;
++
++//******************************************
++// EFI_HTTP_VERSION
++//******************************************
++typedef enum {
++  GRUB_EFI_HTTPVERSION10,
++  GRUB_EFI_HTTPVERSION11,
++  GRUB_EFI_HTTPVERSIONUNSUPPORTED
++} grub_efi_http_version_t;
++
++//******************************************
++// EFI_HTTPv4_ACCESS_POINT
++//******************************************
++typedef struct {
++  grub_efi_boolean_t use_default_address;
++  grub_efi_ipv4_address_t local_address;
++  grub_efi_ipv4_address_t local_subnet;
++  grub_efi_uint16_t local_port;
++} grub_efi_httpv4_access_point_t;
++
++//******************************************
++// EFI_HTTPv6_ACCESS_POINT
++//******************************************
++typedef struct {
++  grub_efi_ipv6_address_t local_address;
++  grub_efi_uint16_t local_port;
++} grub_efi_httpv6_access_point_t;
++
++//******************************************
++// EFI_HTTP_CONFIG_DATA
++//******************************************
++typedef struct {
++  grub_efi_http_version_t http_version;
++  grub_efi_uint32_t timeout_millisec;
++  grub_efi_boolean_t local_address_is_ipv6;
++  union {
++    grub_efi_httpv4_access_point_t *ipv4_node;
++    grub_efi_httpv6_access_point_t *ipv6_node;
++  } access_point;
++} grub_efi_http_config_data_t;
++
++//******************************************
++// EFI_HTTP_METHOD
++//******************************************
++typedef enum {
++  GRUB_EFI_HTTPMETHODGET,
++  GRUB_EFI_HTTPMETHODPOST,
++  GRUB_EFI_HTTPMETHODPATCH,
++  GRUB_EFI_HTTPMETHODOPTIONS,
++  GRUB_EFI_HTTPMETHODCONNECT,
++  GRUB_EFI_HTTPMETHODHEAD,
++  GRUB_EFI_HTTPMETHODPUT,
++  GRUB_EFI_HTTPMETHODDELETE,
++  GRUB_EFI_HTTPMETHODTRACE,
++} grub_efi_http_method_t;
++
++//******************************************
++// EFI_HTTP_REQUEST_DATA
++//******************************************
++typedef struct {
++  grub_efi_http_method_t method;
++  grub_efi_char16_t *url;
++} grub_efi_http_request_data_t;
++
++typedef enum {
++  GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0,
++  GRUB_EFI_HTTP_STATUS_100_CONTINUE,
++  GRUB_EFI_HTTP_STATUS_101_SWITCHING_PROTOCOLS,
++  GRUB_EFI_HTTP_STATUS_200_OK,
++  GRUB_EFI_HTTP_STATUS_201_CREATED,
++  GRUB_EFI_HTTP_STATUS_202_ACCEPTED,
++  GRUB_EFI_HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION,
++  GRUB_EFI_HTTP_STATUS_204_NO_CONTENT,
++  GRUB_EFI_HTTP_STATUS_205_RESET_CONTENT,
++  GRUB_EFI_HTTP_STATUS_206_PARTIAL_CONTENT,
++  GRUB_EFI_HTTP_STATUS_300_MULTIPLE_CHIOCES,
++  GRUB_EFI_HTTP_STATUS_301_MOVED_PERMANENTLY,
++  GRUB_EFI_HTTP_STATUS_302_FOUND,
++  GRUB_EFI_HTTP_STATUS_303_SEE_OTHER,
++  GRUB_EFI_HTTP_STATUS_304_NOT_MODIFIED,
++  GRUB_EFI_HTTP_STATUS_305_USE_PROXY,
++  GRUB_EFI_HTTP_STATUS_307_TEMPORARY_REDIRECT,
++  GRUB_EFI_HTTP_STATUS_400_BAD_REQUEST,
++  GRUB_EFI_HTTP_STATUS_401_UNAUTHORIZED,
++  GRUB_EFI_HTTP_STATUS_402_PAYMENT_REQUIRED,
++  GRUB_EFI_HTTP_STATUS_403_FORBIDDEN,
++  GRUB_EFI_HTTP_STATUS_404_NOT_FOUND,
++  GRUB_EFI_HTTP_STATUS_405_METHOD_NOT_ALLOWED,
++  GRUB_EFI_HTTP_STATUS_406_NOT_ACCEPTABLE,
++  GRUB_EFI_HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED,
++  GRUB_EFI_HTTP_STATUS_408_REQUEST_TIME_OUT,
++  GRUB_EFI_HTTP_STATUS_409_CONFLICT,
++  GRUB_EFI_HTTP_STATUS_410_GONE,
++  GRUB_EFI_HTTP_STATUS_411_LENGTH_REQUIRED,
++  GRUB_EFI_HTTP_STATUS_412_PRECONDITION_FAILED,
++  GRUB_EFI_HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE,
++  GRUB_EFI_HTTP_STATUS_414_REQUEST_URI_TOO_LARGE,
++  GRUB_EFI_HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE,
++  GRUB_EFI_HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED,
++  GRUB_EFI_HTTP_STATUS_417_EXPECTATION_FAILED,
++  GRUB_EFI_HTTP_STATUS_500_INTERNAL_SERVER_ERROR,
++  GRUB_EFI_HTTP_STATUS_501_NOT_IMPLEMENTED,
++  GRUB_EFI_HTTP_STATUS_502_BAD_GATEWAY,
++  GRUB_EFI_HTTP_STATUS_503_SERVICE_UNAVAILABLE,
++  GRUB_EFI_HTTP_STATUS_504_GATEWAY_TIME_OUT,
++  GRUB_EFI_HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED
++} grub_efi_http_status_code_t;
++
++//******************************************
++// EFI_HTTP_RESPONSE_DATA
++//******************************************
++typedef struct {
++  grub_efi_http_status_code_t status_code;
++} grub_efi_http_response_data_t;
++
++//******************************************
++// EFI_HTTP_HEADER
++//******************************************
++typedef struct {
++  grub_efi_char8_t *field_name;
++  grub_efi_char8_t *field_value;
++} grub_efi_http_header_t;
++
++//******************************************
++// EFI_HTTP_MESSAGE
++//******************************************
++typedef struct {
++  union {
++    grub_efi_http_request_data_t *request;
++    grub_efi_http_response_data_t *response;
++  } data;
++  grub_efi_uint32_t header_count;
++  grub_efi_http_header_t *headers;
++  grub_efi_uint32_t body_length;
++  void *body;
++} grub_efi_http_message_t;
++
++//******************************************
++// EFI_HTTP_TOKEN
++//******************************************
++typedef struct {
++  grub_efi_event_t event;
++  grub_efi_status_t status;
++  grub_efi_http_message_t *message;
++} grub_efi_http_token_t;
++
++struct grub_efi_http {
++  grub_efi_status_t
++  (*get_mode_data) (struct grub_efi_http *this,
++                    grub_efi_http_config_data_t *http_config_data);
++
++  grub_efi_status_t
++  (*configure) (struct grub_efi_http *this,
++                grub_efi_http_config_data_t *http_config_data);
++
++  grub_efi_status_t
++  (*request) (struct grub_efi_http *this,
++              grub_efi_http_token_t *token);
++
++  grub_efi_status_t
++  (*cancel) (struct grub_efi_http *this,
++             grub_efi_http_token_t *token);
++
++  grub_efi_status_t
++  (*response) (struct grub_efi_http *this,
++               grub_efi_http_token_t *token);
++
++  grub_efi_status_t
++  (*poll) (struct grub_efi_http *this);
++};
++typedef struct grub_efi_http grub_efi_http_t;
++
++#endif /* !GRUB_EFI_HTTP_HEADER */
+diff --git a/include/grub/net/efi.h b/include/grub/net/efi.h
+new file mode 100644
+index 00000000000..de90d223e8e
+--- /dev/null
++++ b/include/grub/net/efi.h
+@@ -0,0 +1,144 @@
++#ifndef GRUB_NET_EFI_HEADER
++#define GRUB_NET_EFI_HEADER	1
++
++#include <grub/efi/api.h>
++#include <grub/efi/http.h>
++#include <grub/efi/dhcp.h>
++#include <grub/command.h>
++
++typedef struct grub_efi_net_interface grub_efi_net_interface_t;
++typedef struct grub_efi_net_ip_config grub_efi_net_ip_config_t;
++typedef union grub_efi_net_ip_address grub_efi_net_ip_address_t;
++typedef struct grub_efi_net_ip_manual_address grub_efi_net_ip_manual_address_t;
++
++struct grub_efi_net_interface
++{
++  char *name;
++  int prefer_ip6;
++  struct grub_efi_net_device *dev;
++  struct grub_efi_net_io *io;
++  grub_efi_net_ip_config_t *ip_config;
++  int io_type;
++  struct grub_efi_net_interface *next;
++};
++
++#define efi_net_interface_get_hw_address(inf) inf->ip_config->get_hw_address (inf->dev)
++#define efi_net_interface_get_address(inf) inf->ip_config->get_address (inf->dev)
++#define efi_net_interface_get_route_table(inf) inf->ip_config->get_route_table (inf->dev)
++#define efi_net_interface_set_address(inf, addr, with_subnet) inf->ip_config->set_address (inf->dev, addr, with_subnet)
++#define efi_net_interface_set_gateway(inf, addr) inf->ip_config->set_gateway (inf->dev, addr)
++#define efi_net_interface_set_dns(inf, addr) inf->ip_config->set_dns (inf->dev, addr)
++
++struct grub_efi_net_ip_config
++{
++  char * (*get_hw_address) (struct grub_efi_net_device *dev);
++  char * (*get_address) (struct grub_efi_net_device *dev);
++  char ** (*get_route_table) (struct grub_efi_net_device *dev);
++  grub_efi_net_interface_t * (*best_interface) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address);
++  int (*set_address) (struct grub_efi_net_device *dev, grub_efi_net_ip_manual_address_t *net_ip, int with_subnet);
++  int (*set_gateway) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address);
++  int (*set_dns) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *dns);
++};
++
++union grub_efi_net_ip_address
++{
++  grub_efi_ipv4_address_t ip4;
++  grub_efi_ipv6_address_t ip6;
++};
++
++struct grub_efi_net_ip_manual_address
++{
++  int is_ip6;
++  union
++  {
++    grub_efi_ip4_config2_manual_address_t ip4;
++    grub_efi_ip6_config_manual_address_t ip6;
++  };
++};
++
++struct grub_efi_net_device
++{
++  grub_efi_handle_t handle;
++  grub_efi_ip4_config2_protocol_t *ip4_config;
++  grub_efi_ip6_config_protocol_t *ip6_config;
++  grub_efi_handle_t http_handle;
++  grub_efi_http_t *http;
++  grub_efi_handle_t ip4_pxe_handle;
++  grub_efi_pxe_t *ip4_pxe;
++  grub_efi_handle_t ip6_pxe_handle;
++  grub_efi_pxe_t *ip6_pxe;
++  grub_efi_handle_t dhcp4_handle;
++  grub_efi_dhcp4_protocol_t *dhcp4;
++  grub_efi_handle_t dhcp6_handle;
++  grub_efi_dhcp6_protocol_t *dhcp6;
++  char *card_name;
++  grub_efi_net_interface_t *net_interfaces;
++  struct grub_efi_net_device *next;
++};
++
++struct grub_efi_net_io
++{
++  void (*configure) (struct grub_efi_net_device *dev, int prefer_ip6);
++  grub_err_t (*open) (struct grub_efi_net_device *dev,
++		    int prefer_ip6,
++		    grub_file_t file,
++		    const char *filename,
++		    int type);
++  grub_ssize_t (*read) (struct grub_efi_net_device *dev,
++			int prefer_ip6,
++			grub_file_t file,
++			char *buf,
++			grub_size_t len);
++  grub_err_t (*close) (struct grub_efi_net_device *dev,
++		      int prefer_ip6,
++		      grub_file_t file);
++};
++
++extern struct grub_efi_net_device *net_devices;
++
++extern struct grub_efi_net_io io_http;
++extern struct grub_efi_net_io io_pxe;
++
++extern grub_efi_net_ip_config_t *efi_net_ip4_config;
++extern grub_efi_net_ip_config_t *efi_net_ip6_config;
++
++char *
++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address);
++
++char *
++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address);
++
++char *
++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address);
++
++int
++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest);
++
++int
++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest);
++
++char *
++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev);
++
++char *
++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev);
++
++grub_efi_net_interface_t *
++grub_efi_net_create_interface (struct grub_efi_net_device *dev,
++		const char *interface_name,
++		grub_efi_net_ip_manual_address_t *net_ip,
++		int has_subnet);
++
++int grub_efi_net_fs_init (void);
++void grub_efi_net_fs_fini (void);
++int grub_efi_net_boot_from_https (void);
++int grub_efi_net_boot_from_opa (void);
++
++extern grub_command_func_t grub_efi_net_list_routes;
++extern grub_command_func_t grub_efi_net_list_cards;
++extern grub_command_func_t grub_efi_net_list_addrs;
++extern grub_command_func_t grub_efi_net_add_addr;
++extern grub_command_func_t grub_efi_net_bootp;
++extern grub_command_func_t grub_efi_net_bootp6;
++
++#endif /* ! GRUB_NET_EFI_HEADER */
diff --git a/SOURCES/0179-AUDIT-0-http-boot-tracker-bug.patch b/SOURCES/0179-AUDIT-0-http-boot-tracker-bug.patch
new file mode 100644
index 0000000..3d8d96b
--- /dev/null
+++ b/SOURCES/0179-AUDIT-0-http-boot-tracker-bug.patch
@@ -0,0 +1,62 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Sebastian Krahmer <krahmer@suse.com>
+Date: Tue, 28 Nov 2017 17:24:38 +0800
+Subject: [PATCH] AUDIT-0: http boot tracker bug
+
+Fixing a memory leak in case of error, and a integer overflow, leading to a
+heap overflow due to overly large chunk sizes.
+
+We need to check against some maximum value, otherwise values like 0xffffffff
+will eventually lead in the allocation functions to small sized buffers, since
+the len is rounded up to the next reasonable alignment. The following memcpy
+will then smash the heap, leading to RCE.
+
+This is no big issue for pure http boot, since its going to execute an
+untrusted kernel anyway, but it will break trusted boot scenarios, where only
+signed code is allowed to be executed.
+
+Signed-off-by: Michael Chang <mchang@suse.com>
+---
+ grub-core/net/efi/net.c | 4 +++-
+ grub-core/net/http.c    | 5 ++++-
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
+index 9e0078ac1c6..2bf15447fd5 100644
+--- a/grub-core/net/efi/net.c
++++ b/grub-core/net/efi/net.c
+@@ -645,8 +645,10 @@ grub_efihttp_chunk_read (grub_file_t file, char *buf,
+ 
+       rd = efi_net_interface (read, file, chunk, sz);
+ 
+-      if (rd <= 0)
++      if (rd <= 0) {
++	grub_free (chunk);
+ 	return rd;
++      }
+ 
+       if (buf)
+ 	{
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index 00737c52750..c9c59690a98 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -31,7 +31,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+ enum
+   {
+-    HTTP_PORT = 80
++    HTTP_PORT = 80,
++    HTTP_MAX_CHUNK_SIZE = 0x80000000
+   };
+ 
+ 
+@@ -78,6 +79,8 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
+   if (data->in_chunk_len == 2)
+     {
+       data->chunk_rem = grub_strtoul (ptr, 0, 16);
++      if (data->chunk_rem > HTTP_MAX_CHUNK_SIZE)
++	  return GRUB_ERR_NET_PACKET_TOO_BIG;
+       grub_errno = GRUB_ERR_NONE;
+       if (data->chunk_rem == 0)
+ 	{
diff --git a/SOURCES/0180-grub-core-video-efi_gop.c-Add-support-for-BLT_ONLY-a.patch b/SOURCES/0180-grub-core-video-efi_gop.c-Add-support-for-BLT_ONLY-a.patch
new file mode 100644
index 0000000..33cde3b
--- /dev/null
+++ b/SOURCES/0180-grub-core-video-efi_gop.c-Add-support-for-BLT_ONLY-a.patch
@@ -0,0 +1,56 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Alexander Graf <agraf@suse.de>
+Date: Wed, 1 Feb 2017 23:10:45 +0100
+Subject: [PATCH] grub-core/video/efi_gop.c: Add support for BLT_ONLY adapters
+
+EFI GOP has support for multiple different bitness types of frame buffers
+and for a special "BLT only" type which is always defined to be RGBx.
+
+Because grub2 doesn't ever directly access the frame buffer but instead
+only renders graphics via the BLT interface anyway, we can easily support
+these adapters.
+
+The reason this has come up now is the emerging support for virtio-gpu
+in OVMF. That adapter does not have the notion of a memory mapped frame
+buffer and thus is BLT only.
+
+Signed-off-by: Alexander Graf <agraf@suse.de>
+---
+ grub-core/video/efi_gop.c          | 2 ++
+ include/grub/efi/graphics_output.h | 3 ++-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c
+index 7f9d1c2dfa1..c9e40e8d4e9 100644
+--- a/grub-core/video/efi_gop.c
++++ b/grub-core/video/efi_gop.c
+@@ -121,6 +121,7 @@ grub_video_gop_get_bpp (struct grub_efi_gop_mode_info *in)
+     {
+     case GRUB_EFI_GOT_BGRA8:
+     case GRUB_EFI_GOT_RGBA8:
++    case GRUB_EFI_GOT_BLT_ONLY:
+       return 32;
+ 
+     case GRUB_EFI_GOT_BITMASK:
+@@ -187,6 +188,7 @@ grub_video_gop_fill_real_mode_info (unsigned mode,
+   switch (in->pixel_format)
+     {
+     case GRUB_EFI_GOT_RGBA8:
++    case GRUB_EFI_GOT_BLT_ONLY:
+       out->red_mask_size = 8;
+       out->red_field_pos = 0;
+       out->green_mask_size = 8;
+diff --git a/include/grub/efi/graphics_output.h b/include/grub/efi/graphics_output.h
+index 12977741192..e4388127c66 100644
+--- a/include/grub/efi/graphics_output.h
++++ b/include/grub/efi/graphics_output.h
+@@ -28,7 +28,8 @@ typedef enum
+   {
+     GRUB_EFI_GOT_RGBA8,
+     GRUB_EFI_GOT_BGRA8,
+-    GRUB_EFI_GOT_BITMASK
++    GRUB_EFI_GOT_BITMASK,
++    GRUB_EFI_GOT_BLT_ONLY,
+   }
+   grub_efi_gop_pixel_format_t;
+ 
diff --git a/SOURCES/0181-efi-uga-use-64-bit-for-fb_base.patch b/SOURCES/0181-efi-uga-use-64-bit-for-fb_base.patch
new file mode 100644
index 0000000..bafcb64
--- /dev/null
+++ b/SOURCES/0181-efi-uga-use-64-bit-for-fb_base.patch
@@ -0,0 +1,105 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andrei Borzenkov <arvidjaar@gmail.com>
+Date: Wed, 16 May 2018 13:06:04 -0400
+Subject: [PATCH] efi/uga: use 64 bit for fb_base
+
+We get 64 bit from PCI BAR but then truncate by assigning to 32 bit.
+Make sure to check that pointer does not overflow on 32 bit platform.
+
+Closes: 50931
+---
+ grub-core/video/efi_uga.c | 31 ++++++++++++++++---------------
+ 1 file changed, 16 insertions(+), 15 deletions(-)
+
+diff --git a/grub-core/video/efi_uga.c b/grub-core/video/efi_uga.c
+index 044af1d20d3..97a607c01a5 100644
+--- a/grub-core/video/efi_uga.c
++++ b/grub-core/video/efi_uga.c
+@@ -34,7 +34,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+ static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID;
+ static struct grub_efi_uga_draw_protocol *uga;
+-static grub_uint32_t uga_fb;
++static grub_uint64_t uga_fb;
+ static grub_uint32_t uga_pitch;
+ 
+ static struct
+@@ -52,7 +52,7 @@ static struct
+ #define FBTEST_COUNT	8
+ 
+ static int
+-find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len)
++find_line_len (grub_uint64_t *fb_base, grub_uint32_t *line_len)
+ {
+   grub_uint32_t *base = (grub_uint32_t *) (grub_addr_t) *fb_base;
+   int i;
+@@ -67,7 +67,7 @@ find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len)
+ 	    {
+ 	      if ((base[j] & RGB_MASK) == RGB_MAGIC)
+ 		{
+-		  *fb_base = (grub_uint32_t) (grub_addr_t) base;
++		  *fb_base = (grub_uint64_t) (grub_addr_t) base;
+ 		  *line_len = j << 2;
+ 
+ 		  return 1;
+@@ -84,7 +84,7 @@ find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len)
+ /* Context for find_framebuf.  */
+ struct find_framebuf_ctx
+ {
+-  grub_uint32_t *fb_base;
++  grub_uint64_t *fb_base;
+   grub_uint32_t *line_len;
+   int found;
+ };
+@@ -129,7 +129,9 @@ find_card (grub_pci_device_t dev, grub_pci_id_t pciid, void *data)
+ 	      if (i == 5)
+ 		break;
+ 
+-	      old_bar2 = grub_pci_read (addr + 4);
++	      i++;
++	      addr += 4;
++	      old_bar2 = grub_pci_read (addr);
+ 	    }
+ 	  else
+ 	    old_bar2 = 0;
+@@ -138,10 +140,15 @@ find_card (grub_pci_device_t dev, grub_pci_id_t pciid, void *data)
+ 	  base64 <<= 32;
+ 	  base64 |= (old_bar1 & GRUB_PCI_ADDR_MEM_MASK);
+ 
+-	  grub_dprintf ("fb", "%s(%d): 0x%llx\n",
++	  grub_dprintf ("fb", "%s(%d): 0x%" PRIxGRUB_UINT64_T "\n",
+ 			((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) ?
+-			"VMEM" : "MMIO"), i,
+-		       (unsigned long long) base64);
++			"VMEM" : "MMIO"), type == GRUB_PCI_ADDR_MEM_TYPE_64 ? i - 1 : i,
++			base64);
++
++#if GRUB_CPU_SIZEOF_VOID_P == 4
++	  if (old_bar2)
++	    continue;
++#endif
+ 
+ 	  if ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) && (! ctx->found))
+ 	    {
+@@ -149,12 +156,6 @@ find_card (grub_pci_device_t dev, grub_pci_id_t pciid, void *data)
+ 	      if (find_line_len (ctx->fb_base, ctx->line_len))
+ 		ctx->found++;
+ 	    }
+-
+-	  if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
+-	    {
+-	      i++;
+-	      addr += 4;
+-	    }
+ 	}
+     }
+ 
+@@ -162,7 +163,7 @@ find_card (grub_pci_device_t dev, grub_pci_id_t pciid, void *data)
+ }
+ 
+ static int
+-find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len)
++find_framebuf (grub_uint64_t *fb_base, grub_uint32_t *line_len)
+ {
+   struct find_framebuf_ctx ctx = {
+     .fb_base = fb_base,
diff --git a/SOURCES/0182-EFI-console-Do-not-set-text-mode-until-we-actually-n.patch b/SOURCES/0182-EFI-console-Do-not-set-text-mode-until-we-actually-n.patch
new file mode 100644
index 0000000..20aadf6
--- /dev/null
+++ b/SOURCES/0182-EFI-console-Do-not-set-text-mode-until-we-actually-n.patch
@@ -0,0 +1,184 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 6 Mar 2018 17:11:15 +0100
+Subject: [PATCH] EFI: console: Do not set text-mode until we actually need it
+
+If we're running with a hidden menu we may never need text mode, so do not
+change the video-mode to text until we actually need it.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ grub-core/term/efi/console.c | 65 ++++++++++++++++++++++++++++++--------------
+ 1 file changed, 44 insertions(+), 21 deletions(-)
+
+diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
+index 4840cc59d3f..051633d71e9 100644
+--- a/grub-core/term/efi/console.c
++++ b/grub-core/term/efi/console.c
+@@ -24,6 +24,11 @@
+ #include <grub/efi/api.h>
+ #include <grub/efi/console.h>
+ 
++static grub_err_t grub_prepare_for_text_output(struct grub_term_output *term);
++
++static int text_mode_available = -1;
++static int text_colorstate = -1;
++
+ static grub_uint32_t
+ map_char (grub_uint32_t c)
+ {
+@@ -66,14 +71,14 @@ map_char (grub_uint32_t c)
+ }
+ 
+ static void
+-grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)),
++grub_console_putchar (struct grub_term_output *term,
+ 		      const struct grub_unicode_glyph *c)
+ {
+   grub_efi_char16_t str[2 + 30];
+   grub_efi_simple_text_output_interface_t *o;
+   unsigned i, j;
+ 
+-  if (grub_efi_is_finished)
++  if (grub_prepare_for_text_output (term))
+     return;
+ 
+   o = grub_efi_system_table->con_out;
+@@ -223,14 +228,15 @@ grub_console_getkey (struct grub_term_input *term)
+ }
+ 
+ static struct grub_term_coordinate
+-grub_console_getwh (struct grub_term_output *term __attribute__ ((unused)))
++grub_console_getwh (struct grub_term_output *term)
+ {
+   grub_efi_simple_text_output_interface_t *o;
+   grub_efi_uintn_t columns, rows;
+ 
+   o = grub_efi_system_table->con_out;
+-  if (grub_efi_is_finished || efi_call_4 (o->query_mode, o, o->mode->mode,
+-					  &columns, &rows) != GRUB_EFI_SUCCESS)
++  if (grub_prepare_for_text_output (term) != GRUB_ERR_NONE ||
++      efi_call_4 (o->query_mode, o, o->mode->mode,
++		  &columns, &rows) != GRUB_EFI_SUCCESS)
+     {
+       /* Why does this fail?  */
+       columns = 80;
+@@ -245,7 +251,7 @@ grub_console_getxy (struct grub_term_output *term __attribute__ ((unused)))
+ {
+   grub_efi_simple_text_output_interface_t *o;
+ 
+-  if (grub_efi_is_finished)
++  if (grub_efi_is_finished || text_mode_available != 1)
+     return (struct grub_term_coordinate) { 0, 0 };
+ 
+   o = grub_efi_system_table->con_out;
+@@ -253,12 +259,12 @@ grub_console_getxy (struct grub_term_output *term __attribute__ ((unused)))
+ }
+ 
+ static void
+-grub_console_gotoxy (struct grub_term_output *term __attribute__ ((unused)),
++grub_console_gotoxy (struct grub_term_output *term,
+ 		     struct grub_term_coordinate pos)
+ {
+   grub_efi_simple_text_output_interface_t *o;
+ 
+-  if (grub_efi_is_finished)
++  if (grub_prepare_for_text_output (term))
+     return;
+ 
+   o = grub_efi_system_table->con_out;
+@@ -271,7 +277,7 @@ grub_console_cls (struct grub_term_output *term __attribute__ ((unused)))
+   grub_efi_simple_text_output_interface_t *o;
+   grub_efi_int32_t orig_attr;
+ 
+-  if (grub_efi_is_finished)
++  if (grub_efi_is_finished || text_mode_available != 1)
+     return;
+ 
+   o = grub_efi_system_table->con_out;
+@@ -291,6 +297,12 @@ grub_console_setcolorstate (struct grub_term_output *term
+   if (grub_efi_is_finished)
+     return;
+ 
++  if (text_mode_available != 1) {
++    /* Avoid "color_normal" environment writes causing a switch to textmode */
++    text_colorstate = state;
++    return;
++  }
++
+   o = grub_efi_system_table->con_out;
+ 
+   switch (state) {
+@@ -315,7 +327,7 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)),
+ {
+   grub_efi_simple_text_output_interface_t *o;
+ 
+-  if (grub_efi_is_finished)
++  if (grub_efi_is_finished || text_mode_available != 1)
+     return;
+ 
+   o = grub_efi_system_table->con_out;
+@@ -323,18 +335,38 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)),
+ }
+ 
+ static grub_err_t
+-grub_efi_console_output_init (struct grub_term_output *term)
++grub_prepare_for_text_output(struct grub_term_output *term)
+ {
+-  grub_efi_set_text_mode (1);
++  if (grub_efi_is_finished)
++    return GRUB_ERR_BAD_DEVICE;
++
++  if (text_mode_available != -1)
++    return text_mode_available ? 0 : GRUB_ERR_BAD_DEVICE;
++
++  if (! grub_efi_set_text_mode (1))
++    {
++      /* This really should never happen */
++      grub_error (GRUB_ERR_BAD_DEVICE, "cannot set text mode");
++      text_mode_available = 0;
++      return GRUB_ERR_BAD_DEVICE;
++    }
++
+   grub_console_setcursor (term, 1);
++  if (text_colorstate != -1)
++    grub_console_setcolorstate (term, text_colorstate);
++  text_mode_available = 1;
+   return 0;
+ }
+ 
+ static grub_err_t
+ grub_efi_console_output_fini (struct grub_term_output *term)
+ {
++  if (text_mode_available != 1)
++    return 0;
++
+   grub_console_setcursor (term, 0);
+   grub_efi_set_text_mode (0);
++  text_mode_available = -1;
+   return 0;
+ }
+ 
+@@ -348,7 +380,6 @@ static struct grub_term_input grub_console_term_input =
+ static struct grub_term_output grub_console_term_output =
+   {
+     .name = "console",
+-    .init = grub_efi_console_output_init,
+     .fini = grub_efi_console_output_fini,
+     .putchar = grub_console_putchar,
+     .getwh = grub_console_getwh,
+@@ -364,14 +395,6 @@ static struct grub_term_output grub_console_term_output =
+ 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_error (GRUB_ERR_BAD_DEVICE, "cannot set text mode");
+-      return;
+-    }
+-
+   grub_term_register_output ("console", &grub_console_term_output);
+   grub_term_register_input ("console", &grub_console_term_input);
+ }
diff --git a/SOURCES/0183-EFI-console-Add-grub_console_read_key_stroke-helper-.patch b/SOURCES/0183-EFI-console-Add-grub_console_read_key_stroke-helper-.patch
new file mode 100644
index 0000000..6da36b2
--- /dev/null
+++ b/SOURCES/0183-EFI-console-Add-grub_console_read_key_stroke-helper-.patch
@@ -0,0 +1,102 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 6 Jun 2018 15:54:44 +0200
+Subject: [PATCH] EFI: console: Add grub_console_read_key_stroke() helper
+ function
+
+This is a preparation patch for adding getkeystatus() support to the
+EFI console terminal input driver.
+
+We can get modifier status through the simple_text_input read_key_stroke
+method, but if a non-modifier key is (also) pressed the read_key_stroke
+call will consume that key from the firmware's queue.
+
+The new grub_console_read_key_stroke() helper buffers upto 1 key-stroke.
+If it has a non-modifier key buffered, it will return that one, if its
+buffer is empty, it will fills its buffer by getting a new key-stroke.
+
+If called with consume=1 it will empty its buffer after copying the
+key-data to the callers buffer, this is how getkey() will use it.
+
+If called with consume=0 it will keep the last key-stroke buffered, this
+is how getkeystatus() will call it. This means that if a non-modifier
+key gets pressed, repeated getkeystatus() calls will return the modifiers
+of that key-press until it is consumed by a getkey() call.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ grub-core/term/efi/console.c | 51 ++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 40 insertions(+), 11 deletions(-)
+
+diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
+index 051633d71e9..3d36c5c701b 100644
+--- a/grub-core/term/efi/console.c
++++ b/grub-core/term/efi/console.c
+@@ -157,27 +157,56 @@ grub_console_getkey_con (struct grub_term_input *term __attribute__ ((unused)))
+   return grub_efi_translate_key(key);
+ }
+ 
++/*
++ * When more then just modifiers are pressed, our getkeystatus() consumes a
++ * press from the queue, this function buffers the press for the regular
++ * getkey() so that it does not get lost.
++ */
++static int
++grub_console_read_key_stroke (
++                   grub_efi_simple_text_input_ex_interface_t *text_input,
++                   grub_efi_key_data_t *key_data_ret, int *key_ret,
++                   int consume)
++{
++  static grub_efi_key_data_t key_data;
++  grub_efi_status_t status;
++  int key;
++
++  if (!text_input)
++    return GRUB_ERR_EOF;
++
++  key = grub_efi_translate_key (key_data.key);
++  if (key == GRUB_TERM_NO_KEY) {
++    status = efi_call_2 (text_input->read_key_stroke, text_input, &key_data);
++    if (status != GRUB_EFI_SUCCESS)
++      return GRUB_ERR_EOF;
++
++    key = grub_efi_translate_key (key_data.key);
++  }
++
++  *key_data_ret = key_data;
++  *key_ret = key;
++
++  if (consume) {
++    key_data.key.scan_code = 0;
++    key_data.key.unicode_char = 0;
++  }
++
++  return 0;
++}
++
+ static int
+ grub_console_getkey_ex(struct grub_term_input *term)
+ {
+   grub_efi_key_data_t key_data;
+-  grub_efi_status_t status;
+   grub_efi_uint32_t kss;
+   int key = -1;
+ 
+-  grub_efi_simple_text_input_ex_interface_t *text_input = term->data;
+-
+-  status = efi_call_2 (text_input->read_key_stroke, text_input, &key_data);
+-
+-  if (status != GRUB_EFI_SUCCESS)
++  if (grub_console_read_key_stroke (term->data, &key_data, &key, 1) ||
++      key == GRUB_TERM_NO_KEY)
+     return GRUB_TERM_NO_KEY;
+ 
+   kss = key_data.key_state.key_shift_state;
+-  key = grub_efi_translate_key(key_data.key);
+-
+-  if (key == GRUB_TERM_NO_KEY)
+-    return GRUB_TERM_NO_KEY;
+-
+   if (kss & GRUB_EFI_SHIFT_STATE_VALID)
+     {
+       if ((kss & GRUB_EFI_LEFT_SHIFT_PRESSED
diff --git a/SOURCES/0184-EFI-console-Implement-getkeystatus-support.patch b/SOURCES/0184-EFI-console-Implement-getkeystatus-support.patch
new file mode 100644
index 0000000..74fa253
--- /dev/null
+++ b/SOURCES/0184-EFI-console-Implement-getkeystatus-support.patch
@@ -0,0 +1,72 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 6 Jun 2018 16:16:47 +0200
+Subject: [PATCH] EFI: console: Implement getkeystatus() support
+
+Implement getkeystatus() support.
+
+Note that if a non-modifier key gets pressed and repeated calls to
+getkeystatus() are made then it will return the modifier status at the
+time of the non-modifier key, until that key-press gets consumed by a
+getkey() call.
+
+This is a side-effect of how the EFI simple-text-input protocol works
+and cannot be avoided.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ grub-core/term/efi/console.c | 34 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 34 insertions(+)
+
+diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
+index 3d36c5c701b..92dd4996bb7 100644
+--- a/grub-core/term/efi/console.c
++++ b/grub-core/term/efi/console.c
+@@ -223,6 +223,39 @@ grub_console_getkey_ex(struct grub_term_input *term)
+   return key;
+ }
+ 
++static int
++grub_console_getkeystatus(struct grub_term_input *term)
++{
++  grub_efi_key_data_t key_data;
++  grub_efi_uint32_t kss;
++  int key, mods = 0;
++
++  if (grub_efi_is_finished)
++    return 0;
++
++  if (grub_console_read_key_stroke (term->data, &key_data, &key, 0))
++    return 0;
++
++  kss = key_data.key_state.key_shift_state;
++  if (kss & GRUB_EFI_SHIFT_STATE_VALID)
++    {
++      if (kss & GRUB_EFI_LEFT_SHIFT_PRESSED)
++        mods |= GRUB_TERM_STATUS_LSHIFT;
++      if (kss & GRUB_EFI_RIGHT_SHIFT_PRESSED)
++        mods |= GRUB_TERM_STATUS_RSHIFT;
++      if (kss & GRUB_EFI_LEFT_ALT_PRESSED)
++        mods |= GRUB_TERM_STATUS_LALT;
++      if (kss & GRUB_EFI_RIGHT_ALT_PRESSED)
++        mods |= GRUB_TERM_STATUS_RALT;
++      if (kss & GRUB_EFI_LEFT_CONTROL_PRESSED)
++        mods |= GRUB_TERM_STATUS_LCTRL;
++      if (kss & GRUB_EFI_RIGHT_CONTROL_PRESSED)
++        mods |= GRUB_TERM_STATUS_RCTRL;
++    }
++
++  return mods;
++}
++
+ static grub_err_t
+ grub_efi_console_input_init (struct grub_term_input *term)
+ {
+@@ -403,6 +436,7 @@ static struct grub_term_input grub_console_term_input =
+   {
+     .name = "console",
+     .getkey = grub_console_getkey,
++    .getkeystatus = grub_console_getkeystatus,
+     .init = grub_efi_console_input_init,
+   };
+ 
diff --git a/SOURCES/0185-Make-grub_getkeystatus-helper-funtion-available-ever.patch b/SOURCES/0185-Make-grub_getkeystatus-helper-funtion-available-ever.patch
new file mode 100644
index 0000000..9840a55
--- /dev/null
+++ b/SOURCES/0185-Make-grub_getkeystatus-helper-funtion-available-ever.patch
@@ -0,0 +1,87 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 6 Jun 2018 16:47:11 +0200
+Subject: [PATCH] Make grub_getkeystatus helper funtion available everywhere
+
+Move the grub_getkeystatus helper function from
+grub-core/commands/keystatus.c to grub-core/kern/term.c
+and export it so that it can be used outside of the
+keystatus command code too.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ grub-core/commands/keystatus.c | 18 ------------------
+ grub-core/kern/term.c          | 18 ++++++++++++++++++
+ include/grub/term.h            |  1 +
+ 3 files changed, 19 insertions(+), 18 deletions(-)
+
+diff --git a/grub-core/commands/keystatus.c b/grub-core/commands/keystatus.c
+index 460cf4e7e50..ff3f5878163 100644
+--- a/grub-core/commands/keystatus.c
++++ b/grub-core/commands/keystatus.c
+@@ -35,24 +35,6 @@ static const struct grub_arg_option options[] =
+     {0, 0, 0, 0, 0, 0}
+   };
+ 
+-static int
+-grub_getkeystatus (void)
+-{
+-  int status = 0;
+-  grub_term_input_t term;
+-
+-  if (grub_term_poll_usb)
+-    grub_term_poll_usb (0);
+-
+-  FOR_ACTIVE_TERM_INPUTS(term)
+-  {
+-    if (term->getkeystatus)
+-      status |= term->getkeystatus (term);
+-  }
+-
+-  return status;
+-}
+-
+ static grub_err_t
+ grub_cmd_keystatus (grub_extcmd_context_t ctxt,
+ 		    int argc __attribute__ ((unused)),
+diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c
+index 07720ee6746..93bd3378d18 100644
+--- a/grub-core/kern/term.c
++++ b/grub-core/kern/term.c
+@@ -120,6 +120,24 @@ grub_getkey (void)
+     }
+ }
+ 
++int
++grub_getkeystatus (void)
++{
++  int status = 0;
++  grub_term_input_t term;
++
++  if (grub_term_poll_usb)
++    grub_term_poll_usb (0);
++
++  FOR_ACTIVE_TERM_INPUTS(term)
++  {
++    if (term->getkeystatus)
++      status |= term->getkeystatus (term);
++  }
++
++  return status;
++}
++
+ void
+ grub_refresh (void)
+ {
+diff --git a/include/grub/term.h b/include/grub/term.h
+index 8117e2a24da..c215133383f 100644
+--- a/include/grub/term.h
++++ b/include/grub/term.h
+@@ -327,6 +327,7 @@ grub_term_unregister_output (grub_term_output_t term)
+ void grub_putcode (grub_uint32_t code, struct grub_term_output *term);
+ int EXPORT_FUNC(grub_getkey) (void);
+ int EXPORT_FUNC(grub_getkey_noblock) (void);
++int EXPORT_FUNC(grub_getkeystatus) (void);
+ void grub_cls (void);
+ void EXPORT_FUNC(grub_refresh) (void);
+ void grub_puts_terminal (const char *str, struct grub_term_output *term);
diff --git a/SOURCES/0186-Accept-ESC-F8-and-holding-SHIFT-as-user-interrupt-ke.patch b/SOURCES/0186-Accept-ESC-F8-and-holding-SHIFT-as-user-interrupt-ke.patch
new file mode 100644
index 0000000..2945fd6
--- /dev/null
+++ b/SOURCES/0186-Accept-ESC-F8-and-holding-SHIFT-as-user-interrupt-ke.patch
@@ -0,0 +1,94 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 26 Mar 2018 16:15:53 +0200
+Subject: [PATCH] Accept ESC, F8 and holding SHIFT as user interrupt keys
+
+On some devices the ESC key is the hotkey to enter the BIOS/EFI setup
+screen, making it really hard to time pressing it right. Besides that
+ESC is also pretty hard to discover for a user who does not know it
+will unhide the menu.
+
+This commit makes F8, which used to be the hotkey to show the Windows
+boot menu during boot for a long long time, also interrupt sleeps /
+stop the menu countdown.
+
+This solves the ESC gets into the BIOS setup and also somewhat solves
+the discoverability issue, but leaves the timing issue unresolved.
+
+This commit fixes the timing issue by also adding support for keeping
+SHIFT pressed during boot to stop the menu countdown. This matches
+what Ubuntu is doing, which should also help with discoverability.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ grub-core/commands/sleep.c |  2 +-
+ grub-core/kern/term.c      | 16 ++++++++++++++++
+ grub-core/normal/menu.c    |  2 +-
+ include/grub/term.h        |  1 +
+ 4 files changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/commands/sleep.c b/grub-core/commands/sleep.c
+index e77e7900fac..a1370b710c9 100644
+--- a/grub-core/commands/sleep.c
++++ b/grub-core/commands/sleep.c
+@@ -55,7 +55,7 @@ grub_interruptible_millisleep (grub_uint32_t ms)
+   start = grub_get_time_ms ();
+ 
+   while (grub_get_time_ms () - start < ms)
+-    if (grub_getkey_noblock () == GRUB_TERM_ESC)
++    if (grub_key_is_interrupt (grub_getkey_noblock ()))
+       return 1;
+ 
+   return 0;
+diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c
+index 93bd3378d18..6cae4c23e7a 100644
+--- a/grub-core/kern/term.c
++++ b/grub-core/kern/term.c
+@@ -138,6 +138,22 @@ grub_getkeystatus (void)
+   return status;
+ }
+ 
++int
++grub_key_is_interrupt (int key)
++{
++  /* ESC sometimes is the BIOS setup hotkey and may be hard to discover, also
++     check F8, which was the key to get the Windows bootmenu for a long time. */
++  if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F8)
++    return 1;
++
++  /* Pressing keys at the right time during boot is hard to time, also allow
++     interrupting sleeps / the menu countdown by keeping shift pressed. */
++  if (grub_getkeystatus() & (GRUB_TERM_STATUS_LSHIFT|GRUB_TERM_STATUS_RSHIFT))
++    return 1;
++
++  return 0;
++}
++
+ void
+ grub_refresh (void)
+ {
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index 5e2f5283d3d..6cb2a071490 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -655,7 +655,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
+ 	      if (entry >= 0)
+ 		break;
+ 	    }
+-	  if (key == GRUB_TERM_ESC)
++	  if (grub_key_is_interrupt (key))
+ 	    {
+ 	      timeout = -1;
+ 	      break;
+diff --git a/include/grub/term.h b/include/grub/term.h
+index c215133383f..2b079c29b80 100644
+--- a/include/grub/term.h
++++ b/include/grub/term.h
+@@ -328,6 +328,7 @@ void grub_putcode (grub_uint32_t code, struct grub_term_output *term);
+ int EXPORT_FUNC(grub_getkey) (void);
+ int EXPORT_FUNC(grub_getkey_noblock) (void);
+ int EXPORT_FUNC(grub_getkeystatus) (void);
++int EXPORT_FUNC(grub_key_is_interrupt) (int key);
+ void grub_cls (void);
+ void EXPORT_FUNC(grub_refresh) (void);
+ void grub_puts_terminal (const char *str, struct grub_term_output *term);
diff --git a/SOURCES/0187-grub-editenv-Add-incr-command-to-increment-integer-v.patch b/SOURCES/0187-grub-editenv-Add-incr-command-to-increment-integer-v.patch
new file mode 100644
index 0000000..d836274
--- /dev/null
+++ b/SOURCES/0187-grub-editenv-Add-incr-command-to-increment-integer-v.patch
@@ -0,0 +1,93 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 4 Jun 2018 19:49:47 +0200
+Subject: [PATCH] grub-editenv: Add "incr" command to increment integer value
+ env. variables
+
+To be able to automatically detect if the last boot was successful,
+We want to keep count of succesful / failed boots in some integer
+environment variable.
+
+This commit adds a grub-editenvt "incr" command to increment such
+integer value env. variables by 1 for use from various boot scripts.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ util/grub-editenv.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 50 insertions(+)
+
+diff --git a/util/grub-editenv.c b/util/grub-editenv.c
+index 118e89fe57f..2918bb71cfe 100644
+--- a/util/grub-editenv.c
++++ b/util/grub-editenv.c
+@@ -53,6 +53,9 @@ static struct argp_option options[] = {
+   /* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand.  */
+   {N_("unset [NAME ...]"),    0, 0, OPTION_DOC|OPTION_NO_USAGE,
+    N_("Delete variables."), 0},
++  /* TRANSLATORS: "incr" is a keyword. It's a summary of "incr" subcommand.  */
++  {N_("incr [NAME ...]"),     0, 0, OPTION_DOC|OPTION_NO_USAGE,
++   N_("Increase value of integer variables."), 0},
+ 
+   {0,         0, 0, OPTION_DOC, N_("Options:"), -1},
+   {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
+@@ -246,6 +249,51 @@ unset_variables (const char *name, int argc, char *argv[])
+   grub_envblk_close (envblk);
+ }
+ 
++struct get_int_value_params {
++  char *varname;
++  int value;
++};
++
++static int
++get_int_value (const char *varname, const char *value, void *hook_data)
++{
++  struct get_int_value_params *params = hook_data;
++
++  if (strcmp (varname, params->varname) == 0) {
++    params->value = strtol (value, NULL, 10);
++    return 1;
++  }
++  return 0;
++}
++
++static void
++incr_variables (const char *name, int argc, char *argv[])
++{
++  grub_envblk_t envblk;
++  char buf[16];
++
++  envblk = open_envblk_file (name);
++  while (argc)
++    {
++      struct get_int_value_params params = {
++        .varname = argv[0],
++        .value = 0, /* Consider unset variables 0 */
++      };
++
++      grub_envblk_iterate (envblk, &params, get_int_value);
++      snprintf(buf, sizeof(buf), "%d", params.value + 1);
++
++      if (! grub_envblk_set (envblk, argv[0], buf))
++        grub_util_error ("%s", _("environment block too small"));
++
++      argc--;
++      argv++;
++    }
++
++  write_envblk (name, envblk);
++  grub_envblk_close (envblk);
++}
++
+ int
+ main (int argc, char *argv[])
+ {
+@@ -285,6 +333,8 @@ main (int argc, char *argv[])
+     set_variables (filename, argc - curindex, argv + curindex);
+   else if (strcmp (command, "unset") == 0)
+     unset_variables (filename, argc - curindex, argv + curindex);
++  else if (strcmp (command, "incr") == 0)
++    incr_variables (filename, argc - curindex, argv + curindex);
+   else
+     {
+       char *program = xstrdup(program_name);
diff --git a/SOURCES/0188-Add-auto-hide-menu-support.patch b/SOURCES/0188-Add-auto-hide-menu-support.patch
new file mode 100644
index 0000000..efbc9eb
--- /dev/null
+++ b/SOURCES/0188-Add-auto-hide-menu-support.patch
@@ -0,0 +1,191 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 6 Jun 2018 08:44:11 +0200
+Subject: [PATCH] Add auto-hide menu support
+
+On single-os systems we do not want to show the menu, unless something
+went wrong with the previous boot, in which case the user may need the
+menu to debug/fix the problem.
+
+This commit adds a new grub.d/00_menu_auto_hide file which emits a
+config snippet implementing this. I've chosen to do this in a separate
+grub.d file because chances of this going upstream are small and this way
+it will be easier to rebase.
+
+Since auto-hiding the menu requires detecting the previous boot was ok,
+we get fastboot support (where we don't check for a key at all) for free
+so this commit also adds support for this.
+
+The new config-file code uses the following variables:
+
+menu_auto_hide     Set this to "1" to activate the new auto-hide feature
+                   Set this to "2" to auto-hide the menu even when multiple
+                   operating systems are installed. Note the menu will still
+                   auto show after booting an other os as that won't set
+                   boot_success.
+menu_show_once     Set this to "1" to force showing the menu once.
+boot_success       The OS sets this to "1" to indicate a successful boot.
+boot_indeterminate The OS increments this integer when rebooting after e.g.
+                   installing updates or a selinux relabel.
+fastboot           If set to "1" and the conditions for auto-hiding the menu
+                   are met, the menu is not shown and all checks for keypresses
+                   are skipped, booting the default immediately.
+
+30_os-prober.in changes somewhat inspired by:
+https://git.launchpad.net/~ubuntu-core-dev/grub/+git/ubuntu/tree/debian/patches/quick_boot.patch
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+Changes in v2:
+-Drop shutdown_success tests, there is no meaningful way for systemd to set
+ this flag (by the time it knows all filesystems are unmounted or read-only
+-Drop fwsetup_once support, systemd already supports booting directly into
+ the fwsetup by doing "systemctl reboot --firmware"
+---
+ Makefile.util.def                |  6 +++++
+ util/grub.d/00_menu_auto_hide.in | 50 ++++++++++++++++++++++++++++++++++++++++
+ util/grub.d/30_os-prober.in      | 18 +++++++++++++++
+ 3 files changed, 74 insertions(+)
+ create mode 100644 util/grub.d/00_menu_auto_hide.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index cbd661d6348..0fdfdd91fb0 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -448,6 +448,12 @@ script = {
+   installdir = grubconf;
+ };
+ 
++script = {
++  name = '00_menu_auto_hide';
++  common = util/grub.d/00_menu_auto_hide.in;
++  installdir = grubconf;
++};
++
+ script = {
+   name = '01_users';
+   common = util/grub.d/01_users.in;
+diff --git a/util/grub.d/00_menu_auto_hide.in b/util/grub.d/00_menu_auto_hide.in
+new file mode 100644
+index 00000000000..a10fe45bb2c
+--- /dev/null
++++ b/util/grub.d/00_menu_auto_hide.in
+@@ -0,0 +1,50 @@
++#! /bin/sh
++
++# Disable / skip generating menu-auto-hide config parts on serial terminals
++for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do
++  case "$x" in
++    serial*)
++      exit 0
++      ;;
++  esac
++done
++
++cat << EOF
++if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then
++  set last_boot_ok=1
++else
++  set last_boot_ok=0
++fi
++
++# Reset boot_indeterminate after a successful boot
++if [ "\${boot_success}" = "1" ] ; then
++  set boot_indeterminate=0
++  save_env boot_indeterminate
++# Avoid boot_indeterminate causing the menu to be hidden more then once
++elif [ "\${boot_indeterminate}" = "1" ]; then
++  set boot_indeterminate=2
++  save_env boot_indeterminate
++fi
++set boot_success=0
++save_env boot_success
++
++if [ x\$feature_timeout_style = xy ] ; then
++  if [ "\${menu_show_once}" ]; then
++    unset menu_show_once
++    save_env menu_show_once
++    set timeout_style=menu
++    unset timeout
++  elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then
++    set orig_timeout_style=\${timeout_style}
++    set orig_timeout=\${timeout}
++    if [ "\${fastboot}" = "1" ]; then
++      # timeout_style=menu + timeout=0 avoids the countdown code keypress check
++      set timeout_style=menu
++      set timeout=0
++    else
++      set timeout_style=hidden
++      set timeout=1
++    fi
++  fi
++fi
++EOF
+diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in
+index 13a3a6bc752..ab634393a31 100644
+--- a/util/grub.d/30_os-prober.in
++++ b/util/grub.d/30_os-prober.in
+@@ -42,6 +42,7 @@ if [ -z "${OSPROBED}" ] ; then
+ fi
+ 
+ osx_entry() {
++    found_other_os=1
+     # TRANSLATORS: it refers on the OS residing on device %s
+     onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+     hints=""
+@@ -102,6 +103,7 @@ for OS in ${OSPROBED} ; do
+ 
+   case ${BOOT} in
+     chain)
++      found_other_os=1
+ 
+ 	  onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+       cat << EOF
+@@ -132,6 +134,7 @@ EOF
+ EOF
+     ;;
+     efi)
++      found_other_os=1
+ 
+ 	EFIPATH=${DEVICE#*@}
+ 	DEVICE=${DEVICE%@*}
+@@ -176,6 +179,7 @@ EOF
+ 	  LINITRD="${LINITRD#/boot}"
+ 	fi
+ 
++        found_other_os=1
+ 	onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+ 	recovery_params="$(echo "${LPARAMS}" | grep single)" || true
+ 	counter=1
+@@ -249,6 +253,7 @@ EOF
+       done
+     ;;
+     hurd)
++      found_other_os=1
+       onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
+       cat << EOF
+ menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' {
+@@ -275,6 +280,7 @@ EOF
+ EOF
+     ;;
+     minix)
++      found_other_os=1
+ 	  cat << EOF
+ menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" {
+ EOF
+@@ -306,3 +312,15 @@ EOF
+       esac
+   esac
+ done
++
++# We override the results of the menu_auto_hide code here, this is a bit ugly,
++# but grub-mkconfig writes out the file linearly, so this is the only way
++if [ "${found_other_os}" = "1" ]; then
++  cat << EOF
++# Other OS found, undo autohiding of menu unless menu_auto_hide=2
++if [ "\${orig_timeout_style}" -a "\${menu_auto_hide}" != "2" ]; then
++  set timeout_style=\${orig_timeout_style}
++  set timeout=\${orig_timeout}
++fi
++EOF
++fi
diff --git a/SOURCES/0189-Output-a-menu-entry-for-firmware-setup-on-UEFI-FastB.patch b/SOURCES/0189-Output-a-menu-entry-for-firmware-setup-on-UEFI-FastB.patch
new file mode 100644
index 0000000..4daefdb
--- /dev/null
+++ b/SOURCES/0189-Output-a-menu-entry-for-firmware-setup-on-UEFI-FastB.patch
@@ -0,0 +1,93 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Steve Langasek <steve.langasek@ubuntu.com>
+Date: Mon, 13 Jan 2014 12:13:12 +0000
+Subject: [PATCH] Output a menu entry for firmware setup on UEFI FastBoot
+ systems
+
+If fastboot is enabled in the BIOS then often it is not possible to
+enter the firmware setup menu, add a menu entry for this.
+
+hdegoede: Cherry picked the Ubuntu patch from:
+https://git.launchpad.net/~ubuntu-core-dev/grub/+git/ubuntu/tree/debian/patches/uefi_firmware_setup.patch
+Into the Fedora / RH grub version
+
+According to:
+https://git.launchpad.net/~ubuntu-core-dev/grub/+git/ubuntu/tree/debian/copyright
+The patch is licensed under GPL-3+
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Makefile.util.def               |  6 ++++++
+ util/grub.d/30_uefi-firmware.in | 46 +++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 52 insertions(+)
+ create mode 100644 util/grub.d/30_uefi-firmware.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 0fdfdd91fb0..5a8c390a1da 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -529,6 +529,12 @@ script = {
+   installdir = grubconf;
+ };
+ 
++script = {
++  name = '30_uefi-firmware';
++  common = util/grub.d/30_uefi-firmware.in;
++  installdir = grubconf;
++};
++
+ script = {
+   name = '40_custom';
+   common = util/grub.d/40_custom.in;
+diff --git a/util/grub.d/30_uefi-firmware.in b/util/grub.d/30_uefi-firmware.in
+new file mode 100644
+index 00000000000..3c9f533d8c6
+--- /dev/null
++++ b/util/grub.d/30_uefi-firmware.in
+@@ -0,0 +1,46 @@
++#! /bin/sh
++set -e
++
++# grub-mkconfig helper script.
++# Copyright (C) 2012  Free Software Foundation, Inc.
++#
++# GRUB is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# GRUB is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++
++prefix="@prefix@"
++exec_prefix="@exec_prefix@"
++datarootdir="@datarootdir@"
++
++export TEXTDOMAIN=@PACKAGE@
++export TEXTDOMAINDIR="@localedir@"
++
++. "@datadir@/@PACKAGE@/grub-mkconfig_lib"
++
++efi_vars_dir=/sys/firmware/efi/vars
++EFI_GLOBAL_VARIABLE=8be4df61-93ca-11d2-aa0d-00e098032b8c
++OsIndications="$efi_vars_dir/OsIndicationsSupported-$EFI_GLOBAL_VARIABLE/data"
++
++if [ -e "$OsIndications" ] && \
++   [ "$(( $(printf 0x%x \'"$(cat $OsIndications | cut -b1)") & 1 ))" = 1 ]; then
++  LABEL="System setup"
++
++  gettext_printf "Adding boot menu entry for EFI firmware configuration\n" >&2
++
++  onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
++
++  cat << EOF
++menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' {
++	fwsetup
++}
++EOF
++fi
diff --git a/SOURCES/0190-Add-grub-set-bootflag-utility.patch b/SOURCES/0190-Add-grub-set-bootflag-utility.patch
new file mode 100644
index 0000000..9adc1c0
--- /dev/null
+++ b/SOURCES/0190-Add-grub-set-bootflag-utility.patch
@@ -0,0 +1,330 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 12 Jun 2018 13:25:16 +0200
+Subject: [PATCH] Add grub-set-bootflag utility
+
+This commit adds a new grub-set-bootflag utility, which can be used
+to set known bootflags in the grubenv: boot_success or menu_show_once.
+
+grub-set-bootflag is different from grub-editenv in 2 ways:
+
+1) It is intended to be executed by regular users through pkexec, so
+running as root if the polkit policy allows this. As such it is written
+to not use any existing grubenv related code for easy auditing.
+
+2) Since it can be executed by regular users it only allows setting
+(assigning a value of 1 to) bootflags which it knows about. Currently
+those are just boot_success and menu_show_once.
+
+This commit also adds a couple of example systemd and polkit files which
+show how this can be used to set boot_success from a user-session:
+
+docs/grub-boot-success.service
+docs/grub-boot-success.timer
+docs/org.gnu.grub.policy
+
+The 2 grub-boot-success.systemd files should be placed in /lib/systemd/user
+and a symlink to grub-boot-success.timer should be added to
+/lib/systemd/user/timers.target.wants.
+
+The org.gnu.grub.policy polkit file should be placed in
+/usr/share/polkit-1/actions.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Makefile.util.def              |   7 ++
+ util/grub-set-bootflag.c       | 158 +++++++++++++++++++++++++++++++++++++++++
+ .gitignore                     |   2 +
+ conf/Makefile.extra-dist       |   3 +
+ docs/grub-boot-success.service |   6 ++
+ docs/grub-boot-success.timer   |   5 ++
+ docs/org.gnu.grub.policy       |  20 ++++++
+ util/grub-set-bootflag.1       |  20 ++++++
+ 8 files changed, 221 insertions(+)
+ create mode 100644 util/grub-set-bootflag.c
+ create mode 100644 docs/grub-boot-success.service
+ create mode 100644 docs/grub-boot-success.timer
+ create mode 100644 docs/org.gnu.grub.policy
+ create mode 100644 util/grub-set-bootflag.1
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 5a8c390a1da..5da55393291 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -1435,3 +1435,10 @@ program = {
+   ldadd = grub-core/gnulib/libgnu.a;
+   ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
+ };
++
++program = {
++  name = grub-set-bootflag;
++  installdir = sbin;
++  mansection = 1;
++  common = util/grub-set-bootflag.c;
++};
+diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c
+new file mode 100644
+index 00000000000..f8dc310909a
+--- /dev/null
++++ b/util/grub-set-bootflag.c
+@@ -0,0 +1,158 @@
++/* grub-set-bootflag.c - tool to set boot-flags in the grubenv. */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2018 Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++/*
++ * NOTE this gets run by users as root (through pkexec), so this does not
++ * use any grub library / util functions to allow for easy auditing.
++ * The grub headers are only included to get certain defines.
++ */
++
++#include <config-util.h>     /* For *_DIR_NAME defines */
++#include <grub/types.h>
++#include <grub/lib/envblk.h> /* For GRUB_ENVBLK_DEFCFG define */
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++
++#define GRUBENV "/" GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME "/" GRUB_ENVBLK_DEFCFG
++#define GRUBENV_SIZE 1024
++
++const char *bootflags[] = {
++  "boot_success",
++  "menu_show_once",
++  NULL
++};
++
++static void usage(void)
++{
++  int i;
++
++  fprintf (stderr, "Usage: 'grub-set-bootflag <bootflag>', where <bootflag> is one of:\n");
++  for (i = 0; bootflags[i]; i++)
++    fprintf (stderr, "  %s\n", bootflags[i]);
++}
++
++int main(int argc, char *argv[])
++{
++  /* NOTE buf must be at least the longest bootflag length + 4 bytes */
++  char env[GRUBENV_SIZE + 1], buf[64], *s;
++  const char *bootflag;
++  int i, len, ret;
++  FILE *f;
++
++  if (argc != 2)
++    {
++      usage();
++      return 1;
++    }
++
++  for (i = 0; bootflags[i]; i++)
++    if (!strcmp (argv[1], bootflags[i]))
++      break;
++  if (!bootflags[i])
++    {
++      fprintf (stderr, "Invalid bootflag: '%s'\n", argv[1]);
++      usage();
++      return 1;
++    }
++
++  bootflag = bootflags[i];
++  len = strlen (bootflag);
++
++  f = fopen (GRUBENV, "r");
++  if (!f)
++    {
++      perror ("Error opening " GRUBENV " for reading");
++      return 1;     
++    }
++
++  ret = fread (env, 1, GRUBENV_SIZE, f);
++  fclose (f);
++  if (ret != GRUBENV_SIZE)
++    {
++      perror ("Error reading from " GRUBENV);
++      return 1;     
++    }
++
++  /* 0 terminate env */
++  env[GRUBENV_SIZE] = 0;
++
++  if (strncmp (env, GRUB_ENVBLK_SIGNATURE, strlen (GRUB_ENVBLK_SIGNATURE)))
++    {
++      fprintf (stderr, "Error invalid environment block\n");
++      return 1;
++    }
++
++  /* Find a pre-existing definition of the bootflag */
++  s = strstr (env, bootflag);
++  while (s && s[len] != '=')
++    s = strstr (s + len, bootflag);
++
++  if (s && ((s[len + 1] != '0' && s[len + 1] != '1') || s[len + 2] != '\n'))
++    {
++      fprintf (stderr, "Pre-existing bootflag '%s' has unexpected value\n", bootflag);
++      return 1;     
++    }
++
++  /* No pre-existing bootflag? -> find free space */
++  if (!s)
++    {
++      for (i = 0; i < (len + 3); i++)
++        buf[i] = '#';
++      buf[i] = 0;
++      s = strstr (env, buf);
++    }
++
++  if (!s)
++    {
++      fprintf (stderr, "No space in grubenv to store bootflag '%s'\n", bootflag);
++      return 1;     
++    }
++
++  /* The grubenv is not 0 terminated, so memcpy the name + '=' , '1', '\n' */
++  snprintf(buf, sizeof(buf), "%s=1\n", bootflag);
++  memcpy(s, buf, len + 3);
++
++  /* "r+", don't truncate so that the diskspace stays reserved */
++  f = fopen (GRUBENV, "r+");
++  if (!f)
++    {
++      perror ("Error opening " GRUBENV " for writing");
++      return 1;     
++    }
++
++  ret = fwrite (env, 1, GRUBENV_SIZE, f);
++  if (ret != GRUBENV_SIZE)
++    {
++      perror ("Error writing to " GRUBENV);
++      return 1;     
++    }
++
++  ret = fflush (f);
++  if (ret)
++    {
++      perror ("Error flushing " GRUBENV);
++      return 1;     
++    }
++
++  fsync (fileno (f));
++  fclose (f);
++
++  return 0;
++}
+diff --git a/.gitignore b/.gitignore
+index 42475592123..6c4cfc53781 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -111,6 +111,8 @@ grub-*.tar.*
+ /grub*-rpm-sort.8
+ /grub*-script-check
+ /grub*-script-check.1
++/grub*-set-bootflag
++/grub*-set-bootflag.1
+ /grub*-set-default
+ /grub*-set-default.8
+ /grub*-setsetpassword
+diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist
+index 39eb94bded6..5946ec24a65 100644
+--- a/conf/Makefile.extra-dist
++++ b/conf/Makefile.extra-dist
+@@ -14,6 +14,9 @@ EXTRA_DIST += util/import_unicode.py
+ EXTRA_DIST += docs/autoiso.cfg
+ EXTRA_DIST += docs/grub.cfg
+ EXTRA_DIST += docs/osdetect.cfg
++EXTRA_DIST += docs/org.gnu.grub.policy
++EXTRA_DIST += docs/grub-boot-success.service
++EXTRA_DIST += docs/grub-boot-success.timer
+ 
+ EXTRA_DIST += conf/i386-cygwin-img-ld.sc
+ 
+diff --git a/docs/grub-boot-success.service b/docs/grub-boot-success.service
+new file mode 100644
+index 00000000000..c8c91c34d49
+--- /dev/null
++++ b/docs/grub-boot-success.service
+@@ -0,0 +1,6 @@
++[Unit]
++Description=Mark boot as successful
++
++[Service]
++Type=oneshot
++ExecStart=/usr/bin/pkexec /usr/sbin/grub2-set-bootflag boot_success
+diff --git a/docs/grub-boot-success.timer b/docs/grub-boot-success.timer
+new file mode 100644
+index 00000000000..221b532781b
+--- /dev/null
++++ b/docs/grub-boot-success.timer
+@@ -0,0 +1,5 @@
++[Unit]
++Description=Mark boot as successful after the user session has run 2 minutes
++
++[Timer]
++OnActiveSec=2min
+diff --git a/docs/org.gnu.grub.policy b/docs/org.gnu.grub.policy
+new file mode 100644
+index 00000000000..18391efc8e7
+--- /dev/null
++++ b/docs/org.gnu.grub.policy
+@@ -0,0 +1,20 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
++<policyconfig>
++  <vendor>GNU GRUB</vendor>
++  <vendor_url>https://www.gnu.org/software/grub/</vendor_url>
++  <action id="org.gnu.grub.set-bootflag">
++    <!-- SECURITY:
++          - A normal active user on the local machine does not need permission
++            to set bootflags to show the menu / mark current boot successful.
++     -->
++    <description>Set GRUB bootflags</description>
++    <message>Authentication is required to modify the bootloaders bootflags</message>
++    <defaults>
++      <allow_any>no</allow_any>
++      <allow_inactive>no</allow_inactive>
++      <allow_active>yes</allow_active>
++    </defaults>
++    <annotate key="org.freedesktop.policykit.exec.path">/usr/sbin/grub2-set-bootflag</annotate>
++  </action>
++</policyconfig>
+diff --git a/util/grub-set-bootflag.1 b/util/grub-set-bootflag.1
+new file mode 100644
+index 00000000000..57801da22a0
+--- /dev/null
++++ b/util/grub-set-bootflag.1
+@@ -0,0 +1,20 @@
++.TH GRUB-SET-BOOTFLAG 1 "Tue Jun 12 2018"
++.SH NAME
++\fBgrub-set-bootflag\fR \(em Set a bootflag in the GRUB environment block.
++
++.SH SYNOPSIS
++\fBgrub-set-bootflag\fR <\fIBOOTFLAG\fR>
++
++.SH DESCRIPTION
++\fBgrub-set-bootflag\fR is a command line to set bootflags in GRUB's
++stored environment.
++
++.SH COMMANDS
++.TP
++\fBBOOTFLAG\fR
++.RS 7
++Bootflag to set, one of \fIboot_success\fR or \fIshow_menu_once\fR.
++.RE
++
++.SH SEE ALSO
++.BR "info grub"
diff --git a/SOURCES/0191-Fix-grub-setpassword-o-s-output-path.patch b/SOURCES/0191-Fix-grub-setpassword-o-s-output-path.patch
new file mode 100644
index 0000000..f26da57
--- /dev/null
+++ b/SOURCES/0191-Fix-grub-setpassword-o-s-output-path.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andy Lutomirski <luto@kernel.org>
+Date: Sun, 11 Jun 2017 19:17:40 -0400
+Subject: [PATCH] Fix grub-setpassword -o's output path
+
+The output path is set up in the command line parsing, but completely ignored
+in the code that actually writes the files.  This patch fixes that.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-setpassword.in | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/util/grub-setpassword.in b/util/grub-setpassword.in
+index cf70257eed6..5ebf50576d6 100644
+--- a/util/grub-setpassword.in
++++ b/util/grub-setpassword.in
+@@ -118,11 +118,11 @@ fi
+ 
+ # on the ESP, these will fail to set the permissions, but it's okay because
+ # the directory is protected.
+-install -m 0600 /dev/null "${grubdir}/user.cfg" 2>/dev/null || :
+-chmod 0600 "${grubdir}/user.cfg" 2>/dev/null || :
+-echo "GRUB2_PASSWORD=${MYPASS}" > "${grubdir}/user.cfg"
++install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
++chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || :
++echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg"
+ 
+-if ! grep -q "^### BEGIN /etc/grub.d/01_users ###$" "${grubdir}/grub.cfg"; then
++if ! grep -q "^### BEGIN /etc/grub.d/01_users ###$" "${OUTPUT_PATH}/grub.cfg"; then
+     echo "WARNING: The current configuration lacks password support!"
+     echo "Update your configuration with @grub_mkconfig@ to support this feature."
+ fi
diff --git a/SOURCES/0192-Make-grub-set-password-be-named-like-all-the-other-g.patch b/SOURCES/0192-Make-grub-set-password-be-named-like-all-the-other-g.patch
new file mode 100644
index 0000000..678b3ad
--- /dev/null
+++ b/SOURCES/0192-Make-grub-set-password-be-named-like-all-the-other-g.patch
@@ -0,0 +1,88 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Sat, 23 Jun 2018 13:19:15 -0400
+Subject: [PATCH] Make grub-set-password be named like all the other grub
+ utilities
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ configure.ac                                       | 2 +-
+ Makefile.util.def                                  | 4 ++--
+ .gitignore                                         | 4 ++--
+ util/{grub-setpassword.8 => grub-set-password.8}   | 8 ++++----
+ util/{grub-setpassword.in => grub-set-password.in} | 0
+ 5 files changed, 9 insertions(+), 9 deletions(-)
+ rename util/{grub-setpassword.8 => grub-set-password.8} (50%)
+ rename util/{grub-setpassword.in => grub-set-password.in} (100%)
+
+diff --git a/configure.ac b/configure.ac
+index 359cac3c26b..5f47a9265f3 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -66,7 +66,7 @@ grub_TRANSFORM([grub-mkrelpath])
+ grub_TRANSFORM([grub-mkrescue])
+ grub_TRANSFORM([grub-probe])
+ grub_TRANSFORM([grub-reboot])
+-grub_TRANSFORM([grub-setpassword])
++grub_TRANSFORM([grub-set-password])
+ grub_TRANSFORM([grub-rpm-sort])
+ grub_TRANSFORM([grub-script-check])
+ grub_TRANSFORM([grub-set-default])
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 5da55393291..97cd8bdebd9 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -756,8 +756,8 @@ script = {
+ };
+ 
+ script = {
+-  name = grub-setpassword;
+-  common = util/grub-setpassword.in;
++  name = grub-set-password;
++  common = util/grub-set-password.in;
+   mansection = 8;
+   installdir = sbin;
+ };
+diff --git a/.gitignore b/.gitignore
+index 6c4cfc53781..a999024652e 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -115,8 +115,8 @@ grub-*.tar.*
+ /grub*-set-bootflag.1
+ /grub*-set-default
+ /grub*-set-default.8
+-/grub*-setsetpassword
+-/grub*-setsetpassword.8
++/grub*-set-password
++/grub*-set-password.8
+ /grub*-shell
+ /grub*-shell-tester
+ /grub*-sparc64-setup
+diff --git a/util/grub-setpassword.8 b/util/grub-set-password.8
+similarity index 50%
+rename from util/grub-setpassword.8
+rename to util/grub-set-password.8
+index dc91dd6697b..9646546e43d 100644
+--- a/util/grub-setpassword.8
++++ b/util/grub-set-password.8
+@@ -1,12 +1,12 @@
+-.TH GRUB-SETPASSWORD 3 "Thu Jun 25 2015"
++.TH GRUB-SET-PASSWORD 3 "Thu Jun 25 2015"
+ .SH NAME
+-\fBgrub-setpassword\fR \(em Generate the user.cfg file containing the hashed grub bootloader password.
++\fBgrub-set-password\fR \(em Generate the user.cfg file containing the hashed grub bootloader password.
+ 
+ .SH SYNOPSIS
+-\fBgrub-setpassword\fR [OPTION]
++\fBgrub-set-password\fR [OPTION]
+ 
+ .SH DESCRIPTION
+-\fBgrub-setpassword\fR outputs the user.cfg file which contains the hashed GRUB bootloader password. This utility only supports configurations where there is a single root user.
++\fBgrub-set-password\fR outputs the user.cfg file which contains the hashed GRUB bootloader password. This utility only supports configurations where there is a single root user.
+ 
+ The file has the format:
+ GRUB2_PASSWORD=<\fIhashed password\fR>.
+diff --git a/util/grub-setpassword.in b/util/grub-set-password.in
+similarity index 100%
+rename from util/grub-setpassword.in
+rename to util/grub-set-password.in
diff --git a/SOURCES/0193-docs-Add-grub-boot-indeterminate.service-example.patch b/SOURCES/0193-docs-Add-grub-boot-indeterminate.service-example.patch
new file mode 100644
index 0000000..44f6ad3
--- /dev/null
+++ b/SOURCES/0193-docs-Add-grub-boot-indeterminate.service-example.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 19 Jun 2018 15:20:54 +0200
+Subject: [PATCH] docs: Add grub-boot-indeterminate.service example
+
+This is an example service file, for use from
+/lib/systemd/system/system-update.target.wants
+to increment the boot_indeterminate variable when
+doing offline updates.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ docs/grub-boot-indeterminate.service | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+ create mode 100644 docs/grub-boot-indeterminate.service
+
+diff --git a/docs/grub-boot-indeterminate.service b/docs/grub-boot-indeterminate.service
+new file mode 100644
+index 00000000000..6c8dcb186b6
+--- /dev/null
++++ b/docs/grub-boot-indeterminate.service
+@@ -0,0 +1,11 @@
++[Unit]
++Description=Mark boot as indeterminate
++DefaultDependencies=false
++Requires=sysinit.target
++After=sysinit.target
++Wants=system-update-pre.target
++Before=system-update-pre.target
++
++[Service]
++Type=oneshot
++ExecStart=/usr/bin/grub2-editenv - incr boot_indeterminate
diff --git a/SOURCES/0194-00_menu_auto_hide-Use-a-timeout-of-60s-for-menu_show.patch b/SOURCES/0194-00_menu_auto_hide-Use-a-timeout-of-60s-for-menu_show.patch
new file mode 100644
index 0000000..367fc6c
--- /dev/null
+++ b/SOURCES/0194-00_menu_auto_hide-Use-a-timeout-of-60s-for-menu_show.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 26 Jun 2018 12:44:29 +0200
+Subject: [PATCH] 00_menu_auto_hide: Use a timeout of 60s for menu_show_once,
+ rather then no timeout
+
+On some UEFI systems with fastboot enabled (USB) keyboards don't work at
+all, not even when explictly asking for keyboard input.
+
+So lets change the timeout from not set (no timeout) to 60 seconds, so
+that on such systems if the menu was requested we continue with the
+default choice after 60 seconds.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ util/grub.d/00_menu_auto_hide.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util/grub.d/00_menu_auto_hide.in b/util/grub.d/00_menu_auto_hide.in
+index a10fe45bb2c..ca95c0d1c9f 100644
+--- a/util/grub.d/00_menu_auto_hide.in
++++ b/util/grub.d/00_menu_auto_hide.in
+@@ -33,7 +33,7 @@ if [ x\$feature_timeout_style = xy ] ; then
+     unset menu_show_once
+     save_env menu_show_once
+     set timeout_style=menu
+-    unset timeout
++    set timeout=60
+   elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then
+     set orig_timeout_style=\${timeout_style}
+     set orig_timeout=\${timeout}
diff --git a/SOURCES/0195-00_menu_auto_hide-Reduce-number-of-save_env-calls.patch b/SOURCES/0195-00_menu_auto_hide-Reduce-number-of-save_env-calls.patch
new file mode 100644
index 0000000..6993508
--- /dev/null
+++ b/SOURCES/0195-00_menu_auto_hide-Reduce-number-of-save_env-calls.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 27 Jun 2018 13:33:43 +0200
+Subject: [PATCH] 00_menu_auto_hide: Reduce number of save_env calls
+
+Normally boot_success will be 1 on every boot (as normally the
+previous boot will have been successful). This means that we end
+up in the code-path to set boot_indeterminate to 0 every boot.
+
+So we do 2 separate save_env calls each boot, one for boot_indeterminate
+and one for boot_success. This results in 2 writes to the disk.
+
+This commit makes us save both boot_success and boot_indeterminate
+in a single call, reducing the number of writes, this reducing wear
+and tear on the underlying storage.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ util/grub.d/00_menu_auto_hide.in | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/util/grub.d/00_menu_auto_hide.in b/util/grub.d/00_menu_auto_hide.in
+index ca95c0d1c9f..ad175870a54 100644
+--- a/util/grub.d/00_menu_auto_hide.in
++++ b/util/grub.d/00_menu_auto_hide.in
+@@ -19,14 +19,12 @@ fi
+ # Reset boot_indeterminate after a successful boot
+ if [ "\${boot_success}" = "1" ] ; then
+   set boot_indeterminate=0
+-  save_env boot_indeterminate
+ # Avoid boot_indeterminate causing the menu to be hidden more then once
+ elif [ "\${boot_indeterminate}" = "1" ]; then
+   set boot_indeterminate=2
+-  save_env boot_indeterminate
+ fi
+ set boot_success=0
+-save_env boot_success
++save_env boot_success boot_indeterminate
+ 
+ if [ x\$feature_timeout_style = xy ] ; then
+   if [ "\${menu_show_once}" ]; then
diff --git a/SOURCES/0196-30_uefi-firmware-fix-use-with-sys-firmware-efi-efiva.patch b/SOURCES/0196-30_uefi-firmware-fix-use-with-sys-firmware-efi-efiva.patch
new file mode 100644
index 0000000..e713d69
--- /dev/null
+++ b/SOURCES/0196-30_uefi-firmware-fix-use-with-sys-firmware-efi-efiva.patch
@@ -0,0 +1,36 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 29 Jun 2018 10:08:22 +0200
+Subject: [PATCH] 30_uefi-firmware: fix use with /sys/firmware/efi/efivars
+
+Fix 30_uefi-firmware checking for the obsolete /sys/firmware/efi/vars
+instead of for the new efivarfs mounted at /sys/firmware/efi/efivars.
+
+Which goes to show that I really should have tested this before blindly
+importing it from Ubuntu.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ util/grub.d/30_uefi-firmware.in | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/util/grub.d/30_uefi-firmware.in b/util/grub.d/30_uefi-firmware.in
+index 3c9f533d8c6..93ececffea7 100644
+--- a/util/grub.d/30_uefi-firmware.in
++++ b/util/grub.d/30_uefi-firmware.in
+@@ -26,12 +26,12 @@ export TEXTDOMAINDIR="@localedir@"
+ 
+ . "@datadir@/@PACKAGE@/grub-mkconfig_lib"
+ 
+-efi_vars_dir=/sys/firmware/efi/vars
++efi_vars_dir=/sys/firmware/efi/efivars
+ EFI_GLOBAL_VARIABLE=8be4df61-93ca-11d2-aa0d-00e098032b8c
+-OsIndications="$efi_vars_dir/OsIndicationsSupported-$EFI_GLOBAL_VARIABLE/data"
++OsIndications="$efi_vars_dir/OsIndicationsSupported-$EFI_GLOBAL_VARIABLE"
+ 
+ if [ -e "$OsIndications" ] && \
+-   [ "$(( $(printf 0x%x \'"$(cat $OsIndications | cut -b1)") & 1 ))" = 1 ]; then
++   [ "$(( $(printf 0x%x \'"$(cat $OsIndications | cut -b5)") & 1 ))" = 1 ]; then
+   LABEL="System setup"
+ 
+   gettext_printf "Adding boot menu entry for EFI firmware configuration\n" >&2
diff --git a/SOURCES/0197-gentpl-add-disable-support.patch b/SOURCES/0197-gentpl-add-disable-support.patch
new file mode 100644
index 0000000..d82d633
--- /dev/null
+++ b/SOURCES/0197-gentpl-add-disable-support.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 11 Jul 2018 13:43:15 -0400
+Subject: [PATCH] gentpl: add 'disable = ' support
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ gentpl.py | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/gentpl.py b/gentpl.py
+index bf8439fa743..a8cd540550f 100644
+--- a/gentpl.py
++++ b/gentpl.py
+@@ -589,11 +589,21 @@ def platform_conditional(platform, closure):
+ #  };
+ #
+ def foreach_enabled_platform(defn, closure):
++    enabled = False
++    disabled = False
+     if 'enable' in defn:
++        enabled = True
+         for platform in GRUB_PLATFORMS:
+             if platform_tagged(defn, platform, "enable"):
+                platform_conditional(platform, closure)
+-    else:
++
++    if 'disable' in defn:
++        disabled = True
++        for platform in GRUB_PLATFORMS:
++            if not platform_tagged(defn, platform, "disable"):
++                platform_conditional(platform, closure)
++
++    if not enabled and not disabled:
+         for platform in GRUB_PLATFORMS:
+             platform_conditional(platform, closure)
+ 
+@@ -652,6 +662,8 @@ def first_time(defn, snippet):
+ def is_platform_independent(defn):
+     if 'enable' in defn:
+         return False
++    if 'disable' in defn:
++        return False
+     for suffix in [ "", "_nodist" ]:
+         template = platform_values(defn, GRUB_PLATFORMS[0], suffix)
+         for platform in GRUB_PLATFORMS[1:]:
diff --git a/SOURCES/0198-gentpl-add-pc-firmware-type.patch b/SOURCES/0198-gentpl-add-pc-firmware-type.patch
new file mode 100644
index 0000000..94737b3
--- /dev/null
+++ b/SOURCES/0198-gentpl-add-pc-firmware-type.patch
@@ -0,0 +1,22 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 11 Jul 2018 13:43:34 -0400
+Subject: [PATCH] gentpl: add 'pc' firmware type
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ gentpl.py | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/gentpl.py b/gentpl.py
+index a8cd540550f..baac6a2af69 100644
+--- a/gentpl.py
++++ b/gentpl.py
+@@ -49,6 +49,7 @@ GROUPS["arm"]      = [ "arm_uboot", "arm_efi", "arm_coreboot" ]
+ GROUPS["arm64"]    = [ "arm64_efi" ]
+ 
+ # Groups based on firmware
++GROUPS["pc"] = [ "i386_pc" ]
+ GROUPS["efi"]  = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi" ]
+ GROUPS["ieee1275"]   = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
+ GROUPS["uboot"] = [ "arm_uboot" ]
diff --git a/SOURCES/0199-blscfg-remove-unused-typedef.patch b/SOURCES/0199-blscfg-remove-unused-typedef.patch
new file mode 100644
index 0000000..819a144
--- /dev/null
+++ b/SOURCES/0199-blscfg-remove-unused-typedef.patch
@@ -0,0 +1,29 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Will Thompson <wjt@endlessm.com>
+Date: Wed, 11 Jul 2018 14:59:52 +0100
+Subject: [PATCH] blscfg: remove unused typedef
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is unused since ‘Use BLS fragment filename as menu entry id and for
+criteria to sort’.
+
+Signed-off-by: Will Thompson <wjt@endlessm.com>
+---
+ grub-core/commands/blscfg.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index cd8659384e4..82fb6cdd182 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -327,8 +327,6 @@ finish:
+     return ret;
+ }
+ 
+-typedef int (*void_cmp_t)(void *, void *);
+-
+ static int bls_cmp(const void *p0, const void *p1, void *state UNUSED)
+ {
+   struct bls_entry * e0 = *(struct bls_entry **)p0;
diff --git a/SOURCES/0200-blscfg-don-t-dynamically-allocate-default_blsdir.patch b/SOURCES/0200-blscfg-don-t-dynamically-allocate-default_blsdir.patch
new file mode 100644
index 0000000..ab076ec
--- /dev/null
+++ b/SOURCES/0200-blscfg-don-t-dynamically-allocate-default_blsdir.patch
@@ -0,0 +1,45 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Will Thompson <wjt@endlessm.com>
+Date: Wed, 11 Jul 2018 15:01:45 +0100
+Subject: [PATCH] blscfg: don't dynamically allocate default_blsdir
+
+Signed-off-by: Will Thompson <wjt@endlessm.com>
+---
+ grub-core/commands/blscfg.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 82fb6cdd182..b61dddb7f43 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -623,7 +623,7 @@ static int find_entry (const char *filename,
+   grub_file_t f = NULL;
+   char *grubenv_path = NULL;
+   grub_envblk_t env = NULL;
+-  char *default_blsdir = NULL;
++  const char *default_blsdir = NULL;
+   grub_fs_t blsdir_fs = NULL;
+   grub_device_t blsdir_dev = NULL;
+   const char *blsdir = NULL;
+@@ -643,10 +643,9 @@ static int find_entry (const char *filename,
+ 
+   // set a default blsdir
+   if (info->platform == PLATFORM_EMU)
+-    default_blsdir = grub_xasprintf ("%s%s", GRUB_BOOT_DEVICE,
+-				     GRUB_BLS_CONFIG_PATH);
++    default_blsdir = GRUB_BOOT_DEVICE GRUB_BLS_CONFIG_PATH;
+   else
+-    default_blsdir = grub_xasprintf ("%s", GRUB_BLS_CONFIG_PATH);
++    default_blsdir = GRUB_BLS_CONFIG_PATH;
+ 
+   grub_env_set ("blsdir", default_blsdir);
+   grub_dprintf ("blscfg", "default_blsdir: \"%s\"\n", default_blsdir);
+@@ -788,8 +787,6 @@ finish:
+   if (f)
+     grub_file_close (f);
+ 
+-  grub_free (default_blsdir);
+-
+   return 0;
+ }
+ 
diff --git a/SOURCES/0201-blscfg-sort-BLS-entries-by-version-field.patch b/SOURCES/0201-blscfg-sort-BLS-entries-by-version-field.patch
new file mode 100644
index 0000000..0ee94af
--- /dev/null
+++ b/SOURCES/0201-blscfg-sort-BLS-entries-by-version-field.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Will Thompson <wjt@endlessm.com>
+Date: Wed, 11 Jul 2018 15:41:09 +0100
+Subject: [PATCH] blscfg: sort BLS entries by 'version' field
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This partially reverts ‘Use BLS fragment filename as menu entry id and
+for criteria to sort’. Sorting by filename only gives the correct order
+if the BLS entries are generated by a version of ostree after this patch
+https://github.com/ostreedev/ostree/commit/9f48e212a3bf9ed418fb3216e4f834d581bc520e
+to use the version (higher is newer) in the filename. Older ostrees,
+including all releases at the time of writing, use the index (lower is
+newer) in the filename, so sorting by filename produces the reverse
+order.
+
+Sorting by 'version' field matches libostree's own
+compare_boot_loader_configs(), so I think it's more correct than relying
+on the filename, particularly since we've already gone to the trouble of
+parsing all the fields in the file.
+
+Signed-off-by: Will Thompson <wjt@endlessm.com>
+---
+ grub-core/commands/blscfg.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index b61dddb7f43..9c928dda470 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -327,10 +327,26 @@ finish:
+     return ret;
+ }
+ 
++/* return 1: p0 is newer than p1 */
++/*        0: p0 and p1 are the same version */
++/*       -1: p1 is newer than p0 */
+ static int bls_cmp(const void *p0, const void *p1, void *state UNUSED)
+ {
+   struct bls_entry * e0 = *(struct bls_entry **)p0;
+   struct bls_entry * e1 = *(struct bls_entry **)p1;
++  const char *v0, *v1;
++  int r;
++
++  v0 = bls_get_val(e0, "version", NULL);
++  v1 = bls_get_val(e1, "version", NULL);
++
++  if (v0 && !v1)
++    return -1;
++  if (!v0 && v1)
++    return 1;
++
++  if ((r = vercmp(v0, v1)) != 0)
++    return r;
+ 
+   return vercmp(e0->filename, e1->filename);
+ }
diff --git a/SOURCES/0202-blscfg-remove-NULL-guards-around-grub_free.patch b/SOURCES/0202-blscfg-remove-NULL-guards-around-grub_free.patch
new file mode 100644
index 0000000..add1766
--- /dev/null
+++ b/SOURCES/0202-blscfg-remove-NULL-guards-around-grub_free.patch
@@ -0,0 +1,48 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Will Thompson <wjt@endlessm.com>
+Date: Thu, 12 Jul 2018 10:14:43 +0100
+Subject: [PATCH] blscfg: remove NULL guards around grub_free()
+
+The internal implementation of grub_free() is NULL-safe. In emu builds,
+it just delegates to the host's free(), which is specified by ANSI C to
+be NULL-safe.
+
+Signed-off-by: Will Thompson <wjt@endlessm.com>
+---
+ grub-core/commands/blscfg.c | 23 ++++++-----------------
+ 1 file changed, 6 insertions(+), 17 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 9c928dda470..bd78559ef68 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -600,23 +600,12 @@ static void create_entry (struct bls_entry *entry, const char *cfgfile)
+   grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0);
+ 
+ finish:
+-  if (initrd)
+-    grub_free (initrd);
+-
+-  if (initrds)
+-    grub_free (initrds);
+-
+-  if (classes)
+-    grub_free (classes);
+-
+-  if (args)
+-    grub_free (args);
+-
+-  if (argv)
+-    grub_free (argv);
+-
+-  if (src)
+-    grub_free (src);
++  grub_free (initrd);
++  grub_free (initrds);
++  grub_free (classes);
++  grub_free (args);
++  grub_free (argv);
++  grub_free (src);
+ }
+ 
+ struct find_entry_info {
diff --git a/SOURCES/0203-blscfg-fix-filename-in-no-linux-key-error.patch b/SOURCES/0203-blscfg-fix-filename-in-no-linux-key-error.patch
new file mode 100644
index 0000000..37795f6
--- /dev/null
+++ b/SOURCES/0203-blscfg-fix-filename-in-no-linux-key-error.patch
@@ -0,0 +1,47 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Will Thompson <wjt@endlessm.com>
+Date: Thu, 12 Jul 2018 10:38:27 +0100
+Subject: [PATCH] blscfg: fix filename in "no 'linux' key" error
+
+In find_entry(), 'filename' is either NULL or a directory in the ESP.
+But previously it was passed to create_entry(), which uses it in an
+error message as if it's the filename of the BLS entry in question.
+
+Since bls_entry now has a 'filename' field, just use that.
+
+Signed-off-by: Will Thompson <wjt@endlessm.com>
+---
+ grub-core/commands/blscfg.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index bd78559ef68..a45f40fe67e 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -514,7 +514,7 @@ static char **bls_make_list (struct bls_entry *entry, const char *key, int *num)
+   return list;
+ }
+ 
+-static void create_entry (struct bls_entry *entry, const char *cfgfile)
++static void create_entry (struct bls_entry *entry)
+ {
+   int argc = 0;
+   const char **argv = NULL;
+@@ -539,7 +539,7 @@ static void create_entry (struct bls_entry *entry, const char *cfgfile)
+   clinux = bls_get_val (entry, "linux", NULL);
+   if (!clinux)
+     {
+-      grub_dprintf ("blscfg", "Skipping file %s with no 'linux' key.\n", cfgfile);
++      grub_dprintf ("blscfg", "Skipping file %s with no 'linux' key.\n", entry->filename);
+       goto finish;
+     }
+ 
+@@ -753,7 +753,7 @@ static int find_entry (const char *filename,
+ 
+   grub_dprintf ("blscfg", "%s Creating %d entries from bls\n", __func__, nentries);
+   for (r = nentries - 1; r >= 0; r--)
+-      create_entry(entries[r], filename);
++      create_entry(entries[r]);
+ 
+   for (r = 0; r < nentries; r++)
+       bls_free_entry (entries[r]);
diff --git a/SOURCES/0204-blscfg-don-t-leak-bls_entry.filename.patch b/SOURCES/0204-blscfg-don-t-leak-bls_entry.filename.patch
new file mode 100644
index 0000000..5080e2e
--- /dev/null
+++ b/SOURCES/0204-blscfg-don-t-leak-bls_entry.filename.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Will Thompson <wjt@endlessm.com>
+Date: Thu, 12 Jul 2018 10:59:10 +0100
+Subject: [PATCH] blscfg: don't leak bls_entry.filename
+
+Zeroing the bls_entry struct before calling grub_free() on one of its
+fields is not going to work too well.
+
+Signed-off-by: Will Thompson <wjt@endlessm.com>
+---
+ grub-core/commands/blscfg.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index a45f40fe67e..11a356de81a 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -166,8 +166,8 @@ static void bls_free_entry(struct bls_entry *entry)
+     }
+ 
+   grub_free (entry->keyvals);
+-  grub_memset (entry, 0, sizeof (*entry));
+   grub_free (entry->filename);
++  grub_memset (entry, 0, sizeof (*entry));
+   grub_free (entry);
+ }
+ 
diff --git a/SOURCES/0205-blscfg-fix-compilation-on-EFI-and-EMU.patch b/SOURCES/0205-blscfg-fix-compilation-on-EFI-and-EMU.patch
new file mode 100644
index 0000000..04aadc3
--- /dev/null
+++ b/SOURCES/0205-blscfg-fix-compilation-on-EFI-and-EMU.patch
@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Will Thompson <wjt@endlessm.com>
+Date: Thu, 12 Jul 2018 19:00:42 +0100
+Subject: [PATCH] blscfg: fix compilation on !EFI and !EMU
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Neither GRUB_MACHINE_EFI nor GRUB_MACHINE_EMU are defined when compiling
+for (eg) i386-pc. In this case, #elif GRUB_MACHINE_EMU is an error:
+
+  commands/blscfg.c: In function ‘grub_cmd_blscfg’:
+  commands/blscfg.c:835:7: error: "GRUB_MACHINE_EMU" is not defined [-Werror=undef]
+   #elif GRUB_MACHINE_EMU
+         ^~~~~~~~~~~~~~~~
+
+Signed-off-by: Will Thompson <wjt@endlessm.com>
+---
+ grub-core/commands/blscfg.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 11a356de81a..53676576ba5 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -843,7 +843,7 @@ grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED,
+   info.platform = PLATFORM_EFI;
+   grub_dprintf ("blscfg", "scanning /EFI/\n");
+   r = fs->dir (dev, "/EFI/", find_entry, &info);
+-#elif GRUB_MACHINE_EMU
++#elif defined(GRUB_MACHINE_EMU)
+   info.platform = PLATFORM_EMU;
+   grub_dprintf ("blscfg", "scanning %s%s\n", GRUB_BOOT_DEVICE,
+ 		GRUB_BLS_CONFIG_PATH);
diff --git a/SOURCES/0206-Add-loadenv-to-blscfg-and-loadenv-source-file-list.patch b/SOURCES/0206-Add-loadenv-to-blscfg-and-loadenv-source-file-list.patch
new file mode 100644
index 0000000..76df19c
--- /dev/null
+++ b/SOURCES/0206-Add-loadenv-to-blscfg-and-loadenv-source-file-list.patch
@@ -0,0 +1,39 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Will Thompson <wjt@endlessm.com>
+Date: Fri, 13 Jul 2018 05:51:54 +0100
+Subject: [PATCH] Add loadenv to blscfg and loadenv source file list
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Without this, `make distcheck` fails because loadenv.h is not included
+in the source tarball.
+
+This broke in ‘Add blscfg command support to parse BootLoaderSpec config
+fragments’.
+
+Signed-off-by: Will Thompson <wjt@endlessm.com>
+---
+ grub-core/Makefile.core.def | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 2851437e098..aa44d66aca4 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -781,6 +781,7 @@ module = {
+ module = {
+   name = blscfg;
+   common = commands/blscfg.c;
++  common = commands/loadenv.h;
+   enable = efi;
+   enable = i386_pc;
+   enable = emu;
+@@ -947,6 +948,7 @@ module = {
+ module = {
+   name = loadenv;
+   common = commands/loadenv.c;
++  common = commands/loadenv.h;
+   common = lib/envblk.c;
+ };
+ 
diff --git a/SOURCES/0207-blscfg-Get-rid-of-the-linuxefi-linux16-linux-distinc.patch b/SOURCES/0207-blscfg-Get-rid-of-the-linuxefi-linux16-linux-distinc.patch
new file mode 100644
index 0000000..df63ac6
--- /dev/null
+++ b/SOURCES/0207-blscfg-Get-rid-of-the-linuxefi-linux16-linux-distinc.patch
@@ -0,0 +1,56 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 16 Jul 2018 11:00:50 -0400
+Subject: [PATCH] blscfg: Get rid of the linuxefi/linux16/linux distinction
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/commands/blscfg.c | 14 +++-----------
+ 1 file changed, 3 insertions(+), 11 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 53676576ba5..c6addc4dc12 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -43,14 +43,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define GRUB_BOOT_DEVICE "($root)"
+ #endif
+ 
+-#ifdef GRUB_MACHINE_EFI
+-#define GRUB_LINUX_CMD "linuxefi"
+-#define GRUB_INITRD_CMD "initrdefi"
+-#else
+-#define GRUB_LINUX_CMD "linux"
+-#define GRUB_INITRD_CMD "initrd"
+-#endif
+-
+ enum
+   {
+     PLATFORM_EFI,
+@@ -563,7 +555,7 @@ static void create_entry (struct bls_entry *entry)
+ 		title, id);
+   if (initrds)
+     {
+-      int initrd_size = sizeof (GRUB_INITRD_CMD);
++      int initrd_size = sizeof ("initrd");
+       char *tmp;
+ 
+       for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
+@@ -579,7 +571,7 @@ static void create_entry (struct bls_entry *entry)
+ 	}
+ 
+ 
+-      tmp = grub_stpcpy(initrd, GRUB_INITRD_CMD);
++      tmp = grub_stpcpy(initrd, "initrd ");
+       for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
+ 	{
+ 	  grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]);
+@@ -592,7 +584,7 @@ static void create_entry (struct bls_entry *entry)
+   src = grub_xasprintf ("load_video\n"
+ 			"set gfx_payload=keep\n"
+ 			"insmod gzio\n"
+-			GRUB_LINUX_CMD " %s%s%s%s\n"
++			"linux %s%s%s%s\n"
+ 			"%s",
+ 			GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "",
+ 			initrd ? initrd : "");
diff --git a/SOURCES/0208-grub-switch-to-blscfg-Only-fix-boot-prefix-for-non-g.patch b/SOURCES/0208-grub-switch-to-blscfg-Only-fix-boot-prefix-for-non-g.patch
new file mode 100644
index 0000000..9b996bc
--- /dev/null
+++ b/SOURCES/0208-grub-switch-to-blscfg-Only-fix-boot-prefix-for-non-g.patch
@@ -0,0 +1,48 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 18 Jul 2018 08:07:37 +0200
+Subject: [PATCH] grub-switch-to-blscfg: Only fix boot prefix for non-generated
+ BLS files
+
+The BLS files are either copied from /lib/modules/$kernelver/bls.conf or
+generated if this file doesn't exist. The shipped bls.conf default path
+for the kernel and initramfs is relative to the boot partition.
+
+But in some setups /boot may not be a mount point so in that case the
+boot prefix has to be added to the BLS. But we already provide this
+prefix for generated BLS files so attempting to add a boot prefix will
+lead to a path that contains the boot prefix twice (i.e: /boot/boot).
+
+Reported-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-switch-to-blscfg.in | 9 ++++-----
+ 1 file changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index 40612e00686..9cf64f8e725 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -236,6 +236,10 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+ 
+     if [ -f "${kernel_dir}/bls.conf" ] ; then
+         cp -af "${kernel_dir}/bls.conf" "${bls_target}"
++        if [ -n "${bootprefix}" ]; then
++            sed -i -e "s,^\(linux[^ \t]*[ \t]\+\).*,\1${bootprefix}${linux},g" "${bls_target}"
++            sed -i -e "/^initrd/ s,\([ \t]\+\)\([^ \t]\+\),\1${bootprefix}\2,g" "${bls_target}"
++        fi
+     else
+         mkbls "${kernelver}" \
+             "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${kernel_dir}")")" \
+@@ -243,11 +247,6 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+             >"${bls_target}"
+     fi
+ 
+-    if [ -n "${bootprefix}" ]; then
+-        sed -i -e "s,^\(linux[^ \t]*[ \t]\+\).*,\1${bootprefix}${linux},g" "${bls_target}"
+-        sed -i -e "/^initrd/ s,\([ \t]\+\)\([^ \t]\+\),\1${bootprefix}\2,g" "${bls_target}"
+-    fi
+-
+     if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
+         arch="$(uname -m)"
+         bls_debug="$(echo ${bls_target} | sed -e "s/\.${arch}/-debug.${arch}/")"
diff --git a/SOURCES/0209-blscfg-Expand-the-BLS-options-field-instead-of-showi.patch b/SOURCES/0209-blscfg-Expand-the-BLS-options-field-instead-of-showi.patch
new file mode 100644
index 0000000..3dca942
--- /dev/null
+++ b/SOURCES/0209-blscfg-Expand-the-BLS-options-field-instead-of-showi.patch
@@ -0,0 +1,130 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 18 Jul 2018 08:08:02 +0200
+Subject: [PATCH] blscfg: Expand the BLS options field instead of showing its
+ variables
+
+The values of the BLS fragment fields can either be string literals or
+grub2 environment variables, the latter will be expanded by grub2 when
+the boot entry is selected.
+
+But from a usability point of view, is much more convenient if the BLS
+parse code expand any variables that are present in the options field.
+
+That will allow users to select an entry in the menu by pressing the e
+key and edit the kernel command line parameters. So for example instead
+of showing the following:
+
+kernel /boot/vmlinuz-4.17.0 $kernelopts
+
+It would show something like the following:
+
+kernel /boot/vmlinuz-4.17.0 root=UUID=cec677c9-c890-4103-b94a-bcc191642935
+
+Suggested-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c | 69 ++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 68 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index c6addc4dc12..80d8814fc3f 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -32,6 +32,8 @@
+ #include <grub/normal.h>
+ #include <grub/lib/envblk.h>
+ 
++#include <stdbool.h>
++
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+ #include "loadenv.h"
+@@ -506,6 +508,70 @@ static char **bls_make_list (struct bls_entry *entry, const char *key, int *num)
+   return list;
+ }
+ 
++static char *field_append(bool is_var, char *buffer, char *start, char *end)
++{
++  char *temp = grub_strndup(start, end - start + 1);
++  const char *field = temp;
++
++  if (is_var) {
++    field = grub_env_get (temp);
++    if (!field)
++      return buffer;
++  }
++
++  if (!buffer) {
++    buffer = grub_strdup(field);
++    if (!buffer)
++      return NULL;
++  } else {
++    buffer = grub_realloc (buffer, grub_strlen(buffer) + grub_strlen(field));
++    if (!buffer)
++      return NULL;
++
++    grub_stpcpy (buffer + grub_strlen(buffer), field);
++  }
++
++  return buffer;
++}
++
++static char *expand_val(char *value)
++{
++  char *buffer = NULL;
++  char *start = value;
++  char *end = value;
++  bool is_var = false;
++
++  while (*value) {
++    if (*value == '$') {
++      if (start != end) {
++	buffer = field_append(is_var, buffer, start, end);
++	if (!buffer)
++	  return NULL;
++      }
++
++      is_var = true;
++      start = value + 1;
++    } else if (is_var) {
++      if (!grub_isalnum(*value) && *value != '_') {
++	buffer = field_append(is_var, buffer, start, end);
++	is_var = false;
++	start = value;
++      }
++    }
++
++    end = value;
++    value++;
++  }
++
++  if (start != end) {
++    buffer = field_append(is_var, buffer, start, end);
++    if (!buffer)
++      return NULL;
++  }
++
++  return buffer;
++}
++
+ static void create_entry (struct bls_entry *entry)
+ {
+   int argc = 0;
+@@ -536,7 +602,7 @@ static void create_entry (struct bls_entry *entry)
+     }
+ 
+   title = bls_get_val (entry, "title", NULL);
+-  options = bls_get_val (entry, "options", NULL);
++  options = expand_val (bls_get_val (entry, "options", NULL));
+   initrds = bls_make_list (entry, "initrd", NULL);
+ 
+   hotkey = bls_get_val (entry, "grub_hotkey", NULL);
+@@ -594,6 +660,7 @@ static void create_entry (struct bls_entry *entry)
+ finish:
+   grub_free (initrd);
+   grub_free (initrds);
++  grub_free (options);
+   grub_free (classes);
+   grub_free (args);
+   grub_free (argv);
diff --git a/SOURCES/0210-blscfg-Fallback-to-search-BLS-snippets-in-boot-loade.patch b/SOURCES/0210-blscfg-Fallback-to-search-BLS-snippets-in-boot-loade.patch
new file mode 100644
index 0000000..d04928f
--- /dev/null
+++ b/SOURCES/0210-blscfg-Fallback-to-search-BLS-snippets-in-boot-loade.patch
@@ -0,0 +1,59 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 18 Jul 2018 08:08:06 +0200
+Subject: [PATCH] blscfg: Fallback to search BLS snippets in
+ /boot/loader/entries
+
+The default path to search the BLS snippets is /loader/entries, this is
+only a correct assumption if $root ($root) is a boot partition but it's
+not true if /boot isn't a mount point.
+
+A user can set a blsdir grub environment variable to choose a different
+path, but instead of failing when /boot is a directory inside the root
+partition fallback to search the BLS in /boot/loader/entries to cover
+that case as well.
+
+Reported-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 80d8814fc3f..321c93069f2 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -692,6 +692,7 @@ static int find_entry (const char *filename,
+   grub_device_t blsdir_dev = NULL;
+   const char *blsdir = NULL;
+   char *saved_env_buf = NULL;
++  int fallback = 0;
+   int r = 0;
+   const char *devid = grub_env_get ("boot");
+ 
+@@ -797,7 +798,9 @@ static int find_entry (const char *filename,
+   }
+   read_entry_info.dirname = blsdir;
+ 
+-  r = blsdir_fs->dir (blsdir_dev, blsdir, read_entry, &read_entry_info);
++read_fallback:
++  r = blsdir_fs->dir (blsdir_dev, read_entry_info.dirname, read_entry,
++		      &read_entry_info);
+   if (r != 0) {
+       grub_dprintf ("blscfg", "read_entry returned error\n");
+       grub_err_t e;
+@@ -807,6 +810,14 @@ static int find_entry (const char *filename,
+ 	} while (e);
+   }
+ 
++  if (!nentries && !fallback && info->platform != PLATFORM_EMU) {
++    read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH;
++    grub_dprintf ("blscfg", "Entries weren't found in %s, fallback to %s\n",
++		  blsdir, read_entry_info.dirname);
++    fallback = 1;
++    goto read_fallback;
++  }
++
+   grub_dprintf ("blscfg", "Sorting %d entries\n", nentries);
+   grub_qsort(&entries[0], nentries, sizeof (struct bls_entry *), bls_cmp, NULL);
+ 
diff --git a/SOURCES/0211-blscfg-Don-t-attempt-to-sort-by-version-if-not-prese.patch b/SOURCES/0211-blscfg-Don-t-attempt-to-sort-by-version-if-not-prese.patch
new file mode 100644
index 0000000..60b609d
--- /dev/null
+++ b/SOURCES/0211-blscfg-Don-t-attempt-to-sort-by-version-if-not-prese.patch
@@ -0,0 +1,82 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 18 Jul 2018 00:58:44 +0200
+Subject: [PATCH] blscfg: Don't attempt to sort by version if not present in
+ all BLS files
+
+Commit a16805341cc ("blscfg: sort BLS entries by 'version' field") made to
+sort by the version field take precedence over the BLS fragment file name.
+
+But it also uses the lack of the version field in one BLS fragment as sort
+criterion, which means that entries could be wrongly sorted if one of them
+doesn't have a version field and others do.
+
+So only sort by version if all the BLS entries have this field defined,
+otherwise just fallback to sorting by the BLS file name.
+
+Reported-by: Hans de Goede <hdegoede@redhat.com>
+Suggested-by: Will Thompson <wjt@endlessm.com>
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c | 27 ++++++++++++++++-----------
+ 1 file changed, 16 insertions(+), 11 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 321c93069f2..69bfb5db295 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -324,23 +324,21 @@ finish:
+ /* return 1: p0 is newer than p1 */
+ /*        0: p0 and p1 are the same version */
+ /*       -1: p1 is newer than p0 */
+-static int bls_cmp(const void *p0, const void *p1, void *state UNUSED)
++static int bls_cmp(const void *p0, const void *p1, void *state)
+ {
+   struct bls_entry * e0 = *(struct bls_entry **)p0;
+   struct bls_entry * e1 = *(struct bls_entry **)p1;
++  bool use_version = *(bool *)state;
+   const char *v0, *v1;
+   int r;
+ 
+-  v0 = bls_get_val(e0, "version", NULL);
+-  v1 = bls_get_val(e1, "version", NULL);
++  if (use_version) {
++    v0 = bls_get_val(e0, "version", NULL);
++    v1 = bls_get_val(e1, "version", NULL);
+ 
+-  if (v0 && !v1)
+-    return -1;
+-  if (!v0 && v1)
+-    return 1;
+-
+-  if ((r = vercmp(v0, v1)) != 0)
+-    return r;
++    if ((r = vercmp(v0, v1)) != 0)
++      return r;
++  }
+ 
+   return vercmp(e0->filename, e1->filename);
+ }
+@@ -692,6 +690,7 @@ static int find_entry (const char *filename,
+   grub_device_t blsdir_dev = NULL;
+   const char *blsdir = NULL;
+   char *saved_env_buf = NULL;
++  bool use_version = true;
+   int fallback = 0;
+   int r = 0;
+   const char *devid = grub_env_get ("boot");
+@@ -819,7 +818,13 @@ read_fallback:
+   }
+ 
+   grub_dprintf ("blscfg", "Sorting %d entries\n", nentries);
+-  grub_qsort(&entries[0], nentries, sizeof (struct bls_entry *), bls_cmp, NULL);
++
++  for (r = 0; r < nentries && use_version; r++) {
++    if (!bls_get_val(entries[r], "version", NULL))
++      use_version = false;
++  }
++
++  grub_qsort(&entries[0], nentries, sizeof (struct bls_entry *), bls_cmp, &use_version);
+ 
+   grub_dprintf ("blscfg", "%s Creating %d entries from bls\n", __func__, nentries);
+   for (r = nentries - 1; r >= 0; r--)
diff --git a/SOURCES/0212-blscfg-remove-logic-to-read-the-grubenv-file-and-set.patch b/SOURCES/0212-blscfg-remove-logic-to-read-the-grubenv-file-and-set.patch
new file mode 100644
index 0000000..f32b620
--- /dev/null
+++ b/SOURCES/0212-blscfg-remove-logic-to-read-the-grubenv-file-and-set.patch
@@ -0,0 +1,292 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Sat, 28 Jul 2018 23:57:15 +0200
+Subject: [PATCH] blscfg: remove logic to read the grubenv file and set the
+ blsdir variable
+
+The BLS grub2 support has a blsdir environment variable that can be set by
+users to override the BLS fragment default path.
+
+Currently the BLS parsing code reads the grubenv file and sets the blsdir
+variable, but it shouldn't be the responsability of the blscfg module to
+do this and instead just use it if the variable has been set (either from
+the grub.cfg file or the grub shell).
+
+This makes the find_entry() function much simpler and consistent for EFI,
+BIOS and grub-emu. It also fixes a bug that caused having menu entries to
+be repeated for each sub-directory that existed under the /EFI directory.
+
+So for example having three different operating systems sharing the ESP,
+would lead to the boot menu entries being repeated three times for grub.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c | 179 ++++----------------------------------------
+ 1 file changed, 16 insertions(+), 163 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 69bfb5db295..bdb1c5a95aa 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -45,13 +45,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define GRUB_BOOT_DEVICE "($root)"
+ #endif
+ 
+-enum
+-  {
+-    PLATFORM_EFI,
+-    PLATFORM_EMU,
+-    PLATFORM_BIOS,
+-  };
+-
+ #define grub_free(x) ({grub_dprintf("blscfg", "%s freeing %p\n", __func__, x); grub_free(x); })
+ 
+ struct keyval
+@@ -666,137 +659,37 @@ finish:
+ }
+ 
+ struct find_entry_info {
++	const char *devid;
+ 	grub_device_t dev;
+ 	grub_fs_t fs;
+ 	int platform;
+ };
+ 
+ /*
+- * filename: if the directory is /EFI/something/ , filename is "something"
+- * info: unused
+- * data: the filesystem object the file is on.
++ * info: the filesystem object the file is on.
+  */
+-static int find_entry (const char *filename,
+-		       const struct grub_dirhook_info *dirhook_info UNUSED,
+-		       void *data)
++static int find_entry (struct find_entry_info *info)
+ {
+-  struct find_entry_info *info = (struct find_entry_info *)data;
+   struct read_entry_info read_entry_info;
+-  grub_file_t f = NULL;
+-  char *grubenv_path = NULL;
+-  grub_envblk_t env = NULL;
+-  const char *default_blsdir = NULL;
+   grub_fs_t blsdir_fs = NULL;
+   grub_device_t blsdir_dev = NULL;
+   const char *blsdir = NULL;
+-  char *saved_env_buf = NULL;
+   bool use_version = true;
+   int fallback = 0;
+   int r = 0;
+-  const char *devid = grub_env_get ("boot");
+-
+-  grub_dprintf("blscfg", "%s got here\n", __func__);
+-  if (filename && (!grub_strcmp (filename, ".") ||
+-		   !grub_strcmp (filename, "..")))
+-    return 0;
+-
+-  if (info->platform == PLATFORM_EFI && !grub_strcasecmp (filename, "boot"))
+-    return 0;
+-
+-  saved_env_buf = grub_malloc (512);
+-
+-  // set a default blsdir
+-  if (info->platform == PLATFORM_EMU)
+-    default_blsdir = GRUB_BOOT_DEVICE GRUB_BLS_CONFIG_PATH;
+-  else
+-    default_blsdir = GRUB_BLS_CONFIG_PATH;
+-
+-  grub_env_set ("blsdir", default_blsdir);
+-  grub_dprintf ("blscfg", "default_blsdir: \"%s\"\n", default_blsdir);
+-
+-  /*
+-   * try to load a grubenv from /EFI/wherever/grubenv
+-   */
+-  if (info->platform == PLATFORM_EFI)
+-    grubenv_path = grub_xasprintf ("(%s)/EFI/%s/grubenv", devid, filename);
+-  else
+-    grubenv_path = grub_xasprintf ("(%s)/grub2/grubenv", devid);
+-
+-  grub_dprintf ("blscfg", "looking for \"%s\"\n", grubenv_path);
+-  f = grub_file_open (grubenv_path);
+-
+-  grub_dprintf ("blscfg", "%s it\n", f ? "found" : "did not find");
+-  grub_free (grubenv_path);
+-  if (f)
+-    {
+-      grub_off_t sz;
+-
+-      grub_dprintf ("blscfg", "getting size\n");
+-      sz = grub_file_size (f);
+-      if (sz == GRUB_FILE_SIZE_UNKNOWN || sz > 1024*1024)
+-	goto finish;
+-
+-      grub_dprintf ("blscfg", "reading env\n");
+-      env = read_envblk_file (f);
+-      if (!env)
+-	goto finish;
+-      grub_dprintf ("blscfg", "read env file\n");
+-
+-      grub_memset (saved_env_buf, '#', 512);
+-      grub_memcpy (saved_env_buf, GRUB_ENVBLK_SIGNATURE,
+-		   sizeof (GRUB_ENVBLK_SIGNATURE));
+-      grub_dprintf ("blscfg", "saving env\n");
+-      saved_env = grub_envblk_open (saved_env_buf, 512);
+-      if (!saved_env)
+-	goto finish;
+-
+-      // save everything listed in "env" with values from our existing grub env
+-      grub_envblk_iterate (env, NULL, save_var);
+-      // set everything from our loaded grubenv into the real grub env
+-      grub_envblk_iterate (env, NULL, set_var);
+-    }
+-  else
+-    {
+-      grub_err_t e;
+-      grub_dprintf ("blscfg", "no such file\n");
+-      do
+-	{
+-	  e = grub_error_pop();
+-	} while (e);
+-
+-    }
+ 
+   blsdir = grub_env_get ("blsdir");
+   if (!blsdir)
+-    goto finish;
++    blsdir = GRUB_BLS_CONFIG_PATH;
+ 
+-  grub_dprintf ("blscfg", "blsdir: \"%s\"\n", blsdir);
+-  blsdir = grub_strdup (blsdir);
+-
+-  if (!blsdir)
+-    goto finish;
+-
+-  grub_dprintf ("blscfg", "blsdir: \"%s\"\n", blsdir);
+-  if (info->platform == PLATFORM_EFI) {
+-    read_entry_info.devid = grub_env_get ("root");
+-    if (!read_entry_info.devid)
+-      goto finish;
+-
+-    blsdir_dev = grub_device_open (read_entry_info.devid);
+-    if (!blsdir_dev)
+-      goto finish;
+-
+-    blsdir_fs = grub_fs_probe (blsdir_dev);
+-    if (!blsdir_fs)
+-      goto finish;
+-
+-  } else {
+-    read_entry_info.devid = devid;
+-    blsdir_dev = info->dev;
+-    blsdir_fs = info->fs;
+-  }
+   read_entry_info.dirname = blsdir;
+ 
++  grub_dprintf ("blscfg", "scanning blsdir: %s\n", GRUB_BLS_CONFIG_PATH);
++
++  blsdir_dev = info->dev;
++  blsdir_fs = info->fs;
++  read_entry_info.devid = info->devid;
++
+ read_fallback:
+   r = blsdir_fs->dir (blsdir_dev, read_entry_info.dirname, read_entry,
+ 		      &read_entry_info);
+@@ -809,7 +702,7 @@ read_fallback:
+ 	} while (e);
+   }
+ 
+-  if (!nentries && !fallback && info->platform != PLATFORM_EMU) {
++  if (!nentries && !fallback) {
+     read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH;
+     grub_dprintf ("blscfg", "Entries weren't found in %s, fallback to %s\n",
+ 		  blsdir, read_entry_info.dirname);
+@@ -832,41 +725,12 @@ read_fallback:
+ 
+   for (r = 0; r < nentries; r++)
+       bls_free_entry (entries[r]);
+-finish:
+-  if (info->platform == PLATFORM_EFI && blsdir_dev)
+-    grub_device_close (blsdir_dev);
+ 
+   nentries = 0;
+ 
+   grub_free (entries);
+   entries = NULL;
+ 
+-  grub_free ((char *)blsdir);
+-
+-  grub_env_unset ("blsdir");
+-
+-  if (saved_env)
+-    {
+-      // remove everything from the real environment that's defined in env
+-      grub_envblk_iterate (env, NULL, unset_var);
+-
+-      // re-set the things from our original environment
+-      grub_envblk_iterate (saved_env, NULL, set_var);
+-      grub_envblk_close (saved_env);
+-      saved_env = NULL;
+-    }
+-  else if (saved_env_buf)
+-    {
+-      // if we have a saved environment, grub_envblk_close() freed this.
+-      grub_free (saved_env_buf);
+-    }
+-
+-  if (env)
+-    grub_envblk_close (env);
+-
+-  if (f)
+-    grub_file_close (f);
+-
+   return 0;
+ }
+ 
+@@ -883,7 +747,6 @@ grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED,
+     {
+       .dev = NULL,
+       .fs = NULL,
+-      .platform = PLATFORM_BIOS,
+     };
+ 
+ 
+@@ -891,13 +754,14 @@ grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED,
+ 
+ #ifdef GRUB_MACHINE_EMU
+   devid = "host";
+-  grub_env_set ("boot", devid);
++#elif defined(GRUB_MACHINE_EFI)
++  devid = grub_env_get ("root");
+ #else
+   devid = grub_env_get ("boot");
++#endif
+   if (!devid)
+     return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ 		       N_("variable `%s' isn't set"), "boot");
+-#endif
+ 
+   grub_dprintf ("blscfg", "opening %s\n", devid);
+   dev = grub_device_open (devid);
+@@ -912,21 +776,10 @@ grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED,
+       goto finish;
+     }
+ 
++  info.devid = devid;
+   info.dev = dev;
+   info.fs = fs;
+-#ifdef GRUB_MACHINE_EFI
+-  info.platform = PLATFORM_EFI;
+-  grub_dprintf ("blscfg", "scanning /EFI/\n");
+-  r = fs->dir (dev, "/EFI/", find_entry, &info);
+-#elif defined(GRUB_MACHINE_EMU)
+-  info.platform = PLATFORM_EMU;
+-  grub_dprintf ("blscfg", "scanning %s%s\n", GRUB_BOOT_DEVICE,
+-		GRUB_BLS_CONFIG_PATH);
+-  find_entry(NULL, NULL, &info);
+-#else
+-  grub_dprintf ("blscfg", "scanning %s\n", GRUB_BLS_CONFIG_PATH);
+-  find_entry(NULL, NULL, &info);
+-#endif
++  find_entry(&info);
+ 
+ finish:
+   if (dev)
diff --git a/SOURCES/0213-Rename-00_menu_auto_hide.in-to-01_menu_auto_hide.in.patch b/SOURCES/0213-Rename-00_menu_auto_hide.in-to-01_menu_auto_hide.in.patch
new file mode 100644
index 0000000..14cc004
--- /dev/null
+++ b/SOURCES/0213-Rename-00_menu_auto_hide.in-to-01_menu_auto_hide.in.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Christian Glombek <lorbus@fedoraproject.org>
+Date: Tue, 31 Jul 2018 11:11:01 +0200
+Subject: [PATCH] Rename 00_menu_auto_hide.in to 01_menu_auto_hide.in
+
+This is necessary to accommodate the fallback counting script which
+needs to run before this one because the menu auto hide script sets
+boot_success = 0, which will be used by the boot counting script
+---
+ Makefile.util.def                                          | 4 ++--
+ util/grub.d/{00_menu_auto_hide.in => 01_menu_auto_hide.in} | 0
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+ rename util/grub.d/{00_menu_auto_hide.in => 01_menu_auto_hide.in} (100%)
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index 97cd8bdebd9..cba4d500198 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -449,8 +449,8 @@ script = {
+ };
+ 
+ script = {
+-  name = '00_menu_auto_hide';
+-  common = util/grub.d/00_menu_auto_hide.in;
++  name = '01_menu_auto_hide';
++  common = util/grub.d/01_menu_auto_hide.in;
+   installdir = grubconf;
+ };
+ 
+diff --git a/util/grub.d/00_menu_auto_hide.in b/util/grub.d/01_menu_auto_hide.in
+similarity index 100%
+rename from util/grub.d/00_menu_auto_hide.in
+rename to util/grub.d/01_menu_auto_hide.in
diff --git a/SOURCES/0214-efinet-also-use-the-firmware-acceleration-for-http.patch b/SOURCES/0214-efinet-also-use-the-firmware-acceleration-for-http.patch
new file mode 100644
index 0000000..5771c8a
--- /dev/null
+++ b/SOURCES/0214-efinet-also-use-the-firmware-acceleration-for-http.patch
@@ -0,0 +1,25 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 30 Jul 2018 14:06:42 -0400
+Subject: [PATCH] efinet: also use the firmware acceleration for http
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/efi/net.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
+index 2bf15447fd5..f208d1b180c 100644
+--- a/grub-core/net/efi/net.c
++++ b/grub-core/net/efi/net.c
+@@ -1324,7 +1324,9 @@ grub_efi_net_boot_from_https (void)
+ 	  && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
+ 	{
+ 	  grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp;
+-	  return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0;
++	  grub_dprintf ("efinet", "url:%s\n", (const char *)uri_dp->uri);
++	  return (grub_strncmp ((const char *)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0 ||
++	          grub_strncmp ((const char *)uri_dp->uri, "http://", sizeof ("http://") - 1) == 0);
+ 	}
+ 
+       if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
diff --git a/SOURCES/0215-efi-http-Make-root_url-reflect-the-protocol-hostname.patch b/SOURCES/0215-efi-http-Make-root_url-reflect-the-protocol-hostname.patch
new file mode 100644
index 0000000..985a037
--- /dev/null
+++ b/SOURCES/0215-efi-http-Make-root_url-reflect-the-protocol-hostname.patch
@@ -0,0 +1,50 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 30 Jul 2018 16:39:57 -0400
+Subject: [PATCH] efi/http: Make root_url reflect the protocol+hostname of our
+ boot url.
+
+This lets you write config files that don't know urls.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/net/efi/http.c | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
+index 3f61fd2fa5b..243acbaa35b 100644
+--- a/grub-core/net/efi/http.c
++++ b/grub-core/net/efi/http.c
+@@ -4,6 +4,7 @@
+ #include <grub/misc.h>
+ #include <grub/net/efi.h>
+ #include <grub/charset.h>
++#include <grub/env.h>
+ 
+ static void
+ http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
+@@ -351,6 +352,24 @@ grub_efihttp_open (struct grub_efi_net_device *dev,
+   grub_err_t err;
+   grub_off_t size;
+   char *buf;
++  char *root_url;
++  grub_efi_ipv6_address_t address;
++  const char *rest;
++
++  if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0)
++    root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server);
++  else
++    root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server);
++  if (root_url)
++    {
++      grub_env_unset ("root_url");
++      grub_env_set ("root_url", root_url);
++      grub_free (root_url);
++    }
++  else
++    {
++      return grub_errno;
++    }
+ 
+   err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0);
+   if (err != GRUB_ERR_NONE)
diff --git a/SOURCES/0216-Disable-multiboot-multiboot2-and-linux16-modules-on-.patch b/SOURCES/0216-Disable-multiboot-multiboot2-and-linux16-modules-on-.patch
new file mode 100644
index 0000000..9dccf5a
--- /dev/null
+++ b/SOURCES/0216-Disable-multiboot-multiboot2-and-linux16-modules-on-.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 11 Jul 2018 13:48:48 -0400
+Subject: [PATCH] Disable multiboot, multiboot2, and linux16 modules on EFI
+ builds.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/Makefile.core.def | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index aa44d66aca4..d3e3bfd4d7a 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -1680,7 +1680,7 @@ module = {
+ 
+   common = loader/multiboot.c;
+   common = loader/multiboot_mbi2.c;
+-  enable = x86;
++  enable = i386_pc;
+   enable = mips;
+ };
+ 
+@@ -1689,7 +1689,7 @@ module = {
+   common = loader/multiboot.c;
+   x86 = loader/i386/multiboot_mbi.c;
+   extra_dist = loader/multiboot_elfxx.c;
+-  enable = x86;
++  enable = i386_pc;
+ };
+ 
+ module = {
diff --git a/SOURCES/0217-Force-everything-to-use-python3.patch b/SOURCES/0217-Force-everything-to-use-python3.patch
new file mode 100644
index 0000000..b4b0d74
--- /dev/null
+++ b/SOURCES/0217-Force-everything-to-use-python3.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 10 Jul 2018 16:54:02 -0400
+Subject: [PATCH] Force everything to use python3
+
+But this still means you need to do PYTHON=python=3 ./autogen.sh if you
+run the world's worst tooling before you patch.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ conf/Makefile.common | 4 ++--
+ gentpl.py            | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/conf/Makefile.common b/conf/Makefile.common
+index c75848f5c06..1ecb921db65 100644
+--- a/conf/Makefile.common
++++ b/conf/Makefile.common
+@@ -128,11 +128,11 @@ BUILT_SOURCES =
+ 
+ .PRECIOUS: $(top_srcdir)/Makefile.util.am
+ $(top_srcdir)/Makefile.util.am: $(top_srcdir)/gentpl.py $(top_srcdir)/Makefile.util.def $(top_srcdir)/Makefile.utilgcry.def
+-	python $^ > $@.new || (rm -f $@.new; exit 1)
++	python3 $^ > $@.new || (rm -f $@.new; exit 1)
+ 	mv $@.new $@
+ 
+ .PRECIOUS: $(top_srcdir)/grub-core/Makefile.core.am
+ $(top_srcdir)/grub-core/Makefile.core.am: $(top_srcdir)/gentpl.py $(top_srcdir)/grub-core/Makefile.core.def $(top_srcdir)/grub-core/Makefile.gcry.def
+ 	if [ "x$$GRUB_CONTRIB" != x ]; then echo "You need to run ./autogen.sh manually." >&2; exit 1; fi
+-	python $^ > $@.new || (rm -f $@.new; exit 1)
++	python3 $^ > $@.new || (rm -f $@.new; exit 1)
+ 	mv $@.new $@
+diff --git a/gentpl.py b/gentpl.py
+index baac6a2af69..6409736e81c 100644
+--- a/gentpl.py
++++ b/gentpl.py
+@@ -1,4 +1,4 @@
+-#! /usr/bin/python
++#! /usr/bin/env python3
+ #  GRUB  --  GRand Unified Bootloader
+ #  Copyright (C) 2010,2011,2012,2013  Free Software Foundation, Inc.
+ #
diff --git a/SOURCES/0218-Fix-an-8-year-old-typo.patch b/SOURCES/0218-Fix-an-8-year-old-typo.patch
new file mode 100644
index 0000000..642e46a
--- /dev/null
+++ b/SOURCES/0218-Fix-an-8-year-old-typo.patch
@@ -0,0 +1,23 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 26 Jul 2018 14:54:44 -0400
+Subject: [PATCH] Fix an 8 year old typo.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ configure.ac | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/configure.ac b/configure.ac
+index 5f47a9265f3..9ab683fefac 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -307,7 +307,7 @@ fi
+ 
+ AC_SUBST(bootdirname)
+ AC_DEFINE_UNQUOTED(GRUB_BOOT_DIR_NAME, "$bootdirname",
+-    [Default boot directory name]")
++    [Default boot directory name])
+ 
+ AC_ARG_WITH([grubdir],
+             AS_HELP_STRING([--with-grubdir=DIR],
diff --git a/SOURCES/0219-autogen-don-t-run-autoreconf-in-the-topdir.patch b/SOURCES/0219-autogen-don-t-run-autoreconf-in-the-topdir.patch
new file mode 100644
index 0000000..e5b7c33
--- /dev/null
+++ b/SOURCES/0219-autogen-don-t-run-autoreconf-in-the-topdir.patch
@@ -0,0 +1,21 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 26 Jul 2018 15:47:48 -0400
+Subject: [PATCH] autogen: don't run autoreconf in the topdir
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ autogen.sh | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/autogen.sh b/autogen.sh
+index 7537561ad0d..f608b9467a0 100755
+--- a/autogen.sh
++++ b/autogen.sh
+@@ -82,6 +82,4 @@ done
+ echo "Saving timestamps..."
+ echo timestamp > stamp-h.in
+ 
+-echo "Running autoreconf..."
+-autoreconf -vi
+ exit 0
diff --git a/SOURCES/0220-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch b/SOURCES/0220-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch
new file mode 100644
index 0000000..292e565
--- /dev/null
+++ b/SOURCES/0220-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch
@@ -0,0 +1,149 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 26 Jun 2018 17:16:06 -0400
+Subject: [PATCH] Make it so we can tell configure which cflags utils are built
+ with
+
+This lets us have kernel.img be built with TARGET_CFLAGS but grub-mkimage and
+friends built with HOST_CFLAGS.  That in turn lets us build with an ARM compiler
+that only has hard-float ABI versions of crt*.o and libgcc*, but still use soft
+float for grub.efi.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ configure.ac         | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ conf/Makefile.common | 23 ++++++++++++-----------
+ gentpl.py            |  8 ++++----
+ 3 files changed, 64 insertions(+), 16 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 9ab683fefac..819212095ff 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -850,11 +850,23 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ) && test "x$p
+   TARGET_CFLAGS="$TARGET_CFLAGS -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow"
+ fi
+ 
++# Should grub utils get the host CFLAGS, or the target CFLAGS?
++AC_ARG_WITH([utils],
++            AS_HELP_STRING([--with-utils=host|target|build],
++                           [choose which flags to build utilities with. (default=target)]),
++	    [have_with_utils=y],
++	    [have_with_utils=n])
++if test x"$have_with_utils" = xy ; then
++  with_utils="$withval"
++else
++  with_utils=target
++fi
++
+ # GRUB doesn't use float or doubles at all. Yet some toolchains may decide
+ # that floats are a good fit to run instead of what's written in the code.
+ # Given that floating point unit is disabled (if present to begin with)
+ # when GRUB is running which may result in various hard crashes.
+-if test x"$platform" != xemu ; then
++if test x"$platform" != xemu -a x"$with_utils" == xtarget ; then
+   AC_CACHE_CHECK([for options to get soft-float], grub_cv_target_cc_soft_float, [
+     grub_cv_target_cc_soft_float=no
+     if test "x$target_cpu" = xarm64; then
+@@ -1939,6 +1951,41 @@ HOST_CPPFLAGS="$HOST_CPPFLAGS -I\$(top_builddir)/include"
+ TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_srcdir)/include"
+ TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_builddir)/include"
+ 
++case "$with_utils" in
++  host)
++    UTILS_CFLAGS=$HOST_CFLAGS
++    UTILS_CPPFLAGS=$HOST_CPPFLAGS
++    UTILS_CCASFLAGS=$HOST_CCASFLAGS
++    UTILS_LDFLAGS=$HOST_LDFLAGS
++    ;;
++  target)
++    UTILS_CFLAGS=$TARGET_CFLAGS
++    UTILS_CPPFLAGS=$TARGET_CPPFLAGS
++    UTILS_CCASFLAGS=$TARGET_CCASFLAGS
++    UTILS_LDFLAGS=$TARGET_LDFLAGS
++    ;;
++  build)
++    UTILS_CFLAGS=$BUILD_CFLAGS
++    UTILS_CPPFLAGS=$BUILD_CPPFLAGS
++    UTILS_CCASFLAGS=$BUILD_CCASFLAGS
++    UTILS_LDFLAGS=$BUILD_LDFLAGS
++    ;;
++  *)
++    AC_MSG_ERROR([--with-utils must be either host, target, or build])
++    ;;
++esac
++AC_MSG_NOTICE([Using $with_utils flags for utilities.])
++
++unset CFLAGS
++unset CPPFLAGS
++unset CCASFLAGS
++unset LDFLAGS
++
++AC_SUBST(UTILS_CFLAGS)
++AC_SUBST(UTILS_CPPFLAGS)
++AC_SUBST(UTILS_CCASFLAGS)
++AC_SUBST(UTILS_LDFLAGS)
++
+ GRUB_TARGET_CPU="${target_cpu}"
+ GRUB_PLATFORM="${platform}"
+ 
+diff --git a/conf/Makefile.common b/conf/Makefile.common
+index 1ecb921db65..b93879804c0 100644
+--- a/conf/Makefile.common
++++ b/conf/Makefile.common
+@@ -40,24 +40,25 @@ CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1
+ CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
+ STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes
+ 
+-CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding
+-LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
+-CPPFLAGS_MODULE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM)
+-CCASFLAGS_MODULE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
++CFLAGS_MODULE = $(TARGET_CFLAGS) $(CFLAGS_PLATFORM) -ffreestanding
++LDFLAGS_MODULE = $(TARGET_LDFLAGS) $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d
++CPPFLAGS_MODULE = $(TARGET_CPPFLAGS) $(CPPFLAGS_DEFAULT) $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM)
++CCASFLAGS_MODULE = $(TARGET_CCASFLAGS) $(CCASFLAGS_DEFAULT) $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
+ 
+ CFLAGS_IMAGE = $(CFLAGS_PLATFORM) -fno-builtin
+ LDFLAGS_IMAGE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-S
+ CPPFLAGS_IMAGE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM)
+ CCASFLAGS_IMAGE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM)
+ 
+-CFLAGS_PROGRAM =
+-LDFLAGS_PROGRAM =
+-CPPFLAGS_PROGRAM =
+-CCASFLAGS_PROGRAM =
++CFLAGS_PROGRAM = $(UTILS_CFLAGS)
++LDFLAGS_PROGRAM = $(UTILS_LDFLAGS)
++CPPFLAGS_PROGRAM = $(UTILS_CPPFLAGS)
++CCASFLAGS_PROGRAM = $(UTILS_CCASFLAGS)
+ 
+-CFLAGS_LIBRARY =
+-CPPFLAGS_LIBRARY =
+-CCASFLAGS_LIBRARY =
++CFLAGS_LIBRARY = $(UTILS_CFLAGS)
++LDFLAGS_LIBRARY = $(UTILS_LDFLAGS)
++CPPFLAGS_LIBRARY = $(UTILS_CPPFLAGS)
++CCASFLAGS_LIBRARY = $(UTILS_CCASFLAGS)
+ 
+ # Other variables
+ 
+diff --git a/gentpl.py b/gentpl.py
+index 6409736e81c..1e4635f4426 100644
+--- a/gentpl.py
++++ b/gentpl.py
+@@ -694,10 +694,10 @@ def module(defn, platform):
+     var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform) + " ## platform sources")
+     var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources")
+     var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform))
+-    var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_MODULE) " + platform_cflags(defn, platform))
+-    var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_MODULE) " + platform_ldflags(defn, platform))
+-    var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform))
+-    var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform))
++    var_set(cname(defn) + "_CFLAGS", "$(CFLAGS_MODULE) " + platform_cflags(defn, platform))
++    var_set(cname(defn) + "_LDFLAGS", "$(LDFLAGS_MODULE) " + platform_ldflags(defn, platform))
++    var_set(cname(defn) + "_CPPFLAGS", "$(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform))
++    var_set(cname(defn) + "_CCASFLAGS", "$(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform))
+     var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF) " + platform_dependencies(defn, platform))
+ 
+     gvar_add("dist_noinst_DATA", extra_dist(defn))
diff --git a/SOURCES/0221-module-verifier-make-it-possible-to-run-checkers-on-.patch b/SOURCES/0221-module-verifier-make-it-possible-to-run-checkers-on-.patch
new file mode 100644
index 0000000..0bdfca1
--- /dev/null
+++ b/SOURCES/0221-module-verifier-make-it-possible-to-run-checkers-on-.patch
@@ -0,0 +1,58 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 1 Aug 2018 10:24:52 -0400
+Subject: [PATCH] module-verifier: make it possible to run checkers on
+ grub-module-verifierxx.c
+
+This makes it so you can treat grub-module-verifierxx.c as a file you can
+build directly, so syntax checkers like vim's "syntastic" plugin, which uses
+"gcc -x c -fsyntax-only" to build it, will work.
+
+One still has to do whatever setup is required to make it pick the right
+include dirs, which -W options we use, etc., but this makes it so you can do
+the checking on the file you're editing, rather than on a different file.
+
+v2: fix the typo in the #else clause in util/grub-module-verifierXX.c
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-module-verifier32.c | 2 ++
+ util/grub-module-verifier64.c | 2 ++
+ util/grub-module-verifierXX.c | 9 +++++++++
+ 3 files changed, 13 insertions(+)
+
+diff --git a/util/grub-module-verifier32.c b/util/grub-module-verifier32.c
+index 257229f8f08..ba7d41aafea 100644
+--- a/util/grub-module-verifier32.c
++++ b/util/grub-module-verifier32.c
+@@ -1,2 +1,4 @@
+ #define MODULEVERIFIER_ELF32 1
++#ifndef GRUB_MODULE_VERIFIERXX
+ #include "grub-module-verifierXX.c"
++#endif
+diff --git a/util/grub-module-verifier64.c b/util/grub-module-verifier64.c
+index 4db6b4bedd1..fc23ef800b3 100644
+--- a/util/grub-module-verifier64.c
++++ b/util/grub-module-verifier64.c
+@@ -1,2 +1,4 @@
+ #define MODULEVERIFIER_ELF64 1
++#ifndef GRUB_MODULE_VERIFIERXX
+ #include "grub-module-verifierXX.c"
++#endif
+diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c
+index 1feaafc9b9e..597ded14362 100644
+--- a/util/grub-module-verifierXX.c
++++ b/util/grub-module-verifierXX.c
+@@ -1,3 +1,12 @@
++#define GRUB_MODULE_VERIFIERXX
++#if !defined(MODULEVERIFIER_ELF32) && !defined(MODULEVERIFIER_ELF64)
++#if __SIZEOF_POINTER__ == 8
++#include "grub-module-verifier64.c"
++#else
++#include "grub-module-verifier32.c"
++#endif
++#endif
++
+ #include <string.h>
+ 
+ #include <grub/elf.h>
diff --git a/SOURCES/0222-grub-module-verifier-report-the-filename-or-modname-.patch b/SOURCES/0222-grub-module-verifier-report-the-filename-or-modname-.patch
new file mode 100644
index 0000000..c27d065
--- /dev/null
+++ b/SOURCES/0222-grub-module-verifier-report-the-filename-or-modname-.patch
@@ -0,0 +1,250 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 1 Aug 2018 10:12:47 -0400
+Subject: [PATCH] grub-module-verifier: report the filename or modname in
+ errors.
+
+Make it so that when grub-module-verifier complains of an issue, it tells you
+which module the issue was with.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-module-verifier.c    |  6 ++---
+ util/grub-module-verifierXX.c  | 58 ++++++++++++++++++++++--------------------
+ include/grub/module_verifier.h |  4 +--
+ 3 files changed, 36 insertions(+), 32 deletions(-)
+
+diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c
+index a79271f6631..03ba1ab437a 100644
+--- a/util/grub-module-verifier.c
++++ b/util/grub-module-verifier.c
+@@ -157,7 +157,7 @@ main (int argc, char **argv)
+     if (strcmp(archs[arch].name, argv[2]) == 0)
+       break;
+   if (arch == ARRAY_SIZE(archs))
+-    grub_util_error("unknown arch: %s", argv[2]);
++    grub_util_error("%s: unknown arch: %s", argv[1], argv[2]);
+ 
+   for (whitelist = 0; whitelist < ARRAY_SIZE(whitelists); whitelist++)
+     if (strcmp(whitelists[whitelist].arch, argv[2]) == 0
+@@ -169,8 +169,8 @@ main (int argc, char **argv)
+   module_size = grub_util_get_image_size (argv[1]);
+   module_img = grub_util_read_image (argv[1]);
+   if (archs[arch].voidp_sizeof == 8)
+-    grub_module_verify64(module_img, module_size, &archs[arch], whitelist_empty);
++    grub_module_verify64(argv[1], module_img, module_size, &archs[arch], whitelist_empty);
+   else
+-    grub_module_verify32(module_img, module_size, &archs[arch], whitelist_empty);
++    grub_module_verify32(argv[1], module_img, module_size, &archs[arch], whitelist_empty);
+   return 0;
+ }
+diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c
+index 597ded14362..a98e2f9b1ac 100644
+--- a/util/grub-module-verifierXX.c
++++ b/util/grub-module-verifierXX.c
+@@ -160,14 +160,15 @@ find_section (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e, const c
+ }
+ 
+ static void
+-check_license (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e)
++check_license (const char * const filename,
++	       const struct grub_module_verifier_arch *arch, Elf_Ehdr *e)
+ {
+   Elf_Shdr *s = find_section (arch, e, ".module_license");
+   if (s && (strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv3") == 0
+ 	    || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv3+") == 0
+ 	    || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv2+") == 0))
+     return;
+-  grub_util_error ("incompatible license");
++  grub_util_error ("%s: incompatible license", filename);
+ }
+ 
+ static Elf_Sym *
+@@ -233,10 +234,10 @@ check_symbols (const struct grub_module_verifier_arch *arch,
+       s = find_section (arch, e, ".moddeps");
+ 
+       if (!s)
+-	grub_util_error ("no symbol table and no .moddeps section");
++	grub_util_error ("%s: no symbol table and no .moddeps section", modname);
+ 
+       if (!s->sh_size)
+-	grub_util_error ("no symbol table and empty .moddeps section");
++	grub_util_error ("%s: no symbol table and empty .moddeps section", modname);
+ 
+       return;
+     }
+@@ -257,7 +258,7 @@ check_symbols (const struct grub_module_verifier_arch *arch,
+ 	  break;
+ 
+ 	default:
+-	  return grub_util_error ("unknown symbol type `%d'", (int) type);
++	  return grub_util_error ("%s: unknown symbol type `%d'", modname, (int) type);
+ 	}
+     }
+ }
+@@ -283,7 +284,8 @@ is_symbol_local(Elf_Sym *sym)
+ }
+ 
+ static void
+-section_check_relocations (const struct grub_module_verifier_arch *arch, void *ehdr,
++section_check_relocations (const char * const modname,
++			   const struct grub_module_verifier_arch *arch, void *ehdr,
+ 			   Elf_Shdr *s, size_t target_seg_size)
+ {
+   Elf_Rel *rel, *max;
+@@ -292,7 +294,7 @@ section_check_relocations (const struct grub_module_verifier_arch *arch, void *e
+ 
+   symtab = get_symtab (arch, ehdr, &symtabsize, &symtabentsize);
+   if (!symtab)
+-    grub_util_error ("relocation without symbol table");
++    grub_util_error ("%s: relocation without symbol table", modname);
+ 
+   for (rel = (Elf_Rel *) ((char *) ehdr + grub_target_to_host (s->sh_offset)),
+ 	 max = (Elf_Rel *) ((char *) rel + grub_target_to_host (s->sh_size));
+@@ -303,7 +305,7 @@ section_check_relocations (const struct grub_module_verifier_arch *arch, void *e
+       unsigned i;
+ 
+       if (target_seg_size < grub_target_to_host (rel->r_offset))
+-	grub_util_error ("reloc offset is out of the segment");
++	grub_util_error ("%s: reloc offset is out of the segment", modname);
+ 
+       grub_uint32_t type = ELF_R_TYPE (grub_target_to_host (rel->r_info));
+ 
+@@ -316,17 +318,17 @@ section_check_relocations (const struct grub_module_verifier_arch *arch, void *e
+       if (arch->supported_relocations[i] != -1)
+ 	continue;
+       if (!arch->short_relocations)
+-	grub_util_error ("unsupported relocation 0x%x", type);
++	grub_util_error ("%s: unsupported relocation 0x%x", modname, type);
+       for (i = 0; arch->short_relocations[i] != -1; i++)
+ 	if (type == arch->short_relocations[i])
+ 	  break;
+       if (arch->short_relocations[i] == -1)
+-	grub_util_error ("unsupported relocation 0x%x", type);
++	grub_util_error ("%s: unsupported relocation 0x%x", modname, type);
+       sym = (Elf_Sym *) ((char *) symtab + symtabentsize * ELF_R_SYM (grub_target_to_host (rel->r_info)));
+ 
+       if (is_symbol_local (sym))
+ 	continue;
+-      grub_util_error ("relocation 0x%x is not module-local", type);
++      grub_util_error ("%s: relocation 0x%x is not module-local", modname, type);
+     }
+ #if defined(MODULEVERIFIER_ELF64)
+   if (arch->machine == EM_AARCH64)
+@@ -351,11 +353,11 @@ section_check_relocations (const struct grub_module_verifier_arch *arch, void *e
+ 		    && ELF_R_TYPE (rel2->r_info) == R_AARCH64_LD64_GOT_LO12_NC)
+ 		  break;
+ 	      if (rel2 >= (Elf_Rela *) max)
+-		grub_util_error ("ADR_GOT_PAGE without matching LD64_GOT_LO12_NC");
++		grub_util_error ("%s: ADR_GOT_PAGE without matching LD64_GOT_LO12_NC", modname);
+ 	      break;
+ 	    case R_AARCH64_LD64_GOT_LO12_NC:
+ 	      if (unmatched_adr_got_page == 0)
+-		grub_util_error ("LD64_GOT_LO12_NC without matching ADR_GOT_PAGE");
++		grub_util_error ("%s: LD64_GOT_LO12_NC without matching ADR_GOT_PAGE", modname);
+ 	      unmatched_adr_got_page--;
+ 	      break;
+ 	    }
+@@ -365,7 +367,8 @@ section_check_relocations (const struct grub_module_verifier_arch *arch, void *e
+ }
+ 
+ static void
+-check_relocations (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e)
++check_relocations (const char * const modname,
++		   const struct grub_module_verifier_arch *arch, Elf_Ehdr *e)
+ {
+   Elf_Shdr *s;
+   unsigned i;
+@@ -378,21 +381,22 @@ check_relocations (const struct grub_module_verifier_arch *arch, Elf_Ehdr *e)
+ 	Elf_Shdr *ts;
+ 
+ 	if (grub_target_to_host32 (s->sh_type) == SHT_REL && !(arch->flags & GRUB_MODULE_VERIFY_SUPPORTS_REL))
+-	  grub_util_error ("unsupported SHT_REL");
++	  grub_util_error ("%s: unsupported SHT_REL", modname);
+ 	if (grub_target_to_host32 (s->sh_type) == SHT_RELA && !(arch->flags & GRUB_MODULE_VERIFY_SUPPORTS_RELA))
+-	  grub_util_error ("unsupported SHT_RELA");
++	  grub_util_error ("%s: unsupported SHT_RELA", modname);
+ 
+ 	/* Find the target segment.  */
+ 	if (grub_target_to_host32 (s->sh_info) >= grub_target_to_host16 (e->e_shnum))
+-	  grub_util_error ("orphaned reloc section");
++	  grub_util_error ("%s: orphaned reloc section", modname);
+ 	ts = (Elf_Shdr *) ((char *) e + grub_target_to_host (e->e_shoff) + grub_target_to_host32 (s->sh_info) * grub_target_to_host16 (e->e_shentsize));
+ 
+-	section_check_relocations (arch, e, s, grub_target_to_host (ts->sh_size));
++	section_check_relocations (modname, arch, e, s, grub_target_to_host (ts->sh_size));
+       }
+ }
+ 
+ void
+-SUFFIX(grub_module_verify) (void *module_img, size_t size,
++SUFFIX(grub_module_verify) (const char * const filename,
++			    void *module_img, size_t size,
+ 			    const struct grub_module_verifier_arch *arch,
+ 			    const char **whitelist_empty)
+ {
+@@ -400,7 +404,7 @@ SUFFIX(grub_module_verify) (void *module_img, size_t size,
+ 
+   /* Check the header size.  */
+   if (size < sizeof (Elf_Ehdr))
+-    grub_util_error ("ELF header smaller than expected");
++    grub_util_error ("%s: ELF header smaller than expected", filename);
+ 
+   /* Check the magic numbers.  */
+   if (e->e_ident[EI_MAG0] != ELFMAG0
+@@ -409,36 +413,36 @@ SUFFIX(grub_module_verify) (void *module_img, size_t size,
+       || e->e_ident[EI_MAG3] != ELFMAG3
+       || e->e_ident[EI_VERSION] != EV_CURRENT
+       || grub_target_to_host32 (e->e_version) != EV_CURRENT)
+-    grub_util_error ("invalid arch-independent ELF magic");
++    grub_util_error ("%s: invalid arch-independent ELF magic", filename);
+ 
+   if (e->e_ident[EI_CLASS] != ELFCLASSXX
+       || e->e_ident[EI_DATA] != (arch->bigendian ? ELFDATA2MSB : ELFDATA2LSB)
+       || grub_target_to_host16 (e->e_machine) != arch->machine)
+-    grub_util_error ("invalid arch-dependent ELF magic");
++    grub_util_error ("%s: invalid arch-dependent ELF magic", filename);
+ 
+   if (grub_target_to_host16 (e->e_type) != ET_REL)
+     {
+-      grub_util_error ("this ELF file is not of the right type");
++      grub_util_error ("%s: this ELF file is not of the right type", filename);
+     }
+ 
+   /* Make sure that every section is within the core.  */
+   if (size < grub_target_to_host (e->e_shoff)
+       + (grub_uint32_t) grub_target_to_host16 (e->e_shentsize) * grub_target_to_host16(e->e_shnum))
+     {
+-      grub_util_error ("ELF sections outside core");
++      grub_util_error ("%s: ELF sections outside core", filename);
+     }
+ 
+-  check_license (arch, e);
++  check_license (filename, arch, e);
+ 
+   Elf_Shdr *s;
+   const char *modname;
+ 
+   s = find_section (arch, e, ".modname");
+   if (!s)
+-    grub_util_error ("no module name found");
++    grub_util_error ("%s: no module name found", filename);
+ 
+   modname = (const char *) e + grub_target_to_host (s->sh_offset);
+ 
+   check_symbols(arch, e, modname, whitelist_empty);
+-  check_relocations(arch, e);
++  check_relocations(modname, arch, e);
+ }
+diff --git a/include/grub/module_verifier.h b/include/grub/module_verifier.h
+index f4870cb9c2d..ba21c75e2eb 100644
+--- a/include/grub/module_verifier.h
++++ b/include/grub/module_verifier.h
+@@ -16,5 +16,5 @@ struct grub_module_verifier_arch {
+   const int *short_relocations;
+ };
+ 
+-void grub_module_verify64(void *module_img, size_t module_size, const struct grub_module_verifier_arch *arch, const char **whitelist_empty);
+-void grub_module_verify32(void *module_img, size_t module_size, const struct grub_module_verifier_arch *arch, const char **whitelist_empty);
++void grub_module_verify64(const char * const filename, void *module_img, size_t module_size, const struct grub_module_verifier_arch *arch, const char **whitelist_empty);
++void grub_module_verify32(const char * const filename, void *module_img, size_t module_size, const struct grub_module_verifier_arch *arch, const char **whitelist_empty);
diff --git a/SOURCES/0223-Make-efi_netfs-not-duplicate-symbols-from-efinet.patch b/SOURCES/0223-Make-efi_netfs-not-duplicate-symbols-from-efinet.patch
new file mode 100644
index 0000000..e1b9bb4
--- /dev/null
+++ b/SOURCES/0223-Make-efi_netfs-not-duplicate-symbols-from-efinet.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Wed, 11 Jul 2018 13:50:00 -0400
+Subject: [PATCH] Make efi_netfs not duplicate symbols from efinet
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/Makefile.core.def | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index d3e3bfd4d7a..715d3a3ec02 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -2186,12 +2186,6 @@ module = {
+ module = {
+   name = efi_netfs;
+   common = net/efi/efi_netfs.c;
+-  common = net/efi/net.c;
+-  common = net/efi/http.c;
+-  common = net/efi/pxe.c;
+-  common = net/efi/ip4_config.c;
+-  common = net/efi/ip6_config.c;
+-  common = net/efi/dhcp.c;
+   enable = efi;
+ };
+ 
diff --git a/SOURCES/0224-Rework-how-the-fdt-command-builds.patch b/SOURCES/0224-Rework-how-the-fdt-command-builds.patch
new file mode 100644
index 0000000..5f66a7a
--- /dev/null
+++ b/SOURCES/0224-Rework-how-the-fdt-command-builds.patch
@@ -0,0 +1,118 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 12 Jul 2018 11:00:45 -0400
+Subject: [PATCH] Rework how the fdt command builds.
+
+Trying to avoid all variants of:
+cat syminfo.lst | sort | gawk -f ../../grub-core/genmoddep.awk > moddep.lst || (rm -f moddep.lst; exit 1)
+grub_fdt_install in linux is not defined
+grub_fdt_load in linux is not defined
+grub_fdt_unload in linux is not defined
+grub_fdt_install in xen_boot is not defined
+grub_fdt_load in xen_boot is not defined
+grub_fdt_unload in xen_boot is not defined
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/Makefile.core.def | 5 ++---
+ grub-core/lib/fdt.c         | 2 --
+ grub-core/loader/efi/fdt.c  | 2 ++
+ include/grub/fdt.h          | 4 ++++
+ grub-core/Makefile.am       | 1 +
+ 5 files changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 715d3a3ec02..203584fb00b 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -166,7 +166,6 @@ kernel = {
+   arm_coreboot = kern/arm/coreboot/init.c;
+   arm_coreboot = kern/arm/coreboot/timer.c;
+   arm_coreboot = kern/arm/coreboot/coreboot.S;
+-  arm_coreboot = lib/fdt.c;
+   arm_coreboot = bus/fdt.c;
+   arm_coreboot = term/ps2.c;
+   arm_coreboot = term/arm/pl050.c;
+@@ -317,6 +316,8 @@ kernel = {
+   arm64 = kern/arm64/dl.c;
+   arm64 = kern/arm64/dl_helper.c;
+ 
++  fdt = lib/fdt.c;
++
+   emu = disk/host.c;
+   emu = kern/emu/cache_s.S;
+   emu = kern/emu/hostdisk.c;
+@@ -1714,7 +1715,6 @@ module = {
+   arm_uboot = loader/arm/linux.c;
+   arm64 = loader/arm64/linux.c;
+   emu = loader/emu/linux.c;
+-  fdt = lib/fdt.c;
+ 
+   common = loader/linux.c;
+   common = lib/cmdline.c;
+@@ -1725,7 +1725,6 @@ module = {
+ module = {
+   name = fdt;
+   efi = loader/efi/fdt.c;
+-  common = lib/fdt.c;
+   enable = fdt;
+ };
+ 
+diff --git a/grub-core/lib/fdt.c b/grub-core/lib/fdt.c
+index 0d371c5633e..37e04bd69e7 100644
+--- a/grub-core/lib/fdt.c
++++ b/grub-core/lib/fdt.c
+@@ -21,8 +21,6 @@
+ #include <grub/mm.h>
+ #include <grub/dl.h>
+ 
+-GRUB_MOD_LICENSE ("GPLv3+");
+-
+ #define FDT_SUPPORTED_VERSION	17
+ 
+ #define FDT_BEGIN_NODE	0x00000001
+diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c
+index a4c6e803645..a9dbcfdfeaf 100644
+--- a/grub-core/loader/efi/fdt.c
++++ b/grub-core/loader/efi/fdt.c
+@@ -26,6 +26,8 @@
+ #include <grub/efi/fdtload.h>
+ #include <grub/efi/memory.h>
+ 
++GRUB_MOD_LICENSE ("GPLv3+");
++
+ static void *loaded_fdt;
+ static void *fdt;
+ 
+diff --git a/include/grub/fdt.h b/include/grub/fdt.h
+index 158b1bc4b3a..6ee57e11ab3 100644
+--- a/include/grub/fdt.h
++++ b/include/grub/fdt.h
+@@ -19,6 +19,8 @@
+ #ifndef GRUB_FDT_HEADER
+ #define GRUB_FDT_HEADER	1
+ 
++#if defined(__arm__) || defined(__aarch64__)
++
+ #include <grub/types.h>
+ #include <grub/symbol.h>
+ 
+@@ -141,4 +143,6 @@ int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const ch
+   grub_fdt_set_prop ((fdt), (nodeoffset), "reg", reg_64, 16);  \
+ })
+ 
++#endif /* defined(__arm__) || defined(__aarch64__) */
++
+ #endif	/* ! GRUB_FDT_HEADER */
+diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
+index 3781bb9cbb9..4062652506d 100644
+--- a/grub-core/Makefile.am
++++ b/grub-core/Makefile.am
+@@ -76,6 +76,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/sb.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdt.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/file.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h
diff --git a/SOURCES/0225-Disable-non-wordsize-allocations-on-arm.patch b/SOURCES/0225-Disable-non-wordsize-allocations-on-arm.patch
new file mode 100644
index 0000000..5c627a3
--- /dev/null
+++ b/SOURCES/0225-Disable-non-wordsize-allocations-on-arm.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 2 Aug 2018 10:56:38 -0400
+Subject: [PATCH] Disable non-wordsize allocations on arm
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ configure.ac | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/configure.ac b/configure.ac
+index 819212095ff..9323c125469 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1234,6 +1234,26 @@ if test "x$target_cpu" = xarm; then
+     done
+   ])
+ 
++  AC_CACHE_CHECK([for options to disable movt and movw relocations],
++		 grub_cv_target_cc_mword_relocations,
++		 [grub_cv_target_cc_mword_relocations=no
++		  for cand in "-mword-relocations" ; do
++		    if test x"$grub_cv_target_cc_mword_relocations" != xno ; then
++		      break
++		    fi
++		    CFLAGS="$TARGET_CFLAGS $cand -Werror"
++		    CPPFLAGS="$TARGET_CPPFLAGS"
++		    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
++				      [grub_cv_target_cc_mword_relocations="$cand"],
++				      [])
++		  done
++		 ])
++  if test x"$grub_cv_target_cc_mword_relocations" = xno ; then
++    AC_MSG_ERROR(["your compiler doesn't support disabling movw/movt relocations"])
++  else
++    TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_mword_relocations"
++  fi
++
+   if test x"$grub_cv_target_cc_mno_movt" != xno ; then
+     # A trick so that clang doesn't see it on link stage
+     TARGET_CPPFLAGS="$TARGET_CPPFLAGS $grub_cv_target_cc_mno_movt"
diff --git a/SOURCES/0226-strip-R-.note.gnu.property-at-more-places.patch b/SOURCES/0226-strip-R-.note.gnu.property-at-more-places.patch
new file mode 100644
index 0000000..0bd0be0
--- /dev/null
+++ b/SOURCES/0226-strip-R-.note.gnu.property-at-more-places.patch
@@ -0,0 +1,82 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 3 Aug 2018 15:07:23 -0400
+Subject: [PATCH] strip "-R .note.gnu.property" at more places.
+
+For whatever reason, sometimes I see:
+
+    lzma_decompress.image:     file format elf32-i386
+    lzma_decompress.image
+    architecture: i386, flags 0x00000012:
+    EXEC_P, HAS_SYMS
+    start address 0x00008200
+
+    Program Header:
+        LOAD off    0x000000c0 vaddr 0x00008200 paddr 0x00008200 align 2**5
+             filesz 0x00000b10 memsz 0x00000b10 flags rwx
+        LOAD off    0x00000bd0 vaddr 0x080480b4 paddr 0x080480b4 align 2**2
+             filesz 0x0000001c memsz 0x0000001c flags r--
+        NOTE off    0x00000bd0 vaddr 0x080480b4 paddr 0x080480b4 align 2**2
+             filesz 0x0000001c memsz 0x0000001c flags r--
+       STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4
+             filesz 0x00000000 memsz 0x00000000 flags rw-
+
+    Sections:
+    Idx Name          Size      VMA       LMA       File off  Algn
+      0 .note.gnu.property 0000001c  080480b4  080480b4  00000bd0  2**2
+                      CONTENTS, ALLOC, LOAD, READONLY, DATA
+      1 .text         00000b10  00008200  00008200  000000c0  2**5
+                      CONTENTS, ALLOC, LOAD, CODE
+    SYMBOL TABLE:
+    080480b4 l    d  .note.gnu.property	00000000 .note.gnu.property
+    00008200 l    d  .text	00000000 .text
+    00000000 l    df *ABS*	00000000 startup_raw.S
+    ...
+
+Which just looks wrong no matter what to my eyes (seriously it's at
+128M? Why?), and when we fail to strip it, we get:
+
+trillian:~/tmp/f29$ hexdump -C usr/lib/grub/i386-pc/lzma_decompress.img | tail -6
+00000b00  ff 45 e8 5a 83 c2 02 89  d1 e9 df fe ff ff 66 90  |.E.Z..........f.|
+00000b10  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+*
+0803feb0  00 00 00 00 04 00 00 00  0c 00 00 00 05 00 00 00  |................|
+0803fec0  47 4e 55 00 02 00 00 c0  04 00 00 00 03 00 00 00  |GNU.............|
+0803fed0
+
+Which is very very much not what we want.
+
+Cut it out.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ Makefile.am | 2 +-
+ gentpl.py   | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index c7b0e6a9c46..287fff66b20 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -209,7 +209,7 @@ pc-chainloader.elf: $(srcdir)/grub-core/tests/boot/kernel-8086.S $(srcdir)/grub-
+ 	$(TARGET_CC) -o $@ $< -static -DTARGET_CHAINLOADER=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -ffreestanding -nostdlib -nostdinc -Wl,--build-id=none -Wl,-N -Wl,-Ttext,0x7c00 -m32
+ 
+ pc-chainloader.bin: pc-chainloader.elf
+-	$(TARGET_OBJCOPY) -O binary --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .reginfo -R .rel.dyn -R .note.gnu.gold-version $< $@;
++	$(TARGET_OBJCOPY) -O binary --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .reginfo -R .rel.dyn -R .note.gnu.gold-version -R .note.gnu.property $< $@;
+ 
+ ntldr.elf: $(srcdir)/grub-core/tests/boot/kernel-8086.S $(srcdir)/grub-core/tests/boot/qemu-shutdown-x86.S
+ 	$(TARGET_CC) -o $@ $< -DTARGET_NTLDR=1 -DSUCCESSFUL_BOOT_STRING=\"$(SUCCESSFUL_BOOT_STRING)\" -static -ffreestanding -nostdlib -nostdinc -Wl,--build-id=none -Wl,-N -Wl,-Ttext,0 -m32
+diff --git a/gentpl.py b/gentpl.py
+index 1e4635f4426..d662c305f66 100644
+--- a/gentpl.py
++++ b/gentpl.py
+@@ -776,7 +776,7 @@ def image(defn, platform):
+ if test x$(TARGET_APPLE_LINKER) = x1; then \
+   $(MACHO2IMG) $< $@; \
+ else \
+-  $(TARGET_OBJCOPY) $(""" + cname(defn) + """_OBJCOPYFLAGS) --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .MIPS.abiflags -R .reginfo -R .rel.dyn -R .note.gnu.gold-version -R .ARM.exidx $< $@; \
++  $(TARGET_OBJCOPY) $(""" + cname(defn) + """_OBJCOPYFLAGS) --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .MIPS.abiflags -R .reginfo -R .rel.dyn -R .note.gnu.gold-version -R .ARM.exidx -R .note.gnu.property $< $@; \
+ fi
+ """)
+ 
diff --git a/SOURCES/0227-Prepend-prefix-when-HTTP-path-is-relative.patch b/SOURCES/0227-Prepend-prefix-when-HTTP-path-is-relative.patch
new file mode 100644
index 0000000..9e90636
--- /dev/null
+++ b/SOURCES/0227-Prepend-prefix-when-HTTP-path-is-relative.patch
@@ -0,0 +1,150 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Stephen Benjamin <stephen@redhat.com>
+Date: Thu, 16 Aug 2018 16:58:51 -0400
+Subject: [PATCH] Prepend prefix when HTTP path is relative
+
+This sets a couple of variables.  With the url http://www.example.com/foo/bar :
+http_path: /foo/bar
+http_url: http://www.example.com/foo/bar
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/main.c    | 10 +++++-
+ grub-core/net/efi/http.c | 82 ++++++++++++++++++++++++++++++++++++------------
+ 2 files changed, 71 insertions(+), 21 deletions(-)
+
+diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
+index da47b18b50e..dcf48726d54 100644
+--- a/grub-core/kern/main.c
++++ b/grub-core/kern/main.c
+@@ -130,11 +130,19 @@ grub_set_prefix_and_root (void)
+   if (fwdevice && fwpath)
+     {
+       char *fw_path;
++      char separator[3] = ")";
+ 
+-      fw_path = grub_xasprintf ("(%s)/%s", fwdevice, fwpath);
++      grub_dprintf ("fw_path", "\n");
++      grub_dprintf ("fw_path", "fwdevice:\"%s\" fwpath:\"%s\"\n", fwdevice, fwpath);
++
++      if (!grub_strncmp(fwdevice, "http", 4) && fwpath[0] != '/')
++	grub_strcpy(separator, ")/");
++
++      fw_path = grub_xasprintf ("(%s%s%s", fwdevice, separator, fwpath);
+       if (fw_path)
+ 	{
+ 	  grub_env_set ("fw_path", fw_path);
++	  grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path);
+ 	  grub_free (fw_path);
+ 	}
+     }
+diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c
+index 243acbaa35b..2a9624dacc4 100644
+--- a/grub-core/net/efi/http.c
++++ b/grub-core/net/efi/http.c
+@@ -9,10 +9,52 @@
+ static void
+ http_configure (struct grub_efi_net_device *dev, int prefer_ip6)
+ {
++  grub_efi_ipv6_address_t address;
+   grub_efi_http_config_data_t http_config;
+   grub_efi_httpv4_access_point_t httpv4_node;
+   grub_efi_httpv6_access_point_t httpv6_node;
+   grub_efi_status_t status;
++  int https;
++  char *http_url;
++  const char *rest, *http_server, *http_path = NULL;
++
++  http_server = grub_env_get ("root");
++  https = grub_strncmp (http_server, "https", 5) ? 1 : 0;
++
++  /* extract http server + port */
++  if (http_server)
++    {
++      http_server = grub_strchr (http_server, ',');
++      if (http_server)
++	http_server++;
++    }
++
++  /* fw_path is like (http,192.168.1.1:8000)/httpboot, extract path part */
++  http_path = grub_env_get ("fw_path");
++  if (http_path)
++    {
++      http_path = grub_strchr (http_path, ')');
++      if (http_path)
++	{
++	  http_path++;
++	  grub_env_unset ("http_path");
++	  grub_env_set ("http_path", http_path);
++	}
++    }
++
++  if (http_server && http_path)
++    {
++      if (grub_efi_string_to_ip6_address (http_server, &address, &rest) && *rest == 0)
++	http_url = grub_xasprintf ("%s://[%s]%s", https ? "https" : "http", http_server, http_path);
++      else
++	http_url = grub_xasprintf ("%s://%s%s", https ? "https" : "http", http_server, http_path);
++      if (http_url)
++	{
++	  grub_env_unset ("http_url");
++	  grub_env_set ("http_url", http_url);
++	  grub_free (http_url);
++	}
++    }
+ 
+   grub_efi_http_t *http = dev->http;
+ 
+@@ -352,32 +394,32 @@ grub_efihttp_open (struct grub_efi_net_device *dev,
+   grub_err_t err;
+   grub_off_t size;
+   char *buf;
+-  char *root_url;
+-  grub_efi_ipv6_address_t address;
+-  const char *rest;
++  char *file_name;
++  const char *http_path;
+ 
+-  if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0)
+-    root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server);
++  /* If path is relative, prepend http_path */
++  http_path = grub_env_get ("http_path");
++  if (http_path && file->device->net->name[0] != '/')
++    file_name = grub_xasprintf ("%s/%s", http_path, file->device->net->name);
+   else
+-    root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server);
+-  if (root_url)
+-    {
+-      grub_env_unset ("root_url");
+-      grub_env_set ("root_url", root_url);
+-      grub_free (root_url);
+-    }
+-  else
+-    {
+-      return grub_errno;
+-    }
++    file_name = grub_strdup (file->device->net->name);
+ 
+-  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0);
++  if (!file_name)
++    return grub_errno;
++
++  err = efihttp_request (dev->http, file->device->net->server, file_name, type, 1, 0);
+   if (err != GRUB_ERR_NONE)
+-    return err;
++    {
++      grub_free (file_name);
++      return err;
++    }
+ 
+-  err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size);
++  err = efihttp_request (dev->http, file->device->net->server, file_name, type, 0, &size);
++  grub_free (file_name);
+   if (err != GRUB_ERR_NONE)
+-    return err;
++    {
++      return err;
++    }
+ 
+   buf = grub_malloc (size);
+   efihttp_read (dev, buf, size);
diff --git a/SOURCES/0228-Make-linux_arm_kernel_header.hdr_offset-be-at-the-ri.patch b/SOURCES/0228-Make-linux_arm_kernel_header.hdr_offset-be-at-the-ri.patch
new file mode 100644
index 0000000..e0becd6
--- /dev/null
+++ b/SOURCES/0228-Make-linux_arm_kernel_header.hdr_offset-be-at-the-ri.patch
@@ -0,0 +1,71 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 16 Aug 2018 11:08:11 -0400
+Subject: [PATCH] Make linux_arm_kernel_header.hdr_offset be at the right place
+
+The kernel in front of me (slightly edited to make objdump work) looks like:
+
+00000000  4d 5a 10 13 4d 5a 10 13  4d 5a 10 13 4d 5a 10 13  |MZ..MZ..MZ..MZ..|
+00000010  4d 5a 10 13 4d 5a 10 13  4d 5a 10 13 00 00 a0 e1  |MZ..MZ..MZ......|
+00000020  f6 03 00 ea 18 28 6f 01  00 00 00 00 00 32 74 00  |.....(o......2t.|
+00000030  01 02 03 04 45 45 45 45  74 a2 00 00 40 00 00 00  |....EEEEt...@...|
+00000040  50 45 00 00 4c 01 04 00  00 00 00 00 00 00 00 00  |PE..L...........|
+00000050  00 00 00 00 90 00 06 03  0b 01 02 14 00 20 74 00  |............. t.|
+00000060  00 14 00 00 00 00 00 00  b4 19 00 00 00 10 00 00  |................|
+00000070  00 30 74 00 00 00 00 00  00 10 00 00 00 02 00 00  |.0t.............|
+00000080  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000090  00 44 74 00 00 10 00 00  00 00 00 00 0a 00 00 00  |.Dt.............|
+000000a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+000000b0  00 00 00 00 06 00 00 00  00 00 00 00 00 00 00 00  |................|
+000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+*
+
+(I don't know why the MZ header is there 7 times, but the offsets work out, so
+it's merely a surprising distraction.)
+
+If linux_arm_kernel_header.reserved2 is 16 bytes, that means hdr_offset is
+here:
+
+00000030  01 02 03 04 45 45 45 45  74 a2 00 00 40 00 00 00  |....EEEEt...@...|
+00000040  50 45 00 00 4c 01 04 00  00 00 00 00 00 00 00 00  |PE..L...........|
+          ^^^^^^^^^^^
+
+But it's supposed to be 4 bytes before that.
+
+This patch makes the reserved field be 3*32 instead of 4*32, and that means we
+can find the PE header correcrtly at 0x40 by reading the value at 0x3c.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/loader/efi/linux.c | 3 +++
+ include/grub/arm/linux.h     | 2 +-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
+index 0622dfa48d4..b56ea0bc041 100644
+--- a/grub-core/loader/efi/linux.c
++++ b/grub-core/loader/efi/linux.c
+@@ -79,7 +79,10 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset,
+   offset = 512;
+ #endif
+ 
++  grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n",
++		kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params);
+   hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
++  grub_dprintf ("linux", "handover_func() = %p\n", hf);
+   hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
+ 
+   return GRUB_ERR_BUG;
+diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h
+index 5900fc8a40c..bed308f22cb 100644
+--- a/include/grub/arm/linux.h
++++ b/include/grub/arm/linux.h
+@@ -31,7 +31,7 @@ struct linux_arm_kernel_header {
+   grub_uint32_t magic;
+   grub_uint32_t start; /* _start */
+   grub_uint32_t end;   /* _edata */
+-  grub_uint32_t reserved2[4];
++  grub_uint32_t reserved2[3];
+   grub_uint32_t hdr_offset;
+ };
+ 
diff --git a/SOURCES/0229-Mark-some-unused-stuff-unused.patch b/SOURCES/0229-Mark-some-unused-stuff-unused.patch
new file mode 100644
index 0000000..2561754
--- /dev/null
+++ b/SOURCES/0229-Mark-some-unused-stuff-unused.patch
@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 27 Aug 2018 13:10:08 -0400
+Subject: [PATCH] Mark some unused stuff unused
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/commands/blscfg.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index bdb1c5a95aa..abd6f00d0de 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -434,7 +434,7 @@ finish:
+ 
+ static grub_envblk_t saved_env = NULL;
+ 
+-static int
++static int UNUSED
+ save_var (const char *name, const char *value, void *whitelist UNUSED)
+ {
+   const char *val = grub_env_get (name);
+@@ -446,7 +446,7 @@ save_var (const char *name, const char *value, void *whitelist UNUSED)
+   return 0;
+ }
+ 
+-static int
++static int UNUSED
+ unset_var (const char *name, const char *value UNUSED, void *whitelist)
+ {
+   grub_dprintf("blscfg", "restoring \"%s\"\n", name);
diff --git a/SOURCES/0230-Make-grub_error-more-verbose.patch b/SOURCES/0230-Make-grub_error-more-verbose.patch
new file mode 100644
index 0000000..6fffdeb
--- /dev/null
+++ b/SOURCES/0230-Make-grub_error-more-verbose.patch
@@ -0,0 +1,98 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 27 Aug 2018 13:14:06 -0400
+Subject: [PATCH] Make grub_error() more verbose
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/efi/mm.c | 17 ++++++++++++++---
+ grub-core/kern/err.c    | 13 +++++++++++--
+ include/grub/err.h      |  5 ++++-
+ 3 files changed, 29 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index 5cdf6c943f2..7692e63ba24 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -157,12 +157,20 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
+ 
+   /* Limit the memory access to less than 4GB for 32-bit platforms.  */
+   if (address > GRUB_EFI_MAX_USABLE_ADDRESS)
+-    return 0;
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT,
++		  N_("invalid memory address (0x%llx > 0x%llx)"),
++		  address, GRUB_EFI_MAX_USABLE_ADDRESS);
++      return NULL;
++    }
+ 
+   b = grub_efi_system_table->boot_services;
+   status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
+   if (status != GRUB_EFI_SUCCESS)
+-    return 0;
++    {
++      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
++      return NULL;
++    }
+ 
+   if (address == 0)
+     {
+@@ -172,7 +180,10 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
+       status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
+       grub_efi_free_pages (0, pages);
+       if (status != GRUB_EFI_SUCCESS)
+-	return 0;
++	{
++	  grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
++	  return NULL;
++	}
+     }
+ 
+   grub_efi_store_alloc (address, pages);
+diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c
+index 53c734de70e..aebfe0cf839 100644
+--- a/grub-core/kern/err.c
++++ b/grub-core/kern/err.c
+@@ -33,15 +33,24 @@ static struct grub_error_saved grub_error_stack_items[GRUB_ERROR_STACK_SIZE];
+ static int grub_error_stack_pos;
+ static int grub_error_stack_assert;
+ 
++#ifdef grub_error
++#undef grub_error
++#endif
++
+ grub_err_t
+-grub_error (grub_err_t n, const char *fmt, ...)
++grub_error (grub_err_t n, const char *file, const int line, const char *fmt, ...)
+ {
+   va_list ap;
++  int m;
+ 
+   grub_errno = n;
+ 
++  m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%d:", file, line);
++  if (m < 0)
++    m = 0;
++
+   va_start (ap, fmt);
+-  grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap);
++  grub_vsnprintf (grub_errmsg + m, sizeof (grub_errmsg) - m, _(fmt), ap);
+   va_end (ap);
+ 
+   return n;
+diff --git a/include/grub/err.h b/include/grub/err.h
+index 1590c688e1d..9b830757d35 100644
+--- a/include/grub/err.h
++++ b/include/grub/err.h
+@@ -84,7 +84,10 @@ struct grub_error_saved
+ extern grub_err_t EXPORT_VAR(grub_errno);
+ extern char EXPORT_VAR(grub_errmsg)[GRUB_MAX_ERRMSG];
+ 
+-grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *fmt, ...);
++grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *file, const int line, const char *fmt, ...);
++
++#define grub_error(n, fmt, ...) grub_error (n, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
++
+ void EXPORT_FUNC(grub_fatal) (const char *fmt, ...) __attribute__ ((noreturn));
+ void EXPORT_FUNC(grub_error_push) (void);
+ int EXPORT_FUNC(grub_error_pop) (void);
diff --git a/SOURCES/0231-arm-arm64-loader-Better-memory-allocation-and-error-.patch b/SOURCES/0231-arm-arm64-loader-Better-memory-allocation-and-error-.patch
new file mode 100644
index 0000000..a5cc064
--- /dev/null
+++ b/SOURCES/0231-arm-arm64-loader-Better-memory-allocation-and-error-.patch
@@ -0,0 +1,307 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Tue, 14 Aug 2018 14:07:44 -0400
+Subject: [PATCH] arm/arm64 loader: Better memory allocation and error
+ messages.
+
+On mustang, our memory map looks like:
+
+Type      Physical start  - end             #Pages        Size Attributes
+reserved  0000004000000000-00000040001fffff 00000200      2MiB UC WC WT WB
+conv-mem  0000004000200000-0000004393ffffff 00393e00  14654MiB UC WC WT WB
+ldr-code  0000004394000000-00000043f7ffffff 00064000   1600MiB UC WC WT WB
+BS-data   00000043f8000000-00000043f801ffff 00000020    128KiB UC WC WT WB
+conv-mem  00000043f8020000-00000043fa15bfff 0000213c  34032KiB UC WC WT WB
+ldr-code  00000043fa15c000-00000043fa2a1fff 00000146   1304KiB UC WC WT WB
+ldr-data  00000043fa2a2000-00000043fa3e8fff 00000147   1308KiB UC WC WT WB
+conv-mem  00000043fa3e9000-00000043fa3e9fff 00000001      4KiB UC WC WT WB
+ldr-data  00000043fa3ea000-00000043fa3eafff 00000001      4KiB UC WC WT WB
+ldr-code  00000043fa3eb000-00000043fa4affff 000000c5    788KiB UC WC WT WB
+BS-code   00000043fa4b0000-00000043fa59ffff 000000f0    960KiB UC WC WT WB
+RT-code   00000043fa5a0000-00000043fa5affff 00000010     64KiB RT UC WC WT WB
+RT-data   00000043fa5b0000-00000043fa5bffff 00000010     64KiB RT UC WC WT WB
+RT-code   00000043fa5c0000-00000043fa5cffff 00000010     64KiB RT UC WC WT WB
+ldr-data  00000043fa5d0000-00000043fa5d0fff 00000001      4KiB UC WC WT WB
+BS-code   00000043fa5d1000-00000043fa5ddfff 0000000d     52KiB UC WC WT WB
+reserved  00000043fa5de000-00000043fa60ffff 00000032    200KiB UC WC WT WB
+ACPI-rec  00000043fa610000-00000043fa6affff 000000a0    640KiB UC WC WT WB
+ACPI-nvs  00000043fa6b0000-00000043fa6bffff 00000010     64KiB UC WC WT WB
+ACPI-rec  00000043fa6c0000-00000043fa70ffff 00000050    320KiB UC WC WT WB
+RT-code   00000043fa710000-00000043fa72ffff 00000020    128KiB RT UC WC WT WB
+RT-data   00000043fa730000-00000043fa78ffff 00000060    384KiB RT UC WC WT WB
+RT-code   00000043fa790000-00000043fa79ffff 00000010     64KiB RT UC WC WT WB
+RT-data   00000043fa7a0000-00000043fa99ffff 00000200      2MiB RT UC WC WT WB
+RT-code   00000043fa9a0000-00000043fa9affff 00000010     64KiB RT UC WC WT WB
+RT-data   00000043fa9b0000-00000043fa9cffff 00000020    128KiB RT UC WC WT WB
+BS-code   00000043fa9d0000-00000043fa9d9fff 0000000a     40KiB UC WC WT WB
+reserved  00000043fa9da000-00000043fa9dbfff 00000002      8KiB UC WC WT WB
+conv-mem  00000043fa9dc000-00000043fc29dfff 000018c2  25352KiB UC WC WT WB
+BS-data   00000043fc29e000-00000043fc78afff 000004ed   5044KiB UC WC WT WB
+conv-mem  00000043fc78b000-00000043fca01fff 00000277   2524KiB UC WC WT WB
+BS-data   00000043fca02000-00000043fcea3fff 000004a2   4744KiB UC WC WT WB
+conv-mem  00000043fcea4000-00000043fcea4fff 00000001      4KiB UC WC WT WB
+BS-data   00000043fcea5000-00000043fd192fff 000002ee   3000KiB UC WC WT WB
+conv-mem  00000043fd193000-00000043fd2b0fff 0000011e   1144KiB UC WC WT WB
+BS-data   00000043fd2b1000-00000043ff80ffff 0000255f  38268KiB UC WC WT WB
+BS-code   00000043ff810000-00000043ff99ffff 00000190   1600KiB UC WC WT WB
+RT-code   00000043ff9a0000-00000043ff9affff 00000010     64KiB RT UC WC WT WB
+conv-mem  00000043ff9b0000-00000043ff9bffff 00000010     64KiB UC WC WT WB
+RT-data   00000043ff9c0000-00000043ff9effff 00000030    192KiB RT UC WC WT WB
+conv-mem  00000043ff9f0000-00000043ffa05fff 00000016     88KiB UC WC WT WB
+BS-data   00000043ffa06000-00000043ffffffff 000005fa   6120KiB UC WC WT WB
+MMIO      0000000010510000-0000000010510fff 00000001      4KiB RT
+MMIO      0000000010548000-0000000010549fff 00000002      8KiB RT
+MMIO      0000000017000000-0000000017001fff 00000002      8KiB RT
+MMIO      000000001c025000-000000001c025fff 00000001      4KiB RT
+
+When we're trying to find the base of ram, if we start with GRUB_UINT_MAX
+(0xffffffff on all platforms) and always use min(), that means we eventually
+decide that the base of ram is GRUB_UINT_MAX, which is lower than our first
+memory address, and thus our allocation of the initramfs, which specifies this
+value as the maximum possible address it can be at, fails.
+
+This patch changes it to start at GRUB_EFI_MAX_USABLE_ADDRESS, which is always
+at least 0xffffffff on 32-bit platforms and at least 0x7ffffffffffffff on
+64-bit platforms.  Additionally, this adds a requirement that the memory we
+choose is actually /allocatable/ conventional memory, not merely
+write-combining.  On this machine that means we wind up with an allocation
+around 0x4392XXXXXX, which is a reasonable address.
+
+This also changes grub_efi_allocate_pages_real() so that if 0 is allocated, it
+tries to allocate again starting with the same max address it did the first
+time, rather than interposing GRUB_EFI_MAX_USABLE_ADDRESS there, so that any
+per-platform constraints on its given address are maintained.
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/efi/mm.c        | 32 ++++++++++++-----
+ grub-core/loader/arm64/linux.c | 78 ++++++++++++++++++++++++++++++++----------
+ 2 files changed, 82 insertions(+), 28 deletions(-)
+
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index 7692e63ba24..306924f73a4 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -154,6 +154,7 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
+ {
+   grub_efi_status_t status;
+   grub_efi_boot_services_t *b;
++  grub_efi_physical_address_t ret = address;
+ 
+   /* Limit the memory access to less than 4GB for 32-bit platforms.  */
+   if (address > GRUB_EFI_MAX_USABLE_ADDRESS)
+@@ -165,19 +166,19 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
+     }
+ 
+   b = grub_efi_system_table->boot_services;
+-  status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
++  status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret);
+   if (status != GRUB_EFI_SUCCESS)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+       return NULL;
+     }
+ 
+-  if (address == 0)
++  if (ret == 0)
+     {
+       /* Uggh, the address 0 was allocated... This is too annoying,
+ 	 so reallocate another one.  */
+-      address = GRUB_EFI_MAX_USABLE_ADDRESS;
+-      status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
++      ret = address;
++      status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret);
+       grub_efi_free_pages (0, pages);
+       if (status != GRUB_EFI_SUCCESS)
+ 	{
+@@ -186,9 +187,9 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
+ 	}
+     }
+ 
+-  grub_efi_store_alloc (address, pages);
++  grub_efi_store_alloc (ret, pages);
+ 
+-  return (void *) ((grub_addr_t) address);
++  return (void *) ((grub_addr_t) ret);
+ }
+ 
+ void *
+@@ -696,11 +697,24 @@ grub_efi_get_ram_base(grub_addr_t *base_addr)
+   if (ret < 1)
+     return GRUB_ERR_BUG;
+ 
+-  for (desc = memory_map, *base_addr = GRUB_UINT_MAX;
++  for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS;
+        (grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size);
+        desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
+-    if (desc->attribute & GRUB_EFI_MEMORY_WB)
+-      *base_addr = grub_min (*base_addr, desc->physical_start);
++    {
++      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY &&
++	  (desc->attribute & GRUB_EFI_MEMORY_WB))
++	{
++	  *base_addr = grub_min (*base_addr, desc->physical_start);
++	  grub_dprintf ("efi", "setting base_addr=0x%016lx\n", *base_addr);
++	}
++      else
++	{
++	  grub_dprintf ("efi", "ignoring address 0x%016lx\n", desc->physical_start);
++	}
++    }
++
++  if (*base_addr == GRUB_EFI_MAX_USABLE_ADDRESS)
++    grub_dprintf ("efi", "base_addr 0x%016lx is probably wrong.\n", *base_addr);
+ 
+   grub_free(memory_map);
+ 
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index 93b5cd306eb..e1110749eb9 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -70,13 +70,15 @@ finalize_params_linux (void)
+ {
+   grub_efi_loaded_image_t *loaded_image = NULL;
+   int node, retval, len;
+-
++  grub_err_t err = GRUB_ERR_NONE;
+   void *fdt;
+ 
+   fdt = grub_fdt_load (0x400);
+-
+   if (!fdt)
+-    goto failure;
++    {
++      err = grub_error(GRUB_ERR_BAD_OS, "failed to load FDT");
++      goto failure;
++    }
+ 
+   node = grub_fdt_find_subnode (fdt, 0, "chosen");
+   if (node < 0)
+@@ -87,17 +89,26 @@ finalize_params_linux (void)
+        */
+       retval = grub_fdt_set_prop32(fdt, 0, "#address-cells", 2);
+       if (retval)
+-	goto failure;
++	{
++	  err = grub_error(retval, "Could not find #address-cells");
++	  goto failure;
++	}
+ 
+       retval = grub_fdt_set_prop32(fdt, 0, "#size-cells", 2);
+       if (retval)
+-	goto failure;
++	{
++	  err = grub_error(retval, "Could not find #size-cells");
++	  goto failure;
++	}
+ 
+       node = grub_fdt_add_subnode (fdt, 0, "chosen");
+     }
+ 
+   if (node < 1)
+-    goto failure;
++    {
++      err = grub_error(grub_errno, "failed to load chosen fdt node.");
++      goto failure;
++    }
+ 
+   /* Set initrd info */
+   if (initrd_start && initrd_end > initrd_start)
+@@ -108,15 +119,26 @@ finalize_params_linux (void)
+       retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start",
+ 				    initrd_start);
+       if (retval)
+-	goto failure;
++	{
++	  err = grub_error(retval, "Failed to set linux,initrd-start property");
++	  goto failure;
++	}
++
+       retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end",
+ 				    initrd_end);
+       if (retval)
+-	goto failure;
++	{
++	  err = grub_error(retval, "Failed to set linux,initrd-end property");
++	  goto failure;
++	}
+     }
+ 
+-  if (grub_fdt_install() != GRUB_ERR_NONE)
+-    goto failure;
++  retval = grub_fdt_install();
++  if (retval != GRUB_ERR_NONE)
++    {
++      err = grub_error(retval, "Failed to install fdt");
++      goto failure;
++    }
+ 
+   grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
+ 		fdt);
+@@ -124,14 +146,20 @@ finalize_params_linux (void)
+   /* Convert command line to UCS-2 */
+   loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
+   if (!loaded_image)
+-    goto failure;
++    {
++      err = grub_error(grub_errno, "Failed to install fdt");
++      goto failure;
++    }
+ 
+   loaded_image->load_options_size = len =
+     (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t);
+   loaded_image->load_options =
+     grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
+   if (!loaded_image->load_options)
+-    return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
++    {
++      err = grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
++      goto failure;
++    }
+ 
+   loaded_image->load_options_size =
+     2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
+@@ -141,7 +169,7 @@ finalize_params_linux (void)
+ 
+ failure:
+   grub_fdt_unload();
+-  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
++  return err;
+ }
+ 
+ static void
+@@ -225,16 +253,28 @@ grub_linux_unload (void)
+ static void *
+ allocate_initrd_mem (int initrd_pages)
+ {
+-  grub_addr_t max_addr;
++  grub_addr_t max_addr = 0;
++  grub_err_t err;
++  void *ret;
+ 
+-  if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE)
+-    return NULL;
++  err = grub_efi_get_ram_base (&max_addr);
++  if (err != GRUB_ERR_NONE)
++    {
++      grub_error (err, "grub_efi_get_ram_base() failed");
++      return NULL;
++    }
++
++  grub_dprintf ("linux", "max_addr: 0x%016lx, INITRD_MAX_ADDRESS_OFFSET: 0x%016llx\n",
++		max_addr, INITRD_MAX_ADDRESS_OFFSET);
+ 
+   max_addr += INITRD_MAX_ADDRESS_OFFSET - 1;
++  grub_dprintf ("linux", "calling grub_efi_allocate_pages_real (0x%016lx, 0x%08x, EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA)", max_addr, initrd_pages);
+ 
+-  return grub_efi_allocate_pages_real (max_addr, initrd_pages,
+-				       GRUB_EFI_ALLOCATE_MAX_ADDRESS,
+-				       GRUB_EFI_LOADER_DATA);
++  ret = grub_efi_allocate_pages_real (max_addr, initrd_pages,
++				      GRUB_EFI_ALLOCATE_MAX_ADDRESS,
++				      GRUB_EFI_LOADER_DATA);
++  grub_dprintf ("linux", "got 0x%016llx\n", (unsigned long long)ret);
++  return ret;
+ }
+ 
+ static grub_err_t
diff --git a/SOURCES/0232-drop-TPM-support-for-legacy-BIOS.patch b/SOURCES/0232-drop-TPM-support-for-legacy-BIOS.patch
new file mode 100644
index 0000000..ab7867b
--- /dev/null
+++ b/SOURCES/0232-drop-TPM-support-for-legacy-BIOS.patch
@@ -0,0 +1,401 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 21 Sep 2018 17:51:16 +0200
+Subject: [PATCH] drop TPM support for legacy BIOS
+
+Currently there's TPM support for both EFI and legacy BIOS.
+
+A software interrupt call interface is used in legacy BIOS to communicate
+with the TPM chips. But with some BIOS firmwares, the machine just hangs
+after doing a BIOS interrupt call for the TCG_HashLogExtendEvent command.
+
+It's hard to know what exactly is causing this, but the Trousers project
+mentions in their docs that they don't use TCG_HashLogExtendEvent [0] due
+the command not working reliable on some BIOS.
+
+The TCG_CompactHashLogExtendEvent is less fragile, since it has a simpler
+interface, doesn't require to setup any data structure and doesn't return
+anything. So it could be used to do measurements and logs events instead.
+
+But even when using this command can be a workaround on some systems, it
+doesn't guarantee that could not fail on others. So since the TPM support
+for some legacy BIOS don't work and can lead to machines failing to boot,
+let's just drop it and only support TPM for EFI.
+
+[0]: http://trousers.sourceforge.net/grub.html
+
+Resolves: rhbz#1579835
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/Makefile.core.def       |   1 -
+ grub-core/kern/i386/pc/tpm.c      | 145 --------------------------------------
+ grub-core/loader/i386/pc/linux.c  |   4 --
+ include/grub/tpm.h                |   2 +-
+ grub-core/boot/i386/pc/boot.S     |  30 +-------
+ grub-core/boot/i386/pc/diskboot.S |  44 ------------
+ 6 files changed, 2 insertions(+), 224 deletions(-)
+ delete mode 100644 grub-core/kern/i386/pc/tpm.c
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 203584fb00b..01c5f9ae351 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -246,7 +246,6 @@ kernel = {
+ 
+   i386_pc = kern/i386/pc/init.c;
+   i386_pc = kern/i386/pc/mmap.c;
+-  i386_pc = kern/i386/pc/tpm.c;
+   i386_pc = term/i386/pc/console.c;
+ 
+   i386_qemu = bus/pci.c;
+diff --git a/grub-core/kern/i386/pc/tpm.c b/grub-core/kern/i386/pc/tpm.c
+deleted file mode 100644
+index f6f264aff2e..00000000000
+--- a/grub-core/kern/i386/pc/tpm.c
++++ /dev/null
+@@ -1,145 +0,0 @@
+-#include <grub/err.h>
+-#include <grub/i18n.h>
+-#include <grub/mm.h>
+-#include <grub/tpm.h>
+-#include <grub/misc.h>
+-#include <grub/i386/pc/int.h>
+-
+-#define TCPA_MAGIC 0x41504354
+-
+-static int tpm_presence = -1;
+-
+-int tpm_present(void);
+-
+-int tpm_present(void)
+-{
+-  struct grub_bios_int_registers regs;
+-
+-  if (tpm_presence != -1)
+-    return tpm_presence;
+-
+-  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+-  regs.eax = 0xbb00;
+-  regs.ebx = TCPA_MAGIC;
+-  grub_bios_interrupt (0x1a, &regs);
+-
+-  if (regs.eax == 0)
+-    tpm_presence = 1;
+-  else
+-    tpm_presence = 0;
+-
+-  return tpm_presence;
+-}
+-
+-grub_err_t
+-grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
+-		 PassThroughToTPM_OutputParamBlock *outbuf)
+-{
+-  struct grub_bios_int_registers regs;
+-  grub_addr_t inaddr, outaddr;
+-
+-  if (!tpm_present())
+-    return 0;
+-
+-  inaddr = (grub_addr_t) inbuf;
+-  outaddr = (grub_addr_t) outbuf;
+-  regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+-  regs.eax = 0xbb02;
+-  regs.ebx = TCPA_MAGIC;
+-  regs.ecx = 0;
+-  regs.edx = 0;
+-  regs.es = (inaddr & 0xffff0000) >> 4;
+-  regs.edi = inaddr & 0xffff;
+-  regs.ds = outaddr >> 4;
+-  regs.esi = outaddr & 0xf;
+-
+-  grub_bios_interrupt (0x1a, &regs);
+-
+-  if (regs.eax)
+-    {
+-	tpm_presence = 0;
+-	return grub_error (GRUB_ERR_IO, N_("TPM error %x, disabling TPM"), regs.eax);
+-    }
+-
+-  return 0;
+-}
+-
+-typedef struct {
+-	grub_uint32_t pcrindex;
+-	grub_uint32_t eventtype;
+-	grub_uint8_t digest[20];
+-	grub_uint32_t eventdatasize;
+-	grub_uint8_t event[0];
+-} GRUB_PACKED Event;
+-
+-typedef struct {
+-	grub_uint16_t ipblength;
+-	grub_uint16_t reserved;
+-	grub_uint32_t hashdataptr;
+-	grub_uint32_t hashdatalen;
+-	grub_uint32_t pcr;
+-	grub_uint32_t reserved2;
+-	grub_uint32_t logdataptr;
+-	grub_uint32_t logdatalen;
+-} GRUB_PACKED EventIncoming;
+-
+-typedef struct {
+-	grub_uint16_t opblength;
+-	grub_uint16_t reserved;
+-	grub_uint32_t eventnum;
+-	grub_uint8_t  hashvalue[20];
+-} GRUB_PACKED EventOutgoing;
+-
+-grub_err_t
+-grub_tpm_log_event(unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
+-		   const char *description)
+-{
+-	struct grub_bios_int_registers regs;
+-	EventIncoming incoming;
+-	EventOutgoing outgoing;
+-	Event *event;
+-	grub_uint32_t datalength;
+-
+-	if (!tpm_present())
+-		return 0;
+-
+-	datalength = grub_strlen(description);
+-	event = grub_zalloc(datalength + sizeof(Event));
+-	if (!event)
+-		return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+-				   N_("cannot allocate TPM event buffer"));
+-
+-	event->pcrindex = pcr;
+-	event->eventtype = 0x0d;
+-	event->eventdatasize = grub_strlen(description);
+-	grub_memcpy(event->event, description, datalength);
+-
+-	incoming.ipblength = sizeof(incoming);
+-	incoming.hashdataptr = (grub_uint32_t)buf;
+-	incoming.hashdatalen = size;
+-	incoming.pcr = pcr;
+-	incoming.logdataptr = (grub_uint32_t)event;
+-	incoming.logdatalen = datalength + sizeof(Event);
+-
+-	regs.flags = GRUB_CPU_INT_FLAGS_DEFAULT;
+-	regs.eax = 0xbb01;
+-	regs.ebx = TCPA_MAGIC;
+-	regs.ecx = 0;
+-	regs.edx = 0;
+-	regs.es = (((grub_addr_t) &incoming) & 0xffff0000) >> 4;
+-	regs.edi = ((grub_addr_t) &incoming) & 0xffff;
+-	regs.ds = (((grub_addr_t) &outgoing) & 0xffff0000) >> 4;
+-	regs.esi = ((grub_addr_t) &outgoing) & 0xffff;
+-
+-	grub_bios_interrupt (0x1a, &regs);
+-
+-	grub_free(event);
+-
+-	if (regs.eax)
+-	  {
+-		tpm_presence = 0;
+-		return grub_error (GRUB_ERR_IO, N_("TPM error %x, disabling TPM"), regs.eax);
+-	  }
+-
+-	return 0;
+-}
+diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
+index cfff25c21b5..783a3cd93bc 100644
+--- a/grub-core/loader/i386/pc/linux.c
++++ b/grub-core/loader/i386/pc/linux.c
+@@ -36,7 +36,6 @@
+ #include <grub/lib/cmdline.h>
+ #include <grub/linux.h>
+ #include <grub/efi/sb.h>
+-#include <grub/tpm.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -162,9 +161,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  grub_tpm_measure (kernel, len, GRUB_BINARY_PCR, "grub_linux16", "Kernel");
+-  grub_print_error();
+-
+   grub_memcpy (&lh, kernel, sizeof (lh));
+   kernel_offset = sizeof (lh);
+ 
+diff --git a/include/grub/tpm.h b/include/grub/tpm.h
+index 972a5edc836..ce52be4ff7f 100644
+--- a/include/grub/tpm.h
++++ b/include/grub/tpm.h
+@@ -69,7 +69,7 @@ typedef struct {
+ grub_err_t EXPORT_FUNC(grub_tpm_measure) (unsigned char *buf, grub_size_t size,
+ 					  grub_uint8_t pcr, const char *kind,
+ 					  const char *description);
+-#if defined (GRUB_MACHINE_EFI) || defined (GRUB_MACHINE_PCBIOS)
++#if defined (GRUB_MACHINE_EFI)
+ grub_err_t grub_tpm_execute(PassThroughToTPM_InputParamBlock *inbuf,
+ 			    PassThroughToTPM_OutputParamBlock *outbuf);
+ grub_err_t grub_tpm_log_event(unsigned char *buf, grub_size_t size,
+diff --git a/grub-core/boot/i386/pc/boot.S b/grub-core/boot/i386/pc/boot.S
+index acab37369ae..ea167fe1206 100644
+--- a/grub-core/boot/i386/pc/boot.S
++++ b/grub-core/boot/i386/pc/boot.S
+@@ -24,14 +24,11 @@
+  *  defines for the code go here
+  */
+ 
+-#define TPM 1
+-
+ 	/* Print message string */
+ #define MSG(x)	movw $x, %si; call LOCAL(message)
+ #define ERR(x)	movw $x, %si; jmp LOCAL(error_message)
+ 
+ 	.macro floppy
+-#ifndef TPM
+ part_start:
+ 
+ LOCAL(probe_values):
+@@ -88,7 +85,6 @@ fd_probe_error_string:	.asciz "Floppy"
+ 	movb	MACRO_DOLLAR(79), %ch
+ 
+ 	jmp	LOCAL(final_init)
+-#endif
+ 	.endm
+ 
+ 	.macro scratch
+@@ -256,7 +252,6 @@ real_start:
+ 	/* set %si to the disk address packet */
+ 	movw	$disk_address_packet, %si
+ 
+-#ifndef TPM
+ 	/* check if LBA is supported */
+ 	movb	$0x41, %ah
+ 	movw	$0x55aa, %bx
+@@ -276,7 +271,6 @@ real_start:
+ 
+ 	andw	$1, %cx
+ 	jz	LOCAL(chs_mode)
+-#endif
+ 
+ LOCAL(lba_mode):
+ 	xorw	%ax, %ax
+@@ -320,9 +314,6 @@ LOCAL(lba_mode):
+ 	jmp	LOCAL(copy_buffer)
+ 
+ LOCAL(chs_mode):
+-#ifdef TPM
+-	jmp	LOCAL(general_error)
+-#else
+ 	/*
+ 	 *  Determine the hard disk geometry from the BIOS!
+ 	 *  We do this first, so that LS-120 IDE floppies work correctly.
+@@ -434,7 +425,7 @@ setup_sectors:
+ 	jc	LOCAL(read_error)
+ 
+ 	movw	%es, %bx
+-#endif /* TPM */
++
+ LOCAL(copy_buffer):
+ 	/*
+ 	 * We need to save %cx and %si because the startup code in
+@@ -457,25 +448,6 @@ LOCAL(copy_buffer):
+ 	popw	%ds
+ 	popa
+ 
+-#ifdef TPM
+-	pusha
+-
+-	movw	$0xBB00, %ax		/* TCG_StatusCheck */
+-	int	$0x1A
+-	test	%eax, %eax
+-	jnz	boot			/* No TPM or TPM deactivated */
+-
+-	movw	$0xBB07, %ax		/* TCG_CompactHashLogExtendEvent */
+-	movw	$GRUB_BOOT_MACHINE_KERNEL_ADDR, %di
+-	xorl	%esi, %esi
+-	movl	$0x41504354, %ebx	/* TCPA */
+-	movl	$0x200, %ecx		/* Measure 512 bytes */
+-	movl	$0x8, %edx		/* PCR 8 */
+-	int	$0x1A
+-
+-boot:
+-	popa
+-#endif
+ 	/* boot kernel */
+ 	jmp	*(LOCAL(kernel_address))
+ 
+diff --git a/grub-core/boot/i386/pc/diskboot.S b/grub-core/boot/i386/pc/diskboot.S
+index f4744ec6fcb..68d31de0c4c 100644
+--- a/grub-core/boot/i386/pc/diskboot.S
++++ b/grub-core/boot/i386/pc/diskboot.S
+@@ -19,8 +19,6 @@
+ #include <grub/symbol.h>
+ #include <grub/machine/boot.h>
+ 
+-#define TPM 1
+-
+ /*
+  *  defines for the code go here
+  */
+@@ -55,21 +53,6 @@ _start:
+ 	/* this sets up for the first run through "bootloop" */
+ 	movw	$LOCAL(firstlist), %di
+ 
+-#ifdef TPM
+-        /* clear EAX to remove potential garbage */
+-	xorl    %eax, %eax
+-	/* 8(%di) = number of sectors to read */
+-	movw    8(%di), %ax
+-
+-	/* Multiply number of sectors to read with 512 bytes. EAX is 32bit
+-	* which is large enough to hold values of up to 4GB. I doubt there
+-	* will ever be a core.img larger than that. ;-) */
+-	shll    $9, %eax
+-
+-	/* write result to bytes_to_measure var */
+-	movl    %eax, bytes_to_measure
+-#endif
+-
+ 	/* save the sector number of the second sector in %ebp */
+ 	movl	(%di), %ebp
+ 
+@@ -307,29 +290,6 @@ LOCAL(copy_buffer):
+ /* END OF MAIN LOOP */
+ 
+ LOCAL(bootit):
+-#ifdef TPM
+-	pusha
+-	movw	$0xBB07, %ax		/* TCG_CompactHashLogExtendEvent */
+-
+-	movw	$0x0, %bx
+-	movw	%bx, %es
+-
+-	/* We've already measured the first 512 bytes, now measure the rest */
+-	xorl	%edi, %edi
+-	movw	$(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200), %di
+-
+-	movl	$0x41504354, %ebx	/* EBX = "TCPA" */
+-
+-	/* %ecx = The length, in bytes, of the buffer to measure  */
+-	movl	$bytes_to_measure, %esi
+-	movl	(%esi), %ecx
+-	xorl	%esi, %esi
+-	movl	$0x9, %edx		/* PCR 9 */
+-
+-	int	$0x1A
+-
+-	popa
+-#endif
+ 	/* print a newline */
+ 	MSG(notification_done)
+ 	popw	%dx	/* this makes sure %dl is our "boot" drive */
+@@ -364,10 +324,6 @@ geometry_error_string:	.asciz "Geom"
+ read_error_string:	.asciz "Read"
+ general_error_string:	.asciz " Error"
+ 
+-#ifdef TPM
+-bytes_to_measure:	.long 0
+-#endif
+-
+ /*
+  * message: write the string pointed to by %si
+  *
diff --git a/SOURCES/0233-Move-quicksort-function-from-kernel.exec-to-the-blsc.patch b/SOURCES/0233-Move-quicksort-function-from-kernel.exec-to-the-blsc.patch
new file mode 100644
index 0000000..61189da
--- /dev/null
+++ b/SOURCES/0233-Move-quicksort-function-from-kernel.exec-to-the-blsc.patch
@@ -0,0 +1,148 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Thu, 27 Sep 2018 10:49:14 +0200
+Subject: [PATCH] Move quicksort function from kernel.exec to the blscfg module
+
+The qsort function is defined in the grub2 kernel and exported for modules
+to use. But this prevents the blscfg.mod to be loaded by old grub2 kernels
+that don't export this symbol.
+
+Loading the latest blscfg module might be useful on legacy BIOS systems to
+avoid updating the first and second stage grub2 images in the boot device.
+
+Since the only caller of the qsort function is the blscfg module, move the
+qsort function out of the grub2 kernel and only have it in the blscfg.mod.
+
+While being there, also remove the grub_bsearch() function that is unused.
+
+Related: rhbz#1633646
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/Makefile.core.def                      |  2 +-
+ grub-core/commands/blscfg.c                      |  3 ++-
+ grub-core/{kern/qsort.c => commands/bls_qsort.h} | 30 +++---------------------
+ include/grub/misc.h                              | 15 ------------
+ 4 files changed, 6 insertions(+), 44 deletions(-)
+ rename grub-core/{kern/qsort.c => commands/bls_qsort.h} (93%)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 01c5f9ae351..f99fc994f6b 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -129,7 +129,6 @@ kernel = {
+   common = kern/rescue_parser.c;
+   common = kern/rescue_reader.c;
+   common = kern/term.c;
+-  common = kern/qsort.c;
+   common = kern/backtrace.c;
+   common = kern/tpm.c;
+ 
+@@ -781,6 +780,7 @@ module = {
+ module = {
+   name = blscfg;
+   common = commands/blscfg.c;
++  common = commands/bls_qsort.h;
+   common = commands/loadenv.h;
+   enable = efi;
+   enable = i386_pc;
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index abd6f00d0de..bec5a9ffe3e 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -36,6 +36,7 @@
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
++#include "bls_qsort.h"
+ #include "loadenv.h"
+ 
+ #define GRUB_BLS_CONFIG_PATH "/loader/entries/"
+@@ -717,7 +718,7 @@ read_fallback:
+       use_version = false;
+   }
+ 
+-  grub_qsort(&entries[0], nentries, sizeof (struct bls_entry *), bls_cmp, &use_version);
++  bls_qsort(&entries[0], nentries, sizeof (struct bls_entry *), bls_cmp, &use_version);
+ 
+   grub_dprintf ("blscfg", "%s Creating %d entries from bls\n", __func__, nentries);
+   for (r = nentries - 1; r >= 0; r--)
+diff --git a/grub-core/kern/qsort.c b/grub-core/commands/bls_qsort.h
+similarity index 93%
+rename from grub-core/kern/qsort.c
+rename to grub-core/commands/bls_qsort.h
+index 7f3fc9ffdae..572765fa3f2 100644
+--- a/grub-core/kern/qsort.c
++++ b/grub-core/commands/bls_qsort.h
+@@ -64,6 +64,7 @@ typedef struct
+ #define	POP(low, high)	((void) (--top, (low = top->lo), (high = top->hi)))
+ #define	STACK_NOT_EMPTY	(stack < top)
+ 
++typedef int (*grub_compar_d_fn_t) (const void *p0, const void *p1, void *state);
+ 
+ /* Order size using quicksort.  This implementation incorporates
+    four optimizations discussed in Sedgewick:
+@@ -89,8 +90,8 @@ typedef struct
+       smaller partition.  This *guarantees* no more than log (total_elems)
+       stack size is needed (actually O(1) in this case)!  */
+ 
+-void
+-grub_qsort (void *const pbase, grub_size_t total_elems, grub_size_t size,
++static inline void UNUSED
++bls_qsort (void *const pbase, grub_size_t total_elems, grub_size_t size,
+ 	    grub_compar_d_fn_t cmp, void *arg)
+ {
+   char *base_ptr = (char *) pbase;
+@@ -252,28 +253,3 @@ grub_qsort (void *const pbase, grub_size_t total_elems, grub_size_t size,
+   }
+ }
+ 
+-void *
+-grub_bsearch (const void *key, const void *base, grub_size_t nmemb, grub_size_t size,
+-	 grub_compar_d_fn_t compar, void *state)
+-{
+-  grub_size_t l, u, idx;
+-  const void *p;
+-  int comparison;
+-
+-  l = 0;
+-  u = nmemb;
+-  while (l < u)
+-    {
+-      idx = (l + u) / 2;
+-      p = (void *) (((const char *) base) + (idx * size));
+-      comparison = (*compar) (key, p, state);
+-      if (comparison < 0)
+-	u = idx;
+-      else if (comparison > 0)
+-	l = idx + 1;
+-      else
+-	return (void *) p;
+-    }
+-
+-  return NULL;
+-}
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index 5f1c1c1be4e..de9016ab709 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -510,19 +510,4 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file,
+ #define grub_max(a, b) (((a) > (b)) ? (a) : (b))
+ #define grub_min(a, b) (((a) < (b)) ? (a) : (b))
+ 
+-typedef int (*grub_compar_d_fn_t) (const void *p0, const void *p1, void *state);
+-
+-void *EXPORT_FUNC(grub_bsearch) (const void *key,
+-			    const void *base,
+-			    grub_size_t nmemb,
+-			    grub_size_t size,
+-			    grub_compar_d_fn_t compar,
+-			    void *state);
+-
+-void EXPORT_FUNC(grub_qsort) (void *const pbase,
+-			 grub_size_t total_elems,
+-			 grub_size_t size,
+-			 grub_compar_d_fn_t cmp,
+-			 void *state);
+-
+ #endif /* ! GRUB_MISC_HEADER */
diff --git a/SOURCES/0234-Include-blscfg-module-for-powerpc-ieee1275.patch b/SOURCES/0234-Include-blscfg-module-for-powerpc-ieee1275.patch
new file mode 100644
index 0000000..a60299b
--- /dev/null
+++ b/SOURCES/0234-Include-blscfg-module-for-powerpc-ieee1275.patch
@@ -0,0 +1,27 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Thu, 27 Sep 2018 19:03:43 +0200
+Subject: [PATCH] Include blscfg module for powerpc ieee1275
+
+The blscfg module is currently not built for powerpc ieee1275, but this
+is still needed when the machine is not booted in bare metal with OPAL.
+
+Related: rhbz#1633646
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/Makefile.core.def | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index f99fc994f6b..5b4841e1f00 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -782,6 +782,7 @@ module = {
+   common = commands/blscfg.c;
+   common = commands/bls_qsort.h;
+   common = commands/loadenv.h;
++  enable = powerpc_ieee1275;
+   enable = efi;
+   enable = i386_pc;
+   enable = emu;
diff --git a/SOURCES/0235-grub-switch-to-blscfg-copy-blscfg-module-for-legacy-.patch b/SOURCES/0235-grub-switch-to-blscfg-copy-blscfg-module-for-legacy-.patch
new file mode 100644
index 0000000..2559203
--- /dev/null
+++ b/SOURCES/0235-grub-switch-to-blscfg-copy-blscfg-module-for-legacy-.patch
@@ -0,0 +1,55 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 28 Sep 2018 10:35:38 +0200
+Subject: [PATCH] grub-switch-to-blscfg: copy blscfg module for legacy BIOS and
+ ppc ieee1275
+
+On platforms that load the blscfg module the latest version should be used,
+so copy the module to the boot directory to make sure that the grub2 kernel
+will load the latest version of the BLS parsing code.
+
+Related: rhbz#1633646
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-switch-to-blscfg.in | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index 9cf64f8e725..1c6bd1882a7 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -53,6 +53,8 @@ blsdir=`echo "/@bootdirname@/loader/entries" | sed 's,//*,/,g'`
+ 
+ backupsuffix=.bak
+ 
++arch="$(uname -m)"
++
+ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
+ 
+@@ -248,7 +250,6 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+     fi
+ 
+     if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
+-        arch="$(uname -m)"
+         bls_debug="$(echo ${bls_target} | sed -e "s/\.${arch}/-debug.${arch}/")"
+         cp -aT  "${bls_target}" "${bls_debug}"
+         title="$(grep '^title[ \t]' "${bls_debug}" | sed -e 's/^title[ \t]*//')"
+@@ -282,6 +283,16 @@ elif ! grep -q '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" ; then
+ fi
+ 
+ if [ "${GENERATE}" -eq 1 ] ; then
++    if [ $arch = "x86_64" ] && [ ! -d /sys/firmware/efi ]; then
++	if ! cp ${prefix}/lib/grub//i386-pc/blscfg.mod ${grubdir}/i386-pc/ ; then
++	    exit 1
++	fi
++    elif [ $arch = "ppc64" -o $arch = "ppc64le" ] && [ ! -d /sys/firmware/opal ]; then
++	if ! cp ${prefix}/lib/grub/powerpc-ieee1275/blscfg.mod ${grubdir}/powerpc-ieee1275/ ; then
++	    exit 1
++	fi
++    fi
++
+     cp -af "${GRUB_CONFIG_FILE}" "${GRUB_CONFIG_FILE}${backupsuffix}"
+     if ! grub2-mkconfig -o "${GRUB_CONFIG_FILE}" ; then
+         cp -af "${GRUB_CONFIG_FILE}${backupsuffix}" "${GRUB_CONFIG_FILE}"
diff --git a/SOURCES/0236-Fix-getroot.c-s-trampolines.patch b/SOURCES/0236-Fix-getroot.c-s-trampolines.patch
new file mode 100644
index 0000000..3a808f7
--- /dev/null
+++ b/SOURCES/0236-Fix-getroot.c-s-trampolines.patch
@@ -0,0 +1,49 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 28 Sep 2018 15:42:19 -0400
+Subject: [PATCH] Fix getroot.c's trampolines.
+
+This makes the stack executable on most of the grub utilities, which is
+bad, and rpmdiff complains about it.
+
+Related: rhbz#1633646
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/osdep/linux/getroot.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
+index 4c5a13022dc..388a0f70638 100644
+--- a/grub-core/osdep/linux/getroot.c
++++ b/grub-core/osdep/linux/getroot.c
+@@ -1264,22 +1264,20 @@ grub_util_get_grub_dev_os (const char *os_dev)
+   return grub_dev;
+ }
+ 
++static void *mp = NULL;
++static void
++btrfs_mount_path_hook(const char *m)
++{
++  mp = strdup (m);
++}
+ 
+ char *
+ grub_util_get_btrfs_subvol (const char *path, char **mount_path)
+ {
+-  char *mp = NULL;
+-
+   if (mount_path)
+     *mount_path = NULL;
+ 
+-  auto void
+-  mount_path_hook (const char *m)
+-  {
+-    mp = strdup (m);
+-  }
+-
+-  grub_find_root_btrfs_mount_path_hook = mount_path_hook;
++  grub_find_root_btrfs_mount_path_hook = btrfs_mount_path_hook;
+   grub_free (grub_find_root_devices_from_mountinfo (path, NULL));
+   grub_find_root_btrfs_mount_path_hook = NULL;
+ 
diff --git a/SOURCES/0237-add-10_linux_bls-grub.d-snippet-to-generate-menu-ent.patch b/SOURCES/0237-add-10_linux_bls-grub.d-snippet-to-generate-menu-ent.patch
new file mode 100644
index 0000000..bb1b012
--- /dev/null
+++ b/SOURCES/0237-add-10_linux_bls-grub.d-snippet-to-generate-menu-ent.patch
@@ -0,0 +1,485 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 3 Oct 2018 20:48:32 +0200
+Subject: [PATCH] add 10_linux_bls grub.d snippet to generate menu entries from
+ BLS files
+
+This grub.d snippet can be used on platforms where the bootloader doesn't
+have BLS support and only can parse a normal grub configuration file.
+
+Portions of this script were taken from the ostree-grub-generator script
+included in the OSTree project.
+
+Resolves: rhbz#1636013
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ Makefile.util.def           |   7 +
+ util/grub.d/10_linux_bls.in | 440 ++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 447 insertions(+)
+ create mode 100644 util/grub.d/10_linux_bls.in
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index cba4d500198..08cc98ddb8b 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -502,6 +502,13 @@ script = {
+   condition = COND_HOST_LINUX;
+ };
+ 
++script = {
++  name = '10_linux_bls';
++  common = util/grub.d/10_linux_bls.in;
++  installdir = grubconf;
++  condition = COND_HOST_LINUX;
++};
++
+ script = {
+   name = '10_xnu';
+   common = util/grub.d/10_xnu.in;
+diff --git a/util/grub.d/10_linux_bls.in b/util/grub.d/10_linux_bls.in
+new file mode 100644
+index 00000000000..3cc7803c6a1
+--- /dev/null
++++ b/util/grub.d/10_linux_bls.in
+@@ -0,0 +1,440 @@
++#! /bin/sh
++set -e
++
++# grub-mkconfig helper script.
++# Copyright (C) 2006,2007,2008,2009,2010  Free Software Foundation, Inc.
++#
++# GRUB is free software: you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation, either version 3 of the License, or
++# (at your option) any later version.
++#
++# GRUB is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++
++prefix="@prefix@"
++exec_prefix="@exec_prefix@"
++datarootdir="@datarootdir@"
++
++. "$pkgdatadir/grub-mkconfig_lib"
++
++export TEXTDOMAIN=@PACKAGE@
++export TEXTDOMAINDIR="@localedir@"
++
++CLASS="--class gnu-linux --class gnu --class os --unrestricted"
++
++if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then
++  OS="$(eval $(grep PRETTY_NAME /etc/os-release) ; echo ${PRETTY_NAME})"
++  CLASS="--class $(eval $(grep '^ID_LIKE=\|^ID=' /etc/os-release) ; [ -n "${ID_LIKE}" ] && echo ${ID_LIKE} || echo ${ID}) ${CLASS}"
++else
++  OS="${GRUB_DISTRIBUTOR}"
++  CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}"
++fi
++
++# loop-AES arranges things so that /dev/loop/X can be our root device, but
++# the initrds that Linux uses don't like that.
++case ${GRUB_DEVICE} in
++  /dev/loop/*|/dev/loop[0-9])
++    GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
++  ;;
++esac
++
++# Default to disabling partition uuid support to maintian compatibility with
++# older kernels.
++GRUB_DISABLE_LINUX_PARTUUID=${GRUB_DISABLE_LINUX_PARTUUID-true}
++
++# btrfs may reside on multiple devices. We cannot pass them as value of root= parameter
++# and mounting btrfs requires user space scanning, so force UUID in this case.
++if ( [ "x${GRUB_DEVICE_UUID}" = "x" ] && [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] ) \
++    || ( [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
++	&& [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ] ) \
++    || ( ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \
++	&& ! test -e "/dev/disk/by-partuuid/${GRUB_DEVICE_PARTUUID}" ) \
++    || ( test -e "${GRUB_DEVICE}" && uses_abstraction "${GRUB_DEVICE}" lvm ); then
++  LINUX_ROOT_DEVICE=${GRUB_DEVICE}
++elif [ "x${GRUB_DEVICE_UUID}" = "x" ] \
++    || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ]; then
++  LINUX_ROOT_DEVICE=PARTUUID=${GRUB_DEVICE_PARTUUID}
++else
++  LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
++fi
++
++case x"$GRUB_FS" in
++    xbtrfs)
++	if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then
++	GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}"
++	else
++	rootsubvol="`make_system_path_relative_to_its_root /`"
++	rootsubvol="${rootsubvol#/}"
++	if [ "x${rootsubvol}" != x ]; then
++	    GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}"
++	fi
++	fi;;
++    xzfs)
++	rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true`
++	bootfs="`make_system_path_relative_to_its_root / | sed -e "s,@$,,"`"
++	LINUX_ROOT_DEVICE="ZFS=${rpool}${bootfs}"
++	;;
++esac
++
++mktitle ()
++{
++  local title_type
++  local version
++  local OS_NAME
++  local OS_VERS
++
++  title_type=$1 && shift
++  version=$1 && shift
++
++  OS_NAME="$(eval $(grep ^NAME= /etc/os-release) ; echo ${NAME})"
++  OS_VERS="$(eval $(grep ^VERSION= /etc/os-release) ; echo ${VERSION})"
++
++  case $title_type in
++    recovery)
++      title=$(printf '%s (%s) %s (recovery mode)' \
++                     "${OS_NAME}" "${version}" "${OS_VERS}")
++      ;;
++    *)
++      title=$(printf '%s (%s) %s' \
++                     "${OS_NAME}" "${version}" "${OS_VERS}")
++      ;;
++  esac
++  echo -n ${title}
++}
++
++title_correction_code=
++
++populate_header_warn()
++{
++cat <<EOF
++
++# This section was generated by a script. Do not modify the generated file - all changes
++# will be lost the next time file is regenerated. Instead edit the BootLoaderSpec files.
++
++EOF
++}
++
++read_config()
++{
++    config_file=${1}
++    title=""
++    initrd=""
++    options=""
++    linux=""
++
++    while read -r line
++    do
++        record=$(echo ${line} | cut -f 1 -d ' ')
++        value=$(echo ${line} | cut -s -f2- -d ' ')
++        case "${record}" in
++            "title")
++                title=${value}
++                ;;
++            "initrd")
++                initrd=${value}
++                ;;
++            "linux")
++                linux=${value}
++                ;;
++            "options")
++                options=${value}
++                ;;
++        esac
++    done < ${config_file}
++}
++
++populate_menu()
++{
++    entries_path="/boot/loader/entries"
++    gettext_printf "Generating boot entries from BLS files...\n" >&2
++    for config in $(ls -v -r $entries_path/*.conf); do
++        read_config ${config}
++        menu="${menu}menuentry '${title}' {\n"
++        menu="${menu}\t linux ${linux} ${options}\n"
++        if [ -n "${initrd}" ] ; then
++            menu="${menu}\t initrd ${boot_prefix}${initrd}\n"
++        fi
++        menu="${menu}}\n\n"
++    done
++    # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation
++    printf "$menu"
++}
++
++linux_entry ()
++{
++  os="$1"
++  version="$2"
++  type="$3"
++  isdebug="$4"
++  args="$5"
++
++  if [ -z "$boot_device_id" ]; then
++      boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
++  fi
++
++  if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then
++    if [ x$dirname = x/ ]; then
++      if [ -z "${prepare_root_cache}" ]; then
++        prepare_grub_to_access_device ${GRUB_DEVICE}
++      fi
++    else
++      if [ -z "${prepare_boot_cache}" ]; then
++        prepare_grub_to_access_device ${GRUB_DEVICE_BOOT}
++      fi
++    fi
++
++    if [ -d /sys/firmware/efi ]; then
++        bootefi_device="`${grub_probe} --target=device /boot/efi/`"
++        prepare_grub_to_access_device ${bootefi_device} boot
++    else
++        boot_device="`${grub_probe} --target=device /boot/`"
++        prepare_grub_to_access_device ${boot_device} boot
++    fi
++
++    populate_header_warn
++    populate_menu
++
++    ${grub_editenv} - set saved_entry=0
++    ${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
++
++    exit 0
++  fi
++
++  if [ x$type != xsimple ] ; then
++      title=$(mktitle "$type" "$version")
++      if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then
++	  replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')"
++	  quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)"
++	  title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;"
++      fi
++      if [ x$isdebug = xdebug ]; then
++	  title="$title${GRUB_LINUX_DEBUG_TITLE_POSTFIX}"
++      fi
++      echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
++  else
++      echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
++  fi
++  if [ x$type != xrecovery ] ; then
++      save_default_entry | grub_add_tab
++  fi
++
++  # Use ELILO's generic "efifb" when it's known to be available.
++  # FIXME: We need an interface to select vesafb in case efifb can't be used.
++  if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then
++      echo "	load_video" | sed "s/^/$submenu_indentation/"
++      if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \
++	  && grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then
++	  echo "	set gfxpayload=keep" | sed "s/^/$submenu_indentation/"
++      fi
++  else
++      if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then
++	  echo "	load_video" | sed "s/^/$submenu_indentation/"
++      fi
++      echo "	set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/"
++  fi
++
++  echo "	insmod gzio" | sed "s/^/$submenu_indentation/"
++
++  if [ x$dirname = x/ ]; then
++    if [ -z "${prepare_root_cache}" ]; then
++      prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | grub_add_tab)"
++    fi
++    printf '%s\n' "${prepare_root_cache}" | sed "s/^/$submenu_indentation/"
++  else
++    if [ -z "${prepare_boot_cache}" ]; then
++      prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | grub_add_tab)"
++    fi
++    printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
++  fi
++  sed "s/^/$submenu_indentation/" << EOF
++	linux	${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
++EOF
++  if test -n "${initrd}" ; then
++    initrd_path=
++    for i in ${initrd}; do
++      initrd_path="${initrd_path} ${rel_dirname}/${i}"
++    done
++    sed "s/^/$submenu_indentation/" << EOF
++	initrd	$(echo $initrd_path)
++EOF
++  fi
++  if test -n "${fdt}" ; then
++    sed "s/^/$submenu_indentation/" << EOF
++	devicetree	${rel_dirname}/${fdt}
++EOF
++  fi
++  sed "s/^/$submenu_indentation/" << EOF
++}
++EOF
++}
++
++machine=`uname -m`
++case "x$machine" in
++    xi?86 | xx86_64)
++	list=
++	for i in /boot/vmlinuz-* /vmlinuz-* /boot/kernel-* ; do
++	    if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi
++	done ;;
++    *)
++	list=
++	for i in /boot/vmlinuz-* /boot/vmlinux-* /vmlinuz-* /vmlinux-* /boot/kernel-* ; do
++                  if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi
++	done ;;
++esac
++
++if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then
++    for i in /boot/ostree/*/vmlinuz-* ; do
++        if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi
++    done
++fi
++
++case "$machine" in
++    i?86) GENKERNEL_ARCH="x86" ;;
++    mips|mips64) GENKERNEL_ARCH="mips" ;;
++    mipsel|mips64el) GENKERNEL_ARCH="mipsel" ;;
++    arm*) GENKERNEL_ARCH="arm" ;;
++    *) GENKERNEL_ARCH="$machine" ;;
++esac
++
++prepare_boot_cache=
++prepare_root_cache=
++boot_device_id=
++title_correction_code=
++
++# Extra indentation to add to menu entries in a submenu. We're not in a submenu
++# yet, so it's empty. In a submenu it will be equal to '\t' (one tab).
++submenu_indentation=""
++
++is_top_level=true
++while [ "x$list" != "x" ] ; do
++  linux=`version_find_latest $list`
++  if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then
++    gettext_printf "Found linux image: %s\n" "$linux" >&2
++  fi
++
++  basename=`basename $linux`
++  dirname=`dirname $linux`
++  rel_dirname=`make_system_path_relative_to_its_root $dirname`
++  version=`echo $basename | sed -e "s,^[^0-9]*-,,g"`
++  alt_version=`echo $version | sed -e "s,\.old$,,g"`
++  linux_root_device_thisversion="${LINUX_ROOT_DEVICE}"
++
++  initrd_early=
++  for i in ${GRUB_EARLY_INITRD_LINUX_STOCK} \
++	   ${GRUB_EARLY_INITRD_LINUX_CUSTOM}; do
++    if test -e "${dirname}/${i}" ; then
++      initrd_early="${initrd_early} ${i}"
++    fi
++  done
++
++  initrd_real=
++  for i in "initrd.img-${version}" "initrd-${version}.img" "initrd-${version}.gz" \
++	   "initrd-${version}" "initramfs-${version}.img" \
++	   "initrd.img-${alt_version}" "initrd-${alt_version}.img" \
++	   "initrd-${alt_version}" "initramfs-${alt_version}.img" \
++	   "initramfs-genkernel-${version}" \
++	   "initramfs-genkernel-${alt_version}" \
++	   "initramfs-genkernel-${GENKERNEL_ARCH}-${version}" \
++	   "initramfs-genkernel-${GENKERNEL_ARCH}-${alt_version}"; do
++    if test -e "${dirname}/${i}" ; then
++      initrd_real="${i}"
++      break
++    fi
++  done
++
++  initrd=
++  if test -n "${initrd_early}" || test -n "${initrd_real}"; then
++    initrd="${initrd_early} ${initrd_real}"
++
++    initrd_display=
++    for i in ${initrd}; do
++      initrd_display="${initrd_display} ${dirname}/${i}"
++    done
++    if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then
++      gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
++    fi
++  fi
++
++  fdt=
++  for i in "dtb-${version}" "dtb-${alt_version}"; do
++    if test -f "${dirname}/${i}/${GRUB_DEFAULT_DTB}" ; then
++      fdt="${i}/${GRUB_DEFAULT_DTB}"
++      break
++    fi
++  done
++
++  config=
++  for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do
++    if test -e "${i}" ; then
++      config="${i}"
++      break
++    fi
++  done
++
++  initramfs=
++  if test -n "${config}" ; then
++      initramfs=`grep CONFIG_INITRAMFS_SOURCE= "${config}" | cut -f2 -d= | tr -d \"`
++  fi
++
++  if test -z "${initramfs}" && test -z "${initrd_real}" ; then
++    # "UUID=" and "ZFS=" magic is parsed by initrd or initramfs.  Since there's
++    # no initrd or builtin initramfs, it can't work here.
++    if [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] \
++	|| [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ]; then
++
++	linux_root_device_thisversion=${GRUB_DEVICE}
++    else
++	linux_root_device_thisversion=PARTUUID=${GRUB_DEVICE_PARTUUID}
++    fi
++  fi
++
++  if [ "x${GRUB_DISABLE_SUBMENU}" = "xyes" ] || [ "x${GRUB_DISABLE_SUBMENU}" = "xy" ]; then
++    GRUB_DISABLE_SUBMENU="true"
++  fi
++
++  if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then
++    linux_entry "${OS}" "${version}" simple standard \
++    "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++    if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
++      linux_entry "${OS}" "${version}" simple debug \
++        "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}"
++    fi
++
++    submenu_indentation="$grub_tab"
++
++    if [ -z "$boot_device_id" ]; then
++	boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
++    fi
++    # TRANSLATORS: %s is replaced with an OS name
++    echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {"
++    is_top_level=false
++  fi
++
++  linux_entry "${OS}" "${version}" advanced standard \
++              "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
++  if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
++    linux_entry "${OS}" "${version}" advanced debug \
++                "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}"
++  fi
++
++  if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
++    linux_entry "${OS}" "${version}" recovery standard \
++                "single ${GRUB_CMDLINE_LINUX}"
++  fi
++
++  list=`echo $list | tr ' ' '\n' | fgrep -vx "$linux" | tr '\n' ' '`
++done
++
++# If at least one kernel was found, then we need to
++# add a closing '}' for the submenu command.
++if [ x"$is_top_level" != xtrue ]; then
++  echo '}'
++fi
++
++echo "$title_correction_code"
diff --git a/SOURCES/0238-Only-set-kernelopts-in-grubenv-if-it-wasn-t-set-befo.patch b/SOURCES/0238-Only-set-kernelopts-in-grubenv-if-it-wasn-t-set-befo.patch
new file mode 100644
index 0000000..be3c867
--- /dev/null
+++ b/SOURCES/0238-Only-set-kernelopts-in-grubenv-if-it-wasn-t-set-befo.patch
@@ -0,0 +1,79 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 5 Oct 2018 16:29:47 +0200
+Subject: [PATCH] Only set kernelopts in grubenv if it wasn't set before
+
+Users may want to use a different command line parameters, so if there's
+a kernelopts var set in grubenv, grub2-mkconfig shouldn't reset it.
+
+While being there, print a warning so users know that they shouldn't edit
+the grub config file and instead edit the BootLoaderSpec config files.
+
+Resolves: rhbz#1636466
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub.d/10_linux.in     | 20 +++++++++++++++++++-
+ util/grub.d/10_linux_bls.in |  4 +++-
+ 2 files changed, 22 insertions(+), 2 deletions(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 9682e97b7f5..01e66e5fc74 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -82,6 +82,20 @@ case x"$GRUB_FS" in
+ 	;;
+ esac
+ 
++populate_header_warn()
++{
++cat <<EOF
++
++# This section was generated by a script. Do not modify the generated file - all changes
++# will be lost the next time file is regenerated. Instead edit the BootLoaderSpec files.
++#
++# The blscfg command parses the BootLoaderSpec files stored in /boot/loader/entries and
++# populates the boot menu. Please refer to the Boot Loader Specification documentation
++# for the files format: https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/.
++
++EOF
++}
++
+ mktitle ()
+ {
+   local title_type
+@@ -141,6 +155,8 @@ linux_entry ()
+         prepare_grub_to_access_device ${boot_device} boot
+     fi
+ 
++    populate_header_warn
++
+     cat << EOF
+ insmod blscfg
+ blscfg
+@@ -150,7 +166,9 @@ fi
+ EOF
+ 
+     ${grub_editenv} - set saved_entry=0
+-    ${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
++    if ! grub2-editenv - list | grep -q kernelopts; then
++	${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
++    fi
+ 
+     exit 0
+   fi
+diff --git a/util/grub.d/10_linux_bls.in b/util/grub.d/10_linux_bls.in
+index 3cc7803c6a1..8a3379578bd 100644
+--- a/util/grub.d/10_linux_bls.in
++++ b/util/grub.d/10_linux_bls.in
+@@ -201,7 +201,9 @@ linux_entry ()
+     populate_menu
+ 
+     ${grub_editenv} - set saved_entry=0
+-    ${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
++    if ! grub2-editenv - list | grep -q kernelopts; then
++	${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
++    fi
+ 
+     exit 0
+   fi
diff --git a/SOURCES/0239-blscfg-don-t-include-.conf-at-the-end-of-our-id.patch b/SOURCES/0239-blscfg-don-t-include-.conf-at-the-end-of-our-id.patch
new file mode 100644
index 0000000..59adb84
--- /dev/null
+++ b/SOURCES/0239-blscfg-don-t-include-.conf-at-the-end-of-our-id.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 11 Oct 2018 15:30:13 -0400
+Subject: [PATCH] blscfg: don't include ".conf" at the end of our "id".
+
+Related: rhbz#1638117
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/commands/blscfg.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index bec5a9ffe3e..3847572dabd 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -575,6 +575,7 @@ static void create_entry (struct bls_entry *entry)
+   char **initrds = NULL;
+   char *initrd = NULL;
+   char *id = entry->filename;
++  char *dotconf = id;
+   char *hotkey = NULL;
+ 
+   char *users = NULL;
+@@ -593,6 +594,16 @@ static void create_entry (struct bls_entry *entry)
+       goto finish;
+     }
+ 
++  /*
++   * strip the ".conf" off the end before we make it our "id" field.
++   */
++  do
++    {
++      dotconf = grub_strstr(dotconf, ".conf");
++    } while (dotconf != NULL && dotconf[5] != '\0');
++  if (dotconf)
++    dotconf[0] = '\0';
++
+   title = bls_get_val (entry, "title", NULL);
+   options = expand_val (bls_get_val (entry, "options", NULL));
+   initrds = bls_make_list (entry, "initrd", NULL);
diff --git a/SOURCES/0240-grub-get-kernel-settings-expose-some-more-config-var.patch b/SOURCES/0240-grub-get-kernel-settings-expose-some-more-config-var.patch
new file mode 100644
index 0000000..2471e5f
--- /dev/null
+++ b/SOURCES/0240-grub-get-kernel-settings-expose-some-more-config-var.patch
@@ -0,0 +1,32 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Thu, 11 Oct 2018 15:31:04 -0400
+Subject: [PATCH] grub-get-kernel-settings: expose some more config variables
+
+This exposes MAKEDEFAULT as GRUB_UPDATE_DEFAULT_KERNEL and DEFAULTDEBUG as
+GRUB_DEFAULT_TO_DEBUG
+
+Related: rhbz#1638117
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ util/grub-get-kernel-settings.in | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/util/grub-get-kernel-settings.in b/util/grub-get-kernel-settings.in
+index 12046219878..7e87dfccc0e 100644
+--- a/util/grub-get-kernel-settings.in
++++ b/util/grub-get-kernel-settings.in
+@@ -76,3 +76,13 @@ if [ "$MAKEDEBUG" = "yes" ]; then
+     echo GRUB_LINUX_DEBUG_TITLE_POSTFIX=\" with debugging\"
+     echo export GRUB_LINUX_DEBUG_TITLE_POSTFIX
+ fi
++if [ "$DEFAULTDEBUG" = "yes" ]; then
++    echo GRUB_DEFAULT_TO_DEBUG=true
++else
++    echo GRUB_DEFAULT_TO_DEBUG=false
++fi
++echo export GRUB_DEFAULT_TO_DEBUG
++if [ "$UPDATEDEFAULT" = "yes" ]; then
++    echo GRUB_UPDATE_DEFAULT_KERNEL=true
++    echo export GRUB_UPDATE_DEFAULT_KERNEL
++fi
diff --git a/SOURCES/0241-blscfg-sort-everything-with-rpm-package-comparison.patch b/SOURCES/0241-blscfg-sort-everything-with-rpm-package-comparison.patch
new file mode 100644
index 0000000..f1d848c
--- /dev/null
+++ b/SOURCES/0241-blscfg-sort-everything-with-rpm-package-comparison.patch
@@ -0,0 +1,161 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Mon, 15 Oct 2018 15:08:33 -0400
+Subject: [PATCH] blscfg: sort everything with rpm *package* comparison
+
+This makes comparisons use the n-v-r tuple, and compare name with name,
+version with version, and release with release.
+
+Related: rhbz#1638103
+
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/commands/blscfg.c | 118 ++++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 108 insertions(+), 10 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 3847572dabd..347128c9ddd 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -206,7 +206,7 @@ static int vercmp(const char * a, const char * b)
+     int isnum;
+     int ret = 0;
+ 
+-  grub_dprintf("blscfg", "%s got here\n", __func__);
++    grub_dprintf("blscfg", "%s got here\n", __func__);
+     if (!grub_strcmp(a, b))
+ 	    return 0;
+ 
+@@ -315,6 +315,81 @@ finish:
+     return ret;
+ }
+ 
++/* returns name/version/release */
++/* NULL string pointer returned if nothing found */
++static void
++split_package_string (char *package_string, char **name,
++                     char **version, char **release)
++{
++  char *package_version, *package_release;
++
++  /* Release */
++  package_release = grub_strrchr (package_string, '-');
++
++  if (package_release != NULL)
++      *package_release++ = '\0';
++
++  *release = package_release;
++
++  if (name == NULL)
++    {
++      *version = package_string;
++    }
++  else
++    {
++      /* Version */
++      package_version = grub_strrchr(package_string, '-');
++
++      if (package_version != NULL)
++	*package_version++ = '\0';
++
++      *version = package_version;
++      /* Name */
++      *name = package_string;
++    }
++
++  /* Bubble up non-null values from release to name */
++  if (name != NULL && *name == NULL)
++    {
++      *name = (*version == NULL ? *release : *version);
++      *version = *release;
++      *release = NULL;
++    }
++  if (*version == NULL)
++    {
++      *version = *release;
++      *release = NULL;
++    }
++}
++
++static int
++split_cmp(char *nvr0, char *nvr1, int has_name)
++{
++  int ret = 0;
++  char *name0, *version0, *release0;
++  char *name1, *version1, *release1;
++
++  split_package_string(nvr0, has_name ? &name0 : NULL, &version0, &release0);
++  split_package_string(nvr1, has_name ? &name1 : NULL, &version1, &release1);
++
++  if (has_name)
++    {
++      ret = vercmp(name0 == NULL ? "" : name0,
++		   name1 == NULL ? "" : name1);
++      if (ret != 0)
++	return ret;
++    }
++
++  ret = vercmp(version0 == NULL ? "" : version0,
++	       version1 == NULL ? "" : version1);
++  if (ret != 0)
++    return ret;
++
++  ret = vercmp(release0 == NULL ? "" : release0,
++	       release1 == NULL ? "" : release1);
++  return ret;
++}
++
+ /* return 1: p0 is newer than p1 */
+ /*        0: p0 and p1 are the same version */
+ /*       -1: p1 is newer than p0 */
+@@ -323,18 +398,41 @@ static int bls_cmp(const void *p0, const void *p1, void *state)
+   struct bls_entry * e0 = *(struct bls_entry **)p0;
+   struct bls_entry * e1 = *(struct bls_entry **)p1;
+   bool use_version = *(bool *)state;
+-  const char *v0, *v1;
+-  int r;
++  char *v0, *v1;
++  char *id0, *id1;
++  int l, r;
+ 
+-  if (use_version) {
+-    v0 = bls_get_val(e0, "version", NULL);
+-    v1 = bls_get_val(e1, "version", NULL);
++  if (use_version)
++    {
++      v0 = grub_strdup(bls_get_val(e0, "version", NULL));
++      v1 = grub_strdup(bls_get_val(e1, "version", NULL));
+ 
+-    if ((r = vercmp(v0, v1)) != 0)
+-      return r;
+-  }
++      r = split_cmp(v0, v1, 0);
+ 
+-  return vercmp(e0->filename, e1->filename);
++      grub_free(v0);
++      grub_free(v1);
++
++      if (r != 0)
++	return r;
++    }
++
++  id0 = grub_strdup(e0->filename);
++  id1 = grub_strdup(e1->filename);
++
++  l = grub_strlen(id0);
++  if (l > 5 && grub_strcmp(id0 + l - 5, ".conf"))
++    id0[l-5] = '\0';
++
++  l = grub_strlen(id1);
++  if (l > 5 && grub_strcmp(id1 + l - 5, ".conf"))
++    id1[l-5] = '\0';
++
++  r = split_cmp(id0, id1, 1);
++
++  grub_free(id0);
++  grub_free(id1);
++
++  return r;
+ }
+ 
+ struct read_entry_info {
diff --git a/SOURCES/0242-10_linux_bls-use-grub2-rpm-sort-instead-of-ls-vr-to-.patch b/SOURCES/0242-10_linux_bls-use-grub2-rpm-sort-instead-of-ls-vr-to-.patch
new file mode 100644
index 0000000..f23cd47
--- /dev/null
+++ b/SOURCES/0242-10_linux_bls-use-grub2-rpm-sort-instead-of-ls-vr-to-.patch
@@ -0,0 +1,43 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 16 Oct 2018 15:48:15 +0200
+Subject: [PATCH] 10_linux_bls: use grub2-rpm-sort instead of ls -vr to sort
+ entries
+
+Using ls -vr is wrong since it's not the same than the RPM sort algorithm.
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub.d/10_linux_bls.in | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/util/grub.d/10_linux_bls.in b/util/grub.d/10_linux_bls.in
+index 8a3379578bd..1bc97f29898 100644
+--- a/util/grub.d/10_linux_bls.in
++++ b/util/grub.d/10_linux_bls.in
+@@ -151,10 +151,22 @@ read_config()
+ 
+ populate_menu()
+ {
+-    entries_path="/boot/loader/entries"
++    blsdir="/boot/loader/entries"
++    local -a files
++    local IFS=$'\n'
+     gettext_printf "Generating boot entries from BLS files...\n" >&2
+-    for config in $(ls -v -r $entries_path/*.conf); do
+-        read_config ${config}
++
++    files=($(for bls in ${blsdir}/*.conf ; do
++        if ! [[ -e "${bls}" ]] ; then
++            continue
++        fi
++        bls="${bls%.conf}"
++        bls="${bls##*/}"
++        echo "${bls}"
++    done | ${kernel_sort} | tac)) || :
++
++    for bls in "${files[@]}" ; do
++        read_config "${blsdir}/${bls}.conf"
+         menu="${menu}menuentry '${title}' {\n"
+         menu="${menu}\t linux ${linux} ${options}\n"
+         if [ -n "${initrd}" ] ; then
diff --git a/SOURCES/0243-don-t-set-saved_entry-on-grub2-mkconfig.patch b/SOURCES/0243-don-t-set-saved_entry-on-grub2-mkconfig.patch
new file mode 100644
index 0000000..8e3ea47
--- /dev/null
+++ b/SOURCES/0243-don-t-set-saved_entry-on-grub2-mkconfig.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 19 Oct 2018 14:42:41 +0200
+Subject: [PATCH] don't set saved_entry on grub2-mkconfig
+
+The original plan was for grub2 to rely on the BLS sort criteria to choose
+the default entry to boot, to avoid modifying any files when a new kernel
+was installed. But that was changed and now 20-grub.install changes the
+default, so 10_linux{,bls} shouldn't overwrite this.
+
+Resolves: rhbz#1636466
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub.d/10_linux.in     | 1 -
+ util/grub.d/10_linux_bls.in | 1 -
+ 2 files changed, 2 deletions(-)
+
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index 01e66e5fc74..b54d2774a7d 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -165,7 +165,6 @@ if [ -s \$prefix/grubenv ]; then
+ fi
+ EOF
+ 
+-    ${grub_editenv} - set saved_entry=0
+     if ! grub2-editenv - list | grep -q kernelopts; then
+ 	${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
+     fi
+diff --git a/util/grub.d/10_linux_bls.in b/util/grub.d/10_linux_bls.in
+index 1bc97f29898..8745e598d0e 100644
+--- a/util/grub.d/10_linux_bls.in
++++ b/util/grub.d/10_linux_bls.in
+@@ -212,7 +212,6 @@ linux_entry ()
+     populate_header_warn
+     populate_menu
+ 
+-    ${grub_editenv} - set saved_entry=0
+     if ! grub2-editenv - list | grep -q kernelopts; then
+ 	${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
+     fi
diff --git a/SOURCES/0244-grub-switch-to-blscfg-use-debug-instead-of-debug-as-.patch b/SOURCES/0244-grub-switch-to-blscfg-use-debug-instead-of-debug-as-.patch
new file mode 100644
index 0000000..9256c23
--- /dev/null
+++ b/SOURCES/0244-grub-switch-to-blscfg-use-debug-instead-of-debug-as-.patch
@@ -0,0 +1,31 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 19 Oct 2018 18:48:27 +0200
+Subject: [PATCH] grub-switch-to-blscfg: use ~debug instead of -debug as suffix
+ to sort correctly
+
+For the debug BLS entries a -debug suffix was added so they are sorted after
+the kernel entries, but that only works with version sort and not rpm sort.
+
+So instead use ~debug prefix so rpm sort algorithm could sort it correctly.
+
+Related: rhbz#1638103
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-switch-to-blscfg.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index 1c6bd1882a7..60cd6ca63cc 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -250,7 +250,7 @@ for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+     fi
+ 
+     if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
+-        bls_debug="$(echo ${bls_target} | sed -e "s/\.${arch}/-debug.${arch}/")"
++        bls_debug="$(echo ${bls_target} | sed -e "s/${kernelver}/${kernelver}~debug/")"
+         cp -aT  "${bls_target}" "${bls_debug}"
+         title="$(grep '^title[ \t]' "${bls_debug}" | sed -e 's/^title[ \t]*//')"
+         blsid="$(grep '^id[ \t]' "${bls_debug}" | sed -e "s/\.${ARCH}/-debug.${arch}/")"
diff --git a/SOURCES/0245-Make-blscfg-debug-messages-more-useful.patch b/SOURCES/0245-Make-blscfg-debug-messages-more-useful.patch
new file mode 100644
index 0000000..9a05606
--- /dev/null
+++ b/SOURCES/0245-Make-blscfg-debug-messages-more-useful.patch
@@ -0,0 +1,175 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 19 Oct 2018 10:03:28 -0400
+Subject: [PATCH] Make blscfg debug messages more useful
+
+Related: rhbz#1640979
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/commands/blscfg.c    | 12 +++++-------
+ grub-core/commands/legacycfg.c |  4 ++--
+ grub-core/commands/menuentry.c | 18 ++++++++++++++----
+ include/grub/normal.h          |  2 +-
+ 4 files changed, 22 insertions(+), 14 deletions(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 347128c9ddd..42892cbfd55 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -46,8 +46,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define GRUB_BOOT_DEVICE "($root)"
+ #endif
+ 
+-#define grub_free(x) ({grub_dprintf("blscfg", "%s freeing %p\n", __func__, x); grub_free(x); })
+-
+ struct keyval
+ {
+   const char *key;
+@@ -134,7 +132,7 @@ static int bls_add_keyval(struct bls_entry *entry, char *key, char *val)
+   kv->val = v;
+ 
+   entry->keyvals[entry->nkeyvals] = kv;
+-  grub_dprintf("blscfg", "new keyval at %p:%p:%p\n", entry->keyvals[entry->nkeyvals], k, v);
++  grub_dprintf("blscfg", "new keyval at %p:%s:%s\n", entry->keyvals[entry->nkeyvals], k, v);
+   entry->nkeyvals = new_n;
+ 
+   return 0;
+@@ -144,7 +142,6 @@ static void bls_free_entry(struct bls_entry *entry)
+ {
+   int i;
+ 
+-  grub_dprintf("blscfg", "%s got here\n", __func__);
+   for (i = 0; i < entry->nkeyvals; i++)
+     {
+       struct keyval *kv = entry->keyvals[i];
+@@ -206,7 +203,7 @@ static int vercmp(const char * a, const char * b)
+     int isnum;
+     int ret = 0;
+ 
+-    grub_dprintf("blscfg", "%s got here\n", __func__);
++    grub_dprintf("blscfg", "%s comparing %s and %s\n", __func__, a, b);
+     if (!grub_strcmp(a, b))
+ 	    return 0;
+ 
+@@ -682,7 +679,7 @@ static void create_entry (struct bls_entry *entry)
+   char **args = NULL;
+ 
+   char *src = NULL;
+-  int i;
++  int i, index;
+ 
+   grub_dprintf("blscfg", "%s got here\n", __func__);
+   clinux = bls_get_val (entry, "linux", NULL);
+@@ -756,7 +753,8 @@ static void create_entry (struct bls_entry *entry)
+ 			GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "",
+ 			initrd ? initrd : "");
+ 
+-  grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0);
++  grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index);
++  grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id);
+ 
+ finish:
+   grub_free (initrd);
+diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c
+index b32f3c74cb1..f9d7627bdc3 100644
+--- a/grub-core/commands/legacycfg.c
++++ b/grub-core/commands/legacycfg.c
+@@ -133,7 +133,7 @@ legacy_file (const char *filename)
+ 	    args[0] = oldname;
+ 	    grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy",
+ 					NULL, NULL,
+-					entrysrc, 0);
++					entrysrc, 0, NULL);
+ 	    grub_free (args);
+ 	    entrysrc[0] = 0;
+ 	    grub_free (oldname);
+@@ -186,7 +186,7 @@ legacy_file (const char *filename)
+ 	}
+       args[0] = entryname;
+       grub_normal_add_menu_entry (1, args, NULL, NULL, NULL,
+-				  NULL, NULL, entrysrc, 0);
++				  NULL, NULL, entrysrc, 0, NULL);
+       grub_free (args);
+     }
+ 
+diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c
+index 2c5363da7f5..8d242b0187e 100644
+--- a/grub-core/commands/menuentry.c
++++ b/grub-core/commands/menuentry.c
+@@ -78,7 +78,7 @@ grub_normal_add_menu_entry (int argc, const char **args,
+ 			    char **classes, const char *id,
+ 			    const char *users, const char *hotkey,
+ 			    const char *prefix, const char *sourcecode,
+-			    int submenu)
++			    int submenu, int *index)
+ {
+   int menu_hotkey = 0;
+   char **menu_args = NULL;
+@@ -149,9 +149,12 @@ grub_normal_add_menu_entry (int argc, const char **args,
+   if (! menu_title)
+     goto fail;
+ 
++  grub_dprintf ("menu", "id:\"%s\"\n", id);
++  grub_dprintf ("menu", "title:\"%s\"\n", menu_title);
+   menu_id = grub_strdup (id ? : menu_title);
+   if (! menu_id)
+     goto fail;
++  grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id);
+ 
+   /* Save argc, args to pass as parameters to block arg later. */
+   menu_args = grub_malloc (sizeof (char*) * (argc + 1));
+@@ -170,8 +173,12 @@ grub_normal_add_menu_entry (int argc, const char **args,
+   }
+ 
+   /* Add the menu entry at the end of the list.  */
++  int ind=0;
+   while (*last)
+-    last = &(*last)->next;
++    {
++      ind++;
++      last = &(*last)->next;
++    }
+ 
+   *last = grub_zalloc (sizeof (**last));
+   if (! *last)
+@@ -190,6 +197,8 @@ grub_normal_add_menu_entry (int argc, const char **args,
+   (*last)->submenu = submenu;
+ 
+   menu->size++;
++  if (index)
++    *index = ind;
+   return GRUB_ERR_NONE;
+ 
+  fail:
+@@ -286,7 +295,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
+ 				       users,
+ 				       ctxt->state[2].arg, 0,
+ 				       ctxt->state[3].arg,
+-				       ctxt->extcmd->cmd->name[0] == 's');
++				       ctxt->extcmd->cmd->name[0] == 's',
++				       NULL);
+ 
+   src = args[argc - 1];
+   args[argc - 1] = NULL;
+@@ -303,7 +313,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
+ 				  ctxt->state[0].args, ctxt->state[4].arg,
+ 				  users,
+ 				  ctxt->state[2].arg, prefix, src + 1,
+-				  ctxt->extcmd->cmd->name[0] == 's');
++				  ctxt->extcmd->cmd->name[0] == 's', NULL);
+ 
+   src[len - 1] = ch;
+   args[argc - 1] = src;
+diff --git a/include/grub/normal.h b/include/grub/normal.h
+index 218cbabccaf..cb9901f41b3 100644
+--- a/include/grub/normal.h
++++ b/include/grub/normal.h
+@@ -145,7 +145,7 @@ grub_normal_add_menu_entry (int argc, const char **args, char **classes,
+ 			    const char *id,
+ 			    const char *users, const char *hotkey,
+ 			    const char *prefix, const char *sourcecode,
+-			    int submenu);
++			    int submenu, int *index);
+ 
+ grub_err_t
+ grub_normal_set_password (const char *user, const char *password);
diff --git a/SOURCES/0246-Make-grub_strtoul-end-pointer-have-the-right-constif.patch b/SOURCES/0246-Make-grub_strtoul-end-pointer-have-the-right-constif.patch
new file mode 100644
index 0000000..99787bd
--- /dev/null
+++ b/SOURCES/0246-Make-grub_strtoul-end-pointer-have-the-right-constif.patch
@@ -0,0 +1,391 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 19 Oct 2018 13:41:48 -0400
+Subject: [PATCH] Make grub_strtoul "end" pointer have the right
+ constification.
+
+Related: rhbz#1640979
+Signed-off-by: Peter Jones <pjones@redhat.com>
+---
+ grub-core/kern/fs.c                | 2 +-
+ grub-core/kern/misc.c              | 8 ++++----
+ grub-core/kern/partition.c         | 2 +-
+ grub-core/lib/legacy_parse.c       | 2 +-
+ grub-core/lib/syslinux_parse.c     | 6 +++---
+ grub-core/loader/i386/xen_fileXX.c | 2 +-
+ grub-core/net/efi/ip4_config.c     | 2 +-
+ grub-core/net/efi/ip6_config.c     | 2 +-
+ grub-core/net/efi/net.c            | 4 ++--
+ grub-core/net/efi/pxe.c            | 6 +++---
+ grub-core/net/http.c               | 4 ++--
+ grub-core/net/net.c                | 8 ++++----
+ grub-core/net/url.c                | 2 +-
+ grub-core/script/execute.c         | 6 +++---
+ grub-core/term/serial.c            | 2 +-
+ grub-core/term/terminfo.c          | 2 +-
+ grub-core/tests/strtoull_test.c    | 2 +-
+ include/grub/misc.h                | 6 +++---
+ 18 files changed, 34 insertions(+), 34 deletions(-)
+
+diff --git a/grub-core/kern/fs.c b/grub-core/kern/fs.c
+index 9085895b6fe..1bd748be83b 100644
+--- a/grub-core/kern/fs.c
++++ b/grub-core/kern/fs.c
+@@ -134,7 +134,7 @@ struct grub_fs_block
+ static grub_err_t
+ grub_fs_blocklist_open (grub_file_t file, const char *name)
+ {
+-  char *p = (char *) name;
++  const char *p = name;
+   unsigned num = 0;
+   unsigned i;
+   grub_disk_t disk = file->device->disk;
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index 5c3899f0e5b..aaae9aa0ab7 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -383,7 +383,7 @@ grub_isspace (int c)
+ }
+ 
+ unsigned long
+-grub_strtoul (const char *str, char **end, int base)
++grub_strtoul (const char *str, const char ** const end, int base)
+ {
+   unsigned long long num;
+ 
+@@ -400,7 +400,7 @@ grub_strtoul (const char *str, char **end, int base)
+ }
+ 
+ unsigned long long
+-grub_strtoull (const char *str, char **end, int base)
++grub_strtoull (const char *str, const char ** const end, int base)
+ {
+   unsigned long long num = 0;
+   int found = 0;
+@@ -901,14 +901,14 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0,
+ 	{
+ 	  if (fmt[0] == '0')
+ 	    zerofill = '0';
+-	  format1 = grub_strtoul (fmt, (char **) &fmt, 10);
++	  format1 = grub_strtoul (fmt, &fmt, 10);
+ 	}
+ 
+       if (*fmt == '.')
+ 	fmt++;
+ 
+       if (grub_isdigit (*fmt))
+-	format2 = grub_strtoul (fmt, (char **) &fmt, 10);
++	format2 = grub_strtoul (fmt, &fmt, 10);
+ 
+       if (*fmt == '$')
+ 	{
+diff --git a/grub-core/kern/partition.c b/grub-core/kern/partition.c
+index e499147cbcb..2c401b866c4 100644
+--- a/grub-core/kern/partition.c
++++ b/grub-core/kern/partition.c
+@@ -126,7 +126,7 @@ grub_partition_probe (struct grub_disk *disk, const char *str)
+       while (*ptr && grub_isalpha (*ptr))
+ 	ptr++;
+       partname_end = ptr; 
+-      num = grub_strtoul (ptr, (char **) &ptr, 0) - 1;
++      num = grub_strtoul (ptr, &ptr, 0) - 1;
+ 
+       curpart = 0;
+       /* Use the first partition map type found.  */
+diff --git a/grub-core/lib/legacy_parse.c b/grub-core/lib/legacy_parse.c
+index ef56150ac77..05719ab2ccb 100644
+--- a/grub-core/lib/legacy_parse.c
++++ b/grub-core/lib/legacy_parse.c
+@@ -418,7 +418,7 @@ adjust_file (const char *in, grub_size_t len)
+     }
+   if (*comma != ',')
+     return grub_legacy_escape (in, len);
+-  part = grub_strtoull (comma + 1, (char **) &rest, 0);
++  part = grub_strtoull (comma + 1, &rest, 0);
+   if (rest[0] == ',' && rest[1] >= 'a' && rest[1] <= 'z')
+     {
+       subpart = rest[1] - 'a';
+diff --git a/grub-core/lib/syslinux_parse.c b/grub-core/lib/syslinux_parse.c
+index 28ba3aef0bb..21ca040ada7 100644
+--- a/grub-core/lib/syslinux_parse.c
++++ b/grub-core/lib/syslinux_parse.c
+@@ -1058,7 +1058,7 @@ write_entry (struct output_buffer *outbuf,
+ 		if (ptr[0] == 'h' && ptr[1] == 'd')
+ 		  {
+ 		    is_fd = 0;
+-		    devn = grub_strtoul (ptr + 2, &ptr, 0);
++		    devn = grub_strtoul (ptr + 2, (const char **)&ptr, 0);
+ 		    continue;
+ 		  }
+ 		if (grub_strncasecmp (ptr, "file=", 5) == 0)
+@@ -1082,12 +1082,12 @@ write_entry (struct output_buffer *outbuf,
+ 		if (ptr[0] == 'f' && ptr[1] == 'd')
+ 		  {
+ 		    is_fd = 1;
+-		    devn = grub_strtoul (ptr + 2, &ptr, 0);
++		    devn = grub_strtoul (ptr + 2, (const char **)&ptr, 0);
+ 		    continue;
+ 		  }
+ 		if (grub_isdigit (ptr[0]))
+ 		  {
+-		    part = grub_strtoul (ptr, &ptr, 0);
++		    part = grub_strtoul (ptr, (const char **)&ptr, 0);
+ 		    continue;
+ 		  }
+ 		/* FIXME: isolinux, ntldr, cmldr, *dos, seg, hide
+diff --git a/grub-core/loader/i386/xen_fileXX.c b/grub-core/loader/i386/xen_fileXX.c
+index fb66e66fe96..293f1ad5c3e 100644
+--- a/grub-core/loader/i386/xen_fileXX.c
++++ b/grub-core/loader/i386/xen_fileXX.c
+@@ -25,7 +25,7 @@ parse_xen_guest (grub_elf_t elf, struct grub_xen_file_info *xi,
+ 		 grub_off_t off, grub_size_t sz)
+ {
+   char *buf;
+-  char *ptr;
++  const char *ptr;
+   int has_paddr = 0;
+ 
+   grub_errno = GRUB_ERR_NONE;
+diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c
+index b711a5d9457..38e2a04747a 100644
+--- a/grub-core/net/efi/ip4_config.c
++++ b/grub-core/net/efi/ip4_config.c
+@@ -62,7 +62,7 @@ grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *addres
+   for (i = 0; i < 4; i++)
+     {
+       unsigned long t;
+-      t = grub_strtoul (ptr, (char **) &ptr, 0);
++      t = grub_strtoul (ptr, &ptr, 0);
+       if (grub_errno)
+ 	{
+ 	  grub_errno = GRUB_ERR_NONE;
+diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c
+index 017c4d05bc7..e0e00c23d21 100644
+--- a/grub-core/net/efi/ip6_config.c
++++ b/grub-core/net/efi/ip6_config.c
+@@ -84,7 +84,7 @@ grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *addres
+ 	  ptr++;
+ 	  continue;
+ 	}
+-      t = grub_strtoul (ptr, (char **) &ptr, 16);
++      t = grub_strtoul (ptr, &ptr, 16);
+       if (grub_errno)
+ 	{
+ 	  grub_errno = GRUB_ERR_NONE;
+diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c
+index f208d1b180c..4c70fc4da2a 100644
+--- a/grub-core/net/efi/net.c
++++ b/grub-core/net/efi/net.c
+@@ -729,7 +729,7 @@ grub_efi_net_parse_address (const char *address,
+ 	{
+ 	  grub_uint32_t subnet_mask_size;
+ 
+-	  subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0);
++	  subnet_mask_size = grub_strtoul (rest + 1, &rest, 0);
+ 
+ 	  if (!grub_errno && subnet_mask_size <= 32 && *rest == 0)
+ 	    {
+@@ -758,7 +758,7 @@ grub_efi_net_parse_address (const char *address,
+ 	{
+ 	  grub_efi_uint8_t prefix_length;
+ 
+-	  prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0);
++	  prefix_length = grub_strtoul (rest + 1, &rest, 0);
+ 	  if (!grub_errno && prefix_length <= 128 && *rest == 0)
+ 	    {
+ 	      ip6->prefix_length = prefix_length;
+diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c
+index 531949cba5c..73e2bb01c1b 100644
+--- a/grub-core/net/efi/pxe.c
++++ b/grub-core/net/efi/pxe.c
+@@ -187,7 +187,7 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
+ 	  ptr++;
+ 	  continue;
+ 	}
+-      t = grub_strtoul (ptr, (char **) &ptr, 16);
++      t = grub_strtoul (ptr, &ptr, 16);
+       if (grub_errno)
+ 	{
+ 	  grub_errno = GRUB_ERR_NONE;
+@@ -225,7 +225,7 @@ pxe_open (struct grub_efi_net_device *dev,
+ 	  int type __attribute__((unused)))
+ {
+   int i;
+-  char *p;
++  const char *p;
+   grub_efi_status_t status;
+   grub_efi_pxe_ip_address_t server_ip;
+   grub_efi_uint64_t file_size = 0;
+@@ -313,7 +313,7 @@ pxe_read (struct grub_efi_net_device *dev,
+ 	  grub_size_t len)
+ {
+   int i;
+-  char *p;
++  const char *p;
+   grub_efi_status_t status;
+   grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe;
+   grub_efi_uint64_t bufsz = len;
+diff --git a/grub-core/net/http.c b/grub-core/net/http.c
+index c9c59690a98..b52b558d631 100644
+--- a/grub-core/net/http.c
++++ b/grub-core/net/http.c
+@@ -110,7 +110,7 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
+ 	  return GRUB_ERR_NONE;
+ 	}
+       ptr += sizeof ("HTTP/1.1 ") - 1;
+-      code = grub_strtoul (ptr, &ptr, 10);
++      code = grub_strtoul (ptr, (const char **)&ptr, 10);
+       if (grub_errno)
+ 	return grub_errno;
+       switch (code)
+@@ -137,7 +137,7 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
+       == 0 && !data->size_recv)
+     {
+       ptr += sizeof ("Content-Length: ") - 1;
+-      file->size = grub_strtoull (ptr, &ptr, 10);
++      file->size = grub_strtoull (ptr, (const char **)&ptr, 10);
+       data->size_recv = 1;
+       return GRUB_ERR_NONE;
+     }
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index a571ee92efa..a011b940100 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -411,7 +411,7 @@ parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
+   for (i = 0; i < 4; i++)
+     {
+       unsigned long t;
+-      t = grub_strtoul (ptr, (char **) &ptr, 0);
++      t = grub_strtoul (ptr, &ptr, 0);
+       if (grub_errno)
+ 	{
+ 	  grub_errno = GRUB_ERR_NONE;
+@@ -465,7 +465,7 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
+ 	  ptr++;
+ 	  continue;
+ 	}
+-      t = grub_strtoul (ptr, (char **) &ptr, 16);
++      t = grub_strtoul (ptr, &ptr, 16);
+       if (grub_errno)
+ 	{
+ 	  grub_errno = GRUB_ERR_NONE;
+@@ -577,7 +577,7 @@ grub_net_resolve_net_address (const char *name,
+       addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
+       if (*rest == '/')
+ 	{
+-	  addr->ipv4.masksize = grub_strtoul (rest + 1, (char **) &rest, 0);
++	  addr->ipv4.masksize = grub_strtoul (rest + 1, &rest, 0);
+ 	  if (!grub_errno && *rest == 0)
+ 	    return GRUB_ERR_NONE;
+ 	  grub_errno = GRUB_ERR_NONE;
+@@ -593,7 +593,7 @@ grub_net_resolve_net_address (const char *name,
+       addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+       if (*rest == '/')
+ 	{
+-	  addr->ipv6.masksize = grub_strtoul (rest + 1, (char **) &rest, 0);
++	  addr->ipv6.masksize = grub_strtoul (rest + 1, &rest, 0);
+ 	  if (!grub_errno && *rest == 0)
+ 	    return GRUB_ERR_NONE;
+ 	  grub_errno = GRUB_ERR_NONE;
+diff --git a/grub-core/net/url.c b/grub-core/net/url.c
+index 146858284cd..d9d2fc9a9dc 100644
+--- a/grub-core/net/url.c
++++ b/grub-core/net/url.c
+@@ -235,7 +235,7 @@ extract_http_url_info (char *url, int ssl,
+       c = *port_end;
+       *port_end = '\0';
+ 
+-      portul = grub_strtoul (port_off, &separator, 10);
++      portul = grub_strtoul (port_off, (const char **)&separator, 10);
+       *port_end = c;
+ #ifdef URL_TEST
+       if (portul == ULONG_MAX && errno == ERANGE)
+diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
+index 93965777138..7d327f59d92 100644
+--- a/grub-core/script/execute.c
++++ b/grub-core/script/execute.c
+@@ -146,7 +146,7 @@ replace_scope (struct grub_script_scope *new_scope)
+ grub_err_t
+ grub_script_break (grub_command_t cmd, int argc, char *argv[])
+ {
+-  char *p = 0;
++  const char *p = NULL;
+   unsigned long count;
+ 
+   if (argc == 0)
+@@ -178,7 +178,7 @@ grub_err_t
+ grub_script_shift (grub_command_t cmd __attribute__((unused)),
+ 		   int argc, char *argv[])
+ {
+-  char *p = 0;
++  const char *p = NULL;
+   unsigned long n = 0;
+ 
+   if (! scope)
+@@ -239,7 +239,7 @@ grub_err_t
+ grub_script_return (grub_command_t cmd __attribute__((unused)),
+ 		    int argc, char *argv[])
+ {
+-  char *p;
++  const char *p = NULL;
+   unsigned long n;
+ 
+   if (! scope || argc > 1)
+diff --git a/grub-core/term/serial.c b/grub-core/term/serial.c
+index db80b3ba0fb..f9271b09239 100644
+--- a/grub-core/term/serial.c
++++ b/grub-core/term/serial.c
+@@ -269,7 +269,7 @@ grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args)
+ 
+   if (state[OPTION_BASE_CLOCK].set)
+     {
+-      char *ptr;
++      const char *ptr;
+       config.base_clock = grub_strtoull (state[OPTION_BASE_CLOCK].arg, &ptr, 0);
+       if (grub_errno)
+ 	return grub_errno;
+diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c
+index 29df35e6d20..537a5c0cb0b 100644
+--- a/grub-core/term/terminfo.c
++++ b/grub-core/term/terminfo.c
+@@ -737,7 +737,7 @@ grub_cmd_terminfo (grub_extcmd_context_t ctxt, int argc, char **args)
+ 
+   if (state[OPTION_GEOMETRY].set)
+     {
+-      char *ptr = state[OPTION_GEOMETRY].arg;
++      const char *ptr = state[OPTION_GEOMETRY].arg;
+       w = grub_strtoul (ptr, &ptr, 0);
+       if (grub_errno)
+ 	return grub_errno;
+diff --git a/grub-core/tests/strtoull_test.c b/grub-core/tests/strtoull_test.c
+index 7da615ff33e..5488ab26b43 100644
+--- a/grub-core/tests/strtoull_test.c
++++ b/grub-core/tests/strtoull_test.c
+@@ -25,7 +25,7 @@ static void
+ strtoull_testcase (const char *input, int base, unsigned long long expected,
+ 		   int num_digits, grub_err_t error)
+ {
+-  char *output;
++  const char *output;
+   unsigned long long value;
+   grub_errno = 0;
+   value = grub_strtoull(input, &output, base);
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index de9016ab709..1258ec6bbf3 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -288,11 +288,11 @@ grub_strncasecmp (const char *s1, const char *s2, grub_size_t n)
+     - (int) grub_tolower ((grub_uint8_t) *s2);
+ }
+ 
+-unsigned long EXPORT_FUNC(grub_strtoul) (const char *str, char **end, int base);
+-unsigned long long EXPORT_FUNC(grub_strtoull) (const char *str, char **end, int base);
++unsigned long EXPORT_FUNC(grub_strtoul) (const char *str, const char ** const end, int base);
++unsigned long long EXPORT_FUNC(grub_strtoull) (const char *str, const char ** const end, int base);
+ 
+ static inline long
+-grub_strtol (const char *str, char **end, int base)
++grub_strtol (const char *str, const char ** const end, int base)
+ {
+   int negative = 0;
+   unsigned long long magnitude;
diff --git a/SOURCES/0247-Fix-menu-entry-selection-based-on-ID-and-title.patch b/SOURCES/0247-Fix-menu-entry-selection-based-on-ID-and-title.patch
new file mode 100644
index 0000000..065765c
--- /dev/null
+++ b/SOURCES/0247-Fix-menu-entry-selection-based-on-ID-and-title.patch
@@ -0,0 +1,235 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones@redhat.com>
+Date: Fri, 19 Oct 2018 10:57:52 -0400
+Subject: [PATCH] Fix menu entry selection based on ID and title
+
+Currently if grub_strtoul(saved_entry_value, NULL, 0) does not return an
+error, we assume the value it has produced is a correct index into our
+menu entry list, and do not try to interpret the value as the "id" or
+"title" .  In cases where "id" or "title" start with a numeral, this
+makes them impossible to use as selection criteria.
+
+This patch splits the search into three phases - matching id, matching
+title, and only once those have been exhausted, trying to interpret the
+ID as a numeral.  In that case, we also require that the entire string
+is numeric, not merely a string with leading numeric characters.
+
+Resolves: rhbz#1640979
+---
+ grub-core/normal/menu.c | 146 +++++++++++++++++++++++++-----------------------
+ 1 file changed, 75 insertions(+), 71 deletions(-)
+
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index 6cb2a071490..95f7abaf2fd 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -164,12 +164,12 @@ grub_menu_set_timeout (int timeout)
+ }
+ 
+ static int
+-menuentry_eq (const char *id, const char *spec)
++menuentry_eq (const char *id, const char *spec, int limit)
+ {
+   const char *ptr1, *ptr2;
+   ptr1 = id;
+   ptr2 = spec;
+-  while (1)
++  while (limit == -1 || ptr1 - id <= limit)
+     {
+       if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0)
+ 	return ptr2 - spec;
+@@ -178,7 +178,11 @@ menuentry_eq (const char *id, const char *spec)
+       if (*ptr2 == '>')
+ 	ptr2++;
+       if (*ptr1 != *ptr2)
+-	return 0;
++	{
++	  if (limit > -1 && ptr1 - id == limit && !*ptr1 && grub_isspace(*ptr2))
++	    return ptr1 -id -1;
++	  return 0;
++	}
+       if (*ptr1 == 0)
+ 	return ptr1 - id;
+       ptr1++;
+@@ -187,6 +191,61 @@ menuentry_eq (const char *id, const char *spec)
+   return 0;
+ }
+ 
++static int
++get_entry_number_helper(grub_menu_t menu,
++			const char * const val, const char ** const tail)
++{
++  /* See if the variable matches the title of a menu entry.  */
++  int entry = -1;
++  grub_menu_entry_t e;
++  int i;
++
++  for (i = 0, e = menu->entry_list; e; i++)
++    {
++      int l = 0;
++      while (val[l] && !grub_isspace(val[l]))
++	l++;
++
++      if (menuentry_eq (e->id, val, l))
++	{
++	  if (tail)
++	    *tail = val + l;
++	  return i;
++	}
++      e = e->next;
++    }
++
++  for (i = 0, e = menu->entry_list; e; i++)
++    {
++      int l = 0;
++      while (val[l] && !grub_isspace(val[l]))
++	l++;
++
++      if (menuentry_eq (e->title, val, l))
++	{
++	  if (tail)
++	    *tail = val + l;
++	  return i;
++	}
++      e = e->next;
++    }
++
++  if (tail)
++    *tail = NULL;
++
++  entry = (int) grub_strtoul (val, tail, 0);
++  if (grub_errno == GRUB_ERR_BAD_NUMBER ||
++      (*tail && **tail && !grub_isspace(**tail)))
++    {
++      entry = -1;
++      if (tail)
++	*tail = NULL;
++      grub_errno = GRUB_ERR_NONE;
++    }
++
++  return entry;
++}
++
+ /* Get the first entry number from the value of the environment variable NAME,
+    which is a space-separated list of non-negative integers.  The entry number
+    which is returned is stripped from the value of NAME.  If no entry number
+@@ -195,9 +254,8 @@ static int
+ get_and_remove_first_entry_number (grub_menu_t menu, const char *name)
+ {
+   const char *val;
+-  char *tail;
++  const char *tail;
+   int entry;
+-  int sz = 0;
+ 
+   val = grub_env_get (name);
+   if (! val)
+@@ -205,50 +263,24 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name)
+ 
+   grub_error_push ();
+ 
+-  entry = (int) grub_strtoul (val, &tail, 0);
++  entry = get_entry_number_helper(menu, val, &tail);
++  if (!(*tail == 0 || grub_isspace(*tail)))
++    entry = -1;
+ 
+-  if (grub_errno == GRUB_ERR_BAD_NUMBER)
++  if (entry >= 0)
+     {
+-      /* See if the variable matches the title of a menu entry.  */
+-      grub_menu_entry_t e = menu->entry_list;
+-      int i;
+-
+-      for (i = 0; e; i++)
+-	{
+-	  sz = menuentry_eq (e->title, val);
+-	  if (sz < 1)
+-	    sz = menuentry_eq (e->id, val);
+-
+-	  if (sz >= 1)
+-	    {
+-	      entry = i;
+-	      break;
+-	    }
+-	  e = e->next;
+-	}
+-
+-      if (sz > 0)
+-	grub_errno = GRUB_ERR_NONE;
+-
+-      if (! e)
+-	entry = -1;
+-    }
+-
+-  if (grub_errno == GRUB_ERR_NONE)
+-    {
+-      if (sz > 0)
+-	tail += sz;
+-
+       /* Skip whitespace to find the next entry.  */
+       while (*tail && grub_isspace (*tail))
+ 	tail++;
+-      grub_env_set (name, tail);
++      if (*tail)
++	grub_env_set (name, tail);
++      else
++	grub_env_unset (name);
+     }
+   else
+     {
+       grub_env_unset (name);
+       grub_errno = GRUB_ERR_NONE;
+-      entry = -1;
+     }
+ 
+   grub_error_pop ();
+@@ -525,6 +557,7 @@ static int
+ get_entry_number (grub_menu_t menu, const char *name)
+ {
+   const char *val;
++  const char *tail;
+   int entry;
+ 
+   val = grub_env_get (name);
+@@ -532,38 +565,9 @@ get_entry_number (grub_menu_t menu, const char *name)
+     return -1;
+ 
+   grub_error_push ();
+-
+-  entry = (int) grub_strtoul (val, 0, 0);
+-
+-  if (grub_errno == GRUB_ERR_BAD_NUMBER)
+-    {
+-      /* See if the variable matches the title of a menu entry.  */
+-      grub_menu_entry_t e = menu->entry_list;
+-      int i;
+-
+-      grub_errno = GRUB_ERR_NONE;
+-
+-      for (i = 0; e; i++)
+-	{
+-	  if (menuentry_eq (e->title, val)
+-	      || menuentry_eq (e->id, val))
+-	    {
+-	      entry = i;
+-	      break;
+-	    }
+-	  e = e->next;
+-	}
+-
+-      if (! e)
+-	entry = -1;
+-    }
+-
+-  if (grub_errno != GRUB_ERR_NONE)
+-    {
+-      grub_errno = GRUB_ERR_NONE;
+-      entry = -1;
+-    }
+-
++  entry = get_entry_number_helper(menu, val, &tail);
++  if (*tail != '\0')
++    entry = -1;
+   grub_error_pop ();
+ 
+   return entry;
diff --git a/SOURCES/0248-Remove-quotes-when-reading-ID-value-from-etc-os-rele.patch b/SOURCES/0248-Remove-quotes-when-reading-ID-value-from-etc-os-rele.patch
new file mode 100644
index 0000000..b81f46f
--- /dev/null
+++ b/SOURCES/0248-Remove-quotes-when-reading-ID-value-from-etc-os-rele.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 21 Nov 2018 15:37:32 +0100
+Subject: [PATCH] Remove quotes when reading ID value from /etc/os-release
+
+The field is used to obtain the path to the GRUB directory in the ESP for
+UEFI installs. But in some OS the ID value is quoted, which leads to some
+of the scripts to fail:
+
+  $ grub2-setpassword
+  /boot/efi/EFI/"redhat"/ does not exist.
+  Usage: /usr/sbin/grub2-setpassword [OPTION]
+
+Related: rhbz#1650706
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-set-password.in     | 2 +-
+ util/grub-switch-to-blscfg.in | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/util/grub-set-password.in b/util/grub-set-password.in
+index 5ebf50576d6..c0b5ebbfdc5 100644
+--- a/util/grub-set-password.in
++++ b/util/grub-set-password.in
+@@ -1,6 +1,6 @@
+ #!/bin/sh -e
+ 
+-EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/')
++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g')
+ if [ -d /sys/firmware/efi/efivars/ ]; then
+     grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
+ else
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index 60cd6ca63cc..d353370cc51 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -40,7 +40,7 @@ etcdefaultgrub=/etc/default/grub
+ 
+ eval "$("${grub_get_kernel_settings}")" || true
+ 
+-EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/')
++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g')
+ if [ -d /sys/firmware/efi/efivars/ ]; then
+     startlink=/etc/grub2-efi.cfg
+     grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'`
diff --git a/SOURCES/0249-blscfg-expand-grub_users-before-passing-to-grub_norm.patch b/SOURCES/0249-blscfg-expand-grub_users-before-passing-to-grub_norm.patch
new file mode 100644
index 0000000..d5951b4
--- /dev/null
+++ b/SOURCES/0249-blscfg-expand-grub_users-before-passing-to-grub_norm.patch
@@ -0,0 +1,38 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Wed, 21 Nov 2018 15:38:50 +0100
+Subject: [PATCH] blscfg: expand grub_users before passing to
+ grub_normal_add_menu_entry()
+
+The "grub_users" field from the BLS snippet file is used to specifcy the
+users that are allowed to execute a given menu entry if the "superusers"
+environment variable is set.
+
+If the "grub_users" isn't set, the menu entry is unrestricted and it can
+be executed without any authentication and if is set then only the users
+defined in "grub_users" can execute the menu entry after authentication.
+
+But this field can contain an environment variable so has to be expanded
+or otherwise grub2 will wrongly assume that the user is "$var", and will
+populate a menu entry that it's resctrited even when "$var" isn't set.
+
+Resolves: rhbz#1650706
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/blscfg.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
+index 42892cbfd55..c432c6ba27a 100644
+--- a/grub-core/commands/blscfg.c
++++ b/grub-core/commands/blscfg.c
+@@ -704,7 +704,7 @@ static void create_entry (struct bls_entry *entry)
+   initrds = bls_make_list (entry, "initrd", NULL);
+ 
+   hotkey = bls_get_val (entry, "grub_hotkey", NULL);
+-  users = bls_get_val (entry, "grub_users", NULL);
++  users = expand_val (bls_get_val (entry, "grub_users", NULL));
+   classes = bls_make_list (entry, "grub_class", NULL);
+   args = bls_make_list (entry, "grub_arg", &argc);
+ 
diff --git a/SOURCES/0250-Make-the-menu-entry-users-option-argument-to-be-opti.patch b/SOURCES/0250-Make-the-menu-entry-users-option-argument-to-be-opti.patch
new file mode 100644
index 0000000..50479ce
--- /dev/null
+++ b/SOURCES/0250-Make-the-menu-entry-users-option-argument-to-be-opti.patch
@@ -0,0 +1,46 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Mon, 26 Nov 2018 10:06:42 +0100
+Subject: [PATCH] Make the menu entry users option argument to be optional
+
+The --users option is used to restrict the access to specific menu entries
+only to a set of users. But the option requires an argument to either be a
+constant or a variable that has been set. So for example the following:
+
+  menuentry "May be run by superusers or users in $users" --users $users {
+  	    linux /vmlinuz
+  }
+
+Would fail if $users is not defined and grub would discard the menu entry.
+Instead, allow the --users option to have an optional argument and ignore
+the option if the argument was not set.
+
+Related: rhbz#1652434
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/commands/menuentry.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c
+index 8d242b0187e..7004e08ce78 100644
+--- a/grub-core/commands/menuentry.c
++++ b/grub-core/commands/menuentry.c
+@@ -29,7 +29,7 @@ static const struct grub_arg_option options[] =
+   {
+     {"class", 1, GRUB_ARG_OPTION_REPEATABLE,
+      N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING},
+-    {"users", 2, 0,
++    {"users", 2, GRUB_ARG_OPTION_OPTIONAL,
+      N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"),
+      ARG_TYPE_STRING},
+     {"hotkey", 3, 0,
+@@ -280,7 +280,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
+   if (! ctxt->state[3].set && ! ctxt->script)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
+ 
+-  if (ctxt->state[1].set)
++  if (ctxt->state[1].set && ctxt->state[1].arg)
+     users = ctxt->state[1].arg;
+   else if (ctxt->state[5].set)
+     users = NULL;
diff --git a/SOURCES/0251-10_linux_bls-add-missing-menu-entries-options.patch b/SOURCES/0251-10_linux_bls-add-missing-menu-entries-options.patch
new file mode 100644
index 0000000..620c55d
--- /dev/null
+++ b/SOURCES/0251-10_linux_bls-add-missing-menu-entries-options.patch
@@ -0,0 +1,56 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Thu, 22 Nov 2018 16:12:19 +0100
+Subject: [PATCH] 10_linux_bls: add missing menu entries options
+
+The script that generates menu entries in the grub.cfg from BLS snippets
+wasn't filling some important options, like the --id, --class and --user
+if these were defined in the BLS.
+
+Resolves: rhbz#1652434
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub.d/10_linux_bls.in | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/util/grub.d/10_linux_bls.in b/util/grub.d/10_linux_bls.in
+index 8745e598d0e..8cff4c58ab5 100644
+--- a/util/grub.d/10_linux_bls.in
++++ b/util/grub.d/10_linux_bls.in
+@@ -127,6 +127,9 @@ read_config()
+     initrd=""
+     options=""
+     linux=""
++    grub_users=""
++    grub_arg=""
++    grub_class=""
+ 
+     while read -r line
+     do
+@@ -145,6 +148,15 @@ read_config()
+             "options")
+                 options=${value}
+                 ;;
++            "grub_users")
++                grub_users=${value}
++                ;;
++            "grub_arg")
++                grub_arg=${value}
++                ;;
++            "grub_class")
++                grub_class=${value}
++                ;;
+         esac
+     done < ${config_file}
+ }
+@@ -167,7 +179,8 @@ populate_menu()
+ 
+     for bls in "${files[@]}" ; do
+         read_config "${blsdir}/${bls}.conf"
+-        menu="${menu}menuentry '${title}' {\n"
++
++        menu="${menu}menuentry '${title}' --class ${grub_class} ${grub_arg} --users ${grub_users} --id ${bls} {\n"
+         menu="${menu}\t linux ${linux} ${options}\n"
+         if [ -n "${initrd}" ] ; then
+             menu="${menu}\t initrd ${boot_prefix}${initrd}\n"
diff --git a/SOURCES/0252-Fix-menu-entry-selection-based-on-title.patch b/SOURCES/0252-Fix-menu-entry-selection-based-on-title.patch
new file mode 100644
index 0000000..31825b0
--- /dev/null
+++ b/SOURCES/0252-Fix-menu-entry-selection-based-on-title.patch
@@ -0,0 +1,41 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Fri, 30 Nov 2018 16:39:09 +0100
+Subject: [PATCH] Fix menu entry selection based on title
+
+The get_entry_number_helper() function assumes that there could be a set
+of entries identifiers in a variable (i.e: as used in the fallback case)
+so iterates over the string until it finds a space to get the first id.
+
+But this should only be done for indexes or entries id, since the title
+can contain spaces. In the case of title, the complete string should be
+used to select a given entry.
+
+Resolves: rhbz#1654936
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/normal/menu.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index 95f7abaf2fd..fc25c702f3c 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -217,14 +217,11 @@ get_entry_number_helper(grub_menu_t menu,
+ 
+   for (i = 0, e = menu->entry_list; e; i++)
+     {
+-      int l = 0;
+-      while (val[l] && !grub_isspace(val[l]))
+-	l++;
+ 
+-      if (menuentry_eq (e->title, val, l))
++      if (menuentry_eq (e->title, val, -1))
+ 	{
+ 	  if (tail)
+-	    *tail = val + l;
++	    *tail = NULL;
+ 	  return i;
+ 	}
+       e = e->next;
diff --git a/SOURCES/0253-BLS-files-should-only-be-copied-by-grub-switch-to-bl.patch b/SOURCES/0253-BLS-files-should-only-be-copied-by-grub-switch-to-bl.patch
new file mode 100644
index 0000000..1fc6e2d
--- /dev/null
+++ b/SOURCES/0253-BLS-files-should-only-be-copied-by-grub-switch-to-bl.patch
@@ -0,0 +1,120 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 4 Dec 2018 10:48:45 +0100
+Subject: [PATCH] BLS files should only be copied by grub-switch-to-blscfg if
+ BLS isn't set
+
+Currently the grub-switch-to-blscfg script doesn't update the grub.cfg if
+GRUB_ENABLE_BLSCFG=true is already set in /etc/default/grub. But it still
+copies the BLS files which may overwrite fields modified by the user.
+
+Related: rhbz#1638117
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-switch-to-blscfg.in | 80 +++++++++++++++++++++++--------------------
+ 1 file changed, 42 insertions(+), 38 deletions(-)
+
+diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in
+index d353370cc51..eeea1307706 100644
+--- a/util/grub-switch-to-blscfg.in
++++ b/util/grub-switch-to-blscfg.in
+@@ -220,49 +220,51 @@ EOF
+     ) | cat
+ }
+ 
+-for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
+-    bls_target="${blsdir}/${MACHINE_ID}-${kernelver}.conf"
+-    linux="/vmlinuz-${kernelver}"
+-    linux_path="/boot${linux}"
+-    kernel_dir="/lib/modules/${kernelver}"
++copy_bls() {
++    for kernelver in $(cd /lib/modules/ ; ls -1) "" ; do
++	bls_target="${blsdir}/${MACHINE_ID}-${kernelver}.conf"
++	linux="/vmlinuz-${kernelver}"
++	linux_path="/boot${linux}"
++	kernel_dir="/lib/modules/${kernelver}"
+ 
+-    if [ ! -d "${kernel_dir}" ] ; then
+-        continue
+-    fi
+-    if [ ! -f "${linux_path}" ]; then
+-        continue
+-    fi
++	if [ ! -d "${kernel_dir}" ] ; then
++            continue
++	fi
++	if [ ! -f "${linux_path}" ]; then
++            continue
++	fi
+ 
+-    linux_relpath="$("${grub_mkrelpath}" "${linux_path}")"
+-    bootprefix="${linux_relpath%%"${linux}"}"
++	linux_relpath="$("${grub_mkrelpath}" "${linux_path}")"
++	bootprefix="${linux_relpath%%"${linux}"}"
+ 
+-    if [ -f "${kernel_dir}/bls.conf" ] ; then
+-        cp -af "${kernel_dir}/bls.conf" "${bls_target}"
+-        if [ -n "${bootprefix}" ]; then
+-            sed -i -e "s,^\(linux[^ \t]*[ \t]\+\).*,\1${bootprefix}${linux},g" "${bls_target}"
+-            sed -i -e "/^initrd/ s,\([ \t]\+\)\([^ \t]\+\),\1${bootprefix}\2,g" "${bls_target}"
+-        fi
+-    else
+-        mkbls "${kernelver}" \
+-            "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${kernel_dir}")")" \
+-            "${bootprefix}" \
+-            >"${bls_target}"
+-    fi
++	if [ -f "${kernel_dir}/bls.conf" ] ; then
++            cp -af "${kernel_dir}/bls.conf" "${bls_target}"
++            if [ -n "${bootprefix}" ]; then
++		sed -i -e "s,^\(linux[^ \t]*[ \t]\+\).*,\1${bootprefix}${linux},g" "${bls_target}"
++		sed -i -e "/^initrd/ s,\([ \t]\+\)\([^ \t]\+\),\1${bootprefix}\2,g" "${bls_target}"
++            fi
++	else
++            mkbls "${kernelver}" \
++		  "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${kernel_dir}")")" \
++		  "${bootprefix}" \
++		  >"${bls_target}"
++	fi
+ 
+-    if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
+-        bls_debug="$(echo ${bls_target} | sed -e "s/${kernelver}/${kernelver}~debug/")"
+-        cp -aT  "${bls_target}" "${bls_debug}"
+-        title="$(grep '^title[ \t]' "${bls_debug}" | sed -e 's/^title[ \t]*//')"
+-        blsid="$(grep '^id[ \t]' "${bls_debug}" | sed -e "s/\.${ARCH}/-debug.${arch}/")"
+-        sed -i -e "s/^title.*/title ${title}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${bls_debug}"
+-        sed -i -e "s/^id.*/${blsid}/" "${bls_debug}"
+-        sed -i -e "s/^options.*/options \$kernelopts ${GRUB_CMDLINE_LINUX_DEBUG}/" "${bls_debug}"
+-    fi
+-done
++	if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
++            bls_debug="$(echo ${bls_target} | sed -e "s/${kernelver}/${kernelver}~debug/")"
++            cp -aT  "${bls_target}" "${bls_debug}"
++            title="$(grep '^title[ \t]' "${bls_debug}" | sed -e 's/^title[ \t]*//')"
++            blsid="$(grep '^id[ \t]' "${bls_debug}" | sed -e "s/\.${ARCH}/-debug.${arch}/")"
++            sed -i -e "s/^title.*/title ${title}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${bls_debug}"
++            sed -i -e "s/^id.*/${blsid}/" "${bls_debug}"
++            sed -i -e "s/^options.*/options \$kernelopts ${GRUB_CMDLINE_LINUX_DEBUG}/" "${bls_debug}"
++	fi
++    done
+ 
+-if [ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then
+-    mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf"
+-fi
++    if [ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then
++	mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf"
++    fi
++}
+ 
+ GENERATE=0
+ if grep '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" \
+@@ -283,6 +285,8 @@ elif ! grep -q '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" ; then
+ fi
+ 
+ if [ "${GENERATE}" -eq 1 ] ; then
++    copy_bls
++
+     if [ $arch = "x86_64" ] && [ ! -d /sys/firmware/efi ]; then
+ 	if ! cp ${prefix}/lib/grub//i386-pc/blscfg.mod ${grubdir}/i386-pc/ ; then
+ 	    exit 1
diff --git a/SOURCES/0254-Fix-get_entry_number-wrongly-dereferencing-the-tail-.patch b/SOURCES/0254-Fix-get_entry_number-wrongly-dereferencing-the-tail-.patch
new file mode 100644
index 0000000..f1667a1
--- /dev/null
+++ b/SOURCES/0254-Fix-get_entry_number-wrongly-dereferencing-the-tail-.patch
@@ -0,0 +1,34 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Tue, 4 Dec 2018 10:53:49 +0100
+Subject: [PATCH] Fix get_entry_number() wrongly dereferencing the tail pointer
+
+The get_entry_number_helper() function attempts to lookup a boot entry by
+either title or id matching the value of an environment variable. If they
+are a substring of the variable, the tail pointer is set to the first char
+of the remainder of the string.
+
+When get_entry_number() calls this function, it checks if this first char
+is a NUL byte, to know if the variable matched correctly. But tail can be
+set to NULL as well to indicate that there isn't a remainder in the string.
+
+Resolves: rhbz#1654936
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ grub-core/normal/menu.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index fc25c702f3c..7e32c498aa8 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -563,7 +563,7 @@ get_entry_number (grub_menu_t menu, const char *name)
+ 
+   grub_error_push ();
+   entry = get_entry_number_helper(menu, val, &tail);
+-  if (*tail != '\0')
++  if (tail && *tail != '\0')
+     entry = -1;
+   grub_error_pop ();
+ 
diff --git a/SOURCES/0255-Make-grub2-mkconfig-to-honour-GRUB_CMDLINE_LINUX-in-.patch b/SOURCES/0255-Make-grub2-mkconfig-to-honour-GRUB_CMDLINE_LINUX-in-.patch
new file mode 100644
index 0000000..71fbd51
--- /dev/null
+++ b/SOURCES/0255-Make-grub2-mkconfig-to-honour-GRUB_CMDLINE_LINUX-in-.patch
@@ -0,0 +1,99 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Javier Martinez Canillas <javierm@redhat.com>
+Date: Mon, 10 Dec 2018 13:11:58 +0100
+Subject: [PATCH] Make grub2-mkconfig to honour GRUB_CMDLINE_LINUX in
+ /etc/default/grub
+
+The kernelopts grub environment variable is set with the GRUB_CMDLINE_LINUX
+value only if wasn't set before. This is because the kernel cmdline params
+of the entries are not in the grub.cfg anymore so grub2-mkconfig shouldn't
+have side effects on neither the entries nor their kernel cmdline params.
+
+But there's a lot of documentation pointing at modifying GRUB_CMDLINE_LINUX
+to change the kernel cmdline params and users have built a muscle memory on
+it, so the BLS support should be compatible.
+
+Make the grub2-mkconfig script update the $kernelopts environment variable
+unless the --no-grubenv-update option is used.
+
+Resolves: rhbz#1637875
+
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+---
+ util/grub-mkconfig.8        | 4 ++++
+ util/grub-mkconfig.in       | 6 ++++++
+ util/grub.d/10_linux.in     | 2 +-
+ util/grub.d/10_linux_bls.in | 2 +-
+ 4 files changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/util/grub-mkconfig.8 b/util/grub-mkconfig.8
+index a2d1f577b9b..434fa4deda4 100644
+--- a/util/grub-mkconfig.8
++++ b/util/grub-mkconfig.8
+@@ -13,5 +13,9 @@
+ \fB--output\fR=\fIFILE\fR
+ Write generated output to \fIFILE\fR.
+ 
++.TP
++\fB--no-grubenv-update\fR
++Do not update variables in the grubenv file.
++
+ .SH SEE ALSO
+ .BR "info grub"
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index c20171919d9..5e643e16973 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -50,6 +50,8 @@ grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@"
+ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
+ 
++export GRUB_GRUBENV_UPDATE="yes"
++
+ . "${pkgdatadir}/grub-mkconfig_lib"
+ 
+ # Usage: usage
+@@ -59,6 +61,7 @@ usage () {
+     gettext "Generate a grub config file"; echo
+     echo
+     print_option_help "-o, --output=$(gettext FILE)" "$(gettext "output generated config to FILE [default=stdout]")"
++    print_option_help "--no-grubenv-update" "$(gettext "do not update variables in the grubenv file")"
+     print_option_help "-h, --help" "$(gettext "print this message and exit")"
+     print_option_help "-v, --version" "$(gettext "print the version information and exit")"
+     echo
+@@ -94,6 +97,9 @@ do
+     --output=*)
+ 	grub_cfg=`echo "$option" | sed 's/--output=//'`
+ 	;;
++    --no-grubenv-update)
++	GRUB_GRUBENV_UPDATE="no"
++	;;
+     -*)
+ 	gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2
+ 	usage
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index b54d2774a7d..da2992ac9f1 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -165,7 +165,7 @@ if [ -s \$prefix/grubenv ]; then
+ fi
+ EOF
+ 
+-    if ! grub2-editenv - list | grep -q kernelopts; then
++    if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then
+ 	${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
+     fi
+ 
+diff --git a/util/grub.d/10_linux_bls.in b/util/grub.d/10_linux_bls.in
+index 8cff4c58ab5..175bedd0763 100644
+--- a/util/grub.d/10_linux_bls.in
++++ b/util/grub.d/10_linux_bls.in
+@@ -225,7 +225,7 @@ linux_entry ()
+     populate_header_warn
+     populate_menu
+ 
+-    if ! grub2-editenv - list | grep -q kernelopts; then
++    if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then
+ 	${grub_editenv} - set kernelopts="root=${linux_root_device_thisversion} ro ${args}"
+     fi
+ 
diff --git a/SOURCES/0256-grub-boot-success.timer-Add-a-few-Conditions-for-run.patch b/SOURCES/0256-grub-boot-success.timer-Add-a-few-Conditions-for-run.patch
new file mode 100644
index 0000000..4f82ba2
--- /dev/null
+++ b/SOURCES/0256-grub-boot-success.timer-Add-a-few-Conditions-for-run.patch
@@ -0,0 +1,33 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 3 Sep 2018 13:01:58 +0200
+Subject: [PATCH] grub-boot-success.timer: Add a few Conditions for running the
+ timer
+
+Add 2 Conditions for running the boot-success timer / service:
+
+1) Do not run it for system users, this fixes errors about gdm not being
+allowed to use pkexec when the greeter session lasts for more then 2 minutes:
+https://bugzilla.redhat.com/show_bug.cgi?id=1592201#c6
+
+2) Do not run the timer when pkexec is not available (on minimal installs)
+since then it will just lead to a bunch of errors without doing anything:
+https://bugzilla.redhat.com/show_bug.cgi?id=1619445
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ docs/grub-boot-success.timer | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/docs/grub-boot-success.timer b/docs/grub-boot-success.timer
+index 221b532781b..67bd829b795 100644
+--- a/docs/grub-boot-success.timer
++++ b/docs/grub-boot-success.timer
+@@ -1,5 +1,7 @@
+ [Unit]
+ Description=Mark boot as successful after the user session has run 2 minutes
++ConditionUser=!@system
++ConditionPathExists=/usr/bin/pkexec
+ 
+ [Timer]
+ OnActiveSec=2min
diff --git a/SOURCES/0257-docs-Stop-using-polkit-pkexec-for-grub-boot-success..patch b/SOURCES/0257-docs-Stop-using-polkit-pkexec-for-grub-boot-success..patch
new file mode 100644
index 0000000..bf4ad27
--- /dev/null
+++ b/SOURCES/0257-docs-Stop-using-polkit-pkexec-for-grub-boot-success..patch
@@ -0,0 +1,69 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 14 Sep 2018 16:39:40 +0200
+Subject: [PATCH] docs: Stop using polkit / pkexec for grub-boot-success.timer
+ / service
+
+We also want to call grub2-set-bootflag under gdm and pkexec does not
+work under gdm because the gdm user has /sbin/nologin as shell.
+
+So instead we are going to install grub2-set-bootflag as suid root,
+grub2-set-bootflag was written with this usage in mind, so is safe
+to be made suid root.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ docs/grub-boot-success.service |  2 +-
+ docs/grub-boot-success.timer   |  1 -
+ docs/org.gnu.grub.policy       | 20 --------------------
+ 3 files changed, 1 insertion(+), 22 deletions(-)
+ delete mode 100644 docs/org.gnu.grub.policy
+
+diff --git a/docs/grub-boot-success.service b/docs/grub-boot-success.service
+index c8c91c34d49..80e79584c91 100644
+--- a/docs/grub-boot-success.service
++++ b/docs/grub-boot-success.service
+@@ -3,4 +3,4 @@ Description=Mark boot as successful
+ 
+ [Service]
+ Type=oneshot
+-ExecStart=/usr/bin/pkexec /usr/sbin/grub2-set-bootflag boot_success
++ExecStart=/usr/sbin/grub2-set-bootflag boot_success
+diff --git a/docs/grub-boot-success.timer b/docs/grub-boot-success.timer
+index 67bd829b795..5d8fcba21aa 100644
+--- a/docs/grub-boot-success.timer
++++ b/docs/grub-boot-success.timer
+@@ -1,7 +1,6 @@
+ [Unit]
+ Description=Mark boot as successful after the user session has run 2 minutes
+ ConditionUser=!@system
+-ConditionPathExists=/usr/bin/pkexec
+ 
+ [Timer]
+ OnActiveSec=2min
+diff --git a/docs/org.gnu.grub.policy b/docs/org.gnu.grub.policy
+deleted file mode 100644
+index 18391efc8e7..00000000000
+--- a/docs/org.gnu.grub.policy
++++ /dev/null
+@@ -1,20 +0,0 @@
+-<?xml version="1.0" encoding="UTF-8"?>
+-<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
+-<policyconfig>
+-  <vendor>GNU GRUB</vendor>
+-  <vendor_url>https://www.gnu.org/software/grub/</vendor_url>
+-  <action id="org.gnu.grub.set-bootflag">
+-    <!-- SECURITY:
+-          - A normal active user on the local machine does not need permission
+-            to set bootflags to show the menu / mark current boot successful.
+-     -->
+-    <description>Set GRUB bootflags</description>
+-    <message>Authentication is required to modify the bootloaders bootflags</message>
+-    <defaults>
+-      <allow_any>no</allow_any>
+-      <allow_inactive>no</allow_inactive>
+-      <allow_active>yes</allow_active>
+-    </defaults>
+-    <annotate key="org.freedesktop.policykit.exec.path">/usr/sbin/grub2-set-bootflag</annotate>
+-  </action>
+-</policyconfig>
diff --git a/SOURCES/0258-Fix-the-looking-up-grub.cfg-XXX-while-tftp-booting.patch b/SOURCES/0258-Fix-the-looking-up-grub.cfg-XXX-while-tftp-booting.patch
new file mode 100644
index 0000000..3469f7a
--- /dev/null
+++ b/SOURCES/0258-Fix-the-looking-up-grub.cfg-XXX-while-tftp-booting.patch
@@ -0,0 +1,42 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Date: Tue, 18 Dec 2018 21:27:45 -0500
+Subject: [PATCH] Fix the looking up grub.cfg-XXX while tftp booting.
+
+Currently, grub doesn't look up grub.cfg-UUID, grub.cfg-MAC and grub.cfg-IP
+while the boot is from tftp. That is because the uuid size is got by
+grub_snprintf(, 0, ,), but the grub_snprintf() always returns 0,
+so grub judges there's no available uuid in the client and give up
+the looking up grub.cfg-XXX.
+
+This issue can be fixed by changing grub_snprintf(, 0, ,) behaivior
+to like as snprintf() from glibc, however, somewhere may expect
+such argument as the error, so it's risky.
+
+Let's use sizeof() and grub_strlen() to calculate the uuid size
+instead of grub_snprintf().
+
+Resolves: rhbz#1658500
+---
+ grub-core/net/net.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+diff --git a/grub-core/net/net.c b/grub-core/net/net.c
+index a011b940100..19ff2d486a1 100644
+--- a/grub-core/net/net.c
++++ b/grub-core/net/net.c
+@@ -1942,11 +1942,9 @@ grub_net_search_configfile (char *config)
+       char *client_uuid_var;
+       grub_size_t client_uuid_var_size;
+ 
+-      client_uuid_var_size = grub_snprintf (NULL, 0,
+-                     "net_%s_clientuuid", inf->name);
+-      if (client_uuid_var_size <= 0)
+-	continue;
+-      client_uuid_var_size += 1;
++      client_uuid_var_size = sizeof ("net_") + grub_strlen (inf->name) +
++                     sizeof ("_clientuuid") + 1;
++
+       client_uuid_var = grub_malloc(client_uuid_var_size);
+       if (!client_uuid_var)
+ 	continue;
diff --git a/SOURCES/20-grub.install b/SOURCES/20-grub.install
new file mode 100755
index 0000000..3238e43
--- /dev/null
+++ b/SOURCES/20-grub.install
@@ -0,0 +1,167 @@
+#!/bin/bash
+
+if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then
+    exit 0
+fi
+
+[[ -f /etc/default/grub ]] && . /etc/default/grub
+[[ -f /etc/os-release ]] && . /etc/os-release
+
+COMMAND="$1"
+KERNEL_VERSION="$2"
+BOOT_DIR_ABS="$3"
+KERNEL_IMAGE="$4"
+
+KERNEL_DIR="${KERNEL_IMAGE%/*}"
+
+MACHINE_ID=$KERNEL_INSTALL_MACHINE_ID
+
+# Remove it, since for grub2 the images are always installed in /boot
+rm -rf "${BOOT_DIR_ABS%/*}"
+
+BLS_DIR="/boot/loader/entries"
+
+mkbls() {
+    local kernelver=$1 && shift
+    local datetime=$1 && shift
+
+    local debugname=""
+    local debugid=""
+    local flavor=""
+
+    if [[ "$kernelver" == *\+* ]] ; then
+        local flavor=-"${kernelver##*+}"
+        if [[ "${flavor}" == "-debug" ]]; then
+            local debugname=" with debugging"
+            local debugid="-debug"
+        fi
+    fi
+
+    cat <<EOF
+title ${NAME} (${kernelver}) ${VERSION}${debugname}
+version ${kernelver}${debugid}
+linux /vmlinuz-${kernelver}
+initrd /initramfs-${kernelver}.img
+options \$kernelopts
+id ${ID}-${datetime}-${kernelver}
+grub_users \$grub_users
+grub_arg --unrestricted
+grub_class kernel${flavor}
+EOF
+}
+
+[[ "$KERNEL_VERSION" == *\+* ]] && flavor=-"${KERNEL_VERSION##*+}"
+case "$COMMAND" in
+    add)
+        if [[ "${KERNEL_DIR}" != "/boot" ]]; then
+            for i in \
+                "$KERNEL_IMAGE" \
+                    "$KERNEL_DIR"/System.map \
+                    "$KERNEL_DIR"/config \
+                    "$KERNEL_DIR"/zImage.stub \
+                    "$KERNEL_DIR"/dtb
+            do
+                [[ -e "$i" ]] || continue
+                rm -f "/boot/${i##*/}-${KERNEL_VERSION}"
+                cp -aT "$i" "/boot/${i##*/}-${KERNEL_VERSION}"
+                command -v restorecon &>/dev/null && \
+                    restorecon -R "/boot/${i##*/}-${KERNEL_VERSION}"
+            done
+            # hmac is .vmlinuz-<version>.hmac so needs a special treatment
+            i="$KERNEL_DIR/.${KERNEL_IMAGE##*/}.hmac"
+            if [[ -e "$i" ]]; then
+                rm -f "/boot/.${KERNEL_IMAGE##*/}-${KERNEL_VERSION}.hmac"
+                cp -a "$i" "/boot/.${KERNEL_IMAGE##*/}-${KERNEL_VERSION}.hmac"
+                command -v restorecon &>/dev/null && \
+                    restorecon "/boot/.${KERNEL_IMAGE##*/}-${KERNEL_VERSION}.hmac"
+            fi
+        fi
+
+        if [[ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]] || [[ ! -f /sbin/new-kernel-pkg ]]; then
+            eval "$(grub2-get-kernel-settings)" || true
+            [[ -d "$BLS_DIR" ]] || mkdir -m 0700 -p "$BLS_DIR"
+            BLS_ID="${MACHINE_ID}-${KERNEL_VERSION}"
+            BLS_TARGET="${BLS_DIR}/${BLS_ID}.conf"
+            if [[ -f "${KERNEL_DIR}/bls.conf" ]]; then
+                cp -aT "${KERNEL_DIR}/bls.conf" "${BLS_TARGET}" || exit $?
+            else
+                mkbls "${KERNEL_VERSION}" \
+                    "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${KERNEL_DIR}")")" \
+                    >"${BLS_TARGET}"
+            fi
+
+            LINUX="$(grep '^linux[ \t]' "${BLS_TARGET}" | sed -e 's,^linux[ \t]*,,')"
+            INITRD="$(grep '^initrd[ \t]' "${BLS_TARGET}" | sed -e 's,^initrd[ \t]*,,')"
+            LINUX_RELPATH="$(grub2-mkrelpath /boot${LINUX})"
+            BOOTPREFIX="$(dirname ${LINUX_RELPATH})"
+            ROOTPREFIX="$(dirname "/boot${LINUX}")"
+
+            if [[ $LINUX != $LINUX_RELPATH ]]; then
+                sed -i -e "s,^linux.*,linux ${BOOTPREFIX}${LINUX},g" "${BLS_TARGET}"
+                sed -i -e "s,^initrd.*,initrd ${BOOTPREFIX}${INITRD},g" "${BLS_TARGET}"
+            fi
+
+            if [[ "$KERNEL_VERSION" == *\+* ]] && [ "x$GRUB_DEFAULT_TO_DEBUG" != "xtrue" ]; then
+                GRUB_UPDATE_DEFAULT_KERNEL=false
+            fi
+
+            if [ "x$GRUB_UPDATE_DEFAULT_KERNEL" = "xtrue" ]; then
+                NEWDEFAULT="${BLS_ID}"
+            fi
+
+            if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then
+                ARCH="$(uname -m)"
+                BLS_DEBUG_ID="$(echo ${BLS_ID} | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")"
+                BLS_DEBUG="$(echo ${BLS_TARGET} | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")"
+                cp -aT  "${BLS_TARGET}" "${BLS_DEBUG}"
+                TITLE="$(grep '^title[ \t]' "${BLS_DEBUG}" | sed -e 's/^title[ \t]*//')"
+                sed -i -e "s/^title.*/title ${TITLE}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${BLS_DEBUG}"
+                sed -i -e "s/^id.*/id ${BLS_DEBUG_ID}/" "${BLS_DEBUG}"
+                sed -i -e "s/^options.*/options \$kernelopts ${GRUB_CMDLINE_LINUX_DEBUG}/" "${BLS_DEBUG}"
+                if [ -n "$NEWDEFAULT" -a "x$GRUB_DEFAULT_TO_DEBUG" = "xtrue" ]; then
+                    NEWDEFAULT="${BLS_DEBUG_ID}"
+                fi
+            fi
+            if [ -n "$NEWDEFAULT" ]; then
+                grub2-editenv - set "saved_entry=${NEWDEFAULT}"
+            fi
+
+            # this probably isn't the best place to do this, but it will do for now.
+            if [ -e "${ROOTPREFIX}${INITRD}" -a -e "${ROOTPREFIX}${LINUX}" -a \
+                 "${ROOTPREFIX}${INITRD}" -ot "${ROOTPREFIX}${LINUX}" -a \
+                 -x /usr/lib/kernel/install.d/50-dracut.install ]; then
+                rm -f "${ROOTPREFIX}${INITRD}"
+            fi
+            exit 0
+        fi
+
+        /sbin/new-kernel-pkg --package "kernel${flavor}" --install "$KERNEL_VERSION" || exit $?
+        /sbin/new-kernel-pkg --package "kernel${flavor}" --mkinitrd --dracut --depmod --update "$KERNEL_VERSION" || exit $?
+        /sbin/new-kernel-pkg --package "kernel${flavor}" --rpmposttrans "$KERNEL_VERSION" || exit $?
+        # If grubby is used there's no need to run other installation plugins
+        exit 77
+        ;;
+    remove)
+
+        if [[ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]] || [[ ! -f /sbin/new-kernel-pkg ]]; then
+            ARCH="$(uname -m)"
+            BLS_TARGET="${BLS_DIR}/${MACHINE_ID}-${KERNEL_VERSION}.conf"
+            BLS_DEBUG="$(echo ${BLS_TARGET} | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")"
+            rm -f "${BLS_TARGET}" "${BLS_DEBUG}"
+
+            for i in vmlinuz System.map config zImage.stub dtb; do
+                rm -rf "/boot/${i}-${KERNEL_VERSION}"
+            done
+            # hmac is .vmlinuz-<version>.hmac so needs a special treatment
+            rm -f "/boot/.vmlinuz-${KERNEL_VERSION}.hmac"
+
+            exit 0
+        fi
+
+        /sbin/new-kernel-pkg --package "kernel${flavor+-$flavor}" --rminitrd --rmmoddep --remove "$KERNEL_VERSION" || exit $?
+        # If grubby is used there's no need to run other installation plugins
+        exit 77
+        ;;
+    *)
+        ;;
+esac
diff --git a/SOURCES/99-grub-mkconfig.install b/SOURCES/99-grub-mkconfig.install
new file mode 100644
index 0000000..e370899
--- /dev/null
+++ b/SOURCES/99-grub-mkconfig.install
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then
+    exit 0
+fi
+
+ARCH=$(uname -m)
+
+# Is only needed for ppc64* since we can't assume a BLS capable bootloader there
+if [[ $ARCH != "ppc64" && $ARCH != "ppc64le" ]]; then
+    exit 0
+fi
+
+[[ -f /etc/default/grub ]] && . /etc/default/grub
+
+COMMAND="$1"
+
+case "$COMMAND" in
+    add|remove)
+        grub2-mkconfig --no-grubenv-update -o /boot/grub2/grub.cfg >& /dev/null
+        ;;
+    *)
+        ;;
+esac
diff --git a/SOURCES/gitignore b/SOURCES/gitignore
new file mode 100644
index 0000000..eca17be
--- /dev/null
+++ b/SOURCES/gitignore
@@ -0,0 +1,249 @@
+00_header
+10_*
+20_linux_xen
+30_os-prober
+40_custom
+41_custom
+*.1
+*.8
+aclocal.m4
+ahci_test
+ascii.bitmaps
+ascii.h
+autom4te.cache
+build-grub-gen-asciih
+build-grub-gen-widthspec
+build-grub-mkfont
+cdboot_test
+cmp_test
+config.cache
+config.guess
+config.h
+config-util.h
+config-util.h.in
+config.log
+config.status
+config.sub
+configure
+core_compress_test
+DISTLIST
+docs/*.info
+docs/stamp-vti
+docs/version.texi
+ehci_test
+example_grub_script_test
+example_scripted_test
+example_unit_test
+*.exec
+*.exec.exe
+fddboot_test
+genkernsyms.sh
+gensymlist.sh
+gentrigtables
+gentrigtables.exe
+gettext_strings_test
+grub-bin2h
+/grub-bios-setup
+/grub-bios-setup.exe
+grub_cmd_date
+grub_cmd_echo
+grub_cmd_regexp
+grub_cmd_set_date
+grub_cmd_sleep
+/grub-editenv
+/grub-editenv.exe
+grub-emu
+grub-emu-lite
+grub-emu.exe
+grub-emu-lite.exe
+grub_emu_init.c
+grub_emu_init.h
+/grub-file
+/grub-file.exe
+grub-fstest
+grub-fstest.exe
+grub_fstest_init.c
+grub_fstest_init.h
+grub_func_test
+grub-install
+grub-install.exe
+grub-kbdcomp
+/grub-macbless
+/grub-macbless.exe
+grub-macho2img
+/grub-menulst2cfg
+/grub-menulst2cfg.exe
+/grub-mk*
+grub-mount
+/grub-ofpathname
+/grub-ofpathname.exe
+grub-core/build-grub-pe2elf.exe
+/grub-probe
+/grub-probe.exe
+grub_probe_init.c
+grub_probe_init.h
+/grub-reboot
+grub_script_blanklines
+grub_script_blockarg
+grub_script_break
+grub-script-check
+grub-script-check.exe
+grub_script_check_init.c
+grub_script_check_init.h
+grub_script_comments
+grub_script_continue
+grub_script_dollar
+grub_script_echo1
+grub_script_echo_keywords
+grub_script_escape_comma
+grub_script_eval
+grub_script_expansion
+grub_script_final_semicolon
+grub_script_for1
+grub_script_functions
+grub_script_gettext
+grub_script_if
+grub_script_leading_whitespace
+grub_script_no_commands
+grub_script_not
+grub_script_return
+grub_script_setparams
+grub_script_shift
+grub_script_strcmp
+grub_script_test
+grub_script_vars1
+grub_script_while1
+grub_script.tab.c
+grub_script.tab.h
+grub_script.yy.c
+grub_script.yy.h
+grub-set-default
+grub_setup_init.c
+grub_setup_init.h
+grub-shell
+grub-shell-tester
+grub-sparc64-setup
+grub-sparc64-setup.exe
+/grub-syslinux2cfg
+/grub-syslinux2cfg.exe
+gzcompress_test
+hddboot_test
+help_test
+*.img
+*.image
+*.image.exe
+include/grub/cpu
+include/grub/machine
+install-sh
+lib/libgcrypt-grub
+libgrub_a_init.c
+*.log
+*.lst
+lzocompress_test
+*.marker
+Makefile
+*.mod
+mod-*.c
+missing
+netboot_test
+*.o
+*.a
+ohci_test
+partmap_test
+pata_test
+*.pf2
+*.pp
+po/*.mo
+po/grub.pot
+po/POTFILES
+po/stamp-po
+printf_test
+priority_queue_unit_test
+pseries_test
+stamp-h
+stamp-h1
+stamp-h.in
+symlist.c
+symlist.h
+trigtables.c
+*.trs
+uhci_test
+update-grub_lib
+unidata.c
+xzcompress_test
+Makefile.in
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+compile
+depcomp
+mdate-sh
+texinfo.tex
+grub-core/lib/libgcrypt-grub
+.deps
+.deps-util
+.deps-core
+.dirstamp
+Makefile.util.am
+contrib
+grub-core/bootinfo.txt
+grub-core/Makefile.core.am
+grub-core/Makefile.gcry.def
+grub-core/contrib
+grub-core/gdb_grub
+grub-core/genmod.sh
+grub-core/gensyminfo.sh
+grub-core/gmodule.pl
+grub-core/grub.chrp
+grub-core/modinfo.sh
+grub-core/*.module
+grub-core/*.module.exe
+grub-core/*.pp
+grub-core/kernel.img.bin
+util/bash-completion.d/grub
+grub-core/gnulib/alloca.h
+grub-core/gnulib/arg-nonnull.h
+grub-core/gnulib/c++defs.h
+grub-core/gnulib/charset.alias
+grub-core/gnulib/configmake.h
+grub-core/gnulib/float.h
+grub-core/gnulib/getopt.h
+grub-core/gnulib/langinfo.h
+grub-core/gnulib/ref-add.sed
+grub-core/gnulib/ref-del.sed
+grub-core/gnulib/stdio.h
+grub-core/gnulib/stdlib.h
+grub-core/gnulib/string.h
+grub-core/gnulib/strings.h
+grub-core/gnulib/sys
+grub-core/gnulib/unistd.h
+grub-core/gnulib/warn-on-use.h
+grub-core/gnulib/wchar.h
+grub-core/gnulib/wctype.h
+grub-core/rs_decoder.h
+widthspec.bin
+widthspec.h
+docs/stamp-1
+docs/version-dev.texi
+Makefile.utilgcry.def
+po/*.po
+po/*.gmo
+po/LINGUAS
+po/remove-potcdate.sed
+include/grub/gcrypt/gcrypt.h
+include/grub/gcrypt/g10lib.h
+po/POTFILES.in
+po/POTFILES-shell.in
+/grub-glue-efi
+/grub-render-label
+/grub-glue-efi.exe
+/grub-render-label.exe
+grub-core/gnulib/locale.h
+grub-core/gnulib/unitypes.h
+grub-core/gnulib/uniwidth.h
+build-aux/test-driver
+/garbage-gen
+/garbage-gen.exe
+/grub-fs-tester
+grub-core/build-grub-module-verifier
diff --git a/SOURCES/grub.macros b/SOURCES/grub.macros
new file mode 100644
index 0000000..d59f889
--- /dev/null
+++ b/SOURCES/grub.macros
@@ -0,0 +1,554 @@
+# vim:filetype=spec
+# Modules always contain just 32-bit code
+%global _libdir %{_exec_prefix}/lib
+%global _binaries_in_noarch_packages_terminate_build 0
+#%%undefine _missing_build_ids_terminate_build
+%{expand:%%{!?buildsubdir:%%global buildsubdir grub-%{tarversion}}}
+%{expand:%%{!?_licensedir:%%global license %%%%doc}}
+
+%global _configure ../configure
+
+%if %{?_with_ccache: 1}%{?!_with_ccache: 0}
+%global cc_equals CC=/usr/%{_lib}/ccache/gcc
+%else
+%global cc_equals %{nil}
+%endif
+
+%global cflags_sed						\\\
+	sed							\\\
+		-e 's/-O. //g'					\\\
+		-e 's/-g /-g3 /g'				\\\
+		-e 's/-fplugin=annobin //g'			\\\
+		-e 's,-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 ,,g' \\\
+		-e 's/-fstack-protector[[:alpha:]-]\\+//g'	\\\
+		-e 's/-Wp,-D_FORTIFY_SOURCE=[[:digit:]]\\+//g'	\\\
+		-e 's/--param=ssp-buffer-size=4//g'		\\\
+		-e 's/-mregparm=3/-mregparm=4/g'		\\\
+		-e 's/-fexceptions//g'				\\\
+		-e 's/-fasynchronous-unwind-tables//g'		\\\
+		-e 's/^/ -fno-strict-aliasing /'		\\\
+		%{nil}
+
+%global host_cflags %{expand:%%(echo %{optflags} | %{cflags_sed})}
+%global target_cflags %{expand:%%(echo %{optflags} | %{cflags_sed})}
+
+%global legacy_target_cflags					\\\
+	%{expand:%%(echo %{target_cflags} | 			\\\
+	%{cflags_sed}						\\\
+		-e 's/-m64//g'					\\\
+		-e 's/-mcpu=power[[:alnum:]]\\+/-mcpu=power6/g'	\\\
+	)}
+%global legacy_host_cflags					\\\
+	%{expand:%%(echo %{host_cflags} | 			\\\
+	%{cflags_sed}						\\\
+		-e 's/-m64//g'					\\\
+		-e 's/-mcpu=power[[:alnum:]]\\+/-mcpu=power6/g'	\\\
+	)}
+
+%global efi_host_cflags %{expand:%%(echo %{host_cflags})}
+%global efi_target_cflags %{expand:%%(echo %{target_cflags})}
+
+%global with_efi_arch 0
+%global with_alt_efi_arch 0
+%global with_legacy_arch 0
+%global grubefiarch %{nil}
+%global grublegacyarch %{nil}
+
+# sparc is always compiled 64 bit
+%ifarch %{sparc}
+%global target_cpu_name sparc64
+%global _target_platform %{target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu}
+%global legacy_target_cpu_name %{_arch}
+%global legacy_package_arch ieee1275
+%global platform ieee1275
+%endif
+# ppc is always compiled 64 bit
+%ifarch ppc ppc64 ppc64le
+%global target_cpu_name %{_arch}
+%global legacy_target_cpu_name powerpc
+%global legacy_package_arch %{_arch}
+%global legacy_grub_dir powerpc-ieee1275
+%global _target_platform %{target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu}
+%global platform ieee1275
+%endif
+
+
+%global efi_only aarch64 %{arm}
+%global efi_arch x86_64 ia64 %{efi_only}
+%ifarch %{efi_arch}
+%global with_efi_arch 1
+%else
+%global with_efi_arch 0
+%endif
+%ifarch %{efi_only}
+%global with_efi_only 1
+%else
+%global with_efi_only 0
+%endif
+%{!?with_efi_arch:%global without_efi_arch 0}
+%{?with_efi_arch:%global without_efi_arch 1}
+%{!?with_efi_only:%global without_efi_only 0}
+%{?with_efi_only:%global without_efi_only 1}
+
+### fixme
+%ifarch aarch64 %{arm}
+%global platform_modules " "
+%else
+%global platform_modules " backtrace chain usb usbserial_common usbserial_pl2303 usbserial_ftdi usbserial_usbdebug "
+%endif
+
+%ifarch aarch64 %{arm}
+%global legacy_provides -l
+%endif
+
+%ifarch %{ix86}
+%global efiarch ia32
+%global target_cpu_name i386
+%global grub_target_name i386-efi
+%global package_arch efi-ia32
+
+%global legacy_target_cpu_name i386
+%global legacy_package_arch pc
+%global platform pc
+%endif
+
+%ifarch x86_64
+%global efiarch x64
+%global target_cpu_name %{_arch}
+%global grub_target_name %{_arch}-efi
+%global package_arch efi-x64
+
+%global legacy_target_cpu_name i386
+%global legacy_package_arch pc
+%global platform pc
+
+%global alt_efi_arch ia32
+%global alt_target_cpu_name i386
+%global alt_grub_target_name i386-efi
+%global alt_platform efi
+%global alt_package_arch efi-ia32
+
+%global alt_efi_host_cflags %{expand:%%(echo %{efi_host_cflags})}
+%global alt_efi_target_cflags					\\\
+	%{expand:%%(echo %{target_cflags} |			\\\
+	%{cflags_sed}						\\\
+		-e 's/-m64//g'					\\\
+	)}
+%endif
+
+%ifarch aarch64
+%global efiarch aa64
+%global target_cpu_name aarch64
+%global grub_target_name arm64-efi
+%global package_arch efi-aa64
+%endif
+
+%ifarch %{arm}
+%global efiarch arm
+%global target_cpu_name arm
+%global grub_target_name arm-efi
+%global package_arch efi-arm
+%global efi_target_cflags						\\\
+	%{expand:%%(echo %{optflags} |					\\\
+	%{cflags_sed}							\\\
+		-e 's/-march=armv7-a[[:alnum:]+-]*/&+nofp/g'		\\\
+		-e 's/-mfpu=[[:alnum:]-]\\+//g'				\\\
+		-e 's/-mfloat-abi=[[:alpha:]]\\+/-mfloat-abi=soft/g'	\\\
+	)}
+%endif
+
+%global _target_platform %{target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu}
+%global _alt_target_platform %{alt_target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu}
+
+%ifarch %{efi_arch}
+%global with_efi_arch 1
+%global grubefiname grub%{efiarch}.efi
+%global grubeficdname gcd%{efiarch}.efi
+%global grubefiarch %{target_cpu_name}-efi
+%ifarch %{ix86}
+%global with_efi_modules 0
+%global without_efi_modules 1
+%else
+%global with_efi_modules 1
+%global without_efi_modules 0
+%endif
+%endif
+
+%if 0%{?alt_efi_arch:1}
+%global with_alt_efi_arch 1
+%global grubaltefiname grub%{alt_efi_arch}.efi
+%global grubalteficdname gcd%{alt_efi_arch}.efi
+%global grubaltefiarch %{alt_target_cpu_name}-efi
+%endif
+
+%ifnarch %{efi_only}
+%global with_legacy_arch 1
+%global grublegacyarch %{legacy_target_cpu_name}-%{platform}
+%global moduledir %{legacy_target_cpu_name}-%{platform}
+%endif
+
+%global evr %{epoch}:%{version}-%{release}
+
+%ifarch x86_64
+%global with_efi_common 1
+%global with_legacy_modules 0
+%global with_legacy_common 0
+%else
+%global with_efi_common 0
+%global with_legacy_common 1
+%global with_legacy_modules 1
+%endif
+
+%define define_legacy_variant()						\
+%{expand:%%package %%{1}}						\
+Summary:	Bootloader with support for Linux, Multiboot, and more	\
+Group:		System Environment/Base					\
+Provides:	%{name} = %{evr}					\
+Obsoletes:	%{name} < %{evr}					\
+Requires:	%{name}-common = %{evr}					\
+Requires:	%{name}-tools-minimal = %{evr}				\
+Requires:	%{name}-%{1}-modules = %{evr}				\
+Requires:	gettext which file					\
+Requires:	%{name}-tools-extra = %{evr}				\
+Requires:	%{name}-tools = %{evr}					\
+Requires(pre):	dracut							\
+Requires(post): dracut							\
+%{expand:%%description %%{1}}						\
+%{desc}									\
+This subpackage provides support for %%{1} systems.			\
+									\
+%{expand:%%{?!buildsubdir:%%define buildsubdir grub-%%{1}-%{tarversion}}}\
+%{expand:%%if 0%%{with_legacy_modules}					\
+%%package %%{1}-modules							\
+Summary:	Modules used to build custom grub images		\
+Group:		System Environment/Base					\
+BuildArch:	noarch							\
+Requires:	%%{name}-common = %%{evr}				\
+%%description %%{1}-modules						\
+%%{desc}								\
+This subpackage provides support for rebuilding your own grub.efi.	\
+%%endif									\
+}									\
+									\
+%{expand:%%{?!buildsubdir:%%define buildsubdir grub-%%{1}-%{tarversion}}}\
+%{expand:%%package %%{1}-tools}						\
+Summary:	Support tools for GRUB.					\
+Group:		System Environment/Base					\
+Requires:	gettext os-prober which file system-logos		\
+Requires:	%{name}-common = %{evr}					\
+Requires:	%{name}-tools-minimal = %{evr}				\
+Requires:	os-prober >= 1.58-11					\
+Requires:	gettext which file					\
+									\
+%{expand:%%description %%{1}-tools}					\
+%{desc}									\
+This subpackage provides tools for support of %%{1} platforms.		\
+%{nil}
+
+%define define_efi_variant(o)						\
+%{expand:%%package %{1}}						\
+Summary:	GRUB for EFI systems.					\
+Group:		System Environment/Base					\
+Requires:	efi-filesystem						\
+Requires:	%{name}-common = %{evr}					\
+Requires:	%{name}-tools-minimal >= %{evr}				\
+Requires:	%{name}-tools-extra = %{evr}				\
+Requires:	%{name}-tools = %{evr}					\
+Provides:	%{name}-efi = %{evr}					\
+%{?legacy_provides:Provides:	%{name} = %{evr}}			\
+%{-o:Obsoletes:	%{name}-efi < %{evr}}					\
+									\
+%{expand:%%description %{1}}						\
+%{desc}									\
+This subpackage provides support for %{1} systems.			\
+									\
+%{expand:%%{?!buildsubdir:%%define buildsubdir grub-%{1}-%{tarversion}}}\
+%{expand:%if 0%{?with_efi_modules}					\
+%{expand:%%package %{1}-modules}					\
+Summary:	Modules used to build custom grub.efi images		\
+Group:		System Environment/Base					\
+BuildArch:	noarch							\
+Requires:	%{name}-common = %{evr}					\
+Provides:	%{name}-efi-modules = %{evr}				\
+Obsoletes:	%{name}-efi-modules < %{evr}				\
+%{expand:%%description %{1}-modules}					\
+%{desc}									\
+This subpackage provides support for rebuilding your own grub.efi.	\
+%endif}									\
+									\
+%{expand:%%package %{1}-cdboot}						\
+Summary:	Files used to boot removeable media with EFI		\
+Group:		System Environment/Base					\
+Requires:	%{name}-common = %{evr}					\
+Provides:	%{name}-efi-cdboot = %{evr}				\
+%{expand:%%description %{1}-cdboot}					\
+%{desc}									\
+This subpackage provides optional components of grub used with removeable media on %{1} systems.\
+%{nil}
+
+%global do_common_setup()					\
+%setup -q -n grub-%{tarversion}					\
+rm -fv docs/*.info						\
+cp %{SOURCE6} .gitignore					\
+cp %{SOURCE8} ./grub-core/tests/strtoull_test.c			\
+git init							\
+echo '![[:digit:]][[:digit:]]_*.in' > util/grub.d/.gitignore	\
+echo '!*.[[:digit:]]' > util/.gitignore				\
+echo '!config.h' > include/grub/emu/.gitignore			\
+git config user.email "%{name}-owner@fedoraproject.org"		\
+git config user.name "Fedora Ninjas"				\
+git config gc.auto 0						\
+rm -f configure							\
+git add .							\
+git commit -a -q -m "%{tarversion} baseline."			\
+git apply --index --whitespace=nowarn %{SOURCE3}		\
+git commit -a -q -m "%{tarversion} master."			\
+git am --whitespace=nowarn %%{patches} </dev/null		\
+autoreconf -vi							\
+git add .							\
+git commit -a -q -m "autoreconf"				\
+autoconf							\
+PYTHON=python3 ./autogen.sh					\
+%{nil}
+
+%define do_efi_configure()					\
+%configure							\\\
+	%{cc_equals}						\\\
+	HOST_CFLAGS="%{3} -I$(pwd)"				\\\
+	HOST_CPPFLAGS="${CPPFLAGS} -I$(pwd)"			\\\
+	TARGET_CFLAGS="%{2} -I$(pwd)"				\\\
+	TARGET_CPPFLAGS="${CPPFLAGS} -I$(pwd)"			\\\
+	TARGET_LDFLAGS=-static					\\\
+	--with-platform=efi					\\\
+	--with-utils=host					\\\
+	--target=%{1}						\\\
+	--with-grubdir=%{name}					\\\
+	--program-transform-name=s,grub,%{name},		\\\
+	--disable-grub-mount					\\\
+	--disable-werror || ( cat config.log ; exit 1 )		\
+git add .							\
+git commit -m "After efi configure"				\
+%{nil}
+
+%define do_efi_build_modules()					\
+make %{?_smp_mflags} ascii.h widthspec.h			\
+make %{?_smp_mflags} -C grub-core				\
+%{nil}
+
+%define do_efi_build_all()					\
+make %{?_smp_mflags}						\
+%{nil}
+
+%define do_efi_link_utils()					\
+for x in grub-mkimage ; do					\\\
+	ln ../grub-%{1}-%{tarversion}/${x} ./ ;			\\\
+done								\
+%{nil}
+
+%ifarch x86_64 aarch64 %{arm}
+%define mkimage()						\
+%{4}./grub-mkimage -O %{1} -o %{2}.orig				\\\
+	-p /EFI/%{efi_vendor} -d grub-core ${GRUB_MODULES}	\
+%{4}./grub-mkimage -O %{1} -o %{3}.orig				\\\
+	-p /EFI/BOOT -d grub-core ${GRUB_MODULES}		\
+%{expand:%%{pesign -s -i %%{2}.orig -o %%{2} -a %%{5} -c %%{6} -n %%{7}}}	\
+%{expand:%%{pesign -s -i %%{3}.orig -o %%{3} -a %%{5} -c %%{6} -n %%{7}}}	\
+%{nil}
+%else
+%define mkimage()						\
+%{4}./grub-mkimage -O %{1} -o %{2}				\\\
+	-p /EFI/%{efi_vendor} -d grub-core ${GRUB_MODULES}	\
+%{4}./grub-mkimage -O %{1} -o %{3}				\\\
+	-p /EFI/BOOT -d grub-core ${GRUB_MODULES}		\
+%{nil}
+%endif
+
+%define do_efi_build_images()					\
+GRUB_MODULES="	all_video boot blscfg btrfs			\\\
+		cat configfile					\\\
+		echo efi_netfs efifwsetup efinet ext2		\\\
+		fat font gfxmenu gfxterm gzio			\\\
+		halt hfsplus http iso9660 jpeg			\\\
+		loadenv loopback linux lvm lsefi lsefimmap	\\\
+		mdraid09 mdraid1x minicmd net			\\\
+		normal part_apple part_msdos part_gpt		\\\
+		password_pbkdf2 png reboot			\\\
+		search search_fs_uuid search_fs_file		\\\
+		search_label serial sleep syslinuxcfg test tftp	\\\
+		video xfs"					\
+GRUB_MODULES+=%{platform_modules}				\
+%{expand:%%{mkimage %{1} %{2} %{3} %{4} %{5} %{6} %{7}}}	\
+%{nil}
+
+%define do_primary_efi_build()					\
+cd grub-%{1}-%{tarversion}					\
+%{expand:%%do_efi_configure %%{4} %%{5} %%{6}}			\
+%do_efi_build_all						\
+%{expand:%%do_efi_build_images %{grub_target_name} %{2} %{3} ./ %{7} %{8} %{9}} \
+cd ..								\
+%{nil}
+
+%define do_alt_efi_build()					\
+cd grub-%{1}-%{tarversion}					\
+%{expand:%%do_efi_configure %%{4} %%{5} %%{6}}			\
+%do_efi_build_modules						\
+%{expand:%%do_efi_link_utils %{grubefiarch}}			\
+%{expand:%%do_efi_build_images %{alt_grub_target_name} %{2} %{3} ../grub-%{grubefiarch}-%{tarversion}/ %{7} %{8} %{9}} \
+cd ..								\
+%{nil}
+
+%define do_legacy_build()					\
+cd grub-%{1}-%{tarversion}					\
+%configure							\\\
+	%{cc_equals}						\\\
+	HOST_CFLAGS="%{legacy_host_cflags} -I$(pwd)"		\\\
+	TARGET_CFLAGS="%{legacy_target_cflags} -I$(pwd)"	\\\
+	TARGET_LDFLAGS=-static					\\\
+	--with-platform=%{platform}				\\\
+	--with-utils=host					\\\
+	--target=%{_target_platform}				\\\
+	--with-grubdir=%{name}					\\\
+	--program-transform-name=s,grub,%{name},		\\\
+	--disable-grub-mount					\\\
+	--disable-werror || ( cat config.log ; exit 1 )		\
+git add .							\
+git commit -m "After legacy configure"					\
+make %{?_smp_mflags}						\
+cd ..								\
+%{nil}
+
+%define do_alt_efi_install()					\
+cd grub-%{1}-%{tarversion}					\
+install -d -m 755 $RPM_BUILD_ROOT/usr/lib/grub/%{grubaltefiarch}/ \
+find . '(' -iname gdb_grub					\\\
+	-o -iname kernel.exec					\\\
+	-o -iname kernel.img					\\\
+	-o -iname config.h					\\\
+	-o -iname gmodule.pl					\\\
+	-o -iname modinfo.sh					\\\
+	-o -iname '*.lst'					\\\
+	-o -iname '*.mod'					\\\
+	')'							\\\
+	-exec cp {} $RPM_BUILD_ROOT/usr/lib/grub/%{grubaltefiarch}/ \\\; \
+find $RPM_BUILD_ROOT -type f -iname "*.mod*" -exec chmod a-x {} '\;'	\
+install -m 700 %{2} $RPM_BUILD_ROOT%{efi_esp_dir}/%{2}	\
+install -m 700 %{3} $RPM_BUILD_ROOT%{efi_esp_dir}/%{3} \
+cd ..								\
+%{nil}
+
+%define do_efi_install()					\
+cd grub-%{1}-%{tarversion}					\
+make DESTDIR=$RPM_BUILD_ROOT install				\
+if [ -f $RPM_BUILD_ROOT%{_infodir}/grub.info ]; then		\
+	rm -f $RPM_BUILD_ROOT%{_infodir}/grub.info		\
+fi								\
+if [ -f $RPM_BUILD_ROOT%{_infodir}/grub-dev.info ]; then	\
+	rm -f $RPM_BUILD_ROOT%{_infodir}/grub-dev.info		\
+fi								\
+find $RPM_BUILD_ROOT -iname "*.module" -exec chmod a-x {} '\;'	\
+touch $RPM_BUILD_ROOT%{efi_esp_dir}/grub.cfg			\
+ln -sf ..%{efi_esp_dir}/grub.cfg				\\\
+	$RPM_BUILD_ROOT%{_sysconfdir}/%{name}-efi.cfg		\
+install -m 700 %{2} $RPM_BUILD_ROOT%{efi_esp_dir}/%{2}		\
+install -m 700 %{3} $RPM_BUILD_ROOT%{efi_esp_dir}/%{3}		\
+install -D -m 700 unicode.pf2					\\\
+	$RPM_BUILD_ROOT%{efi_esp_dir}/fonts/unicode.pf2		\
+${RPM_BUILD_ROOT}/%{_bindir}/%{name}-editenv			\\\
+	${RPM_BUILD_ROOT}%{efi_esp_dir}/grubenv create		\
+ln -sf ../efi/EFI/%{efi_vendor}/grubenv				\\\
+	$RPM_BUILD_ROOT/boot/grub2/grubenv			\
+cd ..								\
+%{nil}
+
+%define do_legacy_install()					\
+cd grub-%{1}-%{tarversion}					\
+make DESTDIR=$RPM_BUILD_ROOT install				\
+if [ -f $RPM_BUILD_ROOT%{_infodir}/grub.info ]; then		\
+	rm -f $RPM_BUILD_ROOT%{_infodir}/grub.info		\
+fi								\
+if [ -f $RPM_BUILD_ROOT%{_infodir}/grub-dev.info ]; then	\
+	rm -f $RPM_BUILD_ROOT%{_infodir}/grub-dev.info		\
+fi								\
+ln -s ../boot/%{name}/grub.cfg					\\\
+	${RPM_BUILD_ROOT}%{_sysconfdir}/grub2.cfg		\
+if [ -f $RPM_BUILD_ROOT/%{_libdir}/grub/%{1}/grub2.chrp ]; then \
+	mv $RPM_BUILD_ROOT/%{_libdir}/grub/%{1}/grub2.chrp	\\\
+	   $RPM_BUILD_ROOT/%{_libdir}/grub/%{1}/grub.chrp	\
+fi								\
+if [ %{3} -eq 0 ]; then						\
+	${RPM_BUILD_ROOT}/%{_bindir}/%{name}-editenv		\\\
+		${RPM_BUILD_ROOT}/boot/%{name}/grubenv create	\
+fi								\
+cd ..								\
+%{nil}
+
+%define do_common_install()					\
+install -d -m 0755 						\\\
+	$RPM_BUILD_ROOT%{_datarootdir}/locale/en\@quot		\\\
+	$RPM_BUILD_ROOT%{_datarootdir}/locale/en		\\\
+	$RPM_BUILD_ROOT%{_infodir}/				\
+cp -a $RPM_BUILD_ROOT%{_datarootdir}/locale/en\@quot		\\\
+	$RPM_BUILD_ROOT%{_datarootdir}/locale/en		\
+cp docs/grub.info $RPM_BUILD_ROOT%{_infodir}/%{name}.info	\
+cp docs/grub-dev.info						\\\
+	$RPM_BUILD_ROOT%{_infodir}/%{name}-dev.info		\
+install -d -m 0700 ${RPM_BUILD_ROOT}%{efi_esp_dir}/		\
+install -d -m 0700 ${RPM_BUILD_ROOT}/boot/grub2/		\
+install -d -m 0700 ${RPM_BUILD_ROOT}/boot/loader/entries	\
+install -d -m 0700 ${RPM_BUILD_ROOT}/boot/%{name}/themes/system	\
+install -d -m 0700 ${RPM_BUILD_ROOT}%{_sysconfdir}/default	\
+install -d -m 0700 ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig	\
+touch ${RPM_BUILD_ROOT}%{_sysconfdir}/default/grub		\
+ln -sf ../default/grub						\\\
+	${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/grub		\
+touch ${RPM_BUILD_ROOT}/boot/%{name}/grub.cfg			\
+%{nil}
+
+%define define_legacy_variant_files()				\
+%{expand:%%files %{1}}						\
+%defattr(-,root,root,-)						\
+%config(noreplace) %{_sysconfdir}/%{name}.cfg			\
+%ghost %config(noreplace) /boot/%{name}/grub.cfg		\
+%dir %attr(0700,root,root)/boot/loader/entries			\
+								\
+%{expand:%if 0%{?with_legacy_modules}				\
+%{expand:%%files %{1}-modules}					\
+%defattr(-,root,root)						\
+%dir %{_libdir}/grub/%{2}/					\
+%{_libdir}/grub/%{2}/*						\
+%exclude %{_libdir}/grub/%{2}/*.module				\
+%exclude %{_libdir}/grub/%{2}/{boot,boot_hybrid,cdboot,diskboot,lzma_decompress,pxeboot}.image \
+%exclude %{_libdir}/grub/%{2}/*.o				\
+%else								\
+%%exclude %%{_libdir}/grub/%%{grublegacyarch}/*			\
+%endif}								\
+%{nil}
+
+%define define_efi_variant_files()				\
+%{expand:%%files %{1}}						\
+%defattr(0700,root,root,-)					\
+%config(noreplace) %{_sysconfdir}/%{name}-efi.cfg		\
+%attr(0700,root,root)%{efi_esp_dir}/%{2}			\
+%dir %attr(0700,root,root)%{efi_esp_dir}/fonts			\
+%dir %attr(0700,root,root)/boot/loader/entries			\
+%ghost %config(noreplace) %attr(0700,root,root)%{efi_esp_dir}/grub.cfg	\
+/boot/grub2/grubenv						\
+%ghost %config(noreplace) %attr(0700,root,root)%{efi_esp_dir}/grubenv	\
+%{expand:%if 0%{?without_efi_modules}				\
+%exclude %{_libdir}/grub/%{6}					\
+%exclude %{_libdir}/grub/%{6}/*					\
+%endif}								\
+								\
+%{expand:%if 0%{?with_efi_modules}				\
+%{expand:%%files %{1}-modules}					\
+%defattr(-,root,root,-)						\
+%dir %{_libdir}/grub/%{6}/					\
+%{_libdir}/grub/%{6}/*						\
+%exclude %{_libdir}/grub/%{6}/*.module				\
+%endif}								\
+								\
+%{expand:%%files %{1}-cdboot}					\
+%defattr(0700,root,root,-)					\
+%attr(0700,root,root)%{efi_esp_dir}/%{3}			\
+%attr(0700,root,root)%{efi_esp_dir}/fonts			\
+%{nil}
diff --git a/SOURCES/grub.patches b/SOURCES/grub.patches
new file mode 100644
index 0000000..558efbe
--- /dev/null
+++ b/SOURCES/grub.patches
@@ -0,0 +1,258 @@
+Patch0001: 0001-Add-support-for-Linux-EFI-stub-loading.patch
+Patch0002: 0002-Rework-linux-command.patch
+Patch0003: 0003-Rework-linux16-command.patch
+Patch0004: 0004-Add-secureboot-support-on-efi-chainloader.patch
+Patch0005: 0005-Make-any-of-the-loaders-that-link-in-efi-mode-honor-.patch
+Patch0006: 0006-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch
+Patch0007: 0007-re-write-.gitignore.patch
+Patch0008: 0008-IBM-client-architecture-CAS-reboot-support.patch
+Patch0009: 0009-for-ppc-reset-console-display-attr-when-clear-screen.patch
+Patch0010: 0010-Disable-GRUB-video-support-for-IBM-power-machines.patch
+Patch0011: 0011-Honor-a-symlink-when-generating-configuration-by-gru.patch
+Patch0012: 0012-Move-bash-completion-script-922997.patch
+Patch0013: 0013-Update-to-minilzo-2.08.patch
+Patch0014: 0014-Allow-fallback-to-include-entries-by-title-not-just-.patch
+Patch0015: 0015-Add-GRUB_DISABLE_UUID.patch
+Patch0016: 0016-Make-exit-take-a-return-code.patch
+Patch0017: 0017-Mark-po-exclude.pot-as-binary-so-git-won-t-try-to-di.patch
+Patch0018: 0018-Make-efi-machines-load-an-env-block-from-a-variable.patch
+Patch0019: 0019-DHCP-client-ID-and-UUID-options-added.patch
+Patch0020: 0020-trim-arp-packets-with-abnormal-size.patch
+Patch0021: 0021-Fix-bad-test-on-GRUB_DISABLE_SUBMENU.patch
+Patch0022: 0022-Add-support-for-UEFI-operating-systems-returned-by-o.patch
+Patch0023: 0023-Migrate-PPC-from-Yaboot-to-Grub2.patch
+Patch0024: 0024-Add-fw_path-variable-revised.patch
+Patch0025: 0025-Pass-x-hex-hex-straight-through-unmolested.patch
+Patch0026: 0026-Add-X-option-to-printf-functions.patch
+Patch0027: 0027-Search-for-specific-config-file-for-netboot.patch
+Patch0028: 0028-blscfg-add-blscfg-module-to-parse-Boot-Loader-Specif.patch
+Patch0029: 0029-Add-devicetree-loading.patch
+Patch0030: 0030-Don-t-write-messages-to-the-screen.patch
+Patch0031: 0031-Don-t-print-GNU-GRUB-header.patch
+Patch0032: 0032-Don-t-add-to-highlighted-row.patch
+Patch0033: 0033-Message-string-cleanups.patch
+Patch0034: 0034-Fix-border-spacing-now-that-we-aren-t-displaying-it.patch
+Patch0035: 0035-Use-the-correct-indentation-for-the-term-help-text.patch
+Patch0036: 0036-Indent-menu-entries.patch
+Patch0037: 0037-Fix-margins.patch
+Patch0038: 0038-Use-2-instead-of-1-for-our-right-hand-margin-so-line.patch
+Patch0039: 0039-Enable-pager-by-default.-985860.patch
+Patch0040: 0040-F10-doesn-t-work-on-serial-so-don-t-tell-the-user-to.patch
+Patch0041: 0041-Don-t-say-GNU-Linux-in-generated-menus.patch
+Patch0042: 0042-Don-t-draw-a-border-around-the-menu.patch
+Patch0043: 0043-Use-the-standard-margin-for-the-timeout-string.patch
+Patch0044: 0044-Add-.eh_frame-to-list-of-relocations-stripped.patch
+Patch0045: 0045-Don-t-munge-raw-spaces-when-we-re-doing-our-cmdline-.patch
+Patch0046: 0046-Don-t-require-a-password-to-boot-entries-generated-b.patch
+Patch0047: 0047-Don-t-emit-Booting-.-message.patch
+Patch0048: 0048-Replace-a-lot-of-man-pages-with-slightly-nicer-ones.patch
+Patch0049: 0049-use-fw_path-prefix-when-fallback-searching-for-grub-.patch
+Patch0050: 0050-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch
+Patch0051: 0051-Fix-convert-function-to-support-NVMe-devices.patch
+Patch0052: 0052-reopen-SNP-protocol-for-exclusive-use-by-grub.patch
+Patch0053: 0053-Revert-reopen-SNP-protocol-for-exclusive-use-by-grub.patch
+Patch0054: 0054-Add-grub_util_readlink.patch
+Patch0055: 0055-Make-editenv-chase-symlinks-including-those-across-d.patch
+Patch0056: 0056-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch
+Patch0057: 0057-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch
+Patch0058: 0058-Try-prefix-if-fw_path-doesn-t-work.patch
+Patch0059: 0059-Update-info-with-grub.cfg-netboot-selection-order-11.patch
+Patch0060: 0060-Use-Distribution-Package-Sort-for-grub2-mkconfig-112.patch
+Patch0061: 0061-Handle-rssd-storage-devices.patch
+Patch0062: 0062-Make-grub2-mkconfig-construct-titles-that-look-like-.patch
+Patch0063: 0063-Add-friendly-grub2-password-config-tool-985962.patch
+Patch0064: 0064-Try-to-make-sure-configure.ac-and-grub-rpm-sort-play.patch
+Patch0065: 0065-tcp-add-window-scaling-support.patch
+Patch0066: 0066-efinet-add-filter-for-the-first-exclusive-reopen-of-.patch
+Patch0067: 0067-Fix-security-issue-when-reading-username-and-passwor.patch
+Patch0068: 0068-Warn-if-grub-password-will-not-be-read-1290803.patch
+Patch0069: 0069-Clean-up-grub-setpassword-documentation-1290799.patch
+Patch0070: 0070-Fix-locale-issue-in-grub-setpassword-1294243.patch
+Patch0071: 0071-efiemu-Handle-persistent-RAM-and-unknown-possible-fu.patch
+Patch0072: 0072-efiemu-Fix-compilation-failure.patch
+Patch0073: 0073-Revert-reopen-SNP-protocol-for-exclusive-use-by-grub.patch
+Patch0074: 0074-Add-a-url-parser.patch
+Patch0075: 0075-efinet-and-bootp-add-support-for-dhcpv6.patch
+Patch0076: 0076-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch
+Patch0077: 0077-Normalize-slashes-in-tftp-paths.patch
+Patch0078: 0078-Fix-malformed-tftp-packets.patch
+Patch0079: 0079-bz1374141-fix-incorrect-mask-for-ppc64.patch
+Patch0080: 0080-Make-grub_fatal-also-backtrace.patch
+Patch0081: 0081-Make-grub-editenv-build-again.patch
+Patch0082: 0082-Fix-up-some-man-pages-rpmdiff-noticed.patch
+Patch0083: 0083-Make-exit-take-a-return-code.patch
+Patch0084: 0084-arm64-make-sure-fdt-has-address-cells-and-size-cells.patch
+Patch0085: 0085-Make-our-info-pages-say-grub2-where-appropriate.patch
+Patch0086: 0086-print-more-debug-info-in-our-module-loader.patch
+Patch0087: 0087-macos-just-build-chainloader-entries-don-t-try-any-x.patch
+Patch0088: 0088-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch
+Patch0089: 0089-export-btrfs_subvol-and-btrfs_subvolid.patch
+Patch0090: 0090-grub2-btrfs-03-follow_default.patch
+Patch0091: 0091-grub2-btrfs-04-grub2-install.patch
+Patch0092: 0092-grub2-btrfs-05-grub2-mkconfig.patch
+Patch0093: 0093-grub2-btrfs-06-subvol-mount.patch
+Patch0094: 0094-No-more-Bootable-Snapshot-submenu-in-grub.cfg.patch
+Patch0095: 0095-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch
+Patch0096: 0096-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch
+Patch0097: 0097-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch
+Patch0098: 0098-Use-grub_efi_.-memory-helpers-where-reasonable.patch
+Patch0099: 0099-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch
+Patch0100: 0100-Don-t-use-dynamic-sized-arrays-since-we-don-t-build-.patch
+Patch0101: 0101-don-t-ignore-const.patch
+Patch0102: 0102-don-t-use-int-for-efi-status.patch
+Patch0103: 0103-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch
+Patch0104: 0104-editenv-handle-relative-symlinks.patch
+Patch0105: 0105-Make-libgrub.pp-depend-on-config-util.h.patch
+Patch0106: 0106-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch
+Patch0107: 0107-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch
+Patch0108: 0108-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch
+Patch0109: 0109-align-struct-efi_variable-better.patch
+Patch0110: 0110-Add-quicksort-implementation.patch
+Patch0111: 0111-Add-blscfg-command-support-to-parse-BootLoaderSpec-c.patch
+Patch0112: 0112-Add-BLS-support-to-grub-mkconfig.patch
+Patch0113: 0113-Remove-duplicated-grub_exit-definition-for-grub-emu-.patch
+Patch0114: 0114-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch
+Patch0115: 0115-Enable-blscfg-command-for-the-emu-platform.patch
+Patch0116: 0116-Add-linux-and-initrd-commands-for-grub-emu.patch
+Patch0117: 0117-Fix-the-efidir-in-grub-setpassword.patch
+Patch0118: 0118-Add-grub2-switch-to-blscfg.patch
+Patch0119: 0119-Add-grub_debug_enabled.patch
+Patch0120: 0120-make-better-backtraces.patch
+Patch0121: 0121-normal-don-t-draw-our-startup-message-if-debug-is-se.patch
+Patch0122: 0122-Work-around-some-minor-include-path-weirdnesses.patch
+Patch0123: 0123-Make-it-possible-to-enabled-build-id-sha1.patch
+Patch0124: 0124-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch
+Patch0125: 0125-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch
+Patch0126: 0126-Only-attempt-to-scan-different-BLS-directories-on-EF.patch
+Patch0127: 0127-Core-TPM-support.patch
+Patch0128: 0128-Measure-kernel-initrd.patch
+Patch0129: 0129-Add-BIOS-boot-measurement.patch
+Patch0130: 0130-Measure-kernel-and-initrd-on-BIOS-systems.patch
+Patch0131: 0131-Measure-the-kernel-commandline.patch
+Patch0132: 0132-Measure-commands.patch
+Patch0133: 0133-Measure-multiboot-images-and-modules.patch
+Patch0134: 0134-Fix-boot-when-there-s-no-TPM.patch
+Patch0135: 0135-Rework-TPM-measurements.patch
+Patch0136: 0136-Fix-event-log-prefix.patch
+Patch0137: 0137-Set-the-first-boot-menu-entry-as-default-when-using-.patch
+Patch0138: 0138-tpm-fix-warnings-when-compiling-for-platforms-other-.patch
+Patch0139: 0139-Make-TPM-errors-less-fatal.patch
+Patch0140: 0140-blscfg-handle-multiple-initramfs-images.patch
+Patch0141: 0141-BLS-Fix-grub2-switch-to-blscfg-on-non-EFI-machines.patch
+Patch0142: 0142-BLS-Use-etcdefaultgrub-instead-of-etc.patch
+Patch0143: 0143-Add-missing-options-to-grub2-switch-to-blscfg-man-pa.patch
+Patch0144: 0144-Make-grub2-switch-to-blscfg-to-generate-debug-BLS-wh.patch
+Patch0145: 0145-Make-grub2-switch-to-blscfg-to-generate-BLS-fragment.patch
+Patch0146: 0146-Only-attempt-to-query-dev-mounted-in-boot-efi-as-boo.patch
+Patch0147: 0147-Include-OSTree-path-when-searching-kernels-images-if.patch
+Patch0148: 0148-Use-BLS-version-field-to-compare-entries-if-id-field.patch
+Patch0149: 0149-Add-version-field-to-BLS-generated-by-grub2-switch-t.patch
+Patch0150: 0150-Fixup-for-newer-compiler.patch
+Patch0151: 0151-Don-t-attempt-to-export-the-start-and-_start-symbols.patch
+Patch0152: 0152-Simplify-BLS-entry-key-val-pairs-lookup.patch
+Patch0153: 0153-Add-relative-path-to-the-kernel-and-initrds-BLS-fiel.patch
+Patch0154: 0154-Skip-leading-spaces-on-BLS-field-values.patch
+Patch0155: 0155-Fixup-for-newer-compiler.patch
+Patch0156: 0156-TPM-Fix-hash_log_extend_event-function-prototype.patch
+Patch0157: 0157-TPM-Fix-compiler-warnings.patch
+Patch0158: 0158-grub-switch-to-blscfg.in-get-rid-of-a-bunch-of-bashi.patch
+Patch0159: 0159-grub-switch-to-blscfg.in-Better-boot-prefix-checking.patch
+Patch0160: 0160-Use-boot-loader-entries-as-BLS-directory-path-also-o.patch
+Patch0161: 0161-Use-BLS-fragment-filename-as-menu-entry-id-and-for-c.patch
+Patch0162: 0162-Fix-grub-switch-to-blscfg-boot-prefix-handling.patch
+Patch0163: 0163-Revert-trim-arp-packets-with-abnormal-size.patch
+Patch0164: 0164-Use-xid-to-match-DHCP-replies.patch
+Patch0165: 0165-Add-support-for-non-Ethernet-network-cards.patch
+Patch0166: 0166-misc-fix-invalid-character-recongition-in-strto-l.patch
+Patch0167: 0167-net-read-bracketed-ipv6-addrs-and-port-numbers.patch
+Patch0168: 0168-net-read-bracketed-ipv6-addrs-and-port-numbers-pjone.patch
+Patch0169: 0169-bootp-New-net_bootp6-command.patch
+Patch0170: 0170-Put-back-our-code-to-add-a-local-route.patch
+Patch0171: 0171-efinet-UEFI-IPv6-PXE-support.patch
+Patch0172: 0172-grub.texi-Add-net_bootp6-doument.patch
+Patch0173: 0173-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch
+Patch0174: 0174-efinet-Setting-network-from-UEFI-device-path.patch
+Patch0175: 0175-efinet-Setting-DNS-server-from-UEFI-protocol.patch
+Patch0176: 0176-Fix-one-more-coverity-complaint.patch
+Patch0177: 0177-Fix-grub_net_hwaddr_to_str.patch
+Patch0178: 0178-Support-UEFI-networking-protocols.patch
+Patch0179: 0179-AUDIT-0-http-boot-tracker-bug.patch
+Patch0180: 0180-grub-core-video-efi_gop.c-Add-support-for-BLT_ONLY-a.patch
+Patch0181: 0181-efi-uga-use-64-bit-for-fb_base.patch
+Patch0182: 0182-EFI-console-Do-not-set-text-mode-until-we-actually-n.patch
+Patch0183: 0183-EFI-console-Add-grub_console_read_key_stroke-helper-.patch
+Patch0184: 0184-EFI-console-Implement-getkeystatus-support.patch
+Patch0185: 0185-Make-grub_getkeystatus-helper-funtion-available-ever.patch
+Patch0186: 0186-Accept-ESC-F8-and-holding-SHIFT-as-user-interrupt-ke.patch
+Patch0187: 0187-grub-editenv-Add-incr-command-to-increment-integer-v.patch
+Patch0188: 0188-Add-auto-hide-menu-support.patch
+Patch0189: 0189-Output-a-menu-entry-for-firmware-setup-on-UEFI-FastB.patch
+Patch0190: 0190-Add-grub-set-bootflag-utility.patch
+Patch0191: 0191-Fix-grub-setpassword-o-s-output-path.patch
+Patch0192: 0192-Make-grub-set-password-be-named-like-all-the-other-g.patch
+Patch0193: 0193-docs-Add-grub-boot-indeterminate.service-example.patch
+Patch0194: 0194-00_menu_auto_hide-Use-a-timeout-of-60s-for-menu_show.patch
+Patch0195: 0195-00_menu_auto_hide-Reduce-number-of-save_env-calls.patch
+Patch0196: 0196-30_uefi-firmware-fix-use-with-sys-firmware-efi-efiva.patch
+Patch0197: 0197-gentpl-add-disable-support.patch
+Patch0198: 0198-gentpl-add-pc-firmware-type.patch
+Patch0199: 0199-blscfg-remove-unused-typedef.patch
+Patch0200: 0200-blscfg-don-t-dynamically-allocate-default_blsdir.patch
+Patch0201: 0201-blscfg-sort-BLS-entries-by-version-field.patch
+Patch0202: 0202-blscfg-remove-NULL-guards-around-grub_free.patch
+Patch0203: 0203-blscfg-fix-filename-in-no-linux-key-error.patch
+Patch0204: 0204-blscfg-don-t-leak-bls_entry.filename.patch
+Patch0205: 0205-blscfg-fix-compilation-on-EFI-and-EMU.patch
+Patch0206: 0206-Add-loadenv-to-blscfg-and-loadenv-source-file-list.patch
+Patch0207: 0207-blscfg-Get-rid-of-the-linuxefi-linux16-linux-distinc.patch
+Patch0208: 0208-grub-switch-to-blscfg-Only-fix-boot-prefix-for-non-g.patch
+Patch0209: 0209-blscfg-Expand-the-BLS-options-field-instead-of-showi.patch
+Patch0210: 0210-blscfg-Fallback-to-search-BLS-snippets-in-boot-loade.patch
+Patch0211: 0211-blscfg-Don-t-attempt-to-sort-by-version-if-not-prese.patch
+Patch0212: 0212-blscfg-remove-logic-to-read-the-grubenv-file-and-set.patch
+Patch0213: 0213-Rename-00_menu_auto_hide.in-to-01_menu_auto_hide.in.patch
+Patch0214: 0214-efinet-also-use-the-firmware-acceleration-for-http.patch
+Patch0215: 0215-efi-http-Make-root_url-reflect-the-protocol-hostname.patch
+Patch0216: 0216-Disable-multiboot-multiboot2-and-linux16-modules-on-.patch
+Patch0217: 0217-Force-everything-to-use-python3.patch
+Patch0218: 0218-Fix-an-8-year-old-typo.patch
+Patch0219: 0219-autogen-don-t-run-autoreconf-in-the-topdir.patch
+Patch0220: 0220-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch
+Patch0221: 0221-module-verifier-make-it-possible-to-run-checkers-on-.patch
+Patch0222: 0222-grub-module-verifier-report-the-filename-or-modname-.patch
+Patch0223: 0223-Make-efi_netfs-not-duplicate-symbols-from-efinet.patch
+Patch0224: 0224-Rework-how-the-fdt-command-builds.patch
+Patch0225: 0225-Disable-non-wordsize-allocations-on-arm.patch
+Patch0226: 0226-strip-R-.note.gnu.property-at-more-places.patch
+Patch0227: 0227-Prepend-prefix-when-HTTP-path-is-relative.patch
+Patch0228: 0228-Make-linux_arm_kernel_header.hdr_offset-be-at-the-ri.patch
+Patch0229: 0229-Mark-some-unused-stuff-unused.patch
+Patch0230: 0230-Make-grub_error-more-verbose.patch
+Patch0231: 0231-arm-arm64-loader-Better-memory-allocation-and-error-.patch
+Patch0232: 0232-drop-TPM-support-for-legacy-BIOS.patch
+Patch0233: 0233-Move-quicksort-function-from-kernel.exec-to-the-blsc.patch
+Patch0234: 0234-Include-blscfg-module-for-powerpc-ieee1275.patch
+Patch0235: 0235-grub-switch-to-blscfg-copy-blscfg-module-for-legacy-.patch
+Patch0236: 0236-Fix-getroot.c-s-trampolines.patch
+Patch0237: 0237-add-10_linux_bls-grub.d-snippet-to-generate-menu-ent.patch
+Patch0238: 0238-Only-set-kernelopts-in-grubenv-if-it-wasn-t-set-befo.patch
+Patch0239: 0239-blscfg-don-t-include-.conf-at-the-end-of-our-id.patch
+Patch0240: 0240-grub-get-kernel-settings-expose-some-more-config-var.patch
+Patch0241: 0241-blscfg-sort-everything-with-rpm-package-comparison.patch
+Patch0242: 0242-10_linux_bls-use-grub2-rpm-sort-instead-of-ls-vr-to-.patch
+Patch0243: 0243-don-t-set-saved_entry-on-grub2-mkconfig.patch
+Patch0244: 0244-grub-switch-to-blscfg-use-debug-instead-of-debug-as-.patch
+Patch0245: 0245-Make-blscfg-debug-messages-more-useful.patch
+Patch0246: 0246-Make-grub_strtoul-end-pointer-have-the-right-constif.patch
+Patch0247: 0247-Fix-menu-entry-selection-based-on-ID-and-title.patch
+Patch0248: 0248-Remove-quotes-when-reading-ID-value-from-etc-os-rele.patch
+Patch0249: 0249-blscfg-expand-grub_users-before-passing-to-grub_norm.patch
+Patch0250: 0250-Make-the-menu-entry-users-option-argument-to-be-opti.patch
+Patch0251: 0251-10_linux_bls-add-missing-menu-entries-options.patch
+Patch0252: 0252-Fix-menu-entry-selection-based-on-title.patch
+Patch0253: 0253-BLS-files-should-only-be-copied-by-grub-switch-to-bl.patch
+Patch0254: 0254-Fix-get_entry_number-wrongly-dereferencing-the-tail-.patch
+Patch0255: 0255-Make-grub2-mkconfig-to-honour-GRUB_CMDLINE_LINUX-in-.patch
+Patch0256: 0256-grub-boot-success.timer-Add-a-few-Conditions-for-run.patch
+Patch0257: 0257-docs-Stop-using-polkit-pkexec-for-grub-boot-success..patch
+Patch0258: 0258-Fix-the-looking-up-grub.cfg-XXX-while-tftp-booting.patch
diff --git a/SOURCES/release-to-master.patch b/SOURCES/release-to-master.patch
new file mode 100644
index 0000000..a1b6e6a
--- /dev/null
+++ b/SOURCES/release-to-master.patch
@@ -0,0 +1,16760 @@
+diff --git a/configure.ac b/configure.ac
+index edd184154f7e9aad556b6437b8ec22bc79d5a057..c7888e40f6695ee23a43fb98420d6cbcd3d86622 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -31,7 +31,7 @@ dnl (such as BUILD_CC, BUILD_CFLAGS, etc.) for the build type and variables
+ dnl with the prefix "TARGET_" (such as TARGET_CC, TARGET_CFLAGS, etc.) are
+ dnl used for the target type. See INSTALL for full list of variables.
+ 
+-AC_INIT([GRUB],[2.02],[bug-grub@gnu.org])
++AC_INIT([GRUB],[2.03],[bug-grub@gnu.org])
+ 
+ AC_CONFIG_AUX_DIR([build-aux])
+ 
+@@ -167,6 +167,7 @@ case "$target_cpu"-"$platform" in
+   mipsel-fuloong) platform=loongson ;;
+   mipsel-loongson) ;;
+   arm-uboot) ;;
++  arm-coreboot) ;;
+   arm-efi) ;;
+   arm64-efi) ;;
+   *-emu) ;;
+@@ -203,7 +204,8 @@ case "$host_os" in
+ esac
+ 
+ case "$host_os" in
+-  cygwin | windows* | mingw32*)	have_exec=n ;;
++  cygwin) have_exec=y ;;
++  windows* | mingw32*) have_exec=n ;;
+   aros*) have_exec=n ;;
+   *) have_exec=y;;
+ esac
+@@ -373,7 +375,10 @@ case "$host_os" in
+      ;;
+   *)
+      AC_CHECK_SIZEOF(off_t)
+-     test x"$ac_cv_sizeof_off_t" = x8 || AC_MSG_ERROR([Large file support is required]);;
++     if test x"$ac_cv_sizeof_off_t" != x8 ; then
++       AC_CHECK_SIZEOF(off64_t)
++       test x"$ac_cv_sizeof_off64_t" = x8 || AC_MSG_ERROR([Large file support is required])
++     fi;;
+ esac
+ 
+ if test x$USE_NLS = xno; then
+@@ -456,6 +461,16 @@ case "$build_os" in
+ esac
+ AC_SUBST(BUILD_EXEEXT)
+ 
++# In some build environments like termux /bin/sh is not a valid
++# shebang. Use $SHELL instead if it's executable and /bin/sh isn't
++BUILD_SHEBANG=/bin/sh
++for she in /bin/sh "$SHELL"; do
++  if test -x "$she" ; then
++    BUILD_SHEBANG="$she"
++  fi
++done
++AC_SUBST(BUILD_SHEBANG)
++
+ # For gnulib.
+ gl_INIT
+ 
+@@ -1905,6 +1920,7 @@ AM_CONDITIONAL([COND_mipsel], [test x$target_cpu = xmipsel])
+ AM_CONDITIONAL([COND_mipseb], [test x$target_cpu = xmips])
+ AM_CONDITIONAL([COND_arm], [test x$target_cpu = xarm ])
+ AM_CONDITIONAL([COND_arm_uboot], [test x$target_cpu = xarm -a x$platform = xuboot])
++AM_CONDITIONAL([COND_arm_coreboot], [test x$target_cpu = xarm -a x$platform = xcoreboot])
+ AM_CONDITIONAL([COND_arm_efi], [test x$target_cpu = xarm -a x$platform = xefi])
+ AM_CONDITIONAL([COND_arm64], [test x$target_cpu = xarm64 ])
+ AM_CONDITIONAL([COND_arm64_efi], [test x$target_cpu = xarm64 -a x$platform = xefi])
+diff --git a/Makefile.util.def b/Makefile.util.def
+index f9caccb9780ffe8d4b31c8a19399ba7bbd308e56..3180ac880a9aa86e94fb47a7386bfa324425bff0 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -99,6 +99,7 @@ library = {
+   common = grub-core/fs/ext2.c;
+   common = grub-core/fs/fat.c;
+   common = grub-core/fs/exfat.c;
++  common = grub-core/fs/f2fs.c;
+   common = grub-core/fs/fshelp.c;
+   common = grub-core/fs/hfs.c;
+   common = grub-core/fs/hfsplus.c;
+@@ -774,6 +775,12 @@ script = {
+   common = tests/xfs_test.in;
+ };
+ 
++script = {
++  testcase;
++  name = f2fs_test;
++  common = tests/f2fs_test.in;
++};
++
+ script = {
+   testcase;
+   name = nilfs2_test;
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 2dfa22a9271bd6624fad9b91ce051ac12202dfbd..9590e87d9c080d6675a9521d91ef6a47d39f2751 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -68,11 +68,11 @@ kernel = {
+   i386_pc_ldflags          = '$(TARGET_IMG_LDFLAGS)';
+   i386_pc_ldflags          = '$(TARGET_IMG_BASE_LDOPT),0x9000';
+   i386_qemu_ldflags        = '$(TARGET_IMG_LDFLAGS)';
+-  i386_qemu_ldflags        = '$(TARGET_IMG_BASE_LDOPT),0x8200';
++  i386_qemu_ldflags        = '$(TARGET_IMG_BASE_LDOPT),0x9000';
+   i386_coreboot_ldflags    = '$(TARGET_IMG_LDFLAGS)';
+-  i386_coreboot_ldflags    = '$(TARGET_IMG_BASE_LDOPT),0x8200';
++  i386_coreboot_ldflags    = '$(TARGET_IMG_BASE_LDOPT),0x9000';
+   i386_multiboot_ldflags   = '$(TARGET_IMG_LDFLAGS)';
+-  i386_multiboot_ldflags   = '$(TARGET_IMG_BASE_LDOPT),0x8200';
++  i386_multiboot_ldflags   = '$(TARGET_IMG_BASE_LDOPT),0x9000';
+   i386_ieee1275_ldflags    = '$(TARGET_IMG_LDFLAGS)';
+   i386_ieee1275_ldflags    = '$(TARGET_IMG_BASE_LDOPT),0x10000';
+   i386_xen_ldflags         = '$(TARGET_IMG_LDFLAGS)';
+@@ -92,6 +92,8 @@ kernel = {
+   emu_cppflags = '$(CPPFLAGS_GNULIB)';
+   arm_uboot_ldflags       = '-Wl,-r,-d';
+   arm_uboot_stripflags    = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
++  arm_coreboot_ldflags       = '-Wl,-r,-d';
++  arm_coreboot_stripflags    = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
+ 
+   i386_pc_startup = kern/i386/pc/startup.S;
+   i386_efi_startup = kern/i386/efi/startup.S;
+@@ -105,7 +107,8 @@ kernel = {
+   mips_startup = kern/mips/startup.S;
+   sparc64_ieee1275_startup = kern/sparc64/ieee1275/crt0.S;
+   powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S;
+-  arm_uboot_startup = kern/arm/uboot/startup.S;
++  arm_uboot_startup = kern/arm/startup.S;
++  arm_coreboot_startup = kern/arm/startup.S;
+   arm_efi_startup = kern/arm/efi/startup.S;
+   arm64_efi_startup = kern/arm64/efi/startup.S;
+ 
+@@ -149,6 +152,21 @@ kernel = {
+   uboot = kern/uboot/init.c;
+   uboot = kern/uboot/hw.c;
+   uboot = term/uboot/console.c;
++  arm_uboot = kern/arm/uboot/init.c;
++  arm_uboot = kern/arm/uboot/uboot.S;
++
++  arm_coreboot = kern/arm/coreboot/init.c;
++  arm_coreboot = kern/arm/coreboot/timer.c;
++  arm_coreboot = kern/arm/coreboot/coreboot.S;
++  arm_coreboot = lib/fdt.c;
++  arm_coreboot = bus/fdt.c;
++  arm_coreboot = term/ps2.c;
++  arm_coreboot = term/arm/pl050.c;
++  arm_coreboot = term/arm/cros.c;
++  arm_coreboot = term/arm/cros_ec.c;
++  arm_coreboot = bus/spi/rk3288_spi.c;
++  arm_coreboot = commands/keylayouts.c;
++  arm_coreboot = kern/arm/coreboot/dma.c;
+ 
+   terminfoinkernel = term/terminfo.c;
+   terminfoinkernel = term/tparm.c;
+@@ -164,7 +182,7 @@ kernel = {
+   i386_multiboot = kern/i386/coreboot/init.c;
+   i386_qemu = kern/i386/qemu/init.c;
+   i386_coreboot_multiboot_qemu = term/i386/pc/vga_text.c;
+-  i386_coreboot = video/i386/coreboot/cbfb.c;
++  coreboot = video/coreboot/cbfb.c;
+ 
+   efi = disk/efi/efidisk.c;
+   efi = kern/efi/efi.c;
+@@ -211,7 +229,6 @@ kernel = {
+   ia64_efi = kern/ia64/cache.c;
+ 
+   arm_efi = kern/arm/efi/init.c;
+-  arm_efi = kern/arm/efi/misc.c;
+   arm_efi = kern/efi/fdt.c;
+ 
+   arm64_efi = kern/arm64/efi/init.c;
+@@ -225,8 +242,10 @@ kernel = {
+   i386_qemu = kern/vga_init.c;
+   i386_qemu = kern/i386/qemu/mmap.c;
+ 
+-  i386_coreboot = kern/i386/coreboot/mmap.c;
++  coreboot = kern/coreboot/mmap.c;
+   i386_coreboot = kern/i386/coreboot/cbtable.c;
++  coreboot = kern/coreboot/cbtable.c;
++  arm_coreboot = kern/arm/coreboot/cbtable.c;
+ 
+   i386_multiboot = kern/i386/multiboot_mmap.c;
+ 
+@@ -238,6 +257,7 @@ kernel = {
+   mips_qemu_mips = term/ns8250.c;
+   mips_qemu_mips = term/serial.c;
+   mips_qemu_mips = term/at_keyboard.c;
++  mips_qemu_mips = term/ps2.c;
+   mips_qemu_mips = commands/boot.c;
+   mips_qemu_mips = commands/keylayouts.c;
+   mips_qemu_mips = term/i386/pc/vga_text.c;
+@@ -253,6 +273,7 @@ kernel = {
+   mips_loongson = bus/pci.c;
+   mips_loongson = kern/mips/loongson/init.c;
+   mips_loongson = term/at_keyboard.c;
++  mips_loongson = term/ps2.c;
+   mips_loongson = commands/boot.c;
+   mips_loongson = term/serial.c;
+   mips_loongson = video/sm712.c;
+@@ -574,7 +595,10 @@ module = {
+ module = {
+   name = ehci;
+   common = bus/usb/ehci.c;
++  arm_coreboot = bus/usb/ehci-fdt.c;
++  pci = bus/usb/ehci-pci.c;
+   enable = pci;
++  enable = arm_coreboot;
+ };
+ 
+ module = {
+@@ -641,6 +665,7 @@ module = {
+ module = {
+   name = cbtable;
+   common = kern/i386/coreboot/cbtable.c;
++  common = kern/coreboot/cbtable.c;
+   enable = i386_pc;
+   enable = i386_efi;
+   enable = i386_qemu;
+@@ -754,6 +779,7 @@ module = {
+   enable = arm_efi;
+   enable = arm64_efi;
+   enable = arm_uboot;
++  enable = arm_coreboot;
+ };
+ 
+ module = {
+@@ -837,17 +863,14 @@ module = {
+   efi = lib/efi/halt.c;
+   ieee1275 = lib/ieee1275/halt.c;
+   emu = lib/emu/halt.c;
+-  uboot = lib/uboot/halt.c;
++  uboot = lib/dummy/halt.c;
++  arm_coreboot = lib/dummy/halt.c;
+ };
+ 
+ module = {
+   name = reboot;
+   i386 = lib/i386/reboot.c;
+   i386 = lib/i386/reboot_trampoline.S;
+-  ia64_efi = lib/efi/reboot.c;
+-  x86_64_efi = lib/efi/reboot.c;
+-  arm_efi = lib/efi/reboot.c;
+-  arm64_efi = lib/efi/reboot.c;
+   powerpc_ieee1275 = lib/ieee1275/reboot.c;
+   sparc64_ieee1275 = lib/ieee1275/reboot.c;
+   mips_arc = lib/mips/arc/reboot.c;
+@@ -855,6 +878,7 @@ module = {
+   mips_qemu_mips = lib/mips/qemu_mips/reboot.c;
+   xen = lib/xen/reboot.c;
+   uboot = lib/uboot/reboot.c;
++  arm_coreboot = lib/dummy/reboot.c;
+   common = commands/reboot.c;
+ };
+ 
+@@ -873,7 +897,6 @@ module = {
+ module = {
+   name = hdparm;
+   common = commands/hdparm.c;
+-  common = lib/hexdump.c;
+   enable = pci;
+   enable = mips_qemu_mips;
+ };
+@@ -1290,6 +1313,11 @@ module = {
+   common = fs/exfat.c;
+ };
+ 
++module = {
++  name = f2fs;
++  common = fs/f2fs.c;
++};
++
+ module = {
+   name = fshelp;
+   common = fs/fshelp.c;
+@@ -1548,7 +1576,8 @@ module = {
+   name = datetime;
+   cmos = lib/cmos_datetime.c;
+   efi = lib/efi/datetime.c;
+-  uboot = lib/uboot/datetime.c;
++  uboot = lib/dummy/datetime.c;
++  arm_coreboot = lib/dummy/datetime.c;
+   sparc64_ieee1275 = lib/ieee1275/datetime.c;
+   powerpc_ieee1275 = lib/ieee1275/datetime.c;
+   sparc64_ieee1275 = lib/ieee1275/cmos.c;
+@@ -1601,8 +1630,6 @@ module = {
+ module = {
+   name = linux16;
+   common = loader/i386/pc/linux.c;
+-  common = loader/linux.c;
+-  common = lib/cmdline.c;
+   enable = x86;
+ };
+ 
+@@ -1637,7 +1664,6 @@ module = {
+   cppflags = "-DGRUB_USE_MULTIBOOT2";
+ 
+   common = loader/multiboot.c;
+-  common = lib/cmdline.c;
+   common = loader/multiboot_mbi2.c;
+   enable = x86;
+   enable = mips;
+@@ -1646,7 +1672,6 @@ module = {
+ module = {
+   name = multiboot;
+   common = loader/multiboot.c;
+-  common = lib/cmdline.c;
+   x86 = loader/i386/multiboot_mbi.c;
+   extra_dist = loader/multiboot_elfxx.c;
+   enable = x86;
+@@ -1654,7 +1679,6 @@ module = {
+ 
+ module = {
+   name = xen_boot;
+-  common = lib/cmdline.c;
+   arm64 = loader/arm64/xen_boot.c;
+   enable = arm64;
+ };
+@@ -1668,7 +1692,9 @@ module = {
+   powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c;
+   sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c;
+   ia64_efi = loader/ia64/efi/linux.c;
+-  arm = loader/arm/linux.c;
++  arm_coreboot = loader/arm/linux.c;
++  arm_efi = loader/arm64/linux.c;
++  arm_uboot = loader/arm/linux.c;
+   arm64 = loader/arm64/linux.c;
+   common = loader/linux.c;
+   common = lib/cmdline.c;
+@@ -1677,7 +1703,7 @@ module = {
+ 
+ module = {
+   name = fdt;
+-  arm64 = loader/arm64/fdt.c;
++  efi = loader/efi/fdt.c;
+   common = lib/fdt.c;
+   enable = fdt;
+ };
+@@ -1869,6 +1895,7 @@ module = {
+ module = {
+   name = at_keyboard;
+   common = term/at_keyboard.c;
++  common = term/ps2.c;
+   enable = x86;
+ };
+ 
+@@ -1961,6 +1988,11 @@ module = {
+   common = tests/example_functional_test.c;
+ };
+ 
++module = {
++  name = strtoull_test;
++  common = tests/strtoull_test.c;
++};
++
+ module = {
+   name = setjmp_test;
+   common = tests/setjmp_test.c;
+diff --git a/grub-core/bus/fdt.c b/grub-core/bus/fdt.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..135da497ba67e7545490e0e73ee3a1fa676a6069
+--- /dev/null
++++ b/grub-core/bus/fdt.c
+@@ -0,0 +1,256 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2016  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/fdtbus.h>
++#include <grub/fdt.h>
++#include <grub/term.h>
++
++static const void *dtb;
++static grub_size_t root_address_cells, root_size_cells;
++/* Pointer to this symbol signals invalid mapping.  */
++char grub_fdtbus_invalid_mapping[1];
++
++struct grub_fdtbus_dev *devs;
++struct grub_fdtbus_driver *drivers;
++
++int
++grub_fdtbus_is_compatible (const char *compat_string,
++			   const struct grub_fdtbus_dev *dev)
++{
++  grub_size_t compatible_size;
++  const char *compatible = grub_fdt_get_prop (dtb, dev->node, "compatible",
++					      &compatible_size);
++  if (!compatible)
++    return 0;
++  const char *compatible_end = compatible + compatible_size;
++  while (compatible < compatible_end)
++    {
++      if (grub_strcmp (compat_string, compatible) == 0)
++	return 1;
++      compatible += grub_strlen (compatible) + 1;
++    }
++  return 0;
++}
++
++static void
++fdtbus_scan (struct grub_fdtbus_dev *parent)
++{
++  int node;
++  for (node = grub_fdt_first_node (dtb, parent ? parent->node : 0); node >= 0;
++       node = grub_fdt_next_node (dtb, node))
++    {
++      struct grub_fdtbus_dev *dev;
++      struct grub_fdtbus_driver *driver;
++      dev = grub_zalloc (sizeof (*dev));
++      if (!dev)
++	{
++	  grub_print_error ();
++	  return;
++	}
++      dev->node = node;
++      dev->next = devs;
++      dev->parent = parent;
++      devs = dev;
++      FOR_LIST_ELEMENTS(driver, drivers)
++	if (!dev->driver && grub_fdtbus_is_compatible (driver->compatible, dev))
++	  {
++	    grub_dprintf ("fdtbus", "Attaching %s\n", driver->compatible);
++	    if (driver->attach (dev) == GRUB_ERR_NONE)
++	      {
++		grub_dprintf ("fdtbus", "Attached %s\n", driver->compatible);
++		dev->driver = driver;
++		break;
++	      }
++	    grub_print_error ();
++	  }
++      fdtbus_scan (dev);
++    }
++}
++
++void
++grub_fdtbus_register (struct grub_fdtbus_driver *driver)
++{
++  struct grub_fdtbus_dev *dev;
++  grub_dprintf ("fdtbus", "Registering %s\n", driver->compatible);
++  grub_list_push (GRUB_AS_LIST_P (&drivers),
++		  GRUB_AS_LIST (driver));
++  for (dev = devs; dev; dev = dev->next)
++    if (!dev->driver && grub_fdtbus_is_compatible (driver->compatible, dev))
++      {
++	grub_dprintf ("fdtbus", "Attaching %s (%p)\n", driver->compatible, dev);
++	if (driver->attach (dev) == GRUB_ERR_NONE)
++	  {
++	    grub_dprintf ("fdtbus", "Attached %s\n", driver->compatible);
++	    dev->driver = driver;
++	  }
++	grub_print_error ();
++      }
++}
++
++void
++grub_fdtbus_unregister (struct grub_fdtbus_driver *driver)
++{
++  grub_list_remove (GRUB_AS_LIST (driver));
++  struct grub_fdtbus_dev *dev;
++  for (dev = devs; dev; dev = dev->next)
++    if (dev->driver == driver)
++      {
++	if (driver->detach)
++	  driver->detach(dev);
++	dev->driver = 0;
++      }
++}
++
++void
++grub_fdtbus_init (const void *dtb_in, grub_size_t size)
++{
++  if (!dtb_in || grub_fdt_check_header (dtb_in, size) < 0)
++    grub_fatal ("invalid FDT");
++  dtb = dtb_in;
++  const grub_uint32_t *prop = grub_fdt_get_prop (dtb, 0, "#address-cells", 0);
++  if (prop)
++    root_address_cells = grub_be_to_cpu32 (*prop);
++  else
++    root_address_cells = 1;
++
++  prop = grub_fdt_get_prop (dtb, 0, "#size-cells", 0);
++  if (prop)
++    root_size_cells = grub_be_to_cpu32 (*prop);
++  else
++    root_size_cells = 1;
++
++  fdtbus_scan (0);
++}
++
++static int
++get_address_cells (const struct grub_fdtbus_dev *dev)
++{
++  const grub_uint32_t *prop;
++  if (!dev)
++    return root_address_cells;
++  prop = grub_fdt_get_prop (dtb, dev->node, "#address-cells", 0);
++  if (prop)
++    return grub_be_to_cpu32 (*prop);
++  return 1;
++}
++
++static int
++get_size_cells (const struct grub_fdtbus_dev *dev)
++{
++  const grub_uint32_t *prop;
++  if (!dev)
++    return root_size_cells;
++  prop = grub_fdt_get_prop (dtb, dev->node, "#size-cells", 0);
++  if (prop)
++    return grub_be_to_cpu32 (*prop);
++  return 1;
++}
++
++static grub_uint64_t
++get64 (const grub_uint32_t *reg, grub_size_t cells)
++{
++  grub_uint64_t val = 0;
++  if (cells >= 1)
++    val = grub_be_to_cpu32 (reg[cells - 1]);
++  if (cells >= 2)
++    val |= ((grub_uint64_t) grub_be_to_cpu32 (reg[cells - 2])) << 32;
++  return val;
++}
++
++static volatile void *
++translate (const struct grub_fdtbus_dev *dev, const grub_uint32_t *reg)
++{
++  volatile void *ret;
++  const grub_uint32_t *ranges;
++  grub_size_t ranges_size, cells_per_mapping;
++  grub_size_t parent_address_cells, child_address_cells, child_size_cells;
++  grub_size_t nmappings, i;
++  if (dev == 0)
++    {
++      grub_uint64_t val;
++      val = get64 (reg, root_address_cells);
++      if (sizeof (void *) == 4 && (val >> 32))
++	return grub_fdtbus_invalid_mapping;
++      return (void *) (grub_addr_t) val;
++    }
++  ranges = grub_fdt_get_prop (dtb, dev->node, "ranges", &ranges_size);
++  if (!ranges)
++    return grub_fdtbus_invalid_mapping;
++  if (ranges_size == 0)
++    return translate (dev->parent, reg);
++  parent_address_cells = get_address_cells (dev->parent);
++  child_address_cells = get_address_cells (dev);
++  child_size_cells = get_size_cells (dev);
++  cells_per_mapping = parent_address_cells + child_address_cells + child_size_cells;
++  nmappings = ranges_size / 4 / cells_per_mapping;
++  for (i = 0; i < nmappings; i++)
++    {
++      const grub_uint32_t *child_addr = &ranges[i * cells_per_mapping];
++      const grub_uint32_t *parent_addr = child_addr + child_address_cells;
++      grub_uint64_t child_size = get64 (parent_addr + parent_address_cells, child_size_cells);
++
++      if (child_address_cells > 2 && grub_memcmp (reg, child_addr, (child_address_cells - 2) * 4) != 0)
++	continue;
++      if (get64 (reg, child_address_cells) < get64 (child_addr, child_address_cells))
++	continue;
++
++      grub_uint64_t offset = get64 (reg, child_address_cells) - get64 (child_addr, child_address_cells);
++      if (offset >= child_size)
++	continue;
++
++      ret = translate (dev->parent, parent_addr);
++      if (grub_fdtbus_is_mapping_valid (ret))
++	ret = (volatile char *) ret + offset;
++      return ret;
++    }
++  return grub_fdtbus_invalid_mapping;
++}
++
++volatile void *
++grub_fdtbus_map_reg (const struct grub_fdtbus_dev *dev, int regno, grub_size_t *size)
++{
++  grub_size_t address_cells, size_cells;
++  address_cells = get_address_cells (dev->parent);
++  size_cells = get_size_cells (dev->parent);
++  const grub_uint32_t *reg = grub_fdt_get_prop (dtb, dev->node, "reg", 0);
++  if (size && size_cells)
++    *size = reg[(address_cells + size_cells) * regno + address_cells];
++  if (size && !size_cells)
++    *size = 0;
++  return translate (dev->parent, reg + (address_cells + size_cells) * regno);
++}
++
++const char *
++grub_fdtbus_get_name (const struct grub_fdtbus_dev *dev)
++{
++  return grub_fdt_get_nodename (dtb, dev->node);
++}
++
++const void *
++grub_fdtbus_get_prop (const struct grub_fdtbus_dev *dev,
++		      const char *name,
++		      grub_uint32_t *len)
++{
++  return grub_fdt_get_prop (dtb, dev->node, name, len);
++}
++
++const void *
++grub_fdtbus_get_fdt (void)
++{
++  return dtb;
++}
+diff --git a/grub-core/bus/spi/rk3288_spi.c b/grub-core/bus/spi/rk3288_spi.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..aacb79ffef103bdbff1bb66dd70229b85b1e8030
+--- /dev/null
++++ b/grub-core/bus/spi/rk3288_spi.c
+@@ -0,0 +1,103 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *
++ *  Copyright (C) 2012  Google Inc.
++ *  Copyright (C) 2016  Free Software Foundation, Inc.
++ *
++ *  This is based on depthcharge code.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/mm.h>
++#include <grub/time.h>
++#include <grub/misc.h>
++#include <grub/fdtbus.h>
++#include <grub/machine/kernel.h>
++
++static grub_err_t
++spi_send (const struct grub_fdtbus_dev *dev, const void *data, grub_size_t sz)
++{
++  const grub_uint8_t *ptr = data, *end = ptr + sz;
++  volatile grub_uint32_t *spi = grub_fdtbus_map_reg (dev, 0, 0);
++  spi[2] = 0;
++  spi[1] = sz - 1;
++  spi[0] = ((1 << 18) | spi[0]) & ~(1 << 19);
++  spi[2] = 1;
++  while (ptr < end)
++    {
++      while (spi[9] & 2);
++      spi[256] = *ptr++;
++    }
++  while (spi[9] & 1);
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++spi_receive (const struct grub_fdtbus_dev *dev, void *data, grub_size_t sz)
++{
++  grub_uint8_t *ptr = data, *end = ptr + sz;
++  volatile grub_uint32_t *spi = grub_fdtbus_map_reg (dev, 0, 0);
++  spi[2] = 0;
++  spi[1] = sz - 1;
++  spi[0] = ((1 << 19) | spi[0]) & ~(1 << 18);
++  spi[2] = 1;
++  while (ptr < end)
++    {
++      while (spi[9] & 8);
++      *ptr++ = spi[512];
++    }
++  while (spi[9] & 1);
++  return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++spi_start (const struct grub_fdtbus_dev *dev)
++{
++  volatile grub_uint32_t *spi = grub_fdtbus_map_reg (dev, 0, 0);
++  spi[3] = 1;
++  return GRUB_ERR_NONE;
++}
++
++static void
++spi_stop (const struct grub_fdtbus_dev *dev)
++{
++  volatile grub_uint32_t *spi = grub_fdtbus_map_reg (dev, 0, 0);
++  spi[3] = 0;
++}
++
++static grub_err_t
++spi_attach(const struct grub_fdtbus_dev *dev)
++{
++  if (!grub_fdtbus_is_mapping_valid (grub_fdtbus_map_reg (dev, 0, 0)))
++    return GRUB_ERR_IO;
++
++  return GRUB_ERR_NONE;
++}
++
++static struct grub_fdtbus_driver spi =
++{
++  .compatible = "rockchip,rk3288-spi",
++  .attach = spi_attach,
++  .send = spi_send,
++  .receive = spi_receive,
++  .start = spi_start,
++  .stop = spi_stop,
++};
++
++void
++grub_rk3288_spi_init (void)
++{
++  grub_fdtbus_register (&spi);
++}
+diff --git a/grub-core/bus/usb/ehci-fdt.c b/grub-core/bus/usb/ehci-fdt.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..29b50bdd5c30d192cc3cba1d7f466a9bcf321d92
+--- /dev/null
++++ b/grub-core/bus/usb/ehci-fdt.c
+@@ -0,0 +1,45 @@
++/* ehci.c - EHCI Support.  */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2011  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/misc.h>
++#include <grub/mm.h>
++#include <grub/time.h>
++#include <grub/usb.h>
++#include <grub/fdtbus.h>
++
++static grub_err_t
++ehci_attach(const struct grub_fdtbus_dev *dev)
++{
++  grub_dprintf ("ehci", "Found generic-ehci\n");
++
++  grub_ehci_init_device (grub_fdtbus_map_reg (dev, 0, 0));
++  return 0;
++}
++
++struct grub_fdtbus_driver ehci =
++{
++  .compatible = "generic-ehci",
++  .attach = ehci_attach
++};
++
++void
++grub_ehci_pci_scan (void)
++{
++  grub_fdtbus_register (&ehci);
++}
+diff --git a/grub-core/bus/usb/ehci-pci.c b/grub-core/bus/usb/ehci-pci.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..65e6cb57438b7dfa35b80bbbe36a1e50629f025f
+--- /dev/null
++++ b/grub-core/bus/usb/ehci-pci.c
+@@ -0,0 +1,208 @@
++/* ehci.c - EHCI Support.  */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2011  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/pci.h>
++#include <grub/cpu/pci.h>
++#include <grub/cs5536.h>
++#include <grub/misc.h>
++#include <grub/mm.h>
++#include <grub/time.h>
++#include <grub/usb.h>
++
++#define GRUB_EHCI_PCI_SBRN_REG  0x60
++#define GRUB_EHCI_ADDR_MEM_MASK	(~0xff)
++
++/* USBLEGSUP bits and related OS OWNED byte offset */
++enum
++{
++  GRUB_EHCI_BIOS_OWNED = (1 << 16),
++  GRUB_EHCI_OS_OWNED = (1 << 24)
++};
++
++/* PCI iteration function... */
++static int
++grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
++		    void *data __attribute__ ((unused)))
++{
++  volatile grub_uint32_t *regs;
++  grub_uint32_t base, base_h;
++  grub_uint32_t eecp_offset;
++  grub_uint32_t usblegsup = 0;
++  grub_uint64_t maxtime;
++  grub_uint32_t interf;
++  grub_uint32_t subclass;
++  grub_uint32_t class;
++  grub_uint8_t release;
++  grub_uint32_t class_code;
++
++  grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: begin\n");
++
++  if (pciid == GRUB_CS5536_PCIID)
++    {
++      grub_uint64_t basereg;
++
++      basereg = grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE);
++      if (!(basereg & GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE))
++	{
++	  /* Shouldn't happen.  */
++	  grub_dprintf ("ehci", "No EHCI address is assigned\n");
++	  return 0;
++	}
++      base = (basereg & GRUB_CS5536_MSR_USB_BASE_ADDR_MASK);
++      basereg |= GRUB_CS5536_MSR_USB_BASE_BUS_MASTER;
++      basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_ENABLED;
++      basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_STATUS;
++      basereg &= ~GRUB_CS5536_MSR_USB_BASE_SMI_ENABLE;
++      grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE, basereg);
++    }
++  else
++    {
++      grub_pci_address_t addr;
++      addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
++      class_code = grub_pci_read (addr) >> 8;
++      interf = class_code & 0xFF;
++      subclass = (class_code >> 8) & 0xFF;
++      class = class_code >> 16;
++
++      /* If this is not an EHCI controller, just return.  */
++      if (class != 0x0c || subclass != 0x03 || interf != 0x20)
++	return 0;
++
++      grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: class OK\n");
++
++      /* Check Serial Bus Release Number */
++      addr = grub_pci_make_address (dev, GRUB_EHCI_PCI_SBRN_REG);
++      release = grub_pci_read_byte (addr);
++      if (release != 0x20)
++	{
++	  grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: Wrong SBRN: %0x\n",
++			release);
++	  return 0;
++	}
++      grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: bus rev. num. OK\n");
++  
++      /* Determine EHCI EHCC registers base address.  */
++      addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
++      base = grub_pci_read (addr);
++      addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG1);
++      base_h = grub_pci_read (addr);
++      /* Stop if registers are mapped above 4G - GRUB does not currently
++       * work with registers mapped above 4G */
++      if (((base & GRUB_PCI_ADDR_MEM_TYPE_MASK) != GRUB_PCI_ADDR_MEM_TYPE_32)
++	  && (base_h != 0))
++	{
++	  grub_dprintf ("ehci",
++			"EHCI grub_ehci_pci_iter: registers above 4G are not supported\n");
++	  return 0;
++	}
++      base &= GRUB_PCI_ADDR_MEM_MASK;
++      if (!base)
++	{
++	  grub_dprintf ("ehci",
++			"EHCI: EHCI is not mapped\n");
++	  return 0;
++	}
++
++      /* Set bus master - needed for coreboot, VMware, broken BIOSes etc. */
++      addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
++      grub_pci_write_word(addr,
++			  GRUB_PCI_COMMAND_MEM_ENABLED
++			  | GRUB_PCI_COMMAND_BUS_MASTER
++			  | grub_pci_read_word(addr));
++      
++      grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: 32-bit EHCI OK\n");
++    }
++
++  grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: iobase of EHCC: %08x\n",
++		(base & GRUB_EHCI_ADDR_MEM_MASK));
++
++  regs = grub_pci_device_map_range (dev,
++				    (base & GRUB_EHCI_ADDR_MEM_MASK),
++				    0x100);
++
++  /* Is there EECP ? */
++  eecp_offset = (grub_le_to_cpu32 (regs[2]) >> 8) & 0xff;
++
++    /* Determine and change ownership. */
++  /* EECP offset valid in HCCPARAMS */
++  /* Ownership can be changed via EECP only */
++  if (pciid != GRUB_CS5536_PCIID && eecp_offset >= 0x40)	
++    {
++      grub_pci_address_t pciaddr_eecp;
++      pciaddr_eecp = grub_pci_make_address (dev, eecp_offset);
++
++      usblegsup = grub_pci_read (pciaddr_eecp);
++      if (usblegsup & GRUB_EHCI_BIOS_OWNED)
++	{
++	  grub_boot_time ("Taking ownership of EHCI controller");
++	  grub_dprintf ("ehci",
++			"EHCI grub_ehci_pci_iter: EHCI owned by: BIOS\n");
++	  /* Ownership change - set OS_OWNED bit */
++	  grub_pci_write (pciaddr_eecp, usblegsup | GRUB_EHCI_OS_OWNED);
++	  /* Ensure PCI register is written */
++	  grub_pci_read (pciaddr_eecp);
++
++	  /* Wait for finish of ownership change, EHCI specification
++	   * doesn't say how long it can take... */
++	  maxtime = grub_get_time_ms () + 1000;
++	  while ((grub_pci_read (pciaddr_eecp) & GRUB_EHCI_BIOS_OWNED)
++		 && (grub_get_time_ms () < maxtime));
++	  if (grub_pci_read (pciaddr_eecp) & GRUB_EHCI_BIOS_OWNED)
++	    {
++	      grub_dprintf ("ehci",
++			    "EHCI grub_ehci_pci_iter: EHCI change ownership timeout");
++	      /* Change ownership in "hard way" - reset BIOS ownership */
++	      grub_pci_write (pciaddr_eecp, GRUB_EHCI_OS_OWNED);
++	      /* Ensure PCI register is written */
++	      grub_pci_read (pciaddr_eecp);
++	    }
++	}
++      else if (usblegsup & GRUB_EHCI_OS_OWNED)
++	/* XXX: What to do in this case - nothing ? Can it happen ? */
++	grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: EHCI owned by: OS\n");
++      else
++	{
++	  grub_dprintf ("ehci",
++			"EHCI grub_ehci_pci_iter: EHCI owned by: NONE\n");
++	  /* XXX: What to do in this case ? Can it happen ?
++	   * Is code below correct ? */
++	  /* Ownership change - set OS_OWNED bit */
++	  grub_pci_write (pciaddr_eecp, GRUB_EHCI_OS_OWNED);
++	  /* Ensure PCI register is written */
++	  grub_pci_read (pciaddr_eecp);
++	}
++
++      /* Disable SMI, just to be sure.  */
++      pciaddr_eecp = grub_pci_make_address (dev, eecp_offset + 4);
++      grub_pci_write (pciaddr_eecp, 0);
++      /* Ensure PCI register is written */
++      grub_pci_read (pciaddr_eecp);
++    }
++
++  grub_dprintf ("ehci", "inithw: EHCI grub_ehci_pci_iter: ownership OK\n");
++
++  grub_ehci_init_device (regs);
++  return 0;
++}
++
++void
++grub_ehci_pci_scan (void)
++{
++  grub_pci_iterate (grub_ehci_pci_iter, NULL);
++}
+diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c
+index 5f4297bb21ec4c28824abb0c442a87a3dd4a872e..d966fc21002602fab3f1b68668ddcb5bfa639442 100644
+--- a/grub-core/bus/usb/ehci.c
++++ b/grub-core/bus/usb/ehci.c
+@@ -22,13 +22,10 @@
+ #include <grub/usb.h>
+ #include <grub/usbtrans.h>
+ #include <grub/misc.h>
+-#include <grub/pci.h>
+-#include <grub/cpu/pci.h>
+-#include <grub/cpu/io.h>
+ #include <grub/time.h>
+ #include <grub/loader.h>
+-#include <grub/cs5536.h>
+ #include <grub/disk.h>
++#include <grub/dma.h>
+ #include <grub/cache.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+@@ -39,8 +36,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
+  *      - is not supporting interrupt transfers
+  */
+ 
+-#define GRUB_EHCI_PCI_SBRN_REG  0x60
+-
+ /* Capability registers offsets */
+ enum
+ {
+@@ -54,7 +49,6 @@ enum
+ #define GRUB_EHCI_EECP_MASK     (0xff << 8)
+ #define GRUB_EHCI_EECP_SHIFT    8
+ 
+-#define GRUB_EHCI_ADDR_MEM_MASK	(~0xff)
+ #define GRUB_EHCI_POINTER_MASK	(~0x1f)
+ 
+ /* Capability register SPARAMS bits */
+@@ -85,13 +79,6 @@ enum
+ 
+ #define GRUB_EHCI_QH_EMPTY 1
+ 
+-/* USBLEGSUP bits and related OS OWNED byte offset */
+-enum
+-{
+-  GRUB_EHCI_BIOS_OWNED = (1 << 16),
+-  GRUB_EHCI_OS_OWNED = (1 << 24)
+-};
+-
+ /* Operational registers offsets */
+ enum
+ {
+@@ -455,9 +442,10 @@ grub_ehci_reset (struct grub_ehci *e)
+ 
+   sync_all_caches (e);
+ 
++  grub_dprintf ("ehci", "reset\n");
++
+   grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
+-			  GRUB_EHCI_CMD_HC_RESET
+-			  | grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
++			  GRUB_EHCI_CMD_HC_RESET);
+   /* Ensure command is written */
+   grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND);
+   /* XXX: How long time could take reset of HC ? */
+@@ -473,116 +461,24 @@ grub_ehci_reset (struct grub_ehci *e)
+ }
+ 
+ /* PCI iteration function... */
+-static int
+-grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+-		    void *data __attribute__ ((unused)))
++void
++grub_ehci_init_device (volatile void *regs)
+ {
+-  grub_uint8_t release;
+-  grub_uint32_t class_code;
+-  grub_uint32_t interf;
+-  grub_uint32_t subclass;
+-  grub_uint32_t class;
+-  grub_uint32_t base, base_h;
+   struct grub_ehci *e;
+-  grub_uint32_t eecp_offset;
+   grub_uint32_t fp;
+   int i;
+-  grub_uint32_t usblegsup = 0;
+-  grub_uint64_t maxtime;
+   grub_uint32_t n_ports;
+   grub_uint8_t caplen;
+ 
+-  grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: begin\n");
+-
+-  if (pciid == GRUB_CS5536_PCIID)
+-    {
+-      grub_uint64_t basereg;
+-
+-      basereg = grub_cs5536_read_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE);
+-      if (!(basereg & GRUB_CS5536_MSR_USB_BASE_MEMORY_ENABLE))
+-	{
+-	  /* Shouldn't happen.  */
+-	  grub_dprintf ("ehci", "No EHCI address is assigned\n");
+-	  return 0;
+-	}
+-      base = (basereg & GRUB_CS5536_MSR_USB_BASE_ADDR_MASK);
+-      basereg |= GRUB_CS5536_MSR_USB_BASE_BUS_MASTER;
+-      basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_ENABLED;
+-      basereg &= ~GRUB_CS5536_MSR_USB_BASE_PME_STATUS;
+-      basereg &= ~GRUB_CS5536_MSR_USB_BASE_SMI_ENABLE;
+-      grub_cs5536_write_msr (dev, GRUB_CS5536_MSR_USB_EHCI_BASE, basereg);
+-    }
+-  else
+-    {
+-      grub_pci_address_t addr;
+-      addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
+-      class_code = grub_pci_read (addr) >> 8;
+-      interf = class_code & 0xFF;
+-      subclass = (class_code >> 8) & 0xFF;
+-      class = class_code >> 16;
+-
+-      /* If this is not an EHCI controller, just return.  */
+-      if (class != 0x0c || subclass != 0x03 || interf != 0x20)
+-	return 0;
+-
+-      grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: class OK\n");
+-
+-      /* Check Serial Bus Release Number */
+-      addr = grub_pci_make_address (dev, GRUB_EHCI_PCI_SBRN_REG);
+-      release = grub_pci_read_byte (addr);
+-      if (release != 0x20)
+-	{
+-	  grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: Wrong SBRN: %0x\n",
+-			release);
+-	  return 0;
+-	}
+-      grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: bus rev. num. OK\n");
+-  
+-      /* Determine EHCI EHCC registers base address.  */
+-      addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0);
+-      base = grub_pci_read (addr);
+-      addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG1);
+-      base_h = grub_pci_read (addr);
+-      /* Stop if registers are mapped above 4G - GRUB does not currently
+-       * work with registers mapped above 4G */
+-      if (((base & GRUB_PCI_ADDR_MEM_TYPE_MASK) != GRUB_PCI_ADDR_MEM_TYPE_32)
+-	  && (base_h != 0))
+-	{
+-	  grub_dprintf ("ehci",
+-			"EHCI grub_ehci_pci_iter: registers above 4G are not supported\n");
+-	  return 0;
+-	}
+-      base &= GRUB_PCI_ADDR_MEM_MASK;
+-      if (!base)
+-	{
+-	  grub_dprintf ("ehci",
+-			"EHCI: EHCI is not mapped\n");
+-	  return 0;
+-	}
+-
+-      /* Set bus master - needed for coreboot, VMware, broken BIOSes etc. */
+-      addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
+-      grub_pci_write_word(addr,
+-			  GRUB_PCI_COMMAND_MEM_ENABLED
+-			  | GRUB_PCI_COMMAND_BUS_MASTER
+-			  | grub_pci_read_word(addr));
+-      
+-      grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: 32-bit EHCI OK\n");
+-    }
+-
+   /* Allocate memory for the controller and fill basic values. */
+   e = grub_zalloc (sizeof (*e));
+   if (!e)
+-    return 1;
++    return;
+   e->framelist_chunk = NULL;
+   e->td_chunk = NULL;
+   e->qh_chunk = NULL;
+-  e->iobase_ehcc = grub_pci_device_map_range (dev,
+-					      (base & GRUB_EHCI_ADDR_MEM_MASK),
+-					      0x100);
++  e->iobase_ehcc = regs;
+ 
+-  grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: iobase of EHCC: %08x\n",
+-		(base & GRUB_EHCI_ADDR_MEM_MASK));
+   grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CAPLEN: %02x\n",
+ 		grub_ehci_ehcc_read8 (e, GRUB_EHCI_EHCC_CAPLEN));
+   grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: VERSION: %04x\n",
+@@ -598,7 +494,7 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+   if (caplen & (sizeof (grub_uint32_t) - 1))
+     {
+       grub_dprintf ("ehci", "Unaligned caplen\n");
+-      return 0;
++      return;
+     }
+   e->iobase = ((volatile grub_uint32_t *) e->iobase_ehcc
+ 	       + (caplen / sizeof (grub_uint32_t)));
+@@ -608,8 +504,8 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+ #endif
+ 
+   grub_dprintf ("ehci",
+-		"EHCI grub_ehci_pci_iter: iobase of oper. regs: %08x\n",
+-		(base & GRUB_EHCI_ADDR_MEM_MASK) + caplen);
++		"EHCI grub_ehci_pci_iter: iobase of oper. regs: %08llxx\n",
++		(unsigned long long) (grub_addr_t) e->iobase_ehcc + caplen);
+   grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: COMMAND: %08x\n",
+ 		grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
+   grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: STATUS: %08x\n",
+@@ -625,10 +521,6 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+   grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CONFIG_FLAG: %08x\n",
+ 		grub_ehci_oper_read32 (e, GRUB_EHCI_CONFIG_FLAG));
+ 
+-  /* Is there EECP ? */
+-  eecp_offset = (grub_ehci_ehcc_read32 (e, GRUB_EHCI_EHCC_CPARAMS)
+-		 & GRUB_EHCI_EECP_MASK) >> GRUB_EHCI_EECP_SHIFT;
+-
+   /* Check format of data structures requested by EHCI */
+   /* XXX: In fact it is not used at any place, it is prepared for future
+    * This implementation uses 32-bits pointers only */
+@@ -732,65 +624,6 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+ 
+   grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: QH/TD init. OK\n");
+ 
+-  /* Determine and change ownership. */
+-  /* EECP offset valid in HCCPARAMS */
+-  /* Ownership can be changed via EECP only */
+-  if (pciid != GRUB_CS5536_PCIID && eecp_offset >= 0x40)	
+-    {
+-      grub_pci_address_t pciaddr_eecp;
+-      pciaddr_eecp = grub_pci_make_address (dev, eecp_offset);
+-
+-      usblegsup = grub_pci_read (pciaddr_eecp);
+-      if (usblegsup & GRUB_EHCI_BIOS_OWNED)
+-	{
+-	  grub_boot_time ("Taking ownership of EHCI controller");
+-	  grub_dprintf ("ehci",
+-			"EHCI grub_ehci_pci_iter: EHCI owned by: BIOS\n");
+-	  /* Ownership change - set OS_OWNED bit */
+-	  grub_pci_write (pciaddr_eecp, usblegsup | GRUB_EHCI_OS_OWNED);
+-	  /* Ensure PCI register is written */
+-	  grub_pci_read (pciaddr_eecp);
+-
+-	  /* Wait for finish of ownership change, EHCI specification
+-	   * doesn't say how long it can take... */
+-	  maxtime = grub_get_time_ms () + 1000;
+-	  while ((grub_pci_read (pciaddr_eecp) & GRUB_EHCI_BIOS_OWNED)
+-		 && (grub_get_time_ms () < maxtime));
+-	  if (grub_pci_read (pciaddr_eecp) & GRUB_EHCI_BIOS_OWNED)
+-	    {
+-	      grub_dprintf ("ehci",
+-			    "EHCI grub_ehci_pci_iter: EHCI change ownership timeout");
+-	      /* Change ownership in "hard way" - reset BIOS ownership */
+-	      grub_pci_write (pciaddr_eecp, GRUB_EHCI_OS_OWNED);
+-	      /* Ensure PCI register is written */
+-	      grub_pci_read (pciaddr_eecp);
+-	    }
+-	}
+-      else if (usblegsup & GRUB_EHCI_OS_OWNED)
+-	/* XXX: What to do in this case - nothing ? Can it happen ? */
+-	grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: EHCI owned by: OS\n");
+-      else
+-	{
+-	  grub_dprintf ("ehci",
+-			"EHCI grub_ehci_pci_iter: EHCI owned by: NONE\n");
+-	  /* XXX: What to do in this case ? Can it happen ?
+-	   * Is code below correct ? */
+-	  /* Ownership change - set OS_OWNED bit */
+-	  grub_pci_write (pciaddr_eecp, GRUB_EHCI_OS_OWNED);
+-	  /* Ensure PCI register is written */
+-	  grub_pci_read (pciaddr_eecp);
+-	}
+-
+-    /* Disable SMI, just to be sure.  */
+-    pciaddr_eecp = grub_pci_make_address (dev, eecp_offset + 4);
+-    grub_pci_write (pciaddr_eecp, 0);
+-    /* Ensure PCI register is written */
+-    grub_pci_read (pciaddr_eecp);
+-
+-    }
+-
+-  grub_dprintf ("ehci", "inithw: EHCI grub_ehci_pci_iter: ownership OK\n");
+-
+   /* Now we can setup EHCI (maybe...) */
+ 
+   /* Check if EHCI is halted and halt it if not */
+@@ -863,8 +696,8 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+   grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: OK at all\n");
+ 
+   grub_dprintf ("ehci",
+-		"EHCI grub_ehci_pci_iter: iobase of oper. regs: %08x\n",
+-		(base & GRUB_EHCI_ADDR_MEM_MASK));
++		"EHCI grub_ehci_pci_iter: iobase of oper. regs: %08llx\n",
++		(unsigned long long) (grub_addr_t) regs);
+   grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: COMMAND: %08x\n",
+ 		grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
+   grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: STATUS: %08x\n",
+@@ -880,7 +713,7 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
+   grub_dprintf ("ehci", "EHCI grub_ehci_pci_iter: CONFIG_FLAG: %08x\n",
+ 		grub_ehci_oper_read32 (e, GRUB_EHCI_CONFIG_FLAG));
+ 
+-  return 0;
++  return;
+ 
+ fail:
+   if (e)
+@@ -894,7 +727,7 @@ fail:
+     }
+   grub_free (e);
+ 
+-  return 0;
++  return;
+ }
+ 
+ static int
+@@ -1891,12 +1724,6 @@ grub_ehci_detect_dev (grub_usb_controller_t dev, int port, int *changed)
+     }
+ }
+ 
+-static void
+-grub_ehci_inithw (void)
+-{
+-  grub_pci_iterate (grub_ehci_pci_iter, NULL);
+-}
+-
+ static grub_err_t
+ grub_ehci_restore_hw (void)
+ {
+@@ -1997,7 +1824,7 @@ GRUB_MOD_INIT (ehci)
+   grub_stop_disk_firmware ();
+ 
+   grub_boot_time ("Initing EHCI hardware");
+-  grub_ehci_inithw ();
++  grub_ehci_pci_scan ();
+   grub_boot_time ("Registering EHCI driver");
+   grub_usb_controller_dev_register (&usb_controller);
+   grub_boot_time ("EHCI driver registered");
+diff --git a/grub-core/bus/usb/usbtrans.c b/grub-core/bus/usb/usbtrans.c
+index 9266e49311c4471d0915aebf9fae05509d0fa5c7..85f081fffb3a2aa7354816c79977ae45a79b1c80 100644
+--- a/grub-core/bus/usb/usbtrans.c
++++ b/grub-core/bus/usb/usbtrans.c
+@@ -18,7 +18,7 @@
+  */
+ 
+ #include <grub/dl.h>
+-#include <grub/pci.h>
++#include <grub/dma.h>
+ #include <grub/mm.h>
+ #include <grub/misc.h>
+ #include <grub/usb.h>
+diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c
+index d901c3892630f2500eda9822c712aae278017907..d1ce99af438914692d1b71b0017050689dd73db9 100644
+--- a/grub-core/commands/efi/lsefi.c
++++ b/grub-core/commands/efi/lsefi.c
+@@ -109,8 +109,10 @@ grub_cmd_lsefi (grub_command_t cmd __attribute__ ((unused)),
+ 
+       status = efi_call_3 (grub_efi_system_table->boot_services->protocols_per_handle,
+ 			   handle, &protocols, &num_protocols);
+-      if (status != GRUB_EFI_SUCCESS)
++      if (status != GRUB_EFI_SUCCESS) {
+ 	grub_printf ("Unable to retrieve protocols\n");
++	continue;
++      }
+       for (j = 0; j < num_protocols; j++)
+ 	{
+ 	  for (k = 0; k < ARRAY_SIZE (known_protocols); k++)
+diff --git a/grub-core/commands/file.c b/grub-core/commands/file.c
+index 12fba99e06a23cb72af67fc4bfb758d97bfa0e67..3ff6d5522d2d572c2af16fec371faeb8e4b28f9d 100644
+--- a/grub-core/commands/file.c
++++ b/grub-core/commands/file.c
+@@ -27,6 +27,8 @@
+ #include <grub/elf.h>
+ #include <grub/xen_file.h>
+ #include <grub/efi/pe32.h>
++#include <grub/arm/linux.h>
++#include <grub/arm64/linux.h>
+ #include <grub/i386/linux.h>
+ #include <grub/xnu.h>
+ #include <grub/machoload.h>
+@@ -383,21 +385,19 @@ grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args)
+       }
+     case IS_ARM_LINUX:
+       {
+-	grub_uint32_t sig, sig_pi;
+-	if (grub_file_read (file, &sig_pi, 4) != 4)
++	struct linux_arm_kernel_header lh;
++
++	if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
+ 	  break;
+-	/* Raspberry pi.  */
+-	if (sig_pi == grub_cpu_to_le32_compile_time (0xea000006))
++	/* Short forward branch in A32 state (for Raspberry pi kernels). */
++	if (lh.code0 == grub_cpu_to_le32_compile_time (0xea000006))
+ 	  {
+ 	    ret = 1;
+ 	    break;
+ 	  }
+ 
+-	if (grub_file_seek (file, 0x24) == (grub_size_t) -1)
+-	  break;
+-	if (grub_file_read (file, &sig, 4) != 4)
+-	  break;
+-	if (sig == grub_cpu_to_le32_compile_time (0x016f2818))
++	if (lh.magic ==
++	    grub_cpu_to_le32_compile_time (GRUB_LINUX_ARM_MAGIC_SIGNATURE))
+ 	  {
+ 	    ret = 1;
+ 	    break;
+@@ -406,13 +406,13 @@ grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args)
+       }
+     case IS_ARM64_LINUX:
+       {
+-	grub_uint32_t sig;
++	struct linux_arm64_kernel_header lh;
+ 
+-	if (grub_file_seek (file, 0x38) == (grub_size_t) -1)
++	if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
+ 	  break;
+-	if (grub_file_read (file, &sig, 4) != 4)
+-	  break;
+-	if (sig == grub_cpu_to_le32_compile_time (0x644d5241))
++
++	if (lh.magic ==
++	    grub_cpu_to_le32_compile_time (GRUB_LINUX_ARM64_MAGIC_SIGNATURE))
+ 	  {
+ 	    ret = 1;
+ 	    break;
+@@ -497,7 +497,7 @@ grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args)
+     case IS_X86_LINUX32:
+     case IS_X86_LINUX:
+       {
+-	struct linux_kernel_header lh;
++	struct linux_i386_kernel_header lh;
+ 	if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
+ 	  break;
+ 	if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
+@@ -508,7 +508,7 @@ grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args)
+ 
+ 	/* FIXME: some really old kernels (< 1.3.73) will fail this.  */
+ 	if (lh.header !=
+-	    grub_cpu_to_le32_compile_time (GRUB_LINUX_MAGIC_SIGNATURE)
++	    grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
+ 	    || grub_le_to_cpu16 (lh.version) < 0x0200)
+ 	  break;
+ 
+@@ -521,7 +521,7 @@ grub_cmd_file (grub_extcmd_context_t ctxt, int argc, char **args)
+ 	/* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
+ 	   still not support 32-bit boot.  */
+ 	if (lh.header !=
+-	    grub_cpu_to_le32_compile_time (GRUB_LINUX_MAGIC_SIGNATURE)
++	    grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
+ 	    || grub_le_to_cpu16 (lh.version) < 0x0203)
+ 	  break;
+ 
+diff --git a/grub-core/commands/i386/coreboot/cb_timestamps.c b/grub-core/commands/i386/coreboot/cb_timestamps.c
+index e72f38d6e057dccfb981d6bbc483d2bdd8a06c98..e97ea6bed98b42d4f03f06ab5bc076fadbfee67f 100644
+--- a/grub-core/commands/i386/coreboot/cb_timestamps.c
++++ b/grub-core/commands/i386/coreboot/cb_timestamps.c
+@@ -20,7 +20,7 @@
+ #include <grub/misc.h>
+ #include <grub/command.h>
+ #include <grub/i18n.h>
+-#include <grub/i386/coreboot/lbio.h>
++#include <grub/coreboot/lbio.h>
+ #include <grub/i386/tsc.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+diff --git a/grub-core/commands/i386/coreboot/cbls.c b/grub-core/commands/i386/coreboot/cbls.c
+index e0a10596fe279331cca94172e1f452fdfe18394f..102291f424ab782c6cd3bcd4ae1effd836cd832e 100644
+--- a/grub-core/commands/i386/coreboot/cbls.c
++++ b/grub-core/commands/i386/coreboot/cbls.c
+@@ -20,7 +20,7 @@
+ #include <grub/misc.h>
+ #include <grub/command.h>
+ #include <grub/i18n.h>
+-#include <grub/i386/coreboot/lbio.h>
++#include <grub/coreboot/lbio.h>
+ #include <grub/i386/tsc.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c
+index f4b7730208ab8ffafb1b0283294a140248839d7a..f35d3a369bad7125cb04e25f0e32c01c00c673b0 100644
+--- a/grub-core/commands/keylayouts.c
++++ b/grub-core/commands/keylayouts.c
+@@ -40,7 +40,7 @@ static struct grub_keyboard_layout layout_us = {
+     /* 0x10 */ 'm',  'n',  'o',  'p',  'q', 'r', 's', 't',
+     /* 0x18 */ 'u',  'v',  'w',  'x',  'y', 'z', '1', '2',
+     /* 0x20 */ '3',  '4',  '5',  '6',  '7', '8', '9', '0',
+-    /* 0x28 */ '\n', '\e', '\b', '\t', ' ', '-', '=', '[',
++    /* 0x28 */ '\n', GRUB_TERM_ESC, GRUB_TERM_BACKSPACE, GRUB_TERM_TAB, ' ', '-', '=', '[',
+     /* According to usage table 0x31 should be mapped to '/'
+        but testing with real keyboard shows that 0x32 is remapped to '/'.
+        Map 0x31 to 0. 
+@@ -82,8 +82,8 @@ static struct grub_keyboard_layout layout_us = {
+     /* 0x10 */ 'M',  'N',  'O',  'P',  'Q', 'R', 'S', 'T',
+     /* 0x18 */ 'U',  'V',  'W',  'X',  'Y', 'Z', '!', '@',
+     /* 0x20 */ '#',  '$',  '%',  '^',  '&', '*', '(', ')',
+-    /* 0x28 */ '\n' | GRUB_TERM_SHIFT, '\e' | GRUB_TERM_SHIFT, 
+-    /* 0x2a */ '\b' | GRUB_TERM_SHIFT, '\t' | GRUB_TERM_SHIFT, 
++    /* 0x28 */ '\n' | GRUB_TERM_SHIFT, GRUB_TERM_ESC | GRUB_TERM_SHIFT,
++    /* 0x2a */ GRUB_TERM_BACKSPACE | GRUB_TERM_SHIFT, GRUB_TERM_TAB | GRUB_TERM_SHIFT,
+     /* 0x2c */ ' '  | GRUB_TERM_SHIFT,  '_', '+', '{',
+     /* According to usage table 0x31 should be mapped to '/'
+        but testing with real keyboard shows that 0x32 is remapped to '/'.
+diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c
+index 0eaf836527944ba69d499050ad080f919d3e57ef..c25161cc4f2c6d4fce6781bfac9bf7796fceb0c7 100644
+--- a/grub-core/commands/ls.c
++++ b/grub-core/commands/ls.c
+@@ -201,6 +201,15 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
+       if (grub_errno == GRUB_ERR_UNKNOWN_FS)
+ 	grub_errno = GRUB_ERR_NONE;
+ 
++#ifdef GRUB_MACHINE_IEEE1275
++      /*
++       * Close device to prevent a double open in grub_normal_print_device_info().
++       * Otherwise it may lead to hangs on some IEEE 1275 platforms.
++       */
++      grub_device_close (dev);
++      dev = NULL;
++#endif
++
+       grub_normal_print_device_info (device_name);
+     }
+   else if (fs)
+diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c
+index 58d4dadf6ee4ec392a09d433802803520704cd7b..2c5363da7f549b85ae04d1d88a78db0b85504c51 100644
+--- a/grub-core/commands/menuentry.c
++++ b/grub-core/commands/menuentry.c
+@@ -52,8 +52,8 @@ static struct
+   int key;
+ } hotkey_aliases[] =
+   {
+-    {"backspace", '\b'},
+-    {"tab", '\t'},
++    {"backspace", GRUB_TERM_BACKSPACE},
++    {"tab", GRUB_TERM_TAB},
+     {"delete", GRUB_TERM_KEY_DC},
+     {"insert", GRUB_TERM_KEY_INSERT},
+     {"f1", GRUB_TERM_KEY_F1},
+diff --git a/grub-core/disk/ahci.c b/grub-core/disk/ahci.c
+index 494a1b7734ef44fef6e887f62b6eb30d0a494284..f2f606423aca4f842f5b16b797a1084cc5791cbb 100644
+--- a/grub-core/disk/ahci.c
++++ b/grub-core/disk/ahci.c
+@@ -82,6 +82,20 @@ enum grub_ahci_hba_port_command
+     GRUB_AHCI_HBA_PORT_CMD_FR = 0x4000,
+   };
+ 
++enum grub_ahci_hba_port_int_status
++  {
++    GRUB_AHCI_HBA_PORT_IS_IFS  = (1UL << 27),
++    GRUB_AHCI_HBA_PORT_IS_HBDS = (1UL << 28),
++    GRUB_AHCI_HBA_PORT_IS_HBFS = (1UL << 29),
++    GRUB_AHCI_HBA_PORT_IS_TFES = (1UL << 30),
++  };
++
++#define GRUB_AHCI_HBA_PORT_IS_FATAL_MASK ( \
++	GRUB_AHCI_HBA_PORT_IS_IFS | \
++	GRUB_AHCI_HBA_PORT_IS_HBDS | \
++	GRUB_AHCI_HBA_PORT_IS_HBFS | \
++	GRUB_AHCI_HBA_PORT_IS_TFES)
++
+ struct grub_ahci_hba
+ {
+   grub_uint32_t cap;
+@@ -1026,7 +1040,8 @@ grub_ahci_readwrite_real (struct grub_ahci_device *dev,
+ 
+   endtime = grub_get_time_ms () + (spinup ? 20000 : 20000);
+   while ((dev->hba->ports[dev->port].command_issue & 1))
+-    if (grub_get_time_ms () > endtime)
++    if (grub_get_time_ms () > endtime ||
++	(dev->hba->ports[dev->port].intstatus & GRUB_AHCI_HBA_PORT_IS_FATAL_MASK))
+       {
+ 	grub_dprintf ("ahci", "AHCI status <%x %x %x %x>\n",
+ 		      dev->hba->ports[dev->port].command_issue,
+@@ -1034,7 +1049,10 @@ grub_ahci_readwrite_real (struct grub_ahci_device *dev,
+ 		      dev->hba->ports[dev->port].intstatus,
+ 		      dev->hba->ports[dev->port].task_file_data);
+ 	dev->hba->ports[dev->port].command_issue = 0;
+-	err = grub_error (GRUB_ERR_IO, "AHCI transfer timed out");
++	if (dev->hba->ports[dev->port].intstatus & GRUB_AHCI_HBA_PORT_IS_FATAL_MASK)
++	  err = grub_error (GRUB_ERR_IO, "AHCI transfer error");
++	else
++	  err = grub_error (GRUB_ERR_IO, "AHCI transfer timed out");
+ 	if (!reset)
+ 	  grub_ahci_reset_port (dev, 1);
+ 	break;
+diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c
+index 0f978ad05079c9535d7ef9bb16462c7d7adeb80e..2a22d2d6c1c3121ec889f33f2aaaf3077723a6c1 100644
+--- a/grub-core/disk/ldm.c
++++ b/grub-core/disk/ldm.c
+@@ -135,7 +135,7 @@ msdos_has_ldm_partition (grub_disk_t dsk)
+   return has_ldm;
+ }
+ 
+-static const grub_gpt_part_type_t ldm_type = GRUB_GPT_PARTITION_TYPE_LDM;
++static const grub_gpt_part_guid_t ldm_type = GRUB_GPT_PARTITION_TYPE_LDM;
+ 
+ /* Helper for gpt_ldm_sector.  */
+ static int
+diff --git a/grub-core/efiemu/i386/loadcore64.c b/grub-core/efiemu/i386/loadcore64.c
+index e49d0b6ff17e02e22e09b306d0a6a32a3b083b78..18facf47fd7678007deb730fb71256edff6292ad 100644
+--- a/grub-core/efiemu/i386/loadcore64.c
++++ b/grub-core/efiemu/i386/loadcore64.c
+@@ -98,6 +98,7 @@ grub_arch_efiemu_relocate_symbols64 (grub_efiemu_segment_t segs,
+ 		    break;
+ 
+ 		  case R_X86_64_PC32:
++		  case R_X86_64_PLT32:
+ 		    err = grub_efiemu_write_value (addr,
+ 						   *addr32 + rel->r_addend
+ 						   + sym.off
+diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c
+index 4849c1ceb6533c1b19eb64d754d45d44282b5acb..be195448dbeb55abcfb117723cd2fc6d75e6e344 100644
+--- a/grub-core/fs/btrfs.c
++++ b/grub-core/fs/btrfs.c
+@@ -175,7 +175,7 @@ struct grub_btrfs_time
+ {
+   grub_int64_t sec;
+   grub_uint32_t nanosec;
+-} __attribute__ ((aligned (4)));
++} GRUB_PACKED;
+ 
+ struct grub_btrfs_inode
+ {
+diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
+index cdce63bcc9d57e82b7a4f6a644803a1d8320935d..b8ad75a0ff7c4f72b67bef123510d99231531daf 100644
+--- a/grub-core/fs/ext2.c
++++ b/grub-core/fs/ext2.c
+@@ -102,6 +102,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define EXT4_FEATURE_INCOMPAT_64BIT		0x0080
+ #define EXT4_FEATURE_INCOMPAT_MMP		0x0100
+ #define EXT4_FEATURE_INCOMPAT_FLEX_BG		0x0200
++#define EXT4_FEATURE_INCOMPAT_ENCRYPT          0x10000
+ 
+ /* The set of back-incompatible features this driver DOES support. Add (OR)
+  * flags here as the related features are implemented into the driver.  */
+@@ -109,7 +110,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
+                                        | EXT4_FEATURE_INCOMPAT_EXTENTS  \
+                                        | EXT4_FEATURE_INCOMPAT_FLEX_BG \
+                                        | EXT2_FEATURE_INCOMPAT_META_BG \
+-                                       | EXT4_FEATURE_INCOMPAT_64BIT)
++                                       | EXT4_FEATURE_INCOMPAT_64BIT \
++                                       | EXT4_FEATURE_INCOMPAT_ENCRYPT)
+ /* List of rationales for the ignored "incompatible" features:
+  * needs_recovery: Not really back-incompatible - was added as such to forbid
+  *                 ext2 drivers from mounting an ext3 volume with a dirty
+@@ -138,6 +140,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define EXT3_JOURNAL_FLAG_DELETED	4
+ #define EXT3_JOURNAL_FLAG_LAST_TAG	8
+ 
++#define EXT4_ENCRYPT_FLAG              0x800
+ #define EXT4_EXTENTS_FLAG		0x80000
+ 
+ /* The ext2 superblock.  */
+@@ -706,6 +709,12 @@ grub_ext2_read_symlink (grub_fshelp_node_t node)
+       grub_ext2_read_inode (diro->data, diro->ino, &diro->inode);
+       if (grub_errno)
+ 	return 0;
++
++      if (diro->inode.flags & grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG))
++       {
++         grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "symlink is encrypted");
++         return 0;
++       }
+     }
+ 
+   symlink = grub_malloc (grub_le_to_cpu32 (diro->inode.size) + 1);
+@@ -749,6 +758,12 @@ grub_ext2_iterate_dir (grub_fshelp_node_t dir,
+ 	return 0;
+     }
+ 
++  if (diro->inode.flags & grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG))
++    {
++      grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "directory is encrypted");
++      return 0;
++    }
++
+   /* Search the file.  */
+   while (fpos < grub_le_to_cpu32 (diro->inode.size))
+     {
+@@ -859,6 +874,12 @@ grub_ext2_open (struct grub_file *file, const char *name)
+ 	goto fail;
+     }
+ 
++  if (fdiro->inode.flags & grub_cpu_to_le32_compile_time (EXT4_ENCRYPT_FLAG))
++    {
++      err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "file is encrypted");
++      goto fail;
++    }
++
+   grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_ext2_inode));
+   grub_free (fdiro);
+ 
+diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..1cad2615f3c9e65e57a12d18b76f4ecc1caa31d8
+--- /dev/null
++++ b/grub-core/fs/f2fs.c
+@@ -0,0 +1,1314 @@
++/*
++ *  f2fs.c - Flash-Friendly File System
++ *
++ *  Written by Jaegeuk Kim <jaegeuk@kernel.org>
++ *
++ *  Copyright (C) 2015  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/err.h>
++#include <grub/file.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/disk.h>
++#include <grub/dl.h>
++#include <grub/types.h>
++#include <grub/charset.h>
++#include <grub/fshelp.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++/* F2FS Magic Number. */
++#define F2FS_SUPER_MAGIC          0xf2f52010
++
++#define CHECKSUM_OFFSET           4092  /* Must be aligned 4 bytes. */
++#define U32_CHECKSUM_OFFSET       (CHECKSUM_OFFSET >> 2)
++#define CRCPOLY_LE                0xedb88320
++
++/* Byte-size offset. */
++#define F2FS_SUPER_OFFSET         ((grub_disk_addr_t)1024)
++#define F2FS_SUPER_OFFSET0        (F2FS_SUPER_OFFSET >> GRUB_DISK_SECTOR_BITS)
++#define F2FS_SUPER_OFFSET1        ((F2FS_SUPER_OFFSET + F2FS_BLKSIZE) >> \
++                                        GRUB_DISK_SECTOR_BITS)
++
++/* 9 bits for 512 bytes. */
++#define F2FS_MIN_LOG_SECTOR_SIZE  9
++
++/* Support only 4KB block. */
++#define F2FS_BLK_BITS             12
++#define F2FS_BLKSIZE              (1 << F2FS_BLK_BITS)
++#define F2FS_BLK_SEC_BITS         (F2FS_BLK_BITS - GRUB_DISK_SECTOR_BITS)
++
++#define VERSION_LEN               256
++#define F2FS_MAX_EXTENSION        64
++
++#define CP_COMPACT_SUM_FLAG       0x00000004
++#define CP_UMOUNT_FLAG            0x00000001
++
++#define MAX_ACTIVE_LOGS           16
++#define MAX_ACTIVE_NODE_LOGS      8
++#define MAX_ACTIVE_DATA_LOGS      8
++#define NR_CURSEG_DATA_TYPE       3
++#define NR_CURSEG_NODE_TYPE       3
++#define NR_CURSEG_TYPE            (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE)
++
++#define ENTRIES_IN_SUM            512
++#define SUMMARY_SIZE              7
++#define SUM_FOOTER_SIZE           5
++#define JENTRY_SIZE               (sizeof(struct grub_f2fs_nat_jent))
++#define SUM_ENTRIES_SIZE          (SUMMARY_SIZE * ENTRIES_IN_SUM)
++#define SUM_JOURNAL_SIZE          (F2FS_BLKSIZE - SUM_FOOTER_SIZE - SUM_ENTRIES_SIZE)
++#define NAT_JOURNAL_ENTRIES       ((SUM_JOURNAL_SIZE - 2) / JENTRY_SIZE)
++#define NAT_JOURNAL_RESERVED      ((SUM_JOURNAL_SIZE - 2) % JENTRY_SIZE)
++
++#define NAT_ENTRY_SIZE            (sizeof(struct grub_f2fs_nat_entry))
++#define NAT_ENTRY_PER_BLOCK       (F2FS_BLKSIZE / NAT_ENTRY_SIZE)
++
++#define F2FS_NAME_LEN             255
++#define F2FS_SLOT_LEN             8
++#define NR_DENTRY_IN_BLOCK        214
++#define SIZE_OF_DIR_ENTRY         11    /* By byte. */
++#define BITS_PER_BYTE             8
++#define SIZE_OF_DENTRY_BITMAP     ((NR_DENTRY_IN_BLOCK + BITS_PER_BYTE - 1) / \
++                                        BITS_PER_BYTE)
++#define SIZE_OF_RESERVED          (F2FS_BLKSIZE - \
++                                        ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
++                                        NR_DENTRY_IN_BLOCK + SIZE_OF_DENTRY_BITMAP))
++
++#define F2FS_INLINE_XATTR_ADDRS   50    /* 200 bytes for inline xattrs. */
++#define DEF_ADDRS_PER_INODE       923   /* Address Pointers in an Inode. */
++
++#define ADDRS_PER_BLOCK           1018  /* Address Pointers in a Direct Block. */
++#define NIDS_PER_BLOCK            1018  /* Node IDs in an Indirect Block. */
++#define NODE_DIR1_BLOCK           (DEF_ADDRS_PER_INODE + 1)
++#define NODE_DIR2_BLOCK           (DEF_ADDRS_PER_INODE + 2)
++#define NODE_IND1_BLOCK           (DEF_ADDRS_PER_INODE + 3)
++#define NODE_IND2_BLOCK           (DEF_ADDRS_PER_INODE + 4)
++#define NODE_DIND_BLOCK           (DEF_ADDRS_PER_INODE + 5)
++
++#define MAX_INLINE_DATA           (4 * (DEF_ADDRS_PER_INODE - \
++                                        F2FS_INLINE_XATTR_ADDRS - 1))
++#define NR_INLINE_DENTRY          (MAX_INLINE_DATA * BITS_PER_BYTE / \
++                                        ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
++                                        BITS_PER_BYTE + 1))
++#define INLINE_DENTRY_BITMAP_SIZE ((NR_INLINE_DENTRY + BITS_PER_BYTE - 1) / \
++                                        BITS_PER_BYTE)
++#define INLINE_RESERVED_SIZE      (MAX_INLINE_DATA - \
++                                        ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
++                                        NR_INLINE_DENTRY + \
++                                        INLINE_DENTRY_BITMAP_SIZE))
++#define CURSEG_HOT_DATA           0
++
++#define CKPT_FLAG_SET(ckpt, f)    (ckpt)->ckpt_flags & \
++                                        grub_cpu_to_le32_compile_time (f)
++
++#define F2FS_INLINE_XATTR         0x01  /* File inline xattr flag. */
++#define F2FS_INLINE_DATA          0x02  /* File inline data flag. */
++#define F2FS_INLINE_DENTRY        0x04  /* File inline dentry flag. */
++#define F2FS_DATA_EXIST           0x08  /* File inline data exist flag. */
++#define F2FS_INLINE_DOTS          0x10  /* File having implicit dot dentries. */
++
++#define MAX_VOLUME_NAME           512
++
++enum FILE_TYPE
++{
++  F2FS_FT_UNKNOWN,
++  F2FS_FT_REG_FILE                = 1,
++  F2FS_FT_DIR                     = 2,
++  F2FS_FT_SYMLINK                 = 7
++};
++
++struct grub_f2fs_superblock
++{
++  grub_uint32_t                   magic;
++  grub_uint16_t                   dummy1[2];
++  grub_uint32_t                   log_sectorsize;
++  grub_uint32_t                   log_sectors_per_block;
++  grub_uint32_t                   log_blocksize;
++  grub_uint32_t                   log_blocks_per_seg;
++  grub_uint32_t                   segs_per_sec;
++  grub_uint32_t                   secs_per_zone;
++  grub_uint32_t                   checksum_offset;
++  grub_uint8_t                    dummy2[40];
++  grub_uint32_t                   cp_blkaddr;
++  grub_uint32_t                   sit_blkaddr;
++  grub_uint32_t                   nat_blkaddr;
++  grub_uint32_t                   ssa_blkaddr;
++  grub_uint32_t                   main_blkaddr;
++  grub_uint32_t                   root_ino;
++  grub_uint32_t                   node_ino;
++  grub_uint32_t                   meta_ino;
++  grub_uint8_t                    uuid[16];
++  grub_uint16_t                   volume_name[MAX_VOLUME_NAME];
++  grub_uint32_t                   extension_count;
++  grub_uint8_t                    extension_list[F2FS_MAX_EXTENSION][8];
++  grub_uint32_t                   cp_payload;
++  grub_uint8_t                    version[VERSION_LEN];
++  grub_uint8_t                    init_version[VERSION_LEN];
++} GRUB_PACKED;
++
++struct grub_f2fs_checkpoint
++{
++  grub_uint64_t                   checkpoint_ver;
++  grub_uint64_t                   user_block_count;
++  grub_uint64_t                   valid_block_count;
++  grub_uint32_t                   rsvd_segment_count;
++  grub_uint32_t                   overprov_segment_count;
++  grub_uint32_t                   free_segment_count;
++  grub_uint32_t                   cur_node_segno[MAX_ACTIVE_NODE_LOGS];
++  grub_uint16_t                   cur_node_blkoff[MAX_ACTIVE_NODE_LOGS];
++  grub_uint32_t                   cur_data_segno[MAX_ACTIVE_DATA_LOGS];
++  grub_uint16_t                   cur_data_blkoff[MAX_ACTIVE_DATA_LOGS];
++  grub_uint32_t                   ckpt_flags;
++  grub_uint32_t                   cp_pack_total_block_count;
++  grub_uint32_t                   cp_pack_start_sum;
++  grub_uint32_t                   valid_node_count;
++  grub_uint32_t                   valid_inode_count;
++  grub_uint32_t                   next_free_nid;
++  grub_uint32_t                   sit_ver_bitmap_bytesize;
++  grub_uint32_t                   nat_ver_bitmap_bytesize;
++  grub_uint32_t                   checksum_offset;
++  grub_uint64_t                   elapsed_time;
++  grub_uint8_t                    alloc_type[MAX_ACTIVE_LOGS];
++  grub_uint8_t                    sit_nat_version_bitmap[3900];
++  grub_uint32_t                   checksum;
++} GRUB_PACKED;
++
++struct grub_f2fs_nat_entry {
++  grub_uint8_t                    version;
++  grub_uint32_t                   ino;
++  grub_uint32_t                   block_addr;
++} GRUB_PACKED;
++
++struct grub_f2fs_nat_jent
++{
++  grub_uint32_t                   nid;
++  struct grub_f2fs_nat_entry      ne;
++} GRUB_PACKED;
++
++struct grub_f2fs_nat_journal {
++  grub_uint16_t                   n_nats;
++  struct grub_f2fs_nat_jent       entries[NAT_JOURNAL_ENTRIES];
++  grub_uint8_t                    reserved[NAT_JOURNAL_RESERVED];
++} GRUB_PACKED;
++
++struct grub_f2fs_nat_block {
++  struct grub_f2fs_nat_entry      ne[NAT_ENTRY_PER_BLOCK];
++} GRUB_PACKED;
++
++struct grub_f2fs_dir_entry
++{
++  grub_uint32_t                   hash_code;
++  grub_uint32_t                   ino;
++  grub_uint16_t                   name_len;
++  grub_uint8_t                    file_type;
++} GRUB_PACKED;
++
++struct grub_f2fs_inline_dentry
++{
++  grub_uint8_t                    dentry_bitmap[INLINE_DENTRY_BITMAP_SIZE];
++  grub_uint8_t                    reserved[INLINE_RESERVED_SIZE];
++  struct grub_f2fs_dir_entry      dentry[NR_INLINE_DENTRY];
++  grub_uint8_t                    filename[NR_INLINE_DENTRY][F2FS_SLOT_LEN];
++} GRUB_PACKED;
++
++struct grub_f2fs_dentry_block {
++  grub_uint8_t                    dentry_bitmap[SIZE_OF_DENTRY_BITMAP];
++  grub_uint8_t                    reserved[SIZE_OF_RESERVED];
++  struct grub_f2fs_dir_entry      dentry[NR_DENTRY_IN_BLOCK];
++  grub_uint8_t                    filename[NR_DENTRY_IN_BLOCK][F2FS_SLOT_LEN];
++} GRUB_PACKED;
++
++struct grub_f2fs_inode
++{
++  grub_uint16_t                   i_mode;
++  grub_uint8_t                    i_advise;
++  grub_uint8_t                    i_inline;
++  grub_uint32_t                   i_uid;
++  grub_uint32_t                   i_gid;
++  grub_uint32_t                   i_links;
++  grub_uint64_t                   i_size;
++  grub_uint64_t                   i_blocks;
++  grub_uint64_t                   i_atime;
++  grub_uint64_t                   i_ctime;
++  grub_uint64_t                   i_mtime;
++  grub_uint32_t                   i_atime_nsec;
++  grub_uint32_t                   i_ctime_nsec;
++  grub_uint32_t                   i_mtime_nsec;
++  grub_uint32_t                   i_generation;
++  grub_uint32_t                   i_current_depth;
++  grub_uint32_t                   i_xattr_nid;
++  grub_uint32_t                   i_flags;
++  grub_uint32_t                   i_pino;
++  grub_uint32_t                   i_namelen;
++  grub_uint8_t                    i_name[F2FS_NAME_LEN];
++  grub_uint8_t                    i_dir_level;
++  grub_uint8_t                    i_ext[12];
++  grub_uint32_t                   i_addr[DEF_ADDRS_PER_INODE];
++  grub_uint32_t                   i_nid[5];
++} GRUB_PACKED;
++
++struct grub_direct_node {
++  grub_uint32_t                   addr[ADDRS_PER_BLOCK];
++} GRUB_PACKED;
++
++struct grub_indirect_node {
++  grub_uint32_t                   nid[NIDS_PER_BLOCK];
++} GRUB_PACKED;
++
++struct grub_f2fs_node
++{
++  union
++  {
++    struct grub_f2fs_inode        i;
++    struct grub_direct_node       dn;
++    struct grub_indirect_node     in;
++    /* Should occupy F2FS_BLKSIZE totally. */
++    char                          buf[F2FS_BLKSIZE - 40];
++  };
++  grub_uint8_t                    dummy[40];
++} GRUB_PACKED;
++
++struct grub_fshelp_node
++{
++  struct grub_f2fs_data           *data;
++  struct grub_f2fs_node           inode;
++  grub_uint32_t                   ino;
++  int inode_read;
++};
++
++struct grub_f2fs_data
++{
++  struct grub_f2fs_superblock     sblock;
++  struct grub_f2fs_checkpoint     ckpt;
++
++  grub_uint32_t                   root_ino;
++  grub_uint32_t                   blocks_per_seg;
++  grub_uint32_t                   cp_blkaddr;
++  grub_uint32_t                   nat_blkaddr;
++
++  struct grub_f2fs_nat_journal    nat_j;
++  char                            *nat_bitmap;
++
++  grub_disk_t                     disk;
++  struct grub_f2fs_node           *inode;
++  struct grub_fshelp_node         diropen;
++};
++
++struct grub_f2fs_dir_iter_ctx
++{
++  struct grub_f2fs_data           *data;
++  grub_fshelp_iterate_dir_hook_t  hook;
++  void                            *hook_data;
++  grub_uint8_t                    *bitmap;
++  grub_uint8_t                    (*filename)[F2FS_SLOT_LEN];
++  struct grub_f2fs_dir_entry      *dentry;
++  int                             max;
++};
++
++struct grub_f2fs_dir_ctx
++{
++  grub_fs_dir_hook_t              hook;
++  void                            *hook_data;
++  struct grub_f2fs_data           *data;
++};
++
++static grub_dl_t my_mod;
++
++static int
++grub_f2fs_test_bit_le (int nr, const grub_uint8_t *addr)
++{
++  return addr[nr >> 3] & (1 << (nr & 7));
++}
++
++static char *
++get_inline_addr (struct grub_f2fs_inode *inode)
++{
++  return (char *) &inode->i_addr[1];
++}
++
++static grub_uint64_t
++grub_f2fs_file_size (struct grub_f2fs_inode *inode)
++{
++  return grub_le_to_cpu64 (inode->i_size);
++}
++
++static grub_uint32_t
++start_cp_addr (struct grub_f2fs_data *data)
++{
++  struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
++  grub_uint32_t start_addr = data->cp_blkaddr;
++
++  if (!(ckpt->checkpoint_ver & grub_cpu_to_le64_compile_time(1)))
++    return start_addr + data->blocks_per_seg;
++
++  return start_addr;
++}
++
++static grub_uint32_t
++start_sum_block (struct grub_f2fs_data *data)
++{
++  struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
++
++  return start_cp_addr (data) + grub_le_to_cpu32 (ckpt->cp_pack_start_sum);
++}
++
++static grub_uint32_t
++sum_blk_addr (struct grub_f2fs_data *data, int base, int type)
++{
++  struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
++
++  return start_cp_addr (data) +
++           grub_le_to_cpu32 (ckpt->cp_pack_total_block_count) -
++           (base + 1) + type;
++}
++
++static void *
++nat_bitmap_ptr (struct grub_f2fs_data *data)
++{
++  struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
++  grub_uint32_t offset;
++
++  if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0)
++    return ckpt->sit_nat_version_bitmap;
++
++  offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize);
++
++  return ckpt->sit_nat_version_bitmap + offset;
++}
++
++static grub_uint32_t
++get_node_id (struct grub_f2fs_node *rn, int off, int inode_block)
++{
++  if (inode_block)
++    return grub_le_to_cpu32 (rn->i.i_nid[off - NODE_DIR1_BLOCK]);
++
++  return grub_le_to_cpu32 (rn->in.nid[off]);
++}
++
++static grub_err_t
++grub_f2fs_block_read (struct grub_f2fs_data *data, grub_uint32_t blkaddr,
++                      void *buf)
++{
++  return grub_disk_read (data->disk,
++                         ((grub_disk_addr_t)blkaddr) << F2FS_BLK_SEC_BITS,
++                         0, F2FS_BLKSIZE, buf);
++}
++
++/* CRC32 */
++static grub_uint32_t
++grub_f2fs_cal_crc32 (const void *buf, const grub_uint32_t len)
++{
++  grub_uint32_t crc = F2FS_SUPER_MAGIC;
++  unsigned char *p = (unsigned char *)buf;
++  grub_uint32_t tmp = len;
++  int i;
++
++  while (tmp--)
++    {
++      crc ^= *p++;
++      for (i = 0; i < 8; i++)
++        crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
++    }
++
++  return crc;
++}
++
++static int
++grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len)
++{
++  grub_uint32_t cal_crc = 0;
++
++  cal_crc = grub_f2fs_cal_crc32 (buf, len);
++
++  return (cal_crc == blk_crc) ? 1 : 0;
++}
++
++static int
++grub_f2fs_test_bit (grub_uint32_t nr, const char *p)
++{
++  int mask;
++
++  p += (nr >> 3);
++  mask = 1 << (7 - (nr & 0x07));
++
++  return mask & *p;
++}
++
++static int
++grub_f2fs_sanity_check_sb (struct grub_f2fs_superblock *sb)
++{
++  grub_uint32_t log_sectorsize, log_sectors_per_block;
++
++  if (sb->magic != grub_cpu_to_le32_compile_time (F2FS_SUPER_MAGIC))
++    return -1;
++
++  if (sb->log_blocksize != grub_cpu_to_le32_compile_time (F2FS_BLK_BITS))
++    return -1;
++
++  log_sectorsize = grub_le_to_cpu32 (sb->log_sectorsize);
++  log_sectors_per_block = grub_le_to_cpu32 (sb->log_sectors_per_block);
++
++  if (log_sectorsize > F2FS_BLK_BITS)
++    return -1;
++
++  if (log_sectorsize < F2FS_MIN_LOG_SECTOR_SIZE)
++    return -1;
++
++  if (log_sectors_per_block + log_sectorsize != F2FS_BLK_BITS)
++    return -1;
++
++  return 0;
++}
++
++static int
++grub_f2fs_read_sb (struct grub_f2fs_data *data, grub_disk_addr_t offset)
++{
++  grub_disk_t disk = data->disk;
++  grub_err_t err;
++
++  /* Read first super block. */
++  err = grub_disk_read (disk, offset, 0, sizeof (data->sblock), &data->sblock);
++  if (err)
++    return -1;
++
++  return grub_f2fs_sanity_check_sb (&data->sblock);
++}
++
++static void *
++validate_checkpoint (struct grub_f2fs_data *data, grub_uint32_t cp_addr,
++                     grub_uint64_t *version)
++{
++  grub_uint32_t *cp_page_1, *cp_page_2;
++  struct grub_f2fs_checkpoint *cp_block;
++  grub_uint64_t cur_version = 0, pre_version = 0;
++  grub_uint32_t crc = 0;
++  grub_uint32_t crc_offset;
++  grub_err_t err;
++
++  /* Read the 1st cp block in this CP pack. */
++  cp_page_1 = grub_malloc (F2FS_BLKSIZE);
++  if (!cp_page_1)
++    return NULL;
++
++  err = grub_f2fs_block_read (data, cp_addr, cp_page_1);
++  if (err)
++    goto invalid_cp1;
++
++  cp_block = (struct grub_f2fs_checkpoint *)cp_page_1;
++  crc_offset = grub_le_to_cpu32 (cp_block->checksum_offset);
++  if (crc_offset != CHECKSUM_OFFSET)
++    goto invalid_cp1;
++
++  crc = grub_le_to_cpu32 (*(cp_page_1 + U32_CHECKSUM_OFFSET));
++  if (!grub_f2fs_crc_valid (crc, cp_block, crc_offset))
++    goto invalid_cp1;
++
++  pre_version = grub_le_to_cpu64 (cp_block->checkpoint_ver);
++
++  /* Read the 2nd cp block in this CP pack. */
++  cp_page_2 = grub_malloc (F2FS_BLKSIZE);
++  if (!cp_page_2)
++    goto invalid_cp1;
++
++  cp_addr += grub_le_to_cpu32 (cp_block->cp_pack_total_block_count) - 1;
++
++  err = grub_f2fs_block_read (data, cp_addr, cp_page_2);
++  if (err)
++    goto invalid_cp2;
++
++  cp_block = (struct grub_f2fs_checkpoint *)cp_page_2;
++  crc_offset = grub_le_to_cpu32 (cp_block->checksum_offset);
++  if (crc_offset != CHECKSUM_OFFSET)
++    goto invalid_cp2;
++
++  crc = grub_le_to_cpu32 (*(cp_page_2 + U32_CHECKSUM_OFFSET));
++  if (!grub_f2fs_crc_valid (crc, cp_block, crc_offset))
++    goto invalid_cp2;
++
++  cur_version = grub_le_to_cpu64 (cp_block->checkpoint_ver);
++  if (cur_version == pre_version)
++    {
++      *version = cur_version;
++      grub_free (cp_page_2);
++
++      return cp_page_1;
++    }
++
++ invalid_cp2:
++  grub_free (cp_page_2);
++
++ invalid_cp1:
++  grub_free (cp_page_1);
++
++  return NULL;
++}
++
++static grub_err_t
++grub_f2fs_read_cp (struct grub_f2fs_data *data)
++{
++  void *cp1, *cp2, *cur_page;
++  grub_uint64_t cp1_version = 0, cp2_version = 0;
++  grub_uint64_t cp_start_blk_no;
++
++  /*
++   * Finding out valid cp block involves read both
++   * sets (cp pack1 and cp pack 2).
++   */
++  cp_start_blk_no = data->cp_blkaddr;
++  cp1 = validate_checkpoint (data, cp_start_blk_no, &cp1_version);
++  if (!cp1 && grub_errno)
++    return grub_errno;
++
++  /* The second checkpoint pack should start at the next segment. */
++  cp_start_blk_no += data->blocks_per_seg;
++  cp2 = validate_checkpoint (data, cp_start_blk_no, &cp2_version);
++  if (!cp2 && grub_errno)
++    {
++      grub_free (cp1);
++      return grub_errno;
++    }
++
++  if (cp1 && cp2)
++    cur_page = (cp2_version > cp1_version) ? cp2 : cp1;
++  else if (cp1)
++    cur_page = cp1;
++  else if (cp2)
++    cur_page = cp2;
++  else
++    return grub_error (GRUB_ERR_BAD_FS, "no checkpoints");
++
++  grub_memcpy (&data->ckpt, cur_page, F2FS_BLKSIZE);
++
++  grub_free (cp1);
++  grub_free (cp2);
++
++  return 0;
++}
++
++static grub_err_t
++get_nat_journal (struct grub_f2fs_data *data)
++{
++  grub_uint32_t block;
++  char *buf;
++  grub_err_t err;
++
++  buf = grub_malloc (F2FS_BLKSIZE);
++  if (!buf)
++    return grub_errno;
++
++  if (CKPT_FLAG_SET(&data->ckpt, CP_COMPACT_SUM_FLAG))
++    block = start_sum_block (data);
++  else if (CKPT_FLAG_SET (&data->ckpt, CP_UMOUNT_FLAG))
++    block = sum_blk_addr (data, NR_CURSEG_TYPE, CURSEG_HOT_DATA);
++  else
++    block = sum_blk_addr (data, NR_CURSEG_DATA_TYPE, CURSEG_HOT_DATA);
++
++  err = grub_f2fs_block_read (data, block, buf);
++  if (err)
++    goto fail;
++
++  if (CKPT_FLAG_SET (&data->ckpt, CP_COMPACT_SUM_FLAG))
++    grub_memcpy (&data->nat_j, buf, SUM_JOURNAL_SIZE);
++  else
++    grub_memcpy (&data->nat_j, buf + SUM_ENTRIES_SIZE, SUM_JOURNAL_SIZE);
++
++ fail:
++  grub_free (buf);
++
++  return err;
++}
++
++static grub_uint32_t
++get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid)
++{
++  grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats);
++  grub_uint32_t blkaddr = 0;
++  grub_uint16_t i;
++
++  for (i = 0; i < n; i++)
++    {
++      if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid)
++        {
++          blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr);
++          break;
++        }
++    }
++
++  return blkaddr;
++}
++
++static grub_uint32_t
++get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
++{
++  struct grub_f2fs_nat_block *nat_block;
++  grub_uint32_t seg_off, block_off, entry_off, block_addr;
++  grub_uint32_t blkaddr;
++  grub_err_t err;
++
++  blkaddr = get_blkaddr_from_nat_journal (data, nid);
++  if (blkaddr)
++    return blkaddr;
++
++  nat_block = grub_malloc (F2FS_BLKSIZE);
++  if (!nat_block)
++    return 0;
++
++  block_off = nid / NAT_ENTRY_PER_BLOCK;
++  entry_off = nid % NAT_ENTRY_PER_BLOCK;
++
++  seg_off = block_off / data->blocks_per_seg;
++  block_addr = data->nat_blkaddr +
++        ((seg_off * data->blocks_per_seg) << 1) +
++        (block_off & (data->blocks_per_seg - 1));
++
++  if (grub_f2fs_test_bit (block_off, data->nat_bitmap))
++    block_addr += data->blocks_per_seg;
++
++  err = grub_f2fs_block_read (data, block_addr, nat_block);
++  if (err)
++    {
++      grub_free (nat_block);
++      return 0;
++    }
++
++  blkaddr = grub_le_to_cpu32 (nat_block->ne[entry_off].block_addr);
++
++  grub_free (nat_block);
++
++  return blkaddr;
++}
++
++static int
++grub_get_node_path (struct grub_f2fs_inode *inode, grub_uint32_t block,
++                    grub_uint32_t offset[4], grub_uint32_t noffset[4])
++{
++  grub_uint32_t direct_blks = ADDRS_PER_BLOCK;
++  grub_uint32_t dptrs_per_blk = NIDS_PER_BLOCK;
++  grub_uint32_t indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
++  grub_uint32_t dindirect_blks = indirect_blks * NIDS_PER_BLOCK;
++  grub_uint32_t direct_index = DEF_ADDRS_PER_INODE;
++  int n = 0;
++  int level = 0;
++
++  if (inode->i_inline & F2FS_INLINE_XATTR)
++    direct_index -= F2FS_INLINE_XATTR_ADDRS;
++
++  noffset[0] = 0;
++
++  if (block < direct_index)
++    {
++      offset[n] = block;
++      goto got;
++    }
++
++  block -= direct_index;
++  if (block < direct_blks)
++    {
++      offset[n++] = NODE_DIR1_BLOCK;
++      noffset[n] = 1;
++      offset[n] = block;
++      level = 1;
++      goto got;
++    }
++
++  block -= direct_blks;
++  if (block < direct_blks)
++    {
++      offset[n++] = NODE_DIR2_BLOCK;
++      noffset[n] = 2;
++      offset[n] = block;
++      level = 1;
++      goto got;
++    }
++
++  block -= direct_blks;
++  if (block < indirect_blks)
++    {
++      offset[n++] = NODE_IND1_BLOCK;
++      noffset[n] = 3;
++      offset[n++] = block / direct_blks;
++      noffset[n] = 4 + offset[n - 1];
++      offset[n] = block % direct_blks;
++      level = 2;
++      goto got;
++    }
++
++  block -= indirect_blks;
++  if (block < indirect_blks)
++    {
++      offset[n++] = NODE_IND2_BLOCK;
++      noffset[n] = 4 + dptrs_per_blk;
++      offset[n++] = block / direct_blks;
++      noffset[n] = 5 + dptrs_per_blk + offset[n - 1];
++      offset[n] = block % direct_blks;
++      level = 2;
++      goto got;
++    }
++
++  block -= indirect_blks;
++  if (block < dindirect_blks)
++    {
++      offset[n++] = NODE_DIND_BLOCK;
++      noffset[n] = 5 + (dptrs_per_blk * 2);
++      offset[n++] = block / indirect_blks;
++      noffset[n] = 6 + (dptrs_per_blk * 2) +
++      offset[n - 1] * (dptrs_per_blk + 1);
++      offset[n++] = (block / direct_blks) % dptrs_per_blk;
++      noffset[n] = 7 + (dptrs_per_blk * 2) +
++      offset[n - 2] * (dptrs_per_blk + 1) + offset[n - 1];
++      offset[n] = block % direct_blks;
++      level = 3;
++      goto got;
++    }
++
++ got:
++  return level;
++}
++
++static grub_err_t
++grub_f2fs_read_node (struct grub_f2fs_data *data,
++                     grub_uint32_t nid, struct grub_f2fs_node *np)
++{
++  grub_uint32_t blkaddr;
++
++  blkaddr = get_node_blkaddr (data, nid);
++  if (!blkaddr)
++    return grub_errno;
++
++  return grub_f2fs_block_read (data, blkaddr, np);
++}
++
++static struct grub_f2fs_data *
++grub_f2fs_mount (grub_disk_t disk)
++{
++  struct grub_f2fs_data *data;
++  grub_err_t err;
++
++  data = grub_malloc (sizeof (*data));
++  if (!data)
++    return NULL;
++
++  data->disk = disk;
++
++  if (grub_f2fs_read_sb (data, F2FS_SUPER_OFFSET0))
++    {
++      if (grub_f2fs_read_sb (data, F2FS_SUPER_OFFSET1))
++        {
++          if (grub_errno == GRUB_ERR_NONE)
++            grub_error (GRUB_ERR_BAD_FS,
++                        "not a F2FS filesystem (no superblock)");
++          goto fail;
++        }
++    }
++
++  data->root_ino = grub_le_to_cpu32 (data->sblock.root_ino);
++  data->cp_blkaddr = grub_le_to_cpu32 (data->sblock.cp_blkaddr);
++  data->nat_blkaddr = grub_le_to_cpu32 (data->sblock.nat_blkaddr);
++  data->blocks_per_seg = 1 <<
++    grub_le_to_cpu32 (data->sblock.log_blocks_per_seg);
++
++  err = grub_f2fs_read_cp (data);
++  if (err)
++    goto fail;
++
++  data->nat_bitmap = nat_bitmap_ptr (data);
++
++  err = get_nat_journal (data);
++  if (err)
++    goto fail;
++
++  data->diropen.data = data;
++  data->diropen.ino = data->root_ino;
++  data->diropen.inode_read = 1;
++  data->inode = &data->diropen.inode;
++
++  err = grub_f2fs_read_node (data, data->root_ino, data->inode);
++  if (err)
++    goto fail;
++
++  return data;
++
++ fail:
++  grub_free (data);
++
++  return NULL;
++}
++
++/* Guarantee inline_data was handled by caller. */
++static grub_disk_addr_t
++grub_f2fs_get_block (grub_fshelp_node_t node, grub_disk_addr_t block_ofs)
++{
++  struct grub_f2fs_data *data = node->data;
++  struct grub_f2fs_inode *inode = &node->inode.i;
++  grub_uint32_t offset[4], noffset[4], nids[4];
++  struct grub_f2fs_node *node_block;
++  grub_uint32_t block_addr = -1;
++  int level, i;
++
++  level = grub_get_node_path (inode, block_ofs, offset, noffset);
++  if (level == 0)
++    return grub_le_to_cpu32 (inode->i_addr[offset[0]]);
++
++  node_block = grub_malloc (F2FS_BLKSIZE);
++  if (!node_block)
++    return -1;
++
++  nids[1] = get_node_id (&node->inode, offset[0], 1);
++
++  /* Get indirect or direct nodes. */
++  for (i = 1; i <= level; i++)
++    {
++      grub_f2fs_read_node (data, nids[i], node_block);
++      if (grub_errno)
++        goto fail;
++
++      if (i < level)
++        nids[i + 1] = get_node_id (node_block, offset[i], 0);
++    }
++
++  block_addr = grub_le_to_cpu32 (node_block->dn.addr[offset[level]]);
++
++ fail:
++  grub_free (node_block);
++
++  return block_addr;
++}
++
++static grub_ssize_t
++grub_f2fs_read_file (grub_fshelp_node_t node,
++                     grub_disk_read_hook_t read_hook, void *read_hook_data,
++                     grub_off_t pos, grub_size_t len, char *buf)
++{
++  struct grub_f2fs_inode *inode = &node->inode.i;
++  grub_off_t filesize = grub_f2fs_file_size (inode);
++  char *inline_addr = get_inline_addr (inode);
++
++  if (inode->i_inline & F2FS_INLINE_DATA)
++    {
++      if (filesize > MAX_INLINE_DATA)
++        return -1;
++
++      if (len > filesize - pos)
++        len = filesize - pos;
++
++      grub_memcpy (buf, inline_addr + pos, len);
++      return len;
++    }
++
++  return grub_fshelp_read_file (node->data->disk, node,
++                                read_hook, read_hook_data,
++                                pos, len, buf, grub_f2fs_get_block,
++                                filesize,
++                                F2FS_BLK_SEC_BITS, 0);
++}
++
++static char *
++grub_f2fs_read_symlink (grub_fshelp_node_t node)
++{
++  char *symlink;
++  struct grub_fshelp_node *diro = node;
++  grub_uint64_t filesize;
++
++  if (!diro->inode_read)
++    {
++      grub_f2fs_read_node (diro->data, diro->ino, &diro->inode);
++      if (grub_errno)
++        return 0;
++    }
++
++  filesize = grub_f2fs_file_size(&diro->inode.i);
++
++  symlink = grub_malloc (filesize + 1);
++  if (!symlink)
++    return 0;
++
++  grub_f2fs_read_file (diro, 0, 0, 0, filesize, symlink);
++  if (grub_errno)
++    {
++      grub_free (symlink);
++      return 0;
++    }
++
++  symlink[filesize] = '\0';
++
++  return symlink;
++}
++
++static int
++grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx)
++{
++  struct grub_fshelp_node *fdiro;
++  int i;
++
++  for (i = 0; i < ctx->max;)
++    {
++      char *filename;
++      enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
++      enum FILE_TYPE ftype;
++      int name_len;
++      int ret;
++
++      if (grub_f2fs_test_bit_le (i, ctx->bitmap) == 0)
++        {
++          i++;
++          continue;
++        }
++
++      ftype = ctx->dentry[i].file_type;
++      name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len);
++      filename = grub_malloc (name_len + 1);
++      if (!filename)
++        return 0;
++
++      grub_memcpy (filename, ctx->filename[i], name_len);
++      filename[name_len] = 0;
++
++      fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
++      if (!fdiro)
++        {
++          grub_free(filename);
++          return 0;
++        }
++
++      if (ftype == F2FS_FT_DIR)
++        type = GRUB_FSHELP_DIR;
++      else if (ftype == F2FS_FT_SYMLINK)
++        type = GRUB_FSHELP_SYMLINK;
++      else if (ftype == F2FS_FT_REG_FILE)
++        type = GRUB_FSHELP_REG;
++
++      fdiro->data = ctx->data;
++      fdiro->ino = grub_le_to_cpu32 (ctx->dentry[i].ino);
++      fdiro->inode_read = 0;
++
++      ret = ctx->hook (filename, type, fdiro, ctx->hook_data);
++      grub_free(filename);
++      if (ret)
++        return 1;
++
++      i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN;
++    }
++
++    return 0;
++}
++
++static int
++grub_f2fs_iterate_inline_dir (struct grub_f2fs_inode *dir,
++                              struct grub_f2fs_dir_iter_ctx *ctx)
++{
++  struct grub_f2fs_inline_dentry *de_blk;
++
++  de_blk = (struct grub_f2fs_inline_dentry *) get_inline_addr (dir);
++
++  ctx->bitmap = de_blk->dentry_bitmap;
++  ctx->dentry = de_blk->dentry;
++  ctx->filename = de_blk->filename;
++  ctx->max = NR_INLINE_DENTRY;
++
++  return grub_f2fs_check_dentries (ctx);
++}
++
++static int
++grub_f2fs_iterate_dir (grub_fshelp_node_t dir,
++                       grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
++{
++  struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
++  struct grub_f2fs_inode *inode;
++  struct grub_f2fs_dir_iter_ctx ctx = {
++    .data = diro->data,
++    .hook = hook,
++    .hook_data = hook_data
++  };
++  grub_off_t fpos = 0;
++
++  if (!diro->inode_read)
++    {
++      grub_f2fs_read_node (diro->data, diro->ino, &diro->inode);
++      if (grub_errno)
++        return 0;
++    }
++
++  inode = &diro->inode.i;
++
++  if (inode->i_inline & F2FS_INLINE_DENTRY)
++    return grub_f2fs_iterate_inline_dir (inode, &ctx);
++
++  while (fpos < grub_f2fs_file_size (inode))
++    {
++      struct grub_f2fs_dentry_block *de_blk;
++      char *buf;
++      int ret;
++
++      buf = grub_zalloc (F2FS_BLKSIZE);
++      if (!buf)
++        return 0;
++
++      grub_f2fs_read_file (diro, 0, 0, fpos, F2FS_BLKSIZE, buf);
++      if (grub_errno)
++        {
++          grub_free (buf);
++          return 0;
++        }
++
++      de_blk = (struct grub_f2fs_dentry_block *) buf;
++
++      ctx.bitmap = de_blk->dentry_bitmap;
++      ctx.dentry = de_blk->dentry;
++      ctx.filename = de_blk->filename;
++      ctx.max = NR_DENTRY_IN_BLOCK;
++
++      ret = grub_f2fs_check_dentries (&ctx);
++      grub_free (buf);
++      if (ret)
++        return 1;
++
++      fpos += F2FS_BLKSIZE;
++    }
++
++  return 0;
++}
++
++static int
++grub_f2fs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype,
++                    grub_fshelp_node_t node, void *data)
++{
++  struct grub_f2fs_dir_ctx *ctx = data;
++  struct grub_dirhook_info info;
++
++  grub_memset (&info, 0, sizeof (info));
++  if (!node->inode_read)
++    {
++      grub_f2fs_read_node (ctx->data, node->ino, &node->inode);
++      if (!grub_errno)
++        node->inode_read = 1;
++      grub_errno = GRUB_ERR_NONE;
++    }
++  if (node->inode_read)
++    {
++      info.mtimeset = 1;
++      info.mtime = grub_le_to_cpu64 (node->inode.i.i_mtime);
++    }
++
++  info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
++  grub_free (node);
++
++  return ctx->hook (filename, &info, ctx->hook_data);
++}
++
++static grub_err_t
++grub_f2fs_dir (grub_device_t device, const char *path,
++               grub_fs_dir_hook_t hook, void *hook_data)
++{
++  struct grub_f2fs_dir_ctx ctx = {
++    .hook = hook,
++    .hook_data = hook_data
++  };
++  struct grub_fshelp_node *fdiro = 0;
++
++  grub_dl_ref (my_mod);
++
++  ctx.data = grub_f2fs_mount (device->disk);
++  if (!ctx.data)
++    goto fail;
++
++  grub_fshelp_find_file (path, &ctx.data->diropen, &fdiro,
++                         grub_f2fs_iterate_dir, grub_f2fs_read_symlink,
++                         GRUB_FSHELP_DIR);
++  if (grub_errno)
++    goto fail;
++
++  grub_f2fs_iterate_dir (fdiro, grub_f2fs_dir_iter, &ctx);
++
++ fail:
++  if (fdiro != &ctx.data->diropen)
++    grub_free (fdiro);
++  grub_free (ctx.data);
++  grub_dl_unref (my_mod);
++
++  return grub_errno;
++}
++
++/* Open a file named NAME and initialize FILE. */
++static grub_err_t
++grub_f2fs_open (struct grub_file *file, const char *name)
++{
++  struct grub_f2fs_data *data = NULL;
++  struct grub_fshelp_node *fdiro = 0;
++  struct grub_f2fs_inode *inode;
++
++  grub_dl_ref (my_mod);
++
++  data = grub_f2fs_mount (file->device->disk);
++  if (!data)
++    goto fail;
++
++  grub_fshelp_find_file (name, &data->diropen, &fdiro,
++                         grub_f2fs_iterate_dir, grub_f2fs_read_symlink,
++                         GRUB_FSHELP_REG);
++  if (grub_errno)
++    goto fail;
++
++  if (!fdiro->inode_read)
++    {
++      grub_f2fs_read_node (data, fdiro->ino, &fdiro->inode);
++      if (grub_errno)
++        goto fail;
++    }
++
++  grub_memcpy (data->inode, &fdiro->inode, sizeof (*data->inode));
++  grub_free (fdiro);
++
++  inode = &(data->inode->i);
++  file->size = grub_f2fs_file_size (inode);
++  file->data = data;
++  file->offset = 0;
++
++  if (inode->i_inline & F2FS_INLINE_DATA && file->size > MAX_INLINE_DATA)
++    grub_error (GRUB_ERR_BAD_FS, "corrupted inline_data: need fsck");
++
++  return 0;
++
++ fail:
++  if (fdiro != &data->diropen)
++    grub_free (fdiro);
++  grub_free (data);
++
++  grub_dl_unref (my_mod);
++
++  return grub_errno;
++}
++
++static grub_ssize_t
++grub_f2fs_read (grub_file_t file, char *buf, grub_size_t len)
++{
++  struct grub_f2fs_data *data = (struct grub_f2fs_data *) file->data;
++
++  return grub_f2fs_read_file (&data->diropen,
++                              file->read_hook, file->read_hook_data,
++                              file->offset, len, buf);
++}
++
++static grub_err_t
++grub_f2fs_close (grub_file_t file)
++{
++  struct grub_f2fs_data *data = (struct grub_f2fs_data *) file->data;
++
++  grub_free (data);
++
++  grub_dl_unref (my_mod);
++
++  return GRUB_ERR_NONE;
++}
++
++static grub_uint8_t *
++grub_f2fs_utf16_to_utf8 (grub_uint16_t *in_buf_le)
++{
++  grub_uint16_t in_buf[MAX_VOLUME_NAME];
++  grub_uint8_t *out_buf;
++  int len = 0;
++
++  out_buf = grub_malloc (MAX_VOLUME_NAME * GRUB_MAX_UTF8_PER_UTF16 + 1);
++  if (!out_buf)
++    return NULL;
++
++  while (*in_buf_le != 0 && len < MAX_VOLUME_NAME) {
++    in_buf[len] = grub_le_to_cpu16 (in_buf_le[len]);
++    len++;
++  }
++
++  *grub_utf16_to_utf8 (out_buf, in_buf, len) = '\0';
++
++  return out_buf;
++}
++
++static grub_err_t
++grub_f2fs_label (grub_device_t device, char **label)
++{
++  struct grub_f2fs_data *data;
++  grub_disk_t disk = device->disk;
++
++  grub_dl_ref (my_mod);
++
++  data = grub_f2fs_mount (disk);
++  if (data)
++    *label = (char *) grub_f2fs_utf16_to_utf8 (data->sblock.volume_name);
++  else
++    *label = NULL;
++
++  grub_free (data);
++  grub_dl_unref (my_mod);
++
++  return grub_errno;
++}
++
++static grub_err_t
++grub_f2fs_uuid (grub_device_t device, char **uuid)
++{
++  struct grub_f2fs_data *data;
++  grub_disk_t disk = device->disk;
++
++  grub_dl_ref (my_mod);
++
++  data = grub_f2fs_mount (disk);
++  if (data)
++    {
++      *uuid =
++        grub_xasprintf
++        ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
++         data->sblock.uuid[0], data->sblock.uuid[1],
++         data->sblock.uuid[2], data->sblock.uuid[3],
++         data->sblock.uuid[4], data->sblock.uuid[5],
++         data->sblock.uuid[6], data->sblock.uuid[7],
++         data->sblock.uuid[8], data->sblock.uuid[9],
++         data->sblock.uuid[10], data->sblock.uuid[11],
++         data->sblock.uuid[12], data->sblock.uuid[13],
++         data->sblock.uuid[14], data->sblock.uuid[15]);
++    }
++  else
++    *uuid = NULL;
++
++  grub_free (data);
++  grub_dl_unref (my_mod);
++
++  return grub_errno;
++}
++
++static struct grub_fs grub_f2fs_fs = {
++  .name                  = "f2fs",
++  .dir                   = grub_f2fs_dir,
++  .open                  = grub_f2fs_open,
++  .read                  = grub_f2fs_read,
++  .close                 = grub_f2fs_close,
++  .label                 = grub_f2fs_label,
++  .uuid                  = grub_f2fs_uuid,
++#ifdef GRUB_UTIL
++  .reserved_first_sector = 1,
++  .blocklist_install     = 0,
++#endif
++  .next                  = 0
++};
++
++GRUB_MOD_INIT (f2fs)
++{
++  grub_fs_register (&grub_f2fs_fs);
++  my_mod = mod;
++}
++
++GRUB_MOD_FINI (f2fs)
++{
++  grub_fs_unregister (&grub_f2fs_fs);
++}
+diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
+index 839bff88963baba7730d788869e1f50481a66a30..00a16098b47aff52a352fa9433e279beae261329 100644
+--- a/grub-core/fs/udf.c
++++ b/grub-core/fs/udf.c
+@@ -321,6 +321,32 @@ struct grub_udf_partmap
+   };
+ } GRUB_PACKED;
+ 
++struct grub_udf_pvd
++{
++  struct grub_udf_tag tag;
++  grub_uint32_t seq_num;
++  grub_uint32_t pvd_num;
++  grub_uint8_t ident[32];
++  grub_uint16_t vol_seq_num;
++  grub_uint16_t max_vol_seq_num;
++  grub_uint16_t interchange_level;
++  grub_uint16_t max_interchange_level;
++  grub_uint32_t charset_list;
++  grub_uint32_t max_charset_list;
++  grub_uint8_t volset_ident[128];
++  struct grub_udf_charspec desc_charset;
++  struct grub_udf_charspec expl_charset;
++  struct grub_udf_extent_ad vol_abstract;
++  struct grub_udf_extent_ad vol_copyright;
++  struct grub_udf_regid app_ident;
++  struct grub_udf_timestamp recording_time;
++  struct grub_udf_regid imp_ident;
++  grub_uint8_t imp_use[64];
++  grub_uint32_t pred_vds_loc;
++  grub_uint16_t flags;
++  grub_uint8_t reserved[22];
++} GRUB_PACKED;
++
+ struct grub_udf_lvd
+ {
+   struct grub_udf_tag tag;
+@@ -348,6 +374,7 @@ struct grub_udf_aed
+ struct grub_udf_data
+ {
+   grub_disk_t disk;
++  struct grub_udf_pvd pvd;
+   struct grub_udf_lvd lvd;
+   struct grub_udf_pd pds[GRUB_UDF_MAX_PDS];
+   struct grub_udf_partmap *pms[GRUB_UDF_MAX_PMS];
+@@ -692,7 +719,17 @@ grub_udf_mount (grub_disk_t disk)
+ 	}
+ 
+       tag.tag_ident = U16 (tag.tag_ident);
+-      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
++      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PVD)
++	{
++	  if (grub_disk_read (disk, block << lbshift, 0,
++			      sizeof (struct grub_udf_pvd),
++			      &data->pvd))
++	    {
++	      grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
++	      goto fail;
++	    }
++	}
++      else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
+ 	{
+ 	  if (data->npd >= GRUB_UDF_MAX_PDS)
+ 	    {
+@@ -860,6 +897,25 @@ read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
+   return outbuf;
+ }
+ 
++static char *
++read_dstring (const grub_uint8_t *raw, grub_size_t sz)
++{
++  grub_size_t len;
++
++  if (raw[0] == 0) {
++      char *outbuf = grub_malloc (1);
++      if (!outbuf)
++	return NULL;
++      outbuf[0] = 0;
++      return outbuf;
++    }
++
++  len = raw[sz - 1];
++  if (len > sz - 1)
++    len = sz - 1;
++  return read_string (raw, len, NULL);
++}
++
+ static int
+ grub_udf_iterate_dir (grub_fshelp_node_t dir,
+ 		      grub_fshelp_iterate_dir_hook_t hook, void *hook_data)
+@@ -1197,7 +1253,7 @@ grub_udf_label (grub_device_t device, char **label)
+ 
+   if (data)
+     {
+-      *label = read_string (data->lvd.ident, sizeof (data->lvd.ident), 0);
++      *label = read_dstring (data->lvd.ident, sizeof (data->lvd.ident));
+       grub_free (data);
+     }
+   else
+@@ -1206,6 +1262,87 @@ grub_udf_label (grub_device_t device, char **label)
+   return grub_errno;
+ }
+ 
++static char *
++gen_uuid_from_volset (char *volset_ident)
++{
++  grub_size_t i;
++  grub_size_t len;
++  grub_size_t nonhexpos;
++  grub_uint8_t buf[17];
++  char *uuid;
++
++  len = grub_strlen (volset_ident);
++  if (len < 8)
++    return NULL;
++
++  uuid = grub_malloc (17);
++  if (!uuid)
++    return NULL;
++
++  if (len > 16)
++    len = 16;
++
++  grub_memset (buf, 0, sizeof (buf));
++  grub_memcpy (buf, volset_ident, len);
++
++  nonhexpos = 16;
++  for (i = 0; i < 16; ++i)
++    {
++      if (!grub_isxdigit (buf[i]))
++        {
++          nonhexpos = i;
++          break;
++        }
++    }
++
++  if (nonhexpos < 8)
++    {
++      grub_snprintf (uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
++                    buf[0], buf[1], buf[2], buf[3],
++                    buf[4], buf[5], buf[6], buf[7]);
++    }
++  else if (nonhexpos < 16)
++    {
++      for (i = 0; i < 8; ++i)
++        uuid[i] = grub_tolower (buf[i]);
++      grub_snprintf (uuid+8, 9, "%02x%02x%02x%02x",
++                    buf[8], buf[9], buf[10], buf[11]);
++    }
++  else
++    {
++      for (i = 0; i < 16; ++i)
++        uuid[i] = grub_tolower (buf[i]);
++      uuid[16] = 0;
++    }
++
++  return uuid;
++}
++
++static grub_err_t
++grub_udf_uuid (grub_device_t device, char **uuid)
++{
++  char *volset_ident;
++  struct grub_udf_data *data;
++  data = grub_udf_mount (device->disk);
++
++  if (data)
++    {
++      volset_ident = read_dstring (data->pvd.volset_ident, sizeof (data->pvd.volset_ident));
++      if (volset_ident)
++        {
++          *uuid = gen_uuid_from_volset (volset_ident);
++          grub_free (volset_ident);
++        }
++      else
++        *uuid = 0;
++      grub_free (data);
++    }
++  else
++    *uuid = 0;
++
++  return grub_errno;
++}
++
+ static struct grub_fs grub_udf_fs = {
+   .name = "udf",
+   .dir = grub_udf_dir,
+@@ -1213,6 +1350,7 @@ static struct grub_fs grub_udf_fs = {
+   .read = grub_udf_read,
+   .close = grub_udf_close,
+   .label = grub_udf_label,
++  .uuid = grub_udf_uuid,
+ #ifdef GRUB_UTIL
+   .reserved_first_sector = 1,
+   .blocklist_install = 1,
+diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
+index 9f66dd6e4c6491e6b2cbfc7866335b432c824502..3b00c744e23c34243df781baa96e5b1b0d88417d 100644
+--- a/grub-core/fs/xfs.c
++++ b/grub-core/fs/xfs.c
+@@ -79,9 +79,18 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #define XFS_SB_FEAT_INCOMPAT_SPINODES   (1 << 1)        /* sparse inode chunks */
+ #define XFS_SB_FEAT_INCOMPAT_META_UUID  (1 << 2)        /* metadata UUID */
+ 
+-/* We do not currently verify metadata UUID so it is safe to read such filesystem */
++/*
++ * Directory entries with ftype are explicitly handled by GRUB code.
++ *
++ * We do not currently read the inode btrees, so it is safe to read filesystems
++ * with the XFS_SB_FEAT_INCOMPAT_SPINODES feature.
++ *
++ * We do not currently verify metadata UUID, so it is safe to read filesystems
++ * with the XFS_SB_FEAT_INCOMPAT_META_UUID feature.
++ */
+ #define XFS_SB_FEAT_INCOMPAT_SUPPORTED \
+ 	(XFS_SB_FEAT_INCOMPAT_FTYPE | \
++	 XFS_SB_FEAT_INCOMPAT_SPINODES | \
+ 	 XFS_SB_FEAT_INCOMPAT_META_UUID)
+ 
+ struct grub_xfs_sblock
+@@ -828,6 +837,9 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
+ 	    entries = (grub_be_to_cpu32 (tail->leaf_count)
+ 		       - grub_be_to_cpu32 (tail->leaf_stale));
+ 
++	    if (!entries)
++	      continue;
++
+ 	    /* Iterate over all entries within this block.  */
+ 	    while ((char *)direntry < (char *)tail)
+ 	      {
+diff --git a/grub-core/fs/zfs/zfs_lz4.c b/grub-core/fs/zfs/zfs_lz4.c
+index 2f73449f0d4c63cadc7b5b4388250a4d474594b6..5453822d0258527ba751e551cbb54753f0331043 100644
+--- a/grub-core/fs/zfs/zfs_lz4.c
++++ b/grub-core/fs/zfs/zfs_lz4.c
+@@ -73,7 +73,6 @@ static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest,
+ #define	U32	grub_uint32_t
+ #define	S32	grub_int32_t
+ #define	U64	grub_uint64_t
+-typedef grub_size_t size_t;
+ 
+ typedef struct _U16_S {
+ 	U16 v;
+@@ -133,10 +132,10 @@ typedef struct _U64_S {
+ 
+ /* Decompression functions */
+ grub_err_t
+-lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len);
++lz4_decompress(void *s_start, void *d_start, grub_size_t s_len, grub_size_t d_len);
+ 
+ grub_err_t
+-lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len)
++lz4_decompress(void *s_start, void *d_start, grub_size_t s_len, grub_size_t d_len)
+ {
+ 	const BYTE *src = s_start;
+ 	U32 bufsiz = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) |
+@@ -167,7 +166,7 @@ LZ4_uncompress_unknownOutputSize(const char *source,
+ 	BYTE *const oend = op + maxOutputSize;
+ 	BYTE *cpy;
+ 
+-	size_t dec[] = { 0, 3, 2, 3, 0, 0, 0, 0 };
++	grub_size_t dec[] = { 0, 3, 2, 3, 0, 0, 0, 0 };
+ 
+ 	/* Main Loop */
+ 	while (ip < iend) {
+@@ -237,8 +236,8 @@ LZ4_uncompress_unknownOutputSize(const char *source,
+ 		/* copy repeated sequence */
+ 		if unlikely(op - ref < STEPSIZE) {
+ #if LZ4_ARCH64
+-			size_t dec2table[] = { 0, 0, 0, -1, 0, 1, 2, 3 };
+-			size_t dec2 = dec2table[op - ref];
++			grub_size_t dec2table[] = { 0, 0, 0, -1, 0, 1, 2, 3 };
++			grub_size_t dec2 = dec2table[op - ref];
+ #else
+ 			const int dec2 = 0;
+ #endif
+diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c
+index 22438277d7456358dfc6bcbb51317fd704987738..dbed64744317c2f849fb2bda8fd5a6b142affe91 100644
+--- a/grub-core/io/bufio.c
++++ b/grub-core/io/bufio.c
+@@ -61,6 +61,13 @@ grub_bufio_open (grub_file_t io, int size)
+     size = ((io->size > GRUB_BUFIO_MAX_SIZE) ? GRUB_BUFIO_MAX_SIZE :
+             io->size);
+ 
++  /*
++   * Round up size to power of 2 which the binary math to
++   * calculate next_buf in grub_bufio_read() requires.
++   */
++  while (size & (size - 1))
++    size = (size | (size - 1)) + 1;
++
+   bufio = grub_zalloc (sizeof (struct grub_bufio) + size);
+   if (! bufio)
+     {
+diff --git a/grub-core/io/gzio.c b/grub-core/io/gzio.c
+index 0f2ea6bd845227265eef205c212e7c52ee03ebcf..86ea8cfdea2e0abd1f73c6df4dca58806c8f2d9b 100644
+--- a/grub-core/io/gzio.c
++++ b/grub-core/io/gzio.c
+@@ -43,6 +43,7 @@
+ #include <grub/dl.h>
+ #include <grub/deflate.h>
+ #include <grub/i18n.h>
++#include <grub/crypto.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+@@ -94,6 +95,14 @@ struct grub_gzio
+   struct huft *tl;
+   /* The distance code table.  */
+   struct huft *td;
++  /* The checksum algorithm */
++  const gcry_md_spec_t *hdesc;
++  /* The wanted checksum */
++  grub_uint32_t orig_checksum;
++  /* The uncompressed length */
++  grub_size_t orig_len;
++  /* Context for checksum calculation */
++  grub_uint8_t *hcontext;
+   /* The lookup bits for the literal/length code table. */
+   int bl;
+   /* The lookup bits for the distance code table.  */
+@@ -140,24 +149,24 @@ eat_field (grub_file_t file, int len)
+ #define OLD_GZIP_MAGIC	grub_le_to_cpu16 (0x9E1F)
+ 
+ /* Compression methods (see algorithm.doc) */
+-#define STORED      0
+-#define COMPRESSED  1
+-#define PACKED      2
+-#define LZHED       3
++#define GRUB_GZ_STORED      0
++#define GRUB_GZ_COMPRESSED  1
++#define GRUB_GZ_PACKED      2
++#define GRUB_GZ_LZHED       3
+ /* methods 4 to 7 reserved */
+-#define DEFLATED    8
+-#define MAX_METHODS 9
++#define GRUB_GZ_DEFLATED    8
++#define GRUB_GZ_MAX_METHODS 9
+ 
+ /* gzip flag byte */
+-#define ASCII_FLAG   0x01	/* bit 0 set: file probably ascii text */
+-#define CONTINUATION 0x02	/* bit 1 set: continuation of multi-part gzip file */
+-#define EXTRA_FIELD  0x04	/* bit 2 set: extra field present */
+-#define ORIG_NAME    0x08	/* bit 3 set: original file name present */
+-#define COMMENT      0x10	/* bit 4 set: file comment present */
+-#define ENCRYPTED    0x20	/* bit 5 set: file is encrypted */
+-#define RESERVED     0xC0	/* bit 6,7:   reserved */
++#define GRUB_GZ_ASCII_FLAG   0x01	/* bit 0 set: file probably ascii text */
++#define GRUB_GZ_CONTINUATION 0x02	/* bit 1 set: continuation of multi-part gzip file */
++#define GRUB_GZ_EXTRA_FIELD  0x04	/* bit 2 set: extra field present */
++#define GRUB_GZ_ORIG_NAME    0x08	/* bit 3 set: original file name present */
++#define GRUB_GZ_COMMENT      0x10	/* bit 4 set: file comment present */
++#define GRUB_GZ_ENCRYPTED    0x20	/* bit 5 set: file is encrypted */
++#define GRUB_GZ_RESERVED     0xC0	/* bit 6,7:   reserved */
+ 
+-#define UNSUPPORTED_FLAGS	(CONTINUATION | ENCRYPTED | RESERVED)
++#define GRUB_GZ_UNSUPPORTED_FLAGS	(GRUB_GZ_CONTINUATION | GRUB_GZ_ENCRYPTED | GRUB_GZ_RESERVED)
+ 
+ /* inflate block codes */
+ #define INFLATE_STORED	0
+@@ -180,7 +189,7 @@ test_gzip_header (grub_file_t file)
+     grub_uint8_t os_type;
+   } hdr;
+   grub_uint16_t extra_len;
+-  grub_uint32_t orig_len;
++  grub_uint32_t crc32;
+   grub_gzio_t gzio = file->data;
+ 
+   if (grub_file_tell (gzio->file) != 0)
+@@ -201,26 +210,29 @@ test_gzip_header (grub_file_t file)
+    *  problem occurs from here on, then we have corrupt or otherwise
+    *  bad data, and the error should be reported to the user.
+    */
+-  if (hdr.method != DEFLATED
+-      || (hdr.flags & UNSUPPORTED_FLAGS)
+-      || ((hdr.flags & EXTRA_FIELD)
++  if (hdr.method != GRUB_GZ_DEFLATED
++      || (hdr.flags & GRUB_GZ_UNSUPPORTED_FLAGS)
++      || ((hdr.flags & GRUB_GZ_EXTRA_FIELD)
+ 	  && (grub_file_read (gzio->file, &extra_len, 2) != 2
+ 	      || eat_field (gzio->file,
+ 			    grub_le_to_cpu16 (extra_len))))
+-      || ((hdr.flags & ORIG_NAME) && eat_field (gzio->file, -1))
+-      || ((hdr.flags & COMMENT) && eat_field (gzio->file, -1)))
++      || ((hdr.flags & GRUB_GZ_ORIG_NAME) && eat_field (gzio->file, -1))
++      || ((hdr.flags & GRUB_GZ_COMMENT) && eat_field (gzio->file, -1)))
+     return 0;
+ 
+   gzio->data_offset = grub_file_tell (gzio->file);
+ 
+   /* FIXME: don't do this on not easily seekable files.  */
+   {
+-    grub_file_seek (gzio->file, grub_file_size (gzio->file) - 4);
+-    if (grub_file_read (gzio->file, &orig_len, 4) != 4)
++    grub_file_seek (gzio->file, grub_file_size (gzio->file) - 8);
++    if (grub_file_read (gzio->file, &crc32, 4) != 4)
++      return 0;
++    gzio->orig_checksum = grub_le_to_cpu32 (crc32);
++    if (grub_file_read (gzio->file, &gzio->orig_len, 4) != 4)
+       return 0;
+     /* FIXME: this does not handle files whose original size is over 4GB.
+        But how can we know the real original size?  */
+-    file->size = grub_le_to_cpu32 (orig_len);
++    file->size = grub_le_to_cpu32 (gzio->orig_len);
+   }
+ 
+   initialize_tables (gzio);
+@@ -1095,7 +1107,23 @@ inflate_window (grub_gzio_t gzio)
+ 
+   gzio->saved_offset += gzio->wp;
+ 
+-  /* XXX do CRC calculation here! */
++  if (gzio->hcontext)
++    {
++      gzio->hdesc->write (gzio->hcontext, gzio->slide, gzio->wp);
++
++      if (gzio->saved_offset == gzio->orig_len)
++	{
++	  grub_uint32_t csum;
++
++	  gzio->hdesc->final (gzio->hcontext);
++	  csum = grub_get_unaligned32 (gzio->hdesc->read (gzio->hcontext));
++	  csum = grub_be_to_cpu32 (csum);
++	  if (csum != gzio->orig_checksum)
++	    grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
++			"checksum mismatch %08x/%08x",
++			gzio->orig_checksum, csum);
++	}
++    }
+ }
+ 
+ 
+@@ -1118,6 +1146,9 @@ initialize_tables (grub_gzio_t gzio)
+   huft_free (gzio->td);
+   gzio->tl = NULL;
+   gzio->td = NULL;
++
++  if (gzio->hcontext)
++    gzio->hdesc->init(gzio->hcontext);
+ }
+ 
+ 
+@@ -1143,6 +1174,9 @@ grub_gzio_open (grub_file_t io, const char *name __attribute__ ((unused)))
+ 
+   gzio->file = io;
+ 
++  gzio->hdesc = GRUB_MD_CRC32;
++  gzio->hcontext = grub_malloc(gzio->hdesc->contextsize);
++
+   file->device = io->device;
+   file->data = gzio;
+   file->fs = &grub_gzio_fs;
+@@ -1151,6 +1185,7 @@ grub_gzio_open (grub_file_t io, const char *name __attribute__ ((unused)))
+   if (! test_gzip_header (file))
+     {
+       grub_errno = GRUB_ERR_NONE;
++      grub_free (gzio->hcontext);
+       grub_free (gzio);
+       grub_free (file);
+       grub_file_seek (io, 0);
+@@ -1183,7 +1218,7 @@ test_zlib_header (grub_gzio_t gzio)
+   flg = get_byte (gzio);
+ 
+   /* Check that compression method is DEFLATE.  */
+-  if ((cmf & 0xf) != DEFLATED)
++  if ((cmf & 0xf) != GRUB_GZ_DEFLATED)
+     {
+       /* TRANSLATORS: It's about given file having some strange format, not
+ 	 complete lack of gzip support.  */
+@@ -1287,6 +1322,7 @@ grub_gzio_close (grub_file_t file)
+   grub_file_close (gzio->file);
+   huft_free (gzio->tl);
+   huft_free (gzio->td);
++  grub_free (gzio->hcontext);
+   grub_free (gzio);
+ 
+   /* No need to close the same device twice.  */
+diff --git a/grub-core/kern/arm/cache.c b/grub-core/kern/arm/cache.c
+index 34154ccdb0e09d7d9fd91c4164fe8577ce449260..af1c4bbf544f0ebcca5c0f58c847c8dddc1f2e91 100644
+--- a/grub-core/kern/arm/cache.c
++++ b/grub-core/kern/arm/cache.c
+@@ -29,6 +29,8 @@ void grub_arm_clean_dcache_range_armv6 (grub_addr_t start, grub_addr_t end,
+ 					grub_addr_t dlinesz);
+ void grub_arm_clean_dcache_range_armv7 (grub_addr_t start, grub_addr_t end,
+ 					grub_addr_t dlinesz);
++void grub_arm_clean_dcache_range_poc_armv7 (grub_addr_t start, grub_addr_t end,
++					    grub_addr_t dlinesz);
+ void grub_arm_invalidate_icache_range_armv6 (grub_addr_t start, grub_addr_t end,
+ 					     grub_addr_t dlinesz);
+ void grub_arm_invalidate_icache_range_armv7 (grub_addr_t start, grub_addr_t end,
+@@ -252,6 +254,38 @@ grub_arch_sync_caches (void *address, grub_size_t len)
+     }
+ }
+ 
++void
++grub_arch_sync_dma_caches (volatile void *address, grub_size_t len)
++{
++  grub_addr_t start = (grub_addr_t) address;
++  grub_addr_t end = start + len;
++
++  if (type == ARCH_UNKNOWN)
++    probe_caches ();
++  start = ALIGN_DOWN (start, grub_arch_cache_max_linesz);
++  end = ALIGN_UP (end, grub_arch_cache_max_linesz);
++  switch (type)
++    {
++    case ARCH_ARMV6:
++      grub_arm_clean_dcache_range_armv6 (start, end, grub_arch_cache_dlinesz);
++      grub_arm_invalidate_icache_range_armv6 (start, end,
++					      grub_arch_cache_ilinesz);
++      break;
++    case ARCH_ARMV5_WRITE_THROUGH:
++    case ARCH_ARMV6_UNIFIED:
++      grub_arm_clean_dcache_range_armv6 (start, end, grub_arch_cache_dlinesz);
++      break;
++    case ARCH_ARMV7:
++      grub_arm_clean_dcache_range_poc_armv7 (start, end, grub_arch_cache_dlinesz);
++      grub_arm_invalidate_icache_range_armv7 (start, end,
++					      grub_arch_cache_ilinesz);
++      break;
++      /* Pacify GCC.  */
++    case ARCH_UNKNOWN:
++      break;
++    }
++}
++
+ void
+ grub_arm_disable_caches_mmu (void)
+ {
+diff --git a/grub-core/kern/arm/coreboot/cbtable.c b/grub-core/kern/arm/coreboot/cbtable.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..8a655bb5cc28fb013674dc792531d8a9ba1c4b85
+--- /dev/null
++++ b/grub-core/kern/arm/coreboot/cbtable.c
+@@ -0,0 +1,40 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2007,2008,2013  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/coreboot/lbio.h>
++#include <grub/types.h>
++#include <grub/err.h>
++#include <grub/misc.h>
++#include <grub/dl.h>
++#include <grub/arm/startup.h>
++
++GRUB_MOD_LICENSE ("GPLv3+");
++
++#pragma GCC diagnostic ignored "-Wcast-align"
++
++grub_linuxbios_table_header_t
++grub_linuxbios_get_tables (void)
++{
++  grub_linuxbios_table_header_t table_header
++    = (grub_linuxbios_table_header_t) grub_arm_saved_registers.r[0];
++
++  if (!grub_linuxbios_check_signature (table_header))
++    return 0;
++
++  return table_header;
++}
+diff --git a/grub-core/kern/arm/coreboot/dma.c b/grub-core/kern/arm/coreboot/dma.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..2c2a6278904631c91bd29b3c4338c606471672fe
+--- /dev/null
++++ b/grub-core/kern/arm/coreboot/dma.c
+@@ -0,0 +1,59 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2007,2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/dl.h>
++#include <grub/dma.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/mm_private.h>
++#include <grub/cache.h>
++
++struct grub_pci_dma_chunk *
++grub_memalign_dma32 (grub_size_t align, grub_size_t size)
++{
++  void *ret;
++  if (align < 64)
++    align = 64;
++  size = ALIGN_UP (size, align);
++  ret = grub_memalign (align, size);
++  if (!ret)
++    return 0;
++  grub_arch_sync_dma_caches (ret, size);
++  return ret;
++}
++
++void
++grub_dma_free (struct grub_pci_dma_chunk *ch)
++{
++  grub_size_t size = (((struct grub_mm_header *) ch) - 1)->size * GRUB_MM_ALIGN;
++  grub_arch_sync_dma_caches (ch, size);
++  grub_free (ch);
++}
++
++volatile void *
++grub_dma_get_virt (struct grub_pci_dma_chunk *ch)
++{
++  return (void *) ch;
++}
++
++grub_uint32_t
++grub_dma_get_phys (struct grub_pci_dma_chunk *ch)
++{
++  return (grub_uint32_t) (grub_addr_t) ch;
++}
++
+diff --git a/grub-core/kern/arm/coreboot/init.c b/grub-core/kern/arm/coreboot/init.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..8d8c5b8291eff9743b0325b76f851d52509b1f4f
+--- /dev/null
++++ b/grub-core/kern/arm/coreboot/init.c
+@@ -0,0 +1,151 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2013  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/kernel.h>
++#include <grub/mm.h>
++#include <grub/memory.h>
++#include <grub/machine/console.h>
++#include <grub/machine/kernel.h>
++#include <grub/offsets.h>
++#include <grub/types.h>
++#include <grub/err.h>
++#include <grub/dl.h>
++#include <grub/misc.h>
++#include <grub/loader.h>
++#include <grub/env.h>
++#include <grub/cache.h>
++#include <grub/time.h>
++#include <grub/symbol.h>
++#include <grub/video.h>
++#include <grub/coreboot/lbio.h>
++#include <grub/fdtbus.h>
++
++extern grub_uint8_t _start[];
++extern grub_uint8_t _end[];
++extern grub_uint8_t _edata[];
++grub_addr_t start_of_ram = ~(grub_addr_t)0;
++
++void  __attribute__ ((noreturn))
++grub_exit (void)
++{
++  /* We can't use grub_fatal() in this function.  This would create an infinite
++     loop, since grub_fatal() calls grub_abort() which in turn calls grub_exit().  */
++  while (1)
++    grub_cpu_idle ();
++}
++
++static grub_uint64_t modend;
++static int have_memory = 0;
++
++/* Helper for grub_machine_init.  */
++static int
++heap_init (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
++	   void *data __attribute__ ((unused)))
++{
++  grub_uint64_t begin = addr, end = addr + size;
++
++#if GRUB_CPU_SIZEOF_VOID_P == 4
++  /* Restrict ourselves to 32-bit memory space.  */
++  if (begin > GRUB_ULONG_MAX)
++    return 0;
++  if (end > GRUB_ULONG_MAX)
++    end = GRUB_ULONG_MAX;
++#endif
++
++  if (start_of_ram > begin)
++    start_of_ram = begin;
++
++  if (type != GRUB_MEMORY_AVAILABLE)
++    return 0;
++
++  if (modend && begin < modend)
++    {
++      if (begin < (grub_addr_t)_start)
++	{
++	  grub_mm_init_region ((void *) (grub_addr_t) begin, (grub_size_t) ((grub_addr_t)_start - begin));
++	  have_memory = 1;
++	}
++      begin = modend;
++    }
++
++  /* Avoid DMA problems.  */
++  if (end >= 0xfe000000)
++    end = 0xfe000000;
++
++  if (end <= begin)
++    return 0;
++
++  grub_mm_init_region ((void *) (grub_addr_t) begin, (grub_size_t) (end - begin));
++
++  have_memory = 1;
++
++  return 0;
++}
++
++void
++grub_machine_init (void)
++{
++  struct grub_module_header *header;
++  void *dtb = 0;
++  grub_size_t dtb_size = 0;
++
++  modend = grub_modules_get_end ();
++
++  grub_video_coreboot_fb_early_init ();
++
++  grub_machine_mmap_iterate (heap_init, NULL);
++  if (!have_memory)
++    grub_fatal ("No memory found");
++
++  grub_video_coreboot_fb_late_init ();
++
++  grub_font_init ();
++  grub_gfxterm_init ();
++
++  FOR_MODULES (header)
++    if (header->type == OBJ_TYPE_DTB)
++      {
++	char *dtb_orig_addr, *dtb_copy;
++	dtb_orig_addr = (char *) header + sizeof (struct grub_module_header);
++
++	dtb_size = header->size - sizeof (struct grub_module_header);
++	dtb = dtb_copy = grub_malloc (dtb_size);
++	grub_memmove (dtb_copy, dtb_orig_addr, dtb_size);
++	break;
++      }
++  if (!dtb)
++    grub_fatal ("No DTB found");
++  grub_fdtbus_init (dtb, dtb_size);
++
++  grub_rk3288_spi_init ();
++
++  grub_machine_timer_init ();
++  grub_cros_init ();
++  grub_pl050_init ();
++}
++
++void
++grub_machine_get_bootlocation (char **device __attribute__ ((unused)),
++			       char **path __attribute__ ((unused)))
++{
++}
++
++void
++grub_machine_fini (int flags __attribute__ ((unused)))
++{
++}
+diff --git a/grub-core/kern/arm/coreboot/timer.c b/grub-core/kern/arm/coreboot/timer.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..d97b844f8487c064922a552a5ea4d5f220031dba
+--- /dev/null
++++ b/grub-core/kern/arm/coreboot/timer.c
+@@ -0,0 +1,101 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2016  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/mm.h>
++#include <grub/machine/kernel.h>
++#include <grub/types.h>
++#include <grub/err.h>
++#include <grub/time.h>
++#include <grub/fdtbus.h>
++#include <grub/misc.h>
++
++grub_uint64_t
++grub_armv7_get_timer_value(void);
++
++grub_uint32_t
++grub_armv7_get_timer_frequency(void);
++
++grub_uint32_t
++grub_arm_pfr1(void);
++
++static int have_timer = 0;
++static volatile grub_uint32_t *sp804_regs;
++
++static grub_uint64_t
++sp804_get_time_ms (void)
++{
++  static grub_uint32_t high, last_low;
++  grub_uint32_t low = ~sp804_regs[1];
++  if (last_low > low)
++    high++;
++  last_low = low;
++  return grub_divmod64 ((((grub_uint64_t) high) << 32) | low,
++			1000, 0);
++}
++
++static grub_err_t
++sp804_attach(const struct grub_fdtbus_dev *dev)
++{
++  if (have_timer)
++    return GRUB_ERR_NONE;
++  sp804_regs = grub_fdtbus_map_reg (dev, 0, 0);
++  if (!grub_fdtbus_is_mapping_valid (sp804_regs))
++    return grub_error (GRUB_ERR_IO, "could not map sp804: %p", sp804_regs);
++  grub_install_get_time_ms (sp804_get_time_ms);
++  have_timer = 1;
++  return GRUB_ERR_NONE;
++}
++
++struct grub_fdtbus_driver sp804 =
++{
++  .compatible = "arm,sp804",
++  .attach = sp804_attach
++};
++
++static grub_uint32_t timer_frequency_in_khz;
++
++static grub_uint64_t
++generic_get_time_ms (void)
++{
++  return grub_divmod64 (grub_armv7_get_timer_value(), timer_frequency_in_khz, 0);
++}
++
++static int
++try_generic_timer (void)
++{
++  if (((grub_arm_pfr1 () >> 16) & 0xf) != 1)
++    return 0;
++  grub_printf ("freq = %x\n", grub_armv7_get_timer_frequency());
++  timer_frequency_in_khz = 0x016e3600 / 1000; //grub_armv7_get_timer_frequency() / 1000;
++  if (timer_frequency_in_khz == 0)
++    return 0;
++  grub_install_get_time_ms (generic_get_time_ms);
++  have_timer = 1;
++  return 1;
++}
++
++void
++grub_machine_timer_init (void)
++{
++  grub_fdtbus_register (&sp804);
++
++  if (!have_timer)
++    try_generic_timer ();
++  if (!have_timer)
++    grub_fatal ("No timer found");
++}
+diff --git a/grub-core/kern/arm/efi/misc.c b/grub-core/kern/arm/efi/misc.c
+deleted file mode 100644
+index 7cd41842ae7662018c2ce5ff847aeb250572ec85..0000000000000000000000000000000000000000
+--- a/grub-core/kern/arm/efi/misc.c
++++ /dev/null
+@@ -1,202 +0,0 @@
+-/* misc.c - various system functions for an arm-based EFI system */
+-/*
+- *  GRUB  --  GRand Unified Bootloader
+- *  Copyright (C) 2013 Free Software Foundation, Inc.
+- *
+- *  GRUB is free software: you can redistribute it and/or modify
+- *  it under the terms of the GNU General Public License as published by
+- *  the Free Software Foundation, either version 3 of the License, or
+- *  (at your option) any later version.
+- *
+- *  GRUB is distributed in the hope that it will be useful,
+- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- *  GNU General Public License for more details.
+- *
+- *  You should have received a copy of the GNU General Public License
+- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+- */
+-
+-#include <grub/misc.h>
+-#include <grub/mm.h>
+-#include <grub/cpu/linux.h>
+-#include <grub/cpu/system.h>
+-#include <grub/efi/efi.h>
+-#include <grub/machine/loader.h>
+-
+-static inline grub_size_t
+-page_align (grub_size_t size)
+-{
+-  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 efi/mm.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_error (GRUB_ERR_IO, "cannot get memory map");
+-	  return 0;
+-	}
+-      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 << 12);
+-
+-  return page_align (mmap_size);
+-}
+-
+-#define NEXT_MEMORY_DESCRIPTOR(desc, size)      \
+-  ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size)))
+-#define PAGE_SHIFT 12
+-
+-void *
+-grub_efi_allocate_loader_memory (grub_uint32_t min_offset, grub_uint32_t size)
+-{
+-  grub_efi_uintn_t desc_size;
+-  grub_efi_memory_descriptor_t *mmap, *mmap_end;
+-  grub_efi_uintn_t mmap_size, tmp_mmap_size;
+-  grub_efi_memory_descriptor_t *desc;
+-  void *mem = NULL;
+-  grub_addr_t min_start = 0;
+-
+-  mmap_size = find_mmap_size();
+-  if (!mmap_size)
+-    return NULL;
+-
+-  mmap = grub_malloc(mmap_size);
+-  if (!mmap)
+-    return NULL;
+-
+-  tmp_mmap_size = mmap_size;
+-  if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)
+-    {
+-      grub_error (GRUB_ERR_IO, "cannot get memory map");
+-      goto fail;
+-    }
+-
+-  mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
+-  /* Find lowest accessible RAM location */
+-  {
+-    int found = 0;
+-    for (desc = mmap ; !found && (desc < mmap_end) ;
+-	 desc = NEXT_MEMORY_DESCRIPTOR(desc, desc_size))
+-      {
+-	switch (desc->type)
+-	  {
+-	  case GRUB_EFI_CONVENTIONAL_MEMORY:
+-	  case GRUB_EFI_LOADER_CODE:
+-	  case GRUB_EFI_LOADER_DATA:
+-	    min_start = desc->physical_start + min_offset;
+-	    found = 1;
+-	    break;
+-	  default:
+-	    break;
+-	  }
+-      }
+-  }
+-
+-  /* First, find free pages for the real mode code
+-     and the memory map buffer.  */
+-  for (desc = mmap ; desc < mmap_end ;
+-       desc = NEXT_MEMORY_DESCRIPTOR(desc, desc_size))
+-    {
+-      grub_uint64_t start, end;
+-
+-      grub_dprintf("mm", "%s: 0x%08x bytes @ 0x%08x\n",
+-		   __FUNCTION__,
+-		   (grub_uint32_t) (desc->num_pages << PAGE_SHIFT),
+-		   (grub_uint32_t) (desc->physical_start));
+-
+-      if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY)
+-	continue;
+-
+-      start = desc->physical_start;
+-      end = start + (desc->num_pages << PAGE_SHIFT);
+-      grub_dprintf("mm", "%s: start=0x%016llx, end=0x%016llx\n",
+-		  __FUNCTION__, start, end);
+-      start = start < min_start ? min_start : start;
+-      if (start + size > end)
+-	continue;
+-      grub_dprintf("mm", "%s: let's allocate some (0x%x) pages @ 0x%08x...\n",
+-		  __FUNCTION__, (size >> PAGE_SHIFT), (grub_addr_t) start);
+-      mem = grub_efi_allocate_pages (start, (size >> PAGE_SHIFT) + 1);
+-      grub_dprintf("mm", "%s: retval=0x%08x\n",
+-		   __FUNCTION__, (grub_addr_t) mem);
+-      if (! mem)
+-	{
+-	  grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory");
+-	  goto fail;
+-	}
+-      break;
+-    }
+-
+-  if (! mem)
+-    {
+-      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory");
+-      goto fail;
+-    }
+-
+-  grub_free (mmap);
+-  return mem;
+-
+- fail:
+-  grub_free (mmap);
+-  return NULL;
+-}
+-
+-grub_err_t
+-grub_efi_prepare_platform (void)
+-{
+-  grub_efi_uintn_t mmap_size;
+-  grub_efi_uintn_t map_key;
+-  grub_efi_uintn_t desc_size;
+-  grub_efi_uint32_t desc_version;
+-  grub_efi_memory_descriptor_t *mmap_buf;
+-  grub_err_t err;
+-
+-  /*
+-   * Cloned from IA64
+-   * Must be done after grub_machine_fini because map_key is used by
+-   *exit_boot_services.
+-   */
+-  mmap_size = find_mmap_size ();
+-  if (! mmap_size)
+-    return GRUB_ERR_OUT_OF_MEMORY;
+-  mmap_buf = grub_efi_allocate_pages (0, page_align (mmap_size) >> 12);
+-  if (! mmap_buf)
+-    return GRUB_ERR_OUT_OF_MEMORY;
+-
+-  err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, &map_key,
+-				       &desc_size, &desc_version);
+-  if (err != GRUB_ERR_NONE)
+-    return err;
+-
+-  return GRUB_ERR_NONE;
+-}
+diff --git a/grub-core/kern/arm/uboot/init.c b/grub-core/kern/arm/uboot/init.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..2a6aa3fdd3dd049848015f6c67dfc0f30a79a9c4
+--- /dev/null
++++ b/grub-core/kern/arm/uboot/init.c
+@@ -0,0 +1,70 @@
++/* init.c - generic U-Boot initialization and finalization */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2016  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/uboot/uboot.h>
++#include <grub/arm/startup.h>
++#include <grub/uboot/api_public.h>
++
++extern int (*grub_uboot_syscall_ptr) (int, int *, ...);
++
++grub_uint32_t
++grub_uboot_get_machine_type (void)
++{
++  return grub_arm_saved_registers.r[1];
++}
++
++grub_addr_t
++grub_uboot_get_boot_data (void)
++{
++  return grub_arm_saved_registers.r[2];
++}
++
++int
++grub_uboot_api_init (void)
++{
++  struct api_signature *start, *end;
++  struct api_signature *p;
++  grub_addr_t grub_uboot_search_hint = grub_arm_saved_registers.sp;
++  if (grub_uboot_search_hint)
++    {
++      /* Extended search range to work around Trim Slice U-Boot issue */
++      start = (struct api_signature *) ((grub_uboot_search_hint & ~0x000fffff)
++					- 0x00500000);
++      end =
++	(struct api_signature *) ((grub_addr_t) start + UBOOT_API_SEARCH_LEN -
++				  API_SIG_MAGLEN + 0x00500000);
++    }
++  else
++    {
++      start = 0;
++      end = (struct api_signature *) (256 * 1024 * 1024);
++    }
++
++  /* Structure alignment is (at least) 8 bytes */
++  for (p = start; p < end; p = (void *) ((grub_addr_t) p + 8))
++    {
++      if (grub_memcmp (&(p->magic), API_SIG_MAGIC, API_SIG_MAGLEN) == 0)
++	{
++	  grub_uboot_syscall_ptr = p->syscall;
++	  return p->version;
++	}
++    }
++
++  return 0;
++}
+diff --git a/grub-core/kern/coreboot/cbtable.c b/grub-core/kern/coreboot/cbtable.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..aec63dbd1209e4c3cbbe165d54a78277ea72f361
+--- /dev/null
++++ b/grub-core/kern/coreboot/cbtable.c
+@@ -0,0 +1,72 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2007,2008,2013  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/i386/coreboot/memory.h>
++#include <grub/coreboot/lbio.h>
++#include <grub/types.h>
++#include <grub/err.h>
++#include <grub/misc.h>
++#include <grub/dl.h>
++
++#pragma GCC diagnostic ignored "-Wcast-align"
++
++/* Helper for grub_linuxbios_table_iterate.  */
++int
++grub_linuxbios_check_signature (grub_linuxbios_table_header_t tbl_header)
++{
++  if (! grub_memcmp (tbl_header->signature, "LBIO", 4))
++    return 1;
++
++  return 0;
++}
++
++grub_err_t
++grub_linuxbios_table_iterate (int (*hook) (grub_linuxbios_table_item_t,
++					   void *),
++			      void *hook_data)
++{
++  grub_linuxbios_table_header_t table_header = grub_linuxbios_get_tables ();
++  grub_linuxbios_table_item_t table_item;
++
++  if (!table_header)
++    return 0;
++
++signature_found:
++
++  table_item =
++    (grub_linuxbios_table_item_t) ((char *) table_header +
++				   table_header->header_size);
++  for (; table_item < (grub_linuxbios_table_item_t) ((char *) table_header
++						     + table_header->header_size
++						     + table_header->table_size);
++       table_item = (grub_linuxbios_table_item_t) ((char *) table_item + table_item->size))
++    {
++      if (table_item->tag == GRUB_LINUXBIOS_MEMBER_LINK
++         && grub_linuxbios_check_signature ((grub_linuxbios_table_header_t) (grub_addr_t)
++                             *(grub_uint64_t *) (table_item + 1)))
++       {
++         table_header = (grub_linuxbios_table_header_t) (grub_addr_t)
++           *(grub_uint64_t *) (table_item + 1);
++         goto signature_found;   
++       }
++      if (hook (table_item, hook_data))
++       return 1;
++    }
++
++  return 0;
++}
+diff --git a/grub-core/kern/i386/coreboot/mmap.c b/grub-core/kern/coreboot/mmap.c
+similarity index 97%
+rename from grub-core/kern/i386/coreboot/mmap.c
+rename to grub-core/kern/coreboot/mmap.c
+index 4d29f6b7d90591939cf5d837b39c5d259a55efb0..caf8f7cef1b4552c720eb3b7ca355eb6cec32955 100644
+--- a/grub-core/kern/i386/coreboot/mmap.c
++++ b/grub-core/kern/coreboot/mmap.c
+@@ -16,8 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <grub/machine/memory.h>
+-#include <grub/machine/lbio.h>
++#include <grub/memory.h>
++#include <grub/coreboot/lbio.h>
+ #include <grub/types.h>
+ #include <grub/err.h>
+ #include <grub/misc.h>
+@@ -49,6 +49,7 @@ iterate_linuxbios_table (grub_linuxbios_table_item_t table_item, void *data)
+     {
+       grub_uint64_t start = mem_region->addr;
+       grub_uint64_t end = mem_region->addr + mem_region->size;
++#ifdef __i386__
+       /* Mark region 0xa0000 - 0x100000 as reserved.  */
+       if (start < 0x100000 && end >= 0xa0000
+ 	  && mem_region->type == GRUB_MACHINE_MEMORY_AVAILABLE)
+@@ -75,6 +76,7 @@ iterate_linuxbios_table (grub_linuxbios_table_item_t table_item, void *data)
+ 	  if (end <= start)
+ 	    continue;
+ 	}
++#endif
+       if (ctx->hook (start, end - start,
+ 		     /* Multiboot mmaps match with the coreboot mmap
+ 		        definition.  Therefore, we can just pass type
+diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
+index d467785fc6ce0763ec1392a65d6b30f1747ab5c4..708581fcbde007fc0174be636771b401d5e69ea2 100644
+--- a/grub-core/kern/efi/efi.c
++++ b/grub-core/kern/efi/efi.c
+@@ -154,6 +154,15 @@ grub_efi_get_loaded_image (grub_efi_handle_t image_handle)
+ 				 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ }
+ 
++void
++grub_reboot (void)
++{
++  grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
++  efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
++              GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL);
++  for (;;) ;
++}
++
+ void
+ grub_exit (void)
+ {
+diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
+index 2c31847bf6db77fab377c90e7ed36897439d6027..3dfdf2d22b02ae8847a3e19a175517d2d71544fa 100644
+--- a/grub-core/kern/efi/init.c
++++ b/grub-core/kern/efi/init.c
+@@ -80,4 +80,5 @@ grub_efi_fini (void)
+ {
+   grub_efidisk_fini ();
+   grub_console_fini ();
++  grub_efi_memory_fini ();
+ }
+diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
+index 20a47aaf5d0df376090510ddb8337ecc8aa18e98..42ad7c570a5532c4f6a5bef9d1ff3295f413aa11 100644
+--- a/grub-core/kern/efi/mm.c
++++ b/grub-core/kern/efi/mm.c
+@@ -49,38 +49,86 @@ static grub_efi_uintn_t finish_desc_size;
+ static grub_efi_uint32_t finish_desc_version;
+ int grub_efi_is_finished = 0;
+ 
++/*
++ * We need to roll back EFI allocations on exit. Remember allocations that
++ * we'll free on exit.
++ */
++struct efi_allocation;
++struct efi_allocation {
++	grub_efi_physical_address_t address;
++	grub_efi_uint64_t pages;
++	struct efi_allocation *next;
++};
++static struct efi_allocation *efi_allocated_memory;
++
++static void
++grub_efi_store_alloc (grub_efi_physical_address_t address,
++                         grub_efi_uintn_t pages)
++{
++  grub_efi_boot_services_t *b;
++  struct efi_allocation *alloc;
++  grub_efi_status_t status;
++
++  b = grub_efi_system_table->boot_services;
++  status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA,
++                           sizeof(*alloc), (void**)&alloc);
++
++  if (status == GRUB_EFI_SUCCESS)
++    {
++      alloc->next = efi_allocated_memory;
++      alloc->address = address;
++      alloc->pages = pages;
++      efi_allocated_memory = alloc;
++    }
++  else
++      grub_printf ("Could not malloc memory to remember EFI allocation. "
++                   "Exiting GRUB won't free all memory.\n");
++}
++
++static void
++grub_efi_drop_alloc (grub_efi_physical_address_t address,
++                           grub_efi_uintn_t pages)
++{
++  struct efi_allocation *ea, *eap;
++  grub_efi_boot_services_t *b;
++
++  b = grub_efi_system_table->boot_services;
++
++  for (eap = NULL, ea = efi_allocated_memory; ea; eap = ea, ea = ea->next)
++    {
++      if (ea->address != address || ea->pages != pages)
++         continue;
++
++      /* Remove the current entry from the list. */
++      if (eap)
++        eap->next = ea->next;
++      else
++        efi_allocated_memory = ea->next;
++
++      /* Then free the memory backing it. */
++      efi_call_1 (b->free_pool, ea);
++
++      /* And leave, we're done. */
++      break;
++    }
++}
++
+ /* Allocate pages. Return the pointer to the first of allocated pages.  */
+ void *
+-grub_efi_allocate_pages (grub_efi_physical_address_t address,
+-			 grub_efi_uintn_t pages)
++grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
++			      grub_efi_uintn_t pages,
++			      grub_efi_allocate_type_t alloctype,
++			      grub_efi_memory_type_t memtype)
+ {
+-  grub_efi_allocate_type_t type;
+   grub_efi_status_t status;
+   grub_efi_boot_services_t *b;
+ 
+-#if 1
+   /* Limit the memory access to less than 4GB for 32-bit platforms.  */
+   if (address > GRUB_EFI_MAX_USABLE_ADDRESS)
+     return 0;
+-#endif
+-
+-#if 1
+-  if (address == 0)
+-    {
+-      type = GRUB_EFI_ALLOCATE_MAX_ADDRESS;
+-      address = GRUB_EFI_MAX_USABLE_ADDRESS;
+-    }
+-  else
+-    type = GRUB_EFI_ALLOCATE_ADDRESS;
+-#else
+-  if (address == 0)
+-    type = GRUB_EFI_ALLOCATE_ANY_PAGES;
+-  else
+-    type = GRUB_EFI_ALLOCATE_ADDRESS;
+-#endif
+ 
+   b = grub_efi_system_table->boot_services;
+-  status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
++  status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
+   if (status != GRUB_EFI_SUCCESS)
+     return 0;
+ 
+@@ -89,15 +137,34 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address,
+       /* Uggh, the address 0 was allocated... This is too annoying,
+ 	 so reallocate another one.  */
+       address = GRUB_EFI_MAX_USABLE_ADDRESS;
+-      status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
++      status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address);
+       grub_efi_free_pages (0, pages);
+       if (status != GRUB_EFI_SUCCESS)
+ 	return 0;
+     }
+ 
++  grub_efi_store_alloc (address, pages);
++
+   return (void *) ((grub_addr_t) address);
+ }
+ 
++void *
++grub_efi_allocate_any_pages (grub_efi_uintn_t pages)
++{
++  return grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS,
++				       pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS,
++				       GRUB_EFI_LOADER_DATA);
++}
++
++void *
++grub_efi_allocate_fixed (grub_efi_physical_address_t address,
++			 grub_efi_uintn_t pages)
++{
++  return grub_efi_allocate_pages_real (address, pages,
++				       GRUB_EFI_ALLOCATE_ADDRESS,
++				       GRUB_EFI_LOADER_DATA);
++}
++
+ /* Free pages starting from ADDRESS.  */
+ void
+ grub_efi_free_pages (grub_efi_physical_address_t address,
+@@ -107,6 +174,8 @@ grub_efi_free_pages (grub_efi_physical_address_t address,
+ 
+   b = grub_efi_system_table->boot_services;
+   efi_call_2 (b->free_pages, address, pages);
++
++  grub_efi_drop_alloc (address, pages);
+ }
+ 
+ #if defined (__i386__) || defined (__x86_64__)
+@@ -217,6 +286,30 @@ grub_efi_finish_boot_services (grub_efi_uintn_t *outbuf_size, void *outbuf,
+   return GRUB_ERR_NONE;
+ }
+ 
++/*
++ * To obtain the UEFI memory map, we must pass a buffer of sufficient size
++ * to hold the entire map. This function returns a sane start value for
++ * buffer size.
++ */
++grub_efi_uintn_t
++grub_efi_find_mmap_size (void)
++{
++  grub_efi_uintn_t mmap_size = 0;
++  grub_efi_uintn_t desc_size;
++
++  if (grub_efi_get_memory_map (&mmap_size, NULL, NULL, &desc_size, 0) < 0)
++    {
++      grub_error (GRUB_ERR_IO, "cannot get EFI memory map size");
++      return 0;
++    }
++
++  /*
++   * Add an extra page, since UEFI can alter the memory map itself on
++   * callbacks or explicit calls, including console output.
++   */
++  return ALIGN_UP (mmap_size + GRUB_EFI_PAGE_SIZE, GRUB_EFI_PAGE_SIZE);
++}
++
+ /* 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.  */
+ int
+@@ -402,7 +495,9 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
+ 	  pages = required_pages;
+ 	}
+ 
+-      addr = grub_efi_allocate_pages (start, pages);
++      addr = grub_efi_allocate_pages_real (start, pages,
++					   GRUB_EFI_ALLOCATE_ADDRESS,
++					   GRUB_EFI_LOADER_CODE);      
+       if (! addr)
+ 	grub_fatal ("cannot allocate conventional memory %p with %u pages",
+ 		    (void *) ((grub_addr_t) start),
+@@ -419,6 +514,20 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
+     grub_fatal ("too little memory");
+ }
+ 
++void
++grub_efi_memory_fini (void)
++{
++  /*
++   * Free all stale allocations. grub_efi_free_pages() will remove
++   * the found entry from the list and it will always find the first
++   * list entry (efi_allocated_memory is the list start). Hence we
++   * remove all entries from the list until none is left altogether.
++   */
++  while (efi_allocated_memory)
++      grub_efi_free_pages (efi_allocated_memory->address,
++                           efi_allocated_memory->pages);
++}
++
+ #if 0
+ /* Print the memory map.  */
+ static void
+@@ -454,8 +563,7 @@ grub_efi_mm_init (void)
+   int mm_status;
+ 
+   /* Prepare a memory region to store two memory maps.  */
+-  memory_map = grub_efi_allocate_pages (0,
+-					2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
++  memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
+   if (! memory_map)
+     grub_fatal ("cannot allocate memory");
+ 
+@@ -473,7 +581,7 @@ grub_efi_mm_init (void)
+       /* Freeing/allocating operations may increase memory map size.  */
+       map_size += desc_size * 32;
+ 
+-      memory_map = grub_efi_allocate_pages (0, 2 * BYTES_TO_PAGES (map_size));
++      memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size));
+       if (! memory_map)
+ 	grub_fatal ("cannot allocate memory");
+ 
+@@ -525,3 +633,34 @@ grub_efi_mm_init (void)
+   grub_efi_free_pages ((grub_addr_t) memory_map,
+ 		       2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
+ }
++
++#if defined (__aarch64__) || defined (__arm__)
++grub_err_t
++grub_efi_get_ram_base(grub_addr_t *base_addr)
++{
++  grub_efi_memory_descriptor_t *memory_map, *desc;
++  grub_efi_uintn_t memory_map_size, desc_size;
++  int ret;
++
++  memory_map_size = grub_efi_find_mmap_size();
++
++  memory_map = grub_malloc (memory_map_size);
++  if (! memory_map)
++    return GRUB_ERR_OUT_OF_MEMORY;
++  ret = grub_efi_get_memory_map (&memory_map_size, memory_map, NULL,
++				 &desc_size, NULL);
++
++  if (ret < 1)
++    return GRUB_ERR_BUG;
++
++  for (desc = memory_map, *base_addr = GRUB_UINT_MAX;
++       (grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size);
++       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
++    if (desc->attribute & GRUB_EFI_MEMORY_WB)
++      *base_addr = grub_min (*base_addr, desc->physical_start);
++
++  grub_free(memory_map);
++
++  return GRUB_ERR_NONE;
++}
++#endif
+diff --git a/grub-core/kern/i386/coreboot/cbtable.c b/grub-core/kern/i386/coreboot/cbtable.c
+index 1669bc0ca23a2fe5dcfb8e2b6c973ddb5e27e880..34a2b59be1ffa926e9dcc931140695cc82be223c 100644
+--- a/grub-core/kern/i386/coreboot/cbtable.c
++++ b/grub-core/kern/i386/coreboot/cbtable.c
+@@ -17,7 +17,7 @@
+  */
+ 
+ #include <grub/i386/coreboot/memory.h>
+-#include <grub/i386/coreboot/lbio.h>
++#include <grub/coreboot/lbio.h>
+ #include <grub/types.h>
+ #include <grub/err.h>
+ #include <grub/misc.h>
+@@ -25,59 +25,20 @@
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+-/* Helper for grub_linuxbios_table_iterate.  */
+-static int
+-check_signature (grub_linuxbios_table_header_t tbl_header)
+-{
+-  if (! grub_memcmp (tbl_header->signature, "LBIO", 4))
+-    return 1;
+-
+-  return 0;
+-}
+-
+-grub_err_t
+-grub_linuxbios_table_iterate (int (*hook) (grub_linuxbios_table_item_t,
+-					   void *),
+-			      void *hook_data)
++grub_linuxbios_table_header_t
++grub_linuxbios_get_tables (void)
+ {
+   grub_linuxbios_table_header_t table_header;
+-  grub_linuxbios_table_item_t table_item;
+-
+   /* Assuming table_header is aligned to its size (8 bytes).  */
+-
+   for (table_header = (grub_linuxbios_table_header_t) 0x500;
+        table_header < (grub_linuxbios_table_header_t) 0x1000; table_header++)
+-    if (check_signature (table_header))
+-      goto signature_found;
++    if (grub_linuxbios_check_signature (table_header))
++      return table_header;
+ 
+   for (table_header = (grub_linuxbios_table_header_t) 0xf0000;
+        table_header < (grub_linuxbios_table_header_t) 0x100000; table_header++)
+-    if (check_signature (table_header))
+-      goto signature_found;
+-
+-  return 0;
+-
+-signature_found:
+-
+-  table_item =
+-    (grub_linuxbios_table_item_t) ((char *) table_header +
+-				   table_header->header_size);
+-  for (; table_item < (grub_linuxbios_table_item_t) ((char *) table_header
+-						     + table_header->header_size
+-						     + table_header->table_size);
+-       table_item = (grub_linuxbios_table_item_t) ((char *) table_item + table_item->size))
+-    {
+-      if (table_item->tag == GRUB_LINUXBIOS_MEMBER_LINK
+-         && check_signature ((grub_linuxbios_table_header_t) (grub_addr_t)
+-                             *(grub_uint64_t *) (table_item + 1)))
+-       {
+-         table_header = (grub_linuxbios_table_header_t) (grub_addr_t)
+-           *(grub_uint64_t *) (table_item + 1);
+-         goto signature_found;   
+-       }
+-      if (hook (table_item, hook_data))
+-       return 1;
+-    }
++    if (grub_linuxbios_check_signature (table_header))
++      return table_header;
+ 
+   return 0;
+ }
+diff --git a/grub-core/kern/i386/tsc.c b/grub-core/kern/i386/tsc.c
+index 2e85289d848946da8260b826ed36114557299278..f266eb13185f20dd4c8f67fdffa9a4790d9e01da 100644
+--- a/grub-core/kern/i386/tsc.c
++++ b/grub-core/kern/i386/tsc.c
+@@ -68,7 +68,7 @@ grub_tsc_init (void)
+ #ifdef GRUB_MACHINE_XEN
+   (void) (grub_tsc_calibrate_from_xen () || calibrate_tsc_hardcode());
+ #elif defined (GRUB_MACHINE_EFI)
+-  (void) (grub_tsc_calibrate_from_pit () || grub_tsc_calibrate_from_pmtimer () || grub_tsc_calibrate_from_efi() || calibrate_tsc_hardcode());
++  (void) (grub_tsc_calibrate_from_pmtimer () || grub_tsc_calibrate_from_pit () || grub_tsc_calibrate_from_efi() || calibrate_tsc_hardcode());
+ #elif defined (GRUB_MACHINE_COREBOOT)
+   (void) (grub_tsc_calibrate_from_pmtimer () || grub_tsc_calibrate_from_pit () || calibrate_tsc_hardcode());
+ #else
+diff --git a/grub-core/kern/ieee1275/ieee1275.c b/grub-core/kern/ieee1275/ieee1275.c
+index 98217029f458dcef3a5b227b300762ff14cf8c52..86f81a3c4671be293d823cd3235a66dff9774faa 100644
+--- a/grub-core/kern/ieee1275/ieee1275.c
++++ b/grub-core/kern/ieee1275/ieee1275.c
+@@ -19,6 +19,7 @@
+ 
+ #include <grub/ieee1275/ieee1275.h>
+ #include <grub/types.h>
++#include <grub/misc.h>
+ 
+ #define IEEE1275_PHANDLE_INVALID  ((grub_ieee1275_cell_t) -1)
+ #define IEEE1275_IHANDLE_INVALID  ((grub_ieee1275_cell_t) 0)
+@@ -482,6 +483,91 @@ grub_ieee1275_close (grub_ieee1275_ihandle_t ihandle)
+   return 0;
+ }
+ 
++int
++grub_ieee1275_decode_unit4 (grub_ieee1275_ihandle_t ihandle,
++                            void *addr, grub_size_t size,
++                            grub_uint32_t *phy_lo, grub_uint32_t *phy_hi,
++                            grub_uint32_t *lun_lo, grub_uint32_t *lun_hi)
++{
++  struct decode_args
++  {
++    struct grub_ieee1275_common_hdr common;
++    grub_ieee1275_cell_t method;
++    grub_ieee1275_cell_t ihandle;
++    grub_ieee1275_cell_t size;
++    grub_ieee1275_cell_t addr;
++    grub_ieee1275_cell_t catch_result;
++    grub_ieee1275_cell_t tgt_h;
++    grub_ieee1275_cell_t tgt_l;
++    grub_ieee1275_cell_t lun_h;
++    grub_ieee1275_cell_t lun_l;
++  }
++  args;
++
++  INIT_IEEE1275_COMMON (&args.common, "call-method", 4, 5);
++  args.method = (grub_ieee1275_cell_t) "decode-unit";
++  args.ihandle = ihandle;
++  args.size = size;
++  args.addr = (grub_ieee1275_cell_t) addr;
++  args.catch_result = 1;
++
++  if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.catch_result))
++    {
++      grub_error (GRUB_ERR_OUT_OF_RANGE, "decode-unit failed\n");
++      return -1;
++    }
++
++  *phy_lo = args.tgt_l;
++  *phy_hi = args.tgt_h;
++  *lun_lo = args.lun_l;
++  *lun_hi = args.lun_h;
++  return 0;
++}
++
++char *
++grub_ieee1275_encode_uint4 (grub_ieee1275_ihandle_t ihandle,
++                            grub_uint32_t phy_lo, grub_uint32_t phy_hi,
++                            grub_uint32_t lun_lo, grub_uint32_t lun_hi,
++                            grub_size_t *size)
++{
++  char *addr;
++  struct encode_args
++  {
++    struct grub_ieee1275_common_hdr common;
++    grub_ieee1275_cell_t method;
++    grub_ieee1275_cell_t ihandle;
++    grub_ieee1275_cell_t tgt_h;
++    grub_ieee1275_cell_t tgt_l;
++    grub_ieee1275_cell_t lun_h;
++    grub_ieee1275_cell_t lun_l;
++    grub_ieee1275_cell_t catch_result;
++    grub_ieee1275_cell_t size;
++    grub_ieee1275_cell_t addr;
++  }
++  args;
++
++  INIT_IEEE1275_COMMON (&args.common, "call-method", 6, 3);
++  args.method = (grub_ieee1275_cell_t) "encode-unit";
++  args.ihandle = ihandle;
++
++  args.tgt_l = phy_lo;
++  args.tgt_h = phy_hi;
++  args.lun_l = lun_lo;
++  args.lun_h = lun_hi;
++  args.catch_result = 1;
++
++  if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.catch_result))
++    {
++      grub_error (GRUB_ERR_OUT_OF_RANGE, "encode-unit failed\n");
++      return 0;
++    }
++
++  addr = (void *)args.addr;
++  *size = args.size;
++  addr = grub_strdup ((char *)args.addr);
++  return addr;
++}
++
+ int
+ grub_ieee1275_claim (grub_addr_t addr, grub_size_t size, unsigned int align,
+ 		     grub_addr_t *result)
+@@ -607,3 +693,117 @@ grub_ieee1275_milliseconds (grub_uint32_t *msecs)
+   *msecs = args.msecs;
+   return 0;
+ }
++
++int
++grub_ieee1275_set_address (grub_ieee1275_ihandle_t ihandle,
++                           grub_uint32_t target, grub_uint32_t lun)
++{
++  struct set_address
++  {
++    struct grub_ieee1275_common_hdr common;
++    grub_ieee1275_cell_t method;
++    grub_ieee1275_cell_t ihandle;
++    grub_ieee1275_cell_t tgt;
++    grub_ieee1275_cell_t lun;
++    grub_ieee1275_cell_t catch_result;
++  }
++  args;
++
++  INIT_IEEE1275_COMMON (&args.common, "call-method", 4, 1);
++
++  /*
++   * IEEE 1275-1994 Standard for Boot (Initialization Configuration)
++   * Firmware: Core Requirements and Practices
++   * E.3.2.2 Bus-specific methods for bus nodes
++   *
++   * A package implementing the scsi-2 device type shall implement the
++   * following bus-specific method:
++   *
++   * set-address ( unit# target# -- )
++   * Sets the SCSI target number (0x0..0xf) and unit number (0..7) to which
++   * subsequent commands apply.
++   */
++  args.method = (grub_ieee1275_cell_t) "set-address";
++  args.ihandle = ihandle;
++  args.tgt = target;
++  args.lun = lun;
++
++  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
++    return -1;
++
++  return args.catch_result;
++}
++
++int
++grub_ieee1275_no_data_command (grub_ieee1275_ihandle_t ihandle,
++                               const void *cmd_addr, grub_ssize_t *result)
++{
++  struct set_address
++  {
++    struct grub_ieee1275_common_hdr common;
++    grub_ieee1275_cell_t method;
++    grub_ieee1275_cell_t ihandle;
++    grub_ieee1275_cell_t cmd_addr;
++    grub_ieee1275_cell_t error;
++    grub_ieee1275_cell_t catch_result;
++  }
++  args;
++
++  INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2);
++
++  /*
++   * IEEE 1275-1994 Standard for Boot (Initialization Configuration)
++   * Firmware: Core Requirements and Practices
++   *
++   * E.3.2.2 Bus-specific methods for bus nodes
++   *
++   * A package implementing the scsi-2 device type shall implement the
++   * following bus-specific method:
++   *
++   * no-data-command ( cmd-addr -- error? )
++   * Executes a simple SCSI command, automatically retrying under
++   * certain conditions.  cmd-addr is the address of a 6-byte command buffer
++   * containing an SCSI command that does not have a data transfer phase.
++   * Executes the command, retrying indefinitely with the same retry criteria
++   * as retry-command.
++   *
++   * error? is nonzero if an error occurred, zero otherwise.
++   * NOTE no-data-command is a convenience function. It provides
++   * no capabilities that are not present in retry-command, but for
++   * those commands that meet its restrictions, it is easier to use.
++   */
++  args.method = (grub_ieee1275_cell_t) "no-data-command";
++  args.ihandle = ihandle;
++  args.cmd_addr = (grub_ieee1275_cell_t) cmd_addr;
++
++  if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
++    return -1;
++
++  if (result)
++    *result = args.error;
++
++  return args.catch_result;
++}
++
++int
++grub_ieee1275_get_block_size (grub_ieee1275_ihandle_t ihandle)
++{
++  struct size_args_ieee1275
++    {
++      struct grub_ieee1275_common_hdr common;
++      grub_ieee1275_cell_t method;
++      grub_ieee1275_cell_t ihandle;
++      grub_ieee1275_cell_t result;
++      grub_ieee1275_cell_t size;
++    } args;
++
++  INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 2);
++  args.method = (grub_ieee1275_cell_t) "block-size";
++  args.ihandle = ihandle;
++  args.result = 1;
++
++  if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.result))
++    return 0;
++
++  return args.size;
++}
+diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
+index 12590225eca1483066ea5e7b7443cea3198f6d9b..0d8ebf58b95e220b233e043d2b380007b48e1235 100644
+--- a/grub-core/kern/ieee1275/init.c
++++ b/grub-core/kern/ieee1275/init.c
+@@ -94,28 +94,12 @@ void
+ grub_machine_get_bootlocation (char **device, char **path)
+ {
+   char *bootpath;
+-  grub_ssize_t bootpath_size;
+   char *filename;
+   char *type;
+ 
+-  if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath",
+-					 &bootpath_size)
+-      || bootpath_size <= 0)
+-    {
+-      /* Should never happen.  */
+-      grub_printf ("/chosen/bootpath property missing!\n");
+-      return;
+-    }
+-
+-  bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64);
++  bootpath = grub_ieee1275_get_boot_dev ();
+   if (! bootpath)
+-    {
+-      grub_print_error ();
+-      return;
+-    }
+-  grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", bootpath,
+-                              (grub_size_t) bootpath_size + 1, 0);
+-  bootpath[bootpath_size] = '\0';
++    return;
+ 
+   /* Transform an OF device path to a GRUB path.  */
+ 
+@@ -126,6 +110,8 @@ grub_machine_get_bootlocation (char **device, char **path)
+       char *ptr;
+       dev = grub_ieee1275_get_aliasdevname (bootpath);
+       canon = grub_ieee1275_canonicalise_devname (dev);
++      if (! canon)
++        return;
+       ptr = canon + grub_strlen (canon) - 1;
+       while (ptr > canon && (*ptr == ',' || *ptr == ':'))
+ 	ptr--;
+diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c
+index ddb778340e4ab74148898b32cd27139fd4f1465b..62929d983bfaa2c83158ee4fe6797125c6d6b844 100644
+--- a/grub-core/kern/ieee1275/openfw.c
++++ b/grub-core/kern/ieee1275/openfw.c
+@@ -561,3 +561,30 @@ grub_ieee1275_canonicalise_devname (const char *path)
+   return NULL;
+ }
+ 
++char *
++grub_ieee1275_get_boot_dev (void)
++{
++  char *bootpath;
++  grub_ssize_t bootpath_size;
++
++  if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath",
++					 &bootpath_size)
++      || bootpath_size <= 0)
++    {
++      /* Should never happen. */
++      grub_printf ("/chosen/bootpath property missing!\n");
++      return NULL;
++    }
++
++  bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64);
++  if (! bootpath)
++    {
++      grub_print_error ();
++      return NULL;
++    }
++  grub_ieee1275_get_property (grub_ieee1275_chosen, "bootpath", bootpath,
++                              (grub_size_t) bootpath_size + 1, 0);
++  bootpath[bootpath_size] = '\0';
++
++  return bootpath;
++}
+diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
+index d1a54df6c12e3358e07aa86366c65af22ca3af5c..3b633d51f4c63e2983e8b3419dc057437224fb93 100644
+--- a/grub-core/kern/misc.c
++++ b/grub-core/kern/misc.c
+@@ -391,12 +391,13 @@ grub_strtoull (const char *str, char **end, int base)
+       unsigned long digit;
+ 
+       digit = grub_tolower (*str) - '0';
+-      if (digit > 9)
+-	{
+-	  digit += '0' - 'a' + 10;
+-	  if (digit >= (unsigned long) base)
+-	    break;
+-	}
++      if (digit >= 'a' - '0')
++	digit += '0' - 'a' + 10;
++      else if (digit > 9)
++	break;
++
++      if (digit >= (unsigned long) base)
++	break;
+ 
+       found = 1;
+ 
+diff --git a/grub-core/kern/sparc64/ieee1275/ieee1275.c b/grub-core/kern/sparc64/ieee1275/ieee1275.c
+index 53be692c3d88940572d423ceb09e4187372fcb5b..5a59aaf06193442fa5ec7a537c9cfb10dd3081aa 100644
+--- a/grub-core/kern/sparc64/ieee1275/ieee1275.c
++++ b/grub-core/kern/sparc64/ieee1275/ieee1275.c
+@@ -89,3 +89,59 @@ grub_ieee1275_alloc_physmem (grub_addr_t *paddr, grub_size_t size,
+ 
+   return args.catch_result;
+ }
++
++grub_uint64_t
++grub_ieee1275_num_blocks (grub_ieee1275_ihandle_t ihandle)
++{
++  struct nblocks_args_ieee1275
++  {
++    struct grub_ieee1275_common_hdr common;
++    grub_ieee1275_cell_t method;
++    grub_ieee1275_cell_t ihandle;
++    grub_ieee1275_cell_t catch_result;
++    grub_ieee1275_cell_t blocks;
++  }
++  args;
++
++  INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 2);
++  args.method = (grub_ieee1275_cell_t) "#blocks";
++  args.ihandle = ihandle;
++  args.catch_result = 1;
++
++  if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.catch_result != 0))
++    return -1;
++
++  /*
++   * If the number of blocks exceeds the range of an unsigned number,
++   * return 0 to alert the caller to try the #blocks64 command.
++   */
++  if (args.blocks >= 0xffffffffULL)
++    return 0;
++
++  return args.blocks;
++}
++
++grub_uint64_t
++grub_ieee1275_num_blocks64 (grub_ieee1275_ihandle_t ihandle)
++{
++  struct nblocks_args_ieee1275
++  {
++    struct grub_ieee1275_common_hdr common;
++    grub_ieee1275_cell_t method;
++    grub_ieee1275_cell_t ihandle;
++    grub_ieee1275_cell_t catch_result;
++    grub_ieee1275_cell_t hi_blocks;
++    grub_ieee1275_cell_t lo_blocks;
++  }
++  args;
++
++  INIT_IEEE1275_COMMON (&args.common, "call-method", 2, 3);
++  args.method = (grub_ieee1275_cell_t) "#blocks64";
++  args.ihandle = ihandle;
++  args.catch_result = 1;
++
++  if ((IEEE1275_CALL_ENTRY_FN (&args) == -1) || (args.catch_result != 0))
++    return -1;
++
++  return ((args.hi_blocks << 32) | (args.lo_blocks));
++}
+diff --git a/grub-core/kern/uboot/init.c b/grub-core/kern/uboot/init.c
+index 5dcc106ed9bcc1fa2cdbe2ba6cbb9e709420ceb3..3e338645c573aa707343235029d9fc45d515a9dc 100644
+--- a/grub-core/kern/uboot/init.c
++++ b/grub-core/kern/uboot/init.c
+@@ -36,30 +36,14 @@
+ extern char __bss_start[];
+ extern char _end[];
+ extern grub_size_t grub_total_module_size;
+-extern int (*grub_uboot_syscall_ptr) (int, int *, ...);
+ static unsigned long timer_start;
+ 
+-extern grub_uint32_t grub_uboot_machine_type;
+-extern grub_addr_t grub_uboot_boot_data;
+-
+ void
+ grub_exit (void)
+ {
+   grub_uboot_return (0);
+ }
+ 
+-grub_uint32_t
+-grub_uboot_get_machine_type (void)
+-{
+-  return grub_uboot_machine_type;
+-}
+-
+-grub_addr_t
+-grub_uboot_get_boot_data (void)
+-{
+-  return grub_uboot_boot_data;
+-}
+-
+ static grub_uint64_t
+ uboot_timer_ms (void)
+ {
+diff --git a/grub-core/kern/uboot/uboot.c b/grub-core/kern/uboot/uboot.c
+index 6800a4beb1c4e83ef9f4ac5da872d2557d8471e1..cf0168e62ddd26db50efd2351499fa7f74fce26c 100644
+--- a/grub-core/kern/uboot/uboot.c
++++ b/grub-core/kern/uboot/uboot.c
+@@ -39,48 +39,13 @@
+  * returns:	0 if the call not found, 1 if serviced
+  */
+ 
+-extern int (*grub_uboot_syscall_ptr) (int, int *, ...);
+ extern int grub_uboot_syscall (int, int *, ...);
+-extern grub_addr_t grub_uboot_search_hint;
+ 
+ static struct sys_info uboot_sys_info;
+ static struct mem_region uboot_mem_info[5];
+ static struct device_info * devices;
+ static int num_devices;
+ 
+-int
+-grub_uboot_api_init (void)
+-{
+-  struct api_signature *start, *end;
+-  struct api_signature *p;
+-
+-  if (grub_uboot_search_hint)
+-    {
+-      /* Extended search range to work around Trim Slice U-Boot issue */
+-      start = (struct api_signature *) ((grub_uboot_search_hint & ~0x000fffff)
+-					- 0x00500000);
+-      end =
+-	(struct api_signature *) ((grub_addr_t) start + UBOOT_API_SEARCH_LEN -
+-				  API_SIG_MAGLEN + 0x00500000);
+-    }
+-  else
+-    {
+-      start = 0;
+-      end = (struct api_signature *) (256 * 1024 * 1024);
+-    }
+-
+-  /* Structure alignment is (at least) 8 bytes */
+-  for (p = start; p < end; p = (void *) ((grub_addr_t) p + 8))
+-    {
+-      if (grub_memcmp (&(p->magic), API_SIG_MAGIC, API_SIG_MAGLEN) == 0)
+-	{
+-	  grub_uboot_syscall_ptr = p->syscall;
+-	  return p->version;
+-	}
+-    }
+-
+-  return 0;
+-}
+ 
+ /*
+  * All functions below are wrappers around the grub_uboot_syscall() function
+diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c
+index 44069067312a890b4e3ebb5130861ed23572bc54..3a73e6e6ce2c5aefc33313e583cb259ea9bc2645 100644
+--- a/grub-core/kern/x86_64/dl.c
++++ b/grub-core/kern/x86_64/dl.c
+@@ -70,6 +70,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+ 	  break;
+ 
+ 	case R_X86_64_PC32:
++	case R_X86_64_PLT32:
+ 	  {
+ 	    grub_int64_t value;
+ 	    value = ((grub_int32_t) *addr32) + rel->r_addend + sym->st_value -
+diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c
+index 683a8aaa711c4eab0208d116cd7275a6ac678986..ca334d5a40e0716bdc9afbb79135c47d174532da 100644
+--- a/grub-core/lib/crypto.c
++++ b/grub-core/lib/crypto.c
+@@ -462,7 +462,7 @@ grub_password_get (char buf[], unsigned buf_size)
+       if (key == '\n' || key == '\r')
+ 	break;
+ 
+-      if (key == '\e')
++      if (key == GRUB_TERM_ESC)
+ 	{
+ 	  cur_len = 0;
+ 	  break;
+@@ -487,7 +487,7 @@ grub_password_get (char buf[], unsigned buf_size)
+   grub_xputs ("\n");
+   grub_refresh ();
+ 
+-  return (key != '\e');
++  return (key != GRUB_TERM_ESC);
+ }
+ #endif
+ 
+diff --git a/grub-core/lib/uboot/datetime.c b/grub-core/lib/dummy/datetime.c
+similarity index 91%
+rename from grub-core/lib/uboot/datetime.c
+rename to grub-core/lib/dummy/datetime.c
+index 4be716928a55b789510dfdcdd1833e29e5cd11fe..cf693fc6b621376b5cae0ca0a74b4421799b5a9e 100644
+--- a/grub-core/lib/uboot/datetime.c
++++ b/grub-core/lib/dummy/datetime.c
+@@ -18,7 +18,6 @@
+ 
+ #include <grub/types.h>
+ #include <grub/symbol.h>
+-#include <grub/uboot/uboot.h>
+ #include <grub/datetime.h>
+ #include <grub/dl.h>
+ 
+@@ -30,12 +29,12 @@ grub_err_t
+ grub_get_datetime (struct grub_datetime *datetime __attribute__ ((unused)))
+ {
+   return grub_error (GRUB_ERR_INVALID_COMMAND,
+-		     "can\'t get datetime using U-Boot");
++		     "can\'t get datetime on this machine");
+ }
+ 
+ grub_err_t
+ grub_set_datetime (struct grub_datetime * datetime __attribute__ ((unused)))
+ {
+   return grub_error (GRUB_ERR_INVALID_COMMAND,
+-		     "can\'t set datetime using U-Boot");
++		     "can\'t set datetime on this machine");
+ }
+diff --git a/grub-core/lib/uboot/halt.c b/grub-core/lib/dummy/halt.c
+similarity index 100%
+rename from grub-core/lib/uboot/halt.c
+rename to grub-core/lib/dummy/halt.c
+diff --git a/grub-core/lib/efi/reboot.c b/grub-core/lib/dummy/reboot.c
+similarity index 77%
+rename from grub-core/lib/efi/reboot.c
+rename to grub-core/lib/dummy/reboot.c
+index 7de8bcb5d6ea128dd406001d970d18ff00ea0f3c..b8cbed8f8117ca9c53cc2087dee87ae68876d64f 100644
+--- a/grub-core/lib/efi/reboot.c
++++ b/grub-core/lib/dummy/reboot.c
+@@ -1,6 +1,6 @@
+ /*
+  *  GRUB  --  GRand Unified Bootloader
+- *  Copyright (C) 2011  Free Software Foundation, Inc.
++ *  Copyright (C) 2013  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
+@@ -16,10 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#include <grub/efi/api.h>
+-#include <grub/efi/efi.h>
+-#include <grub/mm.h>
+ #include <grub/misc.h>
++#include <grub/mm.h>
+ #include <grub/kernel.h>
+ #include <grub/loader.h>
+ 
+@@ -27,7 +25,8 @@ void
+ grub_reboot (void)
+ {
+   grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
+-  efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
+-              GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL);
+-  for (;;) ;
++
++  /* Just stop here */
++
++  while (1);
+ }
+diff --git a/grub-core/lib/fdt.c b/grub-core/lib/fdt.c
+index b5d520f208886aa663d4aac36cec9b43a2d0da42..0d371c5633e84bbf47114bfe2c23427982e25192 100644
+--- a/grub-core/lib/fdt.c
++++ b/grub-core/lib/fdt.c
+@@ -41,11 +41,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ 	(2 * sizeof(grub_uint32_t)	\
+ 	+ ALIGN_UP (grub_strlen (name) + 1, sizeof(grub_uint32_t)))
+ 
+-/* Size needed by a property entry: 1 token (FDT_PROPERTY), plus len and nameoff
+-   fields, plus the property value, plus padding if needed. */
+-#define prop_entry_size(prop_len)	\
+-	(3 * sizeof(grub_uint32_t) + ALIGN_UP(prop_len, sizeof(grub_uint32_t)))
+-
+ #define SKIP_NODE_NAME(name, token, end)	\
+   name = (char *) ((token) + 1);	\
+   while (name < (char *) end)	\
+@@ -86,7 +81,7 @@ static grub_uint32_t *get_next_node (const void *fdt, char *node_name)
+       case FDT_PROP:
+         /* Skip property token and following data (len, nameoff and property
+            value). */
+-        token += prop_entry_size(grub_be_to_cpu32(*(token + 1)))
++        token += grub_fdt_prop_entry_size(grub_be_to_cpu32(*(token + 1)))
+                  / sizeof(*token);
+         break;
+       case FDT_NOP:
+@@ -102,13 +97,13 @@ static grub_uint32_t *get_next_node (const void *fdt, char *node_name)
+ static int get_mem_rsvmap_size (const void *fdt)
+ {
+   int size = 0;
+-  grub_uint64_t *ptr = (void *) ((grub_addr_t) fdt
+-                                 + grub_fdt_get_off_mem_rsvmap (fdt));
++  grub_unaligned_uint64_t *ptr = (void *) ((grub_addr_t) fdt
++					   + grub_fdt_get_off_mem_rsvmap (fdt));
+ 
+   do
+   {
+     size += 2 * sizeof(*ptr);
+-    if (!*ptr && !*(ptr + 1))
++    if (!ptr[0].val && !ptr[1].val)
+       return size;
+     ptr += 2;
+   } while ((grub_addr_t) ptr <= (grub_addr_t) fdt + grub_fdt_get_totalsize (fdt)
+@@ -150,7 +145,7 @@ static int add_subnode (void *fdt, int parentoffset, const char *name)
+     {
+       case FDT_PROP:
+         /* Skip len, nameoff and property value. */
+-        token += prop_entry_size(grub_be_to_cpu32(*(token + 1)))
++        token += grub_fdt_prop_entry_size(grub_be_to_cpu32(*(token + 1)))
+                  / sizeof(*token);
+         break;
+       case FDT_BEGIN_NODE:
+@@ -229,7 +224,7 @@ static int rearrange_blocks (void *fdt, unsigned int clearance)
+   return 0;
+ }
+ 
+-static grub_uint32_t *find_prop (void *fdt, unsigned int nodeoffset,
++static grub_uint32_t *find_prop (const void *fdt, unsigned int nodeoffset,
+ 				 const char *name)
+ {
+   grub_uint32_t *prop = (void *) ((grub_addr_t) fdt
+@@ -249,12 +244,12 @@ static grub_uint32_t *find_prop (void *fdt, unsigned int nodeoffset,
+             && !grub_strcmp (name, (char *) fdt +
+                              grub_fdt_get_off_dt_strings (fdt) + nameoff))
+         {
+-          if (prop + prop_entry_size(grub_be_to_cpu32(*(prop + 1)))
++          if (prop + grub_fdt_prop_entry_size(grub_be_to_cpu32(*(prop + 1)))
+               / sizeof (*prop) >= end)
+             return NULL;
+           return prop;
+         }
+-        prop += prop_entry_size(grub_be_to_cpu32(*(prop + 1))) / sizeof (*prop);
++        prop += grub_fdt_prop_entry_size(grub_be_to_cpu32(*(prop + 1))) / sizeof (*prop);
+       }
+     else if (grub_be_to_cpu32(*prop) == FDT_NOP)
+       prop++;
+@@ -268,9 +263,9 @@ static grub_uint32_t *find_prop (void *fdt, unsigned int nodeoffset,
+    the size allocated for the FDT; if this function is called before the other
+    functions in this file and returns success, the other functions are
+    guaranteed not to access memory locations outside the allocated memory. */
+-int grub_fdt_check_header_nosize (void *fdt)
++int grub_fdt_check_header_nosize (const void *fdt)
+ {
+-  if (((grub_addr_t) fdt & 0x7) || (grub_fdt_get_magic (fdt) != FDT_MAGIC)
++  if (((grub_addr_t) fdt & 0x3) || (grub_fdt_get_magic (fdt) != FDT_MAGIC)
+       || (grub_fdt_get_version (fdt) < FDT_SUPPORTED_VERSION)
+       || (grub_fdt_get_last_comp_version (fdt) > FDT_SUPPORTED_VERSION)
+       || (grub_fdt_get_off_dt_struct (fdt) & 0x00000003)
+@@ -286,7 +281,7 @@ int grub_fdt_check_header_nosize (void *fdt)
+   return 0;
+ }
+ 
+-int grub_fdt_check_header (void *fdt, unsigned int size)
++int grub_fdt_check_header (const void *fdt, unsigned int size)
+ {
+   if (size < sizeof (grub_fdt_header_t)
+       || (grub_fdt_get_totalsize (fdt) > size)
+@@ -295,52 +290,105 @@ int grub_fdt_check_header (void *fdt, unsigned int size)
+   return 0;
+ }
+ 
++static const grub_uint32_t *
++advance_token (const void *fdt, const grub_uint32_t *token, const grub_uint32_t *end, int skip_current)
++{
++  for (; token < end; skip_current = 0)
++  {
++    switch (grub_be_to_cpu32 (*token))
++    {
++      case FDT_BEGIN_NODE:
++	if (skip_current)
++	  {
++	    token = get_next_node (fdt, (char *) (token + 1));
++	    continue;
++	  }
++	char *ptr;
++	for (ptr = (char *) (token + 1); *ptr && ptr < (char *) end; ptr++)
++	  ;
++        if (ptr >= (char *) end)
++          return 0;
++	return token;
++      case FDT_PROP:
++        /* Skip property token and following data (len, nameoff and property
++           value). */
++        if (token >= end - 1)
++          return 0;
++        token += grub_fdt_prop_entry_size(grub_be_to_cpu32(*(token + 1)))
++                 / sizeof(*token);
++        break;
++      case FDT_NOP:
++        token++;
++        break;
++      default:
++        return 0;
++    }
++  }
++  return 0;
++}
++
++int grub_fdt_next_node (const void *fdt, unsigned int currentoffset)
++{
++  const grub_uint32_t *token = (const grub_uint32_t *) fdt + (currentoffset + grub_fdt_get_off_dt_struct (fdt)) / 4;
++  token = advance_token (fdt, token, (const void *) struct_end (fdt), 1);
++  if (!token)
++    return -1;
++  return (int) ((grub_addr_t) token - (grub_addr_t) fdt
++		- grub_fdt_get_off_dt_struct (fdt));
++}			 
++
++int grub_fdt_first_node (const void *fdt, unsigned int parentoffset)
++{
++  const grub_uint32_t *token, *end;
++  char *node_name;
++
++  if (parentoffset & 0x3)
++    return -1;
++  token = (const void *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt)
++                    + parentoffset);
++  end = (const void *) struct_end (fdt);
++  if ((token >= end) || (grub_be_to_cpu32(*token) != FDT_BEGIN_NODE))
++    return -1;
++  SKIP_NODE_NAME(node_name, token, end);
++  token = advance_token (fdt, token, end, 0);
++  if (!token)
++    return -1;
++  return (int) ((grub_addr_t) token - (grub_addr_t) fdt
++		- grub_fdt_get_off_dt_struct (fdt));
++}			 
++
+ /* Find a direct sub-node of a given parent node. */
+ int grub_fdt_find_subnode (const void *fdt, unsigned int parentoffset,
+ 			   const char *name)
+ {
+-  grub_uint32_t *token, *end;
+-  char *node_name;
++  const grub_uint32_t *token, *end;
++  const char *node_name;
++  int skip_current = 0;
+ 
+   if (parentoffset & 0x3)
+     return -1;
+-  token = (void *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt)
++  token = (const void *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct(fdt)
+                     + parentoffset);
+-  end = (void *) struct_end (fdt);
++  end = (const void *) struct_end (fdt);
+   if ((token >= end) || (grub_be_to_cpu32(*token) != FDT_BEGIN_NODE))
+     return -1;
+   SKIP_NODE_NAME(node_name, token, end);
+-  while (token < end)
+-  {
+-    switch (grub_be_to_cpu32(*token))
+-    {
+-      case FDT_BEGIN_NODE:
+-        node_name = (char *) (token + 1);
+-        if (node_name + grub_strlen (name) >= (char *) end)
+-          return -1;
+-        if (!grub_strcmp (node_name, name))
+-          return (int) ((grub_addr_t) token - (grub_addr_t) fdt
+-                        - grub_fdt_get_off_dt_struct (fdt));
+-        token = get_next_node (fdt, node_name);
+-        if (!token)
+-          return -1;
+-        break;
+-      case FDT_PROP:
+-        /* Skip property token and following data (len, nameoff and property
+-           value). */
+-        if (token >= end - 1)
+-          return -1;
+-        token += prop_entry_size(grub_be_to_cpu32(*(token + 1)))
+-                 / sizeof(*token);
+-        break;
+-      case FDT_NOP:
+-        token++;
+-        break;
+-      default:
+-        return -1;
+-    }
++  while (1) {
++    token = advance_token (fdt, token, end, skip_current);
++    if (!token)
++      return -1;
++    skip_current = 1;
++    node_name = (const char *) token + 4;
++    if (grub_strcmp (node_name, name) == 0)
++      return (int) ((grub_addr_t) token - (grub_addr_t) fdt
++		    - grub_fdt_get_off_dt_struct (fdt));
+   }
+-  return -1;
++}
++
++const char *
++grub_fdt_get_nodename (const void *fdt, unsigned int nodeoffset)
++{
++  return (const char *) fdt + grub_fdt_get_off_dt_struct(fdt) + nodeoffset + 4;
+ }
+ 
+ int grub_fdt_add_subnode (void *fdt, unsigned int parentoffset,
+@@ -359,6 +407,24 @@ int grub_fdt_add_subnode (void *fdt, unsigned int parentoffset,
+   return add_subnode (fdt, parentoffset, name);
+ }
+ 
++const void *
++grub_fdt_get_prop (const void *fdt, unsigned int nodeoffset, const char *name,
++		   grub_uint32_t *len)
++{
++  grub_uint32_t *prop;
++  if ((nodeoffset >= grub_fdt_get_size_dt_struct (fdt)) || (nodeoffset & 0x3)
++      || (grub_be_to_cpu32(*(grub_uint32_t *) ((grub_addr_t) fdt
++					       + grub_fdt_get_off_dt_struct (fdt) + nodeoffset))
++          != FDT_BEGIN_NODE))
++    return 0;
++  prop = find_prop (fdt, nodeoffset, name);
++  if (!prop)
++    return 0;
++  if (len)
++    *len = grub_be_to_cpu32 (*(prop + 1));
++  return prop + 3;
++}
++
+ int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
+ 		       const void *val, grub_uint32_t len)
+ {
+@@ -396,12 +462,12 @@ int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
+     unsigned int needed_space = 0;
+ 
+     if (!prop)
+-      needed_space = prop_entry_size(len);
++      needed_space = grub_fdt_prop_entry_size(len);
+     if (!prop_name_present)
+       needed_space += grub_strlen (name) + 1;
+     if (needed_space > get_free_space (fdt))
+       return -1;
+-    if (rearrange_blocks (fdt, !prop ? prop_entry_size(len) : 0) < 0)
++    if (rearrange_blocks (fdt, !prop ? grub_fdt_prop_entry_size(len) : 0) < 0)
+       return -1;
+   }
+   if (!prop_name_present) {
+@@ -418,10 +484,10 @@ int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
+                                 + sizeof(grub_uint32_t));
+ 
+     prop = (void *) (node_name + ALIGN_UP(grub_strlen(node_name) + 1, 4));
+-    grub_memmove (prop + prop_entry_size(len) / sizeof(*prop), prop,
++    grub_memmove (prop + grub_fdt_prop_entry_size(len) / sizeof(*prop), prop,
+                   struct_end(fdt) - (grub_addr_t) prop);
+     grub_fdt_set_size_dt_struct (fdt, grub_fdt_get_size_dt_struct (fdt)
+-                                 + prop_entry_size(len));
++                                 + grub_fdt_prop_entry_size(len));
+     *prop = grub_cpu_to_be32_compile_time (FDT_PROP);
+     *(prop + 2) = grub_cpu_to_be32 (nameoff);
+   }
+@@ -429,7 +495,7 @@ int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
+ 
+   /* Insert padding bytes at the end of the value; if they are not needed, they
+      will be overwritten by the following memcpy. */
+-  *(prop + prop_entry_size(len) / sizeof(grub_uint32_t) - 1) = 0;
++  *(prop + grub_fdt_prop_entry_size(len) / sizeof(grub_uint32_t) - 1) = 0;
+ 
+   grub_memcpy (prop + 3, val, len);
+   return 0;
+diff --git a/grub-core/lib/i386/reboot.c b/grub-core/lib/i386/reboot.c
+index a234244dce5b4c5afd5c68e579c4519a870cda36..dce0b563dcd39ce7acc6d5ec0cc759e67c8c8b87 100644
+--- a/grub-core/lib/i386/reboot.c
++++ b/grub-core/lib/i386/reboot.c
+@@ -16,6 +16,8 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
++#ifndef GRUB_MACHINE_EFI
++
+ #include <grub/relocator.h>
+ #include <grub/cpu/relocator.h>
+ #include <grub/misc.h>
+@@ -58,3 +60,5 @@ grub_reboot (void)
+ 
+   while (1);
+ }
++
++#endif /* GRUB_MACHINE_EFI */
+diff --git a/grub-core/lib/libgcrypt/cipher/crc.c b/grub-core/lib/libgcrypt/cipher/crc.c
+index 9e406f1b19b4d1d49c1ba5140c47d630972c0d8e..28454f8ab728c657d0b440371765030deb35a407 100644
+--- a/grub-core/lib/libgcrypt/cipher/crc.c
++++ b/grub-core/lib/libgcrypt/cipher/crc.c
+@@ -28,116 +28,8 @@
+ #include "cipher.h"
+ 
+ #include "bithelp.h"
++#include "bufhelp.h"
+ 
+-/* Table of CRCs of all 8-bit messages.  Generated by running code
+-   from RFC 1952 modified to print out the table. */
+-static u32 crc32_table[256] = {
+-  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+-  0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+-  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+-  0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+-  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+-  0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+-  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+-  0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+-  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+-  0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+-  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+-  0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+-  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+-  0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+-  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+-  0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+-  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+-  0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+-  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+-  0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+-  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+-  0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+-  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+-  0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+-  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+-  0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+-  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+-  0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+-  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+-  0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+-  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+-  0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+-  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+-  0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+-  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+-  0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+-  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+-  0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+-  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+-  0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+-  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+-  0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+-  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+-};
+-
+-/*
+- * The following function was extracted from RFC 1952 by Simon
+- * Josefsson, for the Shishi project, and modified to be compatible
+- * with the modified CRC-32 used by RFC 1510, and subsequently
+- * modified for GNU Libgcrypt to allow it to be used for calculating
+- * both unmodified CRC-32 and modified CRC-32 values.  Original
+- * copyright and notice from the document follows:
+- *
+- *    Copyright (c) 1996 L. Peter Deutsch
+- *
+- *    Permission is granted to copy and distribute this document for
+- *    any purpose and without charge, including translations into
+- *    other languages and incorporation into compilations, provided
+- *    that the copyright notice and this notice are preserved, and
+- *    that any substantive changes or deletions from the original are
+- *    clearly marked.
+- *
+- * The copyright on RFCs, and consequently the function below, are
+- * supposedly also retroactively claimed by the Internet Society
+- * (according to rfc-editor@rfc-editor.org), with the following
+- * copyright notice:
+- *
+- *    Copyright (C) The Internet Society.  All Rights Reserved.
+- *
+- *    This document and translations of it may be copied and furnished
+- *    to others, and derivative works that comment on or otherwise
+- *    explain it or assist in its implementation may be prepared,
+- *    copied, published and distributed, in whole or in part, without
+- *    restriction of any kind, provided that the above copyright
+- *    notice and this paragraph are included on all such copies and
+- *    derivative works.  However, this document itself may not be
+- *    modified in any way, such as by removing the copyright notice or
+- *    references to the Internet Society or other Internet
+- *    organizations, except as needed for the purpose of developing
+- *    Internet standards in which case the procedures for copyrights
+- *    defined in the Internet Standards process must be followed, or
+- *    as required to translate it into languages other than English.
+- *
+- *    The limited permissions granted above are perpetual and will not be
+- *    revoked by the Internet Society or its successors or assigns.
+- *
+- *    This document and the information contained herein is provided
+- *    on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET
+- *    ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR
+- *    IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE
+- *    OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY
+- *    IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
+- *    PARTICULAR PURPOSE.
+- *
+- */
+-static u32
+-update_crc32 (u32 crc, const void *buf_arg, size_t len)
+-{
+-  const char *buf = buf_arg;
+-  size_t n;
+-
+-  for (n = 0; n < len; n++)
+-    crc = crc32_table[(crc ^ buf[n]) & 0xff] ^ (crc >> 8);
+-
+-  return crc;
+-}
+ 
+ typedef struct
+ {
+@@ -146,8 +38,302 @@ typedef struct
+ }
+ CRC_CONTEXT;
+ 
++
++/*
++ * Code generated by universal_crc by Danjel McGougan
++ *
++ * CRC parameters used:
++ *   bits:       32
++ *   poly:       0x04c11db7
++ *   init:       0xffffffff
++ *   xor:        0xffffffff
++ *   reverse:    true
++ *   non-direct: false
++ *
++ * CRC of the string "123456789" is 0xcbf43926
++ */
++
++static const u32 crc32_table[1024] = {
++  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
++  0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
++  0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
++  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
++  0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
++  0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
++  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
++  0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
++  0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
++  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
++  0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
++  0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
++  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
++  0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
++  0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
++  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
++  0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
++  0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
++  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
++  0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
++  0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
++  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
++  0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
++  0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
++  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
++  0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
++  0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
++  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
++  0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
++  0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
++  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
++  0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
++  0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
++  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
++  0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
++  0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
++  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
++  0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
++  0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
++  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
++  0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
++  0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
++  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
++  0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
++  0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
++  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
++  0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
++  0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
++  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
++  0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
++  0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
++  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
++  0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
++  0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
++  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
++  0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
++  0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
++  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
++  0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
++  0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
++  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
++  0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
++  0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
++  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
++  0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3,
++  0x646cc504, 0x7d77f445, 0x565aa786, 0x4f4196c7,
++  0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb,
++  0xacb54f0c, 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf,
++  0x4ac21251, 0x53d92310, 0x78f470d3, 0x61ef4192,
++  0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496,
++  0x821b9859, 0x9b00a918, 0xb02dfadb, 0xa936cb9a,
++  0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, 0xcd5a0e9e,
++  0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761,
++  0xf1e8e1a6, 0xe8f3d0e7, 0xc3de8324, 0xdac5b265,
++  0x5d5daeaa, 0x44469feb, 0x6f6bcc28, 0x7670fd69,
++  0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d,
++  0xdf4636f3, 0xc65d07b2, 0xed705471, 0xf46b6530,
++  0xbb2af3f7, 0xa231c2b6, 0x891c9175, 0x9007a034,
++  0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38,
++  0x73f379ff, 0x6ae848be, 0x41c51b7d, 0x58de2a3c,
++  0xf0794f05, 0xe9627e44, 0xc24f2d87, 0xdb541cc6,
++  0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2,
++  0x38a0c50d, 0x21bbf44c, 0x0a96a78f, 0x138d96ce,
++  0x5ccc0009, 0x45d73148, 0x6efa628b, 0x77e153ca,
++  0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97,
++  0xded79850, 0xc7cca911, 0xece1fad2, 0xf5facb93,
++  0x7262d75c, 0x6b79e61d, 0x4054b5de, 0x594f849f,
++  0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b,
++  0x65fd6ba7, 0x7ce65ae6, 0x57cb0925, 0x4ed03864,
++  0x0191aea3, 0x188a9fe2, 0x33a7cc21, 0x2abcfd60,
++  0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c,
++  0xc94824ab, 0xd05315ea, 0xfb7e4629, 0xe2657768,
++  0x2f3f79f6, 0x362448b7, 0x1d091b74, 0x04122a35,
++  0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31,
++  0xe7e6f3fe, 0xfefdc2bf, 0xd5d0917c, 0xcccba03d,
++  0x838a36fa, 0x9a9107bb, 0xb1bc5478, 0xa8a76539,
++  0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88,
++  0x5fef5d4f, 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c,
++  0xf35a1243, 0xea412302, 0xc16c70c1, 0xd8774180,
++  0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484,
++  0x71418a1a, 0x685abb5b, 0x4377e898, 0x5a6cd9d9,
++  0x152d4f1e, 0x0c367e5f, 0x271b2d9c, 0x3e001cdd,
++  0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1,
++  0xddf4c516, 0xc4eff457, 0xefc2a794, 0xf6d996d5,
++  0xae07bce9, 0xb71c8da8, 0x9c31de6b, 0x852aef2a,
++  0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e,
++  0x66de36e1, 0x7fc507a0, 0x54e85463, 0x4df36522,
++  0x02b2f3e5, 0x1ba9c2a4, 0x30849167, 0x299fa026,
++  0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b,
++  0x80a96bbc, 0x99b25afd, 0xb29f093e, 0xab84387f,
++  0x2c1c24b0, 0x350715f1, 0x1e2a4632, 0x07317773,
++  0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277,
++  0xcbfad74e, 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d,
++  0xaf96124a, 0xb68d230b, 0x9da070c8, 0x84bb4189,
++  0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85,
++  0x674f9842, 0x7e54a903, 0x5579fac0, 0x4c62cb81,
++  0x8138c51f, 0x9823f45e, 0xb30ea79d, 0xaa1596dc,
++  0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8,
++  0x49e14f17, 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4,
++  0x2d8d8a13, 0x3496bb52, 0x1fbbe891, 0x06a0d9d0,
++  0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f,
++  0x3a1236e8, 0x230907a9, 0x0824546a, 0x113f652b,
++  0x96a779e4, 0x8fbc48a5, 0xa4911b66, 0xbd8a2a27,
++  0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23,
++  0x14bce1bd, 0x0da7d0fc, 0x268a833f, 0x3f91b27e,
++  0x70d024b9, 0x69cb15f8, 0x42e6463b, 0x5bfd777a,
++  0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876,
++  0xb809aeb1, 0xa1129ff0, 0x8a3fcc33, 0x9324fd72,
++  0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59,
++  0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, 0x054f1685,
++  0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1,
++  0x091af964, 0x08d89353, 0x0a9e2d0a, 0x0b5c473d,
++  0x1c26a370, 0x1de4c947, 0x1fa2771e, 0x1e601d29,
++  0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5,
++  0x1235f2c8, 0x13f798ff, 0x11b126a6, 0x10734c91,
++  0x153c5a14, 0x14fe3023, 0x16b88e7a, 0x177ae44d,
++  0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9,
++  0x3f44ee3c, 0x3e86840b, 0x3cc03a52, 0x3d025065,
++  0x365e1758, 0x379c7d6f, 0x35dac336, 0x3418a901,
++  0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd,
++  0x246be590, 0x25a98fa7, 0x27ef31fe, 0x262d5bc9,
++  0x23624d4c, 0x22a0277b, 0x20e69922, 0x2124f315,
++  0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71,
++  0x2d711cf4, 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad,
++  0x709a8dc0, 0x7158e7f7, 0x731e59ae, 0x72dc3399,
++  0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45,
++  0x7e89dc78, 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221,
++  0x798074a4, 0x78421e93, 0x7a04a0ca, 0x7bc6cafd,
++  0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9,
++  0x6bb5866c, 0x6a77ec5b, 0x68315202, 0x69f33835,
++  0x62af7f08, 0x636d153f, 0x612bab66, 0x60e9c151,
++  0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d,
++  0x48d7cb20, 0x4915a117, 0x4b531f4e, 0x4a917579,
++  0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, 0x4d98dda5,
++  0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1,
++  0x41cd3244, 0x400f5873, 0x4249e62a, 0x438b8c1d,
++  0x54f16850, 0x55330267, 0x5775bc3e, 0x56b7d609,
++  0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5,
++  0x5ae239e8, 0x5b2053df, 0x5966ed86, 0x58a487b1,
++  0x5deb9134, 0x5c29fb03, 0x5e6f455a, 0x5fad2f6d,
++  0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9,
++  0xe63cb35c, 0xe7fed96b, 0xe5b86732, 0xe47a0d05,
++  0xef264a38, 0xeee4200f, 0xeca29e56, 0xed60f461,
++  0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd,
++  0xfd13b8f0, 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9,
++  0xfa1a102c, 0xfbd87a1b, 0xf99ec442, 0xf85cae75,
++  0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711,
++  0xf4094194, 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd,
++  0xd9785d60, 0xd8ba3757, 0xdafc890e, 0xdb3ee339,
++  0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5,
++  0xd76b0cd8, 0xd6a966ef, 0xd4efd8b6, 0xd52db281,
++  0xd062a404, 0xd1a0ce33, 0xd3e6706a, 0xd2241a5d,
++  0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049,
++  0xc25756cc, 0xc3953cfb, 0xc1d382a2, 0xc011e895,
++  0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, 0xc90b11f1,
++  0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d,
++  0x91af9640, 0x906dfc77, 0x922b422e, 0x93e92819,
++  0x96a63e9c, 0x976454ab, 0x9522eaf2, 0x94e080c5,
++  0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1,
++  0x98b56f24, 0x99770513, 0x9b31bb4a, 0x9af3d17d,
++  0x8d893530, 0x8c4b5f07, 0x8e0de15e, 0x8fcf8b69,
++  0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5,
++  0x839a6488, 0x82580ebf, 0x801eb0e6, 0x81dcdad1,
++  0x8493cc54, 0x8551a663, 0x8717183a, 0x86d5720d,
++  0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9,
++  0xaeeb787c, 0xaf29124b, 0xad6fac12, 0xacadc625,
++  0xa7f18118, 0xa633eb2f, 0xa4755576, 0xa5b73f41,
++  0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d,
++  0xb5c473d0, 0xb40619e7, 0xb640a7be, 0xb782cd89,
++  0xb2cddb0c, 0xb30fb13b, 0xb1490f62, 0xb08b6555,
++  0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31,
++  0xbcde8ab4, 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed,
++  0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee,
++  0x8f629757, 0x37def032, 0x256b5fdc, 0x9dd738b9,
++  0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701,
++  0x4ad6bfb8, 0xf26ad8dd, 0xe0df7733, 0x58631056,
++  0x5019579f, 0xe8a530fa, 0xfa109f14, 0x42acf871,
++  0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26,
++  0x95ad7f70, 0x2d111815, 0x3fa4b7fb, 0x8718d09e,
++  0x1acfe827, 0xa2738f42, 0xb0c620ac, 0x087a47c9,
++  0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0,
++  0x2f503869, 0x97ec5f0c, 0x8559f0e2, 0x3de59787,
++  0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, 0x7733283f,
++  0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68,
++  0xf02bf8a1, 0x48979fc4, 0x5a22302a, 0xe29e574f,
++  0x7f496ff6, 0xc7f50893, 0xd540a77d, 0x6dfcc018,
++  0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0,
++  0xbafd4719, 0x0241207c, 0x10f48f92, 0xa848e8f7,
++  0x9b14583d, 0x23a83f58, 0x311d90b6, 0x89a1f7d3,
++  0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084,
++  0x5ea070d2, 0xe61c17b7, 0xf4a9b859, 0x4c15df3c,
++  0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, 0xc377486b,
++  0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c,
++  0x446f98f5, 0xfcd3ff90, 0xee66507e, 0x56da371b,
++  0x0eb9274d, 0xb6054028, 0xa4b0efc6, 0x1c0c88a3,
++  0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4,
++  0x3b26f703, 0x839a9066, 0x912f3f88, 0x299358ed,
++  0xb4446054, 0x0cf80731, 0x1e4da8df, 0xa6f1cfba,
++  0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002,
++  0x71f048bb, 0xc94c2fde, 0xdbf98030, 0x6345e755,
++  0x6b3fa09c, 0xd383c7f9, 0xc1366817, 0x798a0f72,
++  0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825,
++  0xae8b8873, 0x1637ef16, 0x048240f8, 0xbc3e279d,
++  0x21e91f24, 0x99557841, 0x8be0d7af, 0x335cb0ca,
++  0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5,
++  0x623b216c, 0xda874609, 0xc832e9e7, 0x708e8e82,
++  0x28ed9ed4, 0x9051f9b1, 0x82e4565f, 0x3a58313a,
++  0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d,
++  0xbd40e1a4, 0x05fc86c1, 0x1749292f, 0xaff54e4a,
++  0x322276f3, 0x8a9e1196, 0x982bbe78, 0x2097d91d,
++  0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5,
++  0xf7965e1c, 0x4f2a3979, 0x5d9f9697, 0xe523f1f2,
++  0x4d6b1905, 0xf5d77e60, 0xe762d18e, 0x5fdeb6eb,
++  0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc,
++  0x88df31ea, 0x3063568f, 0x22d6f961, 0x9a6a9e04,
++  0x07bda6bd, 0xbf01c1d8, 0xadb46e36, 0x15080953,
++  0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174,
++  0x9210d9cd, 0x2aacbea8, 0x38191146, 0x80a57623,
++  0xd8c66675, 0x607a0110, 0x72cfaefe, 0xca73c99b,
++  0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc,
++  0x764dee06, 0xcef18963, 0xdc44268d, 0x64f841e8,
++  0xf92f7951, 0x41931e34, 0x5326b1da, 0xeb9ad6bf,
++  0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907,
++  0x3c9b51be, 0x842736db, 0x96929935, 0x2e2efe50,
++  0x2654b999, 0x9ee8defc, 0x8c5d7112, 0x34e11677,
++  0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120,
++  0xe3e09176, 0x5b5cf613, 0x49e959fd, 0xf1553e98,
++  0x6c820621, 0xd43e6144, 0xc68bceaa, 0x7e37a9cf,
++  0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6,
++  0x591dd66f, 0xe1a1b10a, 0xf3141ee4, 0x4ba87981,
++  0x13cb69d7, 0xab770eb2, 0xb9c2a15c, 0x017ec639,
++  0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e,
++  0x866616a7, 0x3eda71c2, 0x2c6fde2c, 0x94d3b949,
++  0x090481f0, 0xb1b8e695, 0xa30d497b, 0x1bb12e1e,
++  0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6,
++  0xccb0a91f, 0x740cce7a, 0x66b96194, 0xde0506f1
++};
++
+ /* CRC32 */
+ 
++static inline u32
++crc32_next (u32 crc, byte data)
++{
++  return (crc >> 8) ^ crc32_table[(crc & 0xff) ^ data];
++}
++
++/*
++ * Process 4 bytes in one go
++ */
++static inline u32
++crc32_next4 (u32 crc, u32 data)
++{
++  crc ^= data;
++  crc = crc32_table[(crc & 0xff) + 0x300] ^
++        crc32_table[((crc >> 8) & 0xff) + 0x200] ^
++        crc32_table[((crc >> 16) & 0xff) + 0x100] ^
++        crc32_table[(crc >> 24) & 0xff];
++  return crc;
++}
++
+ static void
+ crc32_init (void *context)
+ {
+@@ -156,12 +342,40 @@ crc32_init (void *context)
+ }
+ 
+ static void
+-crc32_write (void *context, const void *inbuf, size_t inlen)
++crc32_write (void *context, const void *inbuf_arg, size_t inlen)
+ {
+   CRC_CONTEXT *ctx = (CRC_CONTEXT *) context;
+-  if (!inbuf)
++  const byte *inbuf = inbuf_arg;
++  u32 crc;
++
++  if (!inbuf || !inlen)
+     return;
+-  ctx->CRC = update_crc32 (ctx->CRC, inbuf, inlen);
++
++  crc = ctx->CRC;
++
++  while (inlen >= 16)
++    {
++      inlen -= 16;
++      crc = crc32_next4(crc, buf_get_le32(&inbuf[0]));
++      crc = crc32_next4(crc, buf_get_le32(&inbuf[4]));
++      crc = crc32_next4(crc, buf_get_le32(&inbuf[8]));
++      crc = crc32_next4(crc, buf_get_le32(&inbuf[12]));
++      inbuf += 16;
++    }
++
++  while (inlen >= 4)
++    {
++      inlen -= 4;
++      crc = crc32_next4(crc, buf_get_le32(inbuf));
++      inbuf += 4;
++    }
++
++  while (inlen--)
++    {
++      crc = crc32_next(crc, *inbuf++);
++    }
++
++  ctx->CRC = crc;
+ }
+ 
+ static byte *
+@@ -176,13 +390,12 @@ crc32_final (void *context)
+ {
+   CRC_CONTEXT *ctx = (CRC_CONTEXT *) context;
+   ctx->CRC ^= 0xffffffffL;
+-  ctx->buf[0] = (ctx->CRC >> 24) & 0xFF;
+-  ctx->buf[1] = (ctx->CRC >> 16) & 0xFF;
+-  ctx->buf[2] = (ctx->CRC >>  8) & 0xFF;
+-  ctx->buf[3] = (ctx->CRC      ) & 0xFF;
++  buf_put_be32 (ctx->buf, ctx->CRC);
+ }
+ 
+ /* CRC32 a'la RFC 1510 */
++/* CRC of the string "123456789" is 0x2dfd2d88 */
++
+ static void
+ crc32rfc1510_init (void *context)
+ {
+@@ -194,82 +407,366 @@ static void
+ crc32rfc1510_final (void *context)
+ {
+   CRC_CONTEXT *ctx = (CRC_CONTEXT *) context;
+-  ctx->buf[0] = (ctx->CRC >> 24) & 0xFF;
+-  ctx->buf[1] = (ctx->CRC >> 16) & 0xFF;
+-  ctx->buf[2] = (ctx->CRC >>  8) & 0xFF;
+-  ctx->buf[3] = (ctx->CRC      ) & 0xFF;
++  buf_put_be32(ctx->buf, ctx->CRC);
+ }
+ 
+ /* CRC24 a'la RFC 2440 */
+ /*
+- * The following CRC 24 routines are adapted from RFC 2440, which has
+- * the following copyright notice:
++ * Code generated by universal_crc by Danjel McGougan
+  *
+- *   Copyright (C) The Internet Society (1998).  All Rights Reserved.
++ * CRC parameters used:
++ *   bits:       24
++ *   poly:       0x864cfb
++ *   init:       0xb704ce
++ *   xor:        0x000000
++ *   reverse:    false
++ *   non-direct: false
+  *
+- *   This document and translations of it may be copied and furnished
+- *   to others, and derivative works that comment on or otherwise
+- *   explain it or assist in its implementation may be prepared,
+- *   copied, published and distributed, in whole or in part, without
+- *   restriction of any kind, provided that the above copyright notice
+- *   and this paragraph are included on all such copies and derivative
+- *   works.  However, this document itself may not be modified in any
+- *   way, such as by removing the copyright notice or references to
+- *   the Internet Society or other Internet organizations, except as
+- *   needed for the purpose of developing Internet standards in which
+- *   case the procedures for copyrights defined in the Internet
+- *   Standards process must be followed, or as required to translate
+- *   it into languages other than English.
+- *
+- *   The limited permissions granted above are perpetual and will not be
+- *   revoked by the Internet Society or its successors or assigns.
+- *
+- *   This document and the information contained herein is provided on
+- *   an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET
+- *   ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR
+- *   IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE
+- *   OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY
+- *   IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+- *   PURPOSE.
++ * CRC of the string "123456789" is 0x21cf02
++ */
++
++static const u32 crc24_table[1024] =
++{
++  0x00000000, 0x00fb4c86, 0x000dd58a, 0x00f6990c,
++  0x00e1e693, 0x001aaa15, 0x00ec3319, 0x00177f9f,
++  0x003981a1, 0x00c2cd27, 0x0034542b, 0x00cf18ad,
++  0x00d86732, 0x00232bb4, 0x00d5b2b8, 0x002efe3e,
++  0x00894ec5, 0x00720243, 0x00849b4f, 0x007fd7c9,
++  0x0068a856, 0x0093e4d0, 0x00657ddc, 0x009e315a,
++  0x00b0cf64, 0x004b83e2, 0x00bd1aee, 0x00465668,
++  0x005129f7, 0x00aa6571, 0x005cfc7d, 0x00a7b0fb,
++  0x00e9d10c, 0x00129d8a, 0x00e40486, 0x001f4800,
++  0x0008379f, 0x00f37b19, 0x0005e215, 0x00feae93,
++  0x00d050ad, 0x002b1c2b, 0x00dd8527, 0x0026c9a1,
++  0x0031b63e, 0x00cafab8, 0x003c63b4, 0x00c72f32,
++  0x00609fc9, 0x009bd34f, 0x006d4a43, 0x009606c5,
++  0x0081795a, 0x007a35dc, 0x008cacd0, 0x0077e056,
++  0x00591e68, 0x00a252ee, 0x0054cbe2, 0x00af8764,
++  0x00b8f8fb, 0x0043b47d, 0x00b52d71, 0x004e61f7,
++  0x00d2a319, 0x0029ef9f, 0x00df7693, 0x00243a15,
++  0x0033458a, 0x00c8090c, 0x003e9000, 0x00c5dc86,
++  0x00eb22b8, 0x00106e3e, 0x00e6f732, 0x001dbbb4,
++  0x000ac42b, 0x00f188ad, 0x000711a1, 0x00fc5d27,
++  0x005beddc, 0x00a0a15a, 0x00563856, 0x00ad74d0,
++  0x00ba0b4f, 0x004147c9, 0x00b7dec5, 0x004c9243,
++  0x00626c7d, 0x009920fb, 0x006fb9f7, 0x0094f571,
++  0x00838aee, 0x0078c668, 0x008e5f64, 0x007513e2,
++  0x003b7215, 0x00c03e93, 0x0036a79f, 0x00cdeb19,
++  0x00da9486, 0x0021d800, 0x00d7410c, 0x002c0d8a,
++  0x0002f3b4, 0x00f9bf32, 0x000f263e, 0x00f46ab8,
++  0x00e31527, 0x001859a1, 0x00eec0ad, 0x00158c2b,
++  0x00b23cd0, 0x00497056, 0x00bfe95a, 0x0044a5dc,
++  0x0053da43, 0x00a896c5, 0x005e0fc9, 0x00a5434f,
++  0x008bbd71, 0x0070f1f7, 0x008668fb, 0x007d247d,
++  0x006a5be2, 0x00911764, 0x00678e68, 0x009cc2ee,
++  0x00a44733, 0x005f0bb5, 0x00a992b9, 0x0052de3f,
++  0x0045a1a0, 0x00beed26, 0x0048742a, 0x00b338ac,
++  0x009dc692, 0x00668a14, 0x00901318, 0x006b5f9e,
++  0x007c2001, 0x00876c87, 0x0071f58b, 0x008ab90d,
++  0x002d09f6, 0x00d64570, 0x0020dc7c, 0x00db90fa,
++  0x00ccef65, 0x0037a3e3, 0x00c13aef, 0x003a7669,
++  0x00148857, 0x00efc4d1, 0x00195ddd, 0x00e2115b,
++  0x00f56ec4, 0x000e2242, 0x00f8bb4e, 0x0003f7c8,
++  0x004d963f, 0x00b6dab9, 0x004043b5, 0x00bb0f33,
++  0x00ac70ac, 0x00573c2a, 0x00a1a526, 0x005ae9a0,
++  0x0074179e, 0x008f5b18, 0x0079c214, 0x00828e92,
++  0x0095f10d, 0x006ebd8b, 0x00982487, 0x00636801,
++  0x00c4d8fa, 0x003f947c, 0x00c90d70, 0x003241f6,
++  0x00253e69, 0x00de72ef, 0x0028ebe3, 0x00d3a765,
++  0x00fd595b, 0x000615dd, 0x00f08cd1, 0x000bc057,
++  0x001cbfc8, 0x00e7f34e, 0x00116a42, 0x00ea26c4,
++  0x0076e42a, 0x008da8ac, 0x007b31a0, 0x00807d26,
++  0x009702b9, 0x006c4e3f, 0x009ad733, 0x00619bb5,
++  0x004f658b, 0x00b4290d, 0x0042b001, 0x00b9fc87,
++  0x00ae8318, 0x0055cf9e, 0x00a35692, 0x00581a14,
++  0x00ffaaef, 0x0004e669, 0x00f27f65, 0x000933e3,
++  0x001e4c7c, 0x00e500fa, 0x001399f6, 0x00e8d570,
++  0x00c62b4e, 0x003d67c8, 0x00cbfec4, 0x0030b242,
++  0x0027cddd, 0x00dc815b, 0x002a1857, 0x00d154d1,
++  0x009f3526, 0x006479a0, 0x0092e0ac, 0x0069ac2a,
++  0x007ed3b5, 0x00859f33, 0x0073063f, 0x00884ab9,
++  0x00a6b487, 0x005df801, 0x00ab610d, 0x00502d8b,
++  0x00475214, 0x00bc1e92, 0x004a879e, 0x00b1cb18,
++  0x00167be3, 0x00ed3765, 0x001bae69, 0x00e0e2ef,
++  0x00f79d70, 0x000cd1f6, 0x00fa48fa, 0x0001047c,
++  0x002ffa42, 0x00d4b6c4, 0x00222fc8, 0x00d9634e,
++  0x00ce1cd1, 0x00355057, 0x00c3c95b, 0x003885dd,
++  0x00000000, 0x00488f66, 0x00901ecd, 0x00d891ab,
++  0x00db711c, 0x0093fe7a, 0x004b6fd1, 0x0003e0b7,
++  0x00b6e338, 0x00fe6c5e, 0x0026fdf5, 0x006e7293,
++  0x006d9224, 0x00251d42, 0x00fd8ce9, 0x00b5038f,
++  0x006cc771, 0x00244817, 0x00fcd9bc, 0x00b456da,
++  0x00b7b66d, 0x00ff390b, 0x0027a8a0, 0x006f27c6,
++  0x00da2449, 0x0092ab2f, 0x004a3a84, 0x0002b5e2,
++  0x00015555, 0x0049da33, 0x00914b98, 0x00d9c4fe,
++  0x00d88ee3, 0x00900185, 0x0048902e, 0x00001f48,
++  0x0003ffff, 0x004b7099, 0x0093e132, 0x00db6e54,
++  0x006e6ddb, 0x0026e2bd, 0x00fe7316, 0x00b6fc70,
++  0x00b51cc7, 0x00fd93a1, 0x0025020a, 0x006d8d6c,
++  0x00b44992, 0x00fcc6f4, 0x0024575f, 0x006cd839,
++  0x006f388e, 0x0027b7e8, 0x00ff2643, 0x00b7a925,
++  0x0002aaaa, 0x004a25cc, 0x0092b467, 0x00da3b01,
++  0x00d9dbb6, 0x009154d0, 0x0049c57b, 0x00014a1d,
++  0x004b5141, 0x0003de27, 0x00db4f8c, 0x0093c0ea,
++  0x0090205d, 0x00d8af3b, 0x00003e90, 0x0048b1f6,
++  0x00fdb279, 0x00b53d1f, 0x006dacb4, 0x002523d2,
++  0x0026c365, 0x006e4c03, 0x00b6dda8, 0x00fe52ce,
++  0x00279630, 0x006f1956, 0x00b788fd, 0x00ff079b,
++  0x00fce72c, 0x00b4684a, 0x006cf9e1, 0x00247687,
++  0x00917508, 0x00d9fa6e, 0x00016bc5, 0x0049e4a3,
++  0x004a0414, 0x00028b72, 0x00da1ad9, 0x009295bf,
++  0x0093dfa2, 0x00db50c4, 0x0003c16f, 0x004b4e09,
++  0x0048aebe, 0x000021d8, 0x00d8b073, 0x00903f15,
++  0x00253c9a, 0x006db3fc, 0x00b52257, 0x00fdad31,
++  0x00fe4d86, 0x00b6c2e0, 0x006e534b, 0x0026dc2d,
++  0x00ff18d3, 0x00b797b5, 0x006f061e, 0x00278978,
++  0x002469cf, 0x006ce6a9, 0x00b47702, 0x00fcf864,
++  0x0049fbeb, 0x0001748d, 0x00d9e526, 0x00916a40,
++  0x00928af7, 0x00da0591, 0x0002943a, 0x004a1b5c,
++  0x0096a282, 0x00de2de4, 0x0006bc4f, 0x004e3329,
++  0x004dd39e, 0x00055cf8, 0x00ddcd53, 0x00954235,
++  0x002041ba, 0x0068cedc, 0x00b05f77, 0x00f8d011,
++  0x00fb30a6, 0x00b3bfc0, 0x006b2e6b, 0x0023a10d,
++  0x00fa65f3, 0x00b2ea95, 0x006a7b3e, 0x0022f458,
++  0x002114ef, 0x00699b89, 0x00b10a22, 0x00f98544,
++  0x004c86cb, 0x000409ad, 0x00dc9806, 0x00941760,
++  0x0097f7d7, 0x00df78b1, 0x0007e91a, 0x004f667c,
++  0x004e2c61, 0x0006a307, 0x00de32ac, 0x0096bdca,
++  0x00955d7d, 0x00ddd21b, 0x000543b0, 0x004dccd6,
++  0x00f8cf59, 0x00b0403f, 0x0068d194, 0x00205ef2,
++  0x0023be45, 0x006b3123, 0x00b3a088, 0x00fb2fee,
++  0x0022eb10, 0x006a6476, 0x00b2f5dd, 0x00fa7abb,
++  0x00f99a0c, 0x00b1156a, 0x006984c1, 0x00210ba7,
++  0x00940828, 0x00dc874e, 0x000416e5, 0x004c9983,
++  0x004f7934, 0x0007f652, 0x00df67f9, 0x0097e89f,
++  0x00ddf3c3, 0x00957ca5, 0x004ded0e, 0x00056268,
++  0x000682df, 0x004e0db9, 0x00969c12, 0x00de1374,
++  0x006b10fb, 0x00239f9d, 0x00fb0e36, 0x00b38150,
++  0x00b061e7, 0x00f8ee81, 0x00207f2a, 0x0068f04c,
++  0x00b134b2, 0x00f9bbd4, 0x00212a7f, 0x0069a519,
++  0x006a45ae, 0x0022cac8, 0x00fa5b63, 0x00b2d405,
++  0x0007d78a, 0x004f58ec, 0x0097c947, 0x00df4621,
++  0x00dca696, 0x009429f0, 0x004cb85b, 0x0004373d,
++  0x00057d20, 0x004df246, 0x009563ed, 0x00ddec8b,
++  0x00de0c3c, 0x0096835a, 0x004e12f1, 0x00069d97,
++  0x00b39e18, 0x00fb117e, 0x002380d5, 0x006b0fb3,
++  0x0068ef04, 0x00206062, 0x00f8f1c9, 0x00b07eaf,
++  0x0069ba51, 0x00213537, 0x00f9a49c, 0x00b12bfa,
++  0x00b2cb4d, 0x00fa442b, 0x0022d580, 0x006a5ae6,
++  0x00df5969, 0x0097d60f, 0x004f47a4, 0x0007c8c2,
++  0x00042875, 0x004ca713, 0x009436b8, 0x00dcb9de,
++  0x00000000, 0x00d70983, 0x00555f80, 0x00825603,
++  0x0051f286, 0x0086fb05, 0x0004ad06, 0x00d3a485,
++  0x0059a88b, 0x008ea108, 0x000cf70b, 0x00dbfe88,
++  0x00085a0d, 0x00df538e, 0x005d058d, 0x008a0c0e,
++  0x00491c91, 0x009e1512, 0x001c4311, 0x00cb4a92,
++  0x0018ee17, 0x00cfe794, 0x004db197, 0x009ab814,
++  0x0010b41a, 0x00c7bd99, 0x0045eb9a, 0x0092e219,
++  0x0041469c, 0x00964f1f, 0x0014191c, 0x00c3109f,
++  0x006974a4, 0x00be7d27, 0x003c2b24, 0x00eb22a7,
++  0x00388622, 0x00ef8fa1, 0x006dd9a2, 0x00bad021,
++  0x0030dc2f, 0x00e7d5ac, 0x006583af, 0x00b28a2c,
++  0x00612ea9, 0x00b6272a, 0x00347129, 0x00e378aa,
++  0x00206835, 0x00f761b6, 0x007537b5, 0x00a23e36,
++  0x00719ab3, 0x00a69330, 0x0024c533, 0x00f3ccb0,
++  0x0079c0be, 0x00aec93d, 0x002c9f3e, 0x00fb96bd,
++  0x00283238, 0x00ff3bbb, 0x007d6db8, 0x00aa643b,
++  0x0029a4ce, 0x00fead4d, 0x007cfb4e, 0x00abf2cd,
++  0x00785648, 0x00af5fcb, 0x002d09c8, 0x00fa004b,
++  0x00700c45, 0x00a705c6, 0x002553c5, 0x00f25a46,
++  0x0021fec3, 0x00f6f740, 0x0074a143, 0x00a3a8c0,
++  0x0060b85f, 0x00b7b1dc, 0x0035e7df, 0x00e2ee5c,
++  0x00314ad9, 0x00e6435a, 0x00641559, 0x00b31cda,
++  0x003910d4, 0x00ee1957, 0x006c4f54, 0x00bb46d7,
++  0x0068e252, 0x00bfebd1, 0x003dbdd2, 0x00eab451,
++  0x0040d06a, 0x0097d9e9, 0x00158fea, 0x00c28669,
++  0x001122ec, 0x00c62b6f, 0x00447d6c, 0x009374ef,
++  0x001978e1, 0x00ce7162, 0x004c2761, 0x009b2ee2,
++  0x00488a67, 0x009f83e4, 0x001dd5e7, 0x00cadc64,
++  0x0009ccfb, 0x00dec578, 0x005c937b, 0x008b9af8,
++  0x00583e7d, 0x008f37fe, 0x000d61fd, 0x00da687e,
++  0x00506470, 0x00876df3, 0x00053bf0, 0x00d23273,
++  0x000196f6, 0x00d69f75, 0x0054c976, 0x0083c0f5,
++  0x00a9041b, 0x007e0d98, 0x00fc5b9b, 0x002b5218,
++  0x00f8f69d, 0x002fff1e, 0x00ada91d, 0x007aa09e,
++  0x00f0ac90, 0x0027a513, 0x00a5f310, 0x0072fa93,
++  0x00a15e16, 0x00765795, 0x00f40196, 0x00230815,
++  0x00e0188a, 0x00371109, 0x00b5470a, 0x00624e89,
++  0x00b1ea0c, 0x0066e38f, 0x00e4b58c, 0x0033bc0f,
++  0x00b9b001, 0x006eb982, 0x00ecef81, 0x003be602,
++  0x00e84287, 0x003f4b04, 0x00bd1d07, 0x006a1484,
++  0x00c070bf, 0x0017793c, 0x00952f3f, 0x004226bc,
++  0x00918239, 0x00468bba, 0x00c4ddb9, 0x0013d43a,
++  0x0099d834, 0x004ed1b7, 0x00cc87b4, 0x001b8e37,
++  0x00c82ab2, 0x001f2331, 0x009d7532, 0x004a7cb1,
++  0x00896c2e, 0x005e65ad, 0x00dc33ae, 0x000b3a2d,
++  0x00d89ea8, 0x000f972b, 0x008dc128, 0x005ac8ab,
++  0x00d0c4a5, 0x0007cd26, 0x00859b25, 0x005292a6,
++  0x00813623, 0x00563fa0, 0x00d469a3, 0x00036020,
++  0x0080a0d5, 0x0057a956, 0x00d5ff55, 0x0002f6d6,
++  0x00d15253, 0x00065bd0, 0x00840dd3, 0x00530450,
++  0x00d9085e, 0x000e01dd, 0x008c57de, 0x005b5e5d,
++  0x0088fad8, 0x005ff35b, 0x00dda558, 0x000aacdb,
++  0x00c9bc44, 0x001eb5c7, 0x009ce3c4, 0x004bea47,
++  0x00984ec2, 0x004f4741, 0x00cd1142, 0x001a18c1,
++  0x009014cf, 0x00471d4c, 0x00c54b4f, 0x001242cc,
++  0x00c1e649, 0x0016efca, 0x0094b9c9, 0x0043b04a,
++  0x00e9d471, 0x003eddf2, 0x00bc8bf1, 0x006b8272,
++  0x00b826f7, 0x006f2f74, 0x00ed7977, 0x003a70f4,
++  0x00b07cfa, 0x00677579, 0x00e5237a, 0x00322af9,
++  0x00e18e7c, 0x003687ff, 0x00b4d1fc, 0x0063d87f,
++  0x00a0c8e0, 0x0077c163, 0x00f59760, 0x00229ee3,
++  0x00f13a66, 0x002633e5, 0x00a465e6, 0x00736c65,
++  0x00f9606b, 0x002e69e8, 0x00ac3feb, 0x007b3668,
++  0x00a892ed, 0x007f9b6e, 0x00fdcd6d, 0x002ac4ee,
++  0x00000000, 0x00520936, 0x00a4126c, 0x00f61b5a,
++  0x004825d8, 0x001a2cee, 0x00ec37b4, 0x00be3e82,
++  0x006b0636, 0x00390f00, 0x00cf145a, 0x009d1d6c,
++  0x002323ee, 0x00712ad8, 0x00873182, 0x00d538b4,
++  0x00d60c6c, 0x0084055a, 0x00721e00, 0x00201736,
++  0x009e29b4, 0x00cc2082, 0x003a3bd8, 0x006832ee,
++  0x00bd0a5a, 0x00ef036c, 0x00191836, 0x004b1100,
++  0x00f52f82, 0x00a726b4, 0x00513dee, 0x000334d8,
++  0x00ac19d8, 0x00fe10ee, 0x00080bb4, 0x005a0282,
++  0x00e43c00, 0x00b63536, 0x00402e6c, 0x0012275a,
++  0x00c71fee, 0x009516d8, 0x00630d82, 0x003104b4,
++  0x008f3a36, 0x00dd3300, 0x002b285a, 0x0079216c,
++  0x007a15b4, 0x00281c82, 0x00de07d8, 0x008c0eee,
++  0x0032306c, 0x0060395a, 0x00962200, 0x00c42b36,
++  0x00111382, 0x00431ab4, 0x00b501ee, 0x00e708d8,
++  0x0059365a, 0x000b3f6c, 0x00fd2436, 0x00af2d00,
++  0x00a37f36, 0x00f17600, 0x00076d5a, 0x0055646c,
++  0x00eb5aee, 0x00b953d8, 0x004f4882, 0x001d41b4,
++  0x00c87900, 0x009a7036, 0x006c6b6c, 0x003e625a,
++  0x00805cd8, 0x00d255ee, 0x00244eb4, 0x00764782,
++  0x0075735a, 0x00277a6c, 0x00d16136, 0x00836800,
++  0x003d5682, 0x006f5fb4, 0x009944ee, 0x00cb4dd8,
++  0x001e756c, 0x004c7c5a, 0x00ba6700, 0x00e86e36,
++  0x005650b4, 0x00045982, 0x00f242d8, 0x00a04bee,
++  0x000f66ee, 0x005d6fd8, 0x00ab7482, 0x00f97db4,
++  0x00474336, 0x00154a00, 0x00e3515a, 0x00b1586c,
++  0x006460d8, 0x003669ee, 0x00c072b4, 0x00927b82,
++  0x002c4500, 0x007e4c36, 0x0088576c, 0x00da5e5a,
++  0x00d96a82, 0x008b63b4, 0x007d78ee, 0x002f71d8,
++  0x00914f5a, 0x00c3466c, 0x00355d36, 0x00675400,
++  0x00b26cb4, 0x00e06582, 0x00167ed8, 0x004477ee,
++  0x00fa496c, 0x00a8405a, 0x005e5b00, 0x000c5236,
++  0x0046ff6c, 0x0014f65a, 0x00e2ed00, 0x00b0e436,
++  0x000edab4, 0x005cd382, 0x00aac8d8, 0x00f8c1ee,
++  0x002df95a, 0x007ff06c, 0x0089eb36, 0x00dbe200,
++  0x0065dc82, 0x0037d5b4, 0x00c1ceee, 0x0093c7d8,
++  0x0090f300, 0x00c2fa36, 0x0034e16c, 0x0066e85a,
++  0x00d8d6d8, 0x008adfee, 0x007cc4b4, 0x002ecd82,
++  0x00fbf536, 0x00a9fc00, 0x005fe75a, 0x000dee6c,
++  0x00b3d0ee, 0x00e1d9d8, 0x0017c282, 0x0045cbb4,
++  0x00eae6b4, 0x00b8ef82, 0x004ef4d8, 0x001cfdee,
++  0x00a2c36c, 0x00f0ca5a, 0x0006d100, 0x0054d836,
++  0x0081e082, 0x00d3e9b4, 0x0025f2ee, 0x0077fbd8,
++  0x00c9c55a, 0x009bcc6c, 0x006dd736, 0x003fde00,
++  0x003cead8, 0x006ee3ee, 0x0098f8b4, 0x00caf182,
++  0x0074cf00, 0x0026c636, 0x00d0dd6c, 0x0082d45a,
++  0x0057ecee, 0x0005e5d8, 0x00f3fe82, 0x00a1f7b4,
++  0x001fc936, 0x004dc000, 0x00bbdb5a, 0x00e9d26c,
++  0x00e5805a, 0x00b7896c, 0x00419236, 0x00139b00,
++  0x00ada582, 0x00ffacb4, 0x0009b7ee, 0x005bbed8,
++  0x008e866c, 0x00dc8f5a, 0x002a9400, 0x00789d36,
++  0x00c6a3b4, 0x0094aa82, 0x0062b1d8, 0x0030b8ee,
++  0x00338c36, 0x00618500, 0x00979e5a, 0x00c5976c,
++  0x007ba9ee, 0x0029a0d8, 0x00dfbb82, 0x008db2b4,
++  0x00588a00, 0x000a8336, 0x00fc986c, 0x00ae915a,
++  0x0010afd8, 0x0042a6ee, 0x00b4bdb4, 0x00e6b482,
++  0x00499982, 0x001b90b4, 0x00ed8bee, 0x00bf82d8,
++  0x0001bc5a, 0x0053b56c, 0x00a5ae36, 0x00f7a700,
++  0x00229fb4, 0x00709682, 0x00868dd8, 0x00d484ee,
++  0x006aba6c, 0x0038b35a, 0x00cea800, 0x009ca136,
++  0x009f95ee, 0x00cd9cd8, 0x003b8782, 0x00698eb4,
++  0x00d7b036, 0x0085b900, 0x0073a25a, 0x0021ab6c,
++  0x00f493d8, 0x00a69aee, 0x005081b4, 0x00028882,
++  0x00bcb600, 0x00eebf36, 0x0018a46c, 0x004aad5a
++};
++
++static inline
++u32 crc24_init (void)
++{
++  return 0xce04b7;
++}
++
++static inline
++u32 crc24_next (u32 crc, byte data)
++{
++  return (crc >> 8) ^ crc24_table[(crc & 0xff) ^ data];
++}
++
++/*
++ * Process 4 bytes in one go
+  */
++static inline
++u32 crc24_next4 (u32 crc, u32 data)
++{
++  crc ^= data;
++  crc = crc24_table[(crc & 0xff) + 0x300] ^
++        crc24_table[((crc >> 8) & 0xff) + 0x200] ^
++        crc24_table[((crc >> 16) & 0xff) + 0x100] ^
++        crc24_table[(crc >> 24) & 0xff];
++  return crc;
++}
+ 
+-#define CRC24_INIT 0xb704ceL
+-#define CRC24_POLY 0x1864cfbL
++static inline
++u32 crc24_final (u32 crc)
++{
++  return crc & 0xffffff;
++}
+ 
+ static void
+ crc24rfc2440_init (void *context)
+ {
+   CRC_CONTEXT *ctx = (CRC_CONTEXT *) context;
+-  ctx->CRC = CRC24_INIT;
++  ctx->CRC = crc24_init();
+ }
+ 
+ static void
+ crc24rfc2440_write (void *context, const void *inbuf_arg, size_t inlen)
+ {
+   const unsigned char *inbuf = inbuf_arg;
+-  int i;
+   CRC_CONTEXT *ctx = (CRC_CONTEXT *) context;
++  u32 crc;
+ 
+-  if (!inbuf)
++  if (!inbuf || !inlen)
+     return;
+ 
+-  while (inlen--) {
+-    ctx->CRC ^= (*inbuf++) << 16;
+-    for (i = 0; i < 8; i++) {
+-      ctx->CRC <<= 1;
+-      if (ctx->CRC & 0x1000000)
+-	ctx->CRC ^= CRC24_POLY;
++  crc = ctx->CRC;
++
++  while (inlen >= 16)
++    {
++      inlen -= 16;
++      crc = crc24_next4(crc, buf_get_le32(&inbuf[0]));
++      crc = crc24_next4(crc, buf_get_le32(&inbuf[4]));
++      crc = crc24_next4(crc, buf_get_le32(&inbuf[8]));
++      crc = crc24_next4(crc, buf_get_le32(&inbuf[12]));
++      inbuf += 16;
+     }
+-  }
++
++  while (inlen >= 4)
++    {
++      inlen -= 4;
++      crc = crc24_next4(crc, buf_get_le32(inbuf));
++      inbuf += 4;
++    }
++
++  while (inlen--)
++    {
++      crc = crc24_next(crc, *inbuf++);
++    }
++
++  ctx->CRC = crc;
+ }
+ 
+ static void
+ crc24rfc2440_final (void *context)
+ {
+   CRC_CONTEXT *ctx = (CRC_CONTEXT *) context;
+-  ctx->buf[0] = (ctx->CRC >> 16) & 0xFF;
+-  ctx->buf[1] = (ctx->CRC >>  8) & 0xFF;
+-  ctx->buf[2] = (ctx->CRC      ) & 0xFF;
++  ctx->CRC = crc24_final(ctx->CRC);
++  buf_put_le32 (ctx->buf, ctx->CRC);
+ }
+ 
+ gcry_md_spec_t _gcry_digest_spec_crc32 =
+diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c
+index 5b39f02bb2e592d85639891db6eb68a97ce12dfa..b4f609d2d01184b8d0a3e5aff448725f80a36a93 100644
+--- a/grub-core/loader/arm/linux.c
++++ b/grub-core/loader/arm/linux.c
+@@ -42,21 +42,18 @@ static grub_size_t linux_size;
+ static char *linux_args;
+ 
+ static grub_uint32_t machine_type;
+-static void *fdt_addr;
++static const void *current_fdt;
+ 
+ typedef void (*kernel_entry_t) (int, unsigned long, void *);
+ 
+-#define LINUX_ZIMAGE_OFFSET	0x24
+-#define LINUX_ZIMAGE_MAGIC	0x016f2818
+-
+ #define LINUX_PHYS_OFFSET        (0x00008000)
+ #define LINUX_INITRD_PHYS_OFFSET (LINUX_PHYS_OFFSET + 0x02000000)
+ #define LINUX_FDT_PHYS_OFFSET    (LINUX_INITRD_PHYS_OFFSET - 0x10000)
+ 
+ static grub_size_t
+-get_atag_size (grub_uint32_t *atag)
++get_atag_size (const grub_uint32_t *atag)
+ {
+-  grub_uint32_t *atag0 = atag;
++  const grub_uint32_t *atag0 = atag;
+   while (atag[0] && atag[1])
+     atag += atag[0];
+   return atag - atag0;
+@@ -68,10 +65,11 @@ get_atag_size (grub_uint32_t *atag)
+  *   Merges in command line parameters and sets up initrd addresses.
+  */
+ static grub_err_t
+-linux_prepare_atag (void)
++linux_prepare_atag (void *target_atag)
+ {
+-  grub_uint32_t *atag_orig = (grub_uint32_t *) fdt_addr;
+-  grub_uint32_t *tmp_atag, *from, *to;
++  const grub_uint32_t *atag_orig = (const grub_uint32_t *) current_fdt;
++  grub_uint32_t *tmp_atag, *to;
++  const grub_uint32_t *from;
+   grub_size_t tmp_size;
+   grub_size_t arg_size = grub_strlen (linux_args);
+   char *cmdline_orig = NULL;
+@@ -142,7 +140,7 @@ linux_prepare_atag (void)
+   to += 2;
+ 
+   /* Copy updated FDT to its launch location */
+-  grub_memcpy (atag_orig, tmp_atag, sizeof (grub_uint32_t) * (to - tmp_atag));
++  grub_memcpy (target_atag, tmp_atag, sizeof (grub_uint32_t) * (to - tmp_atag));
+   grub_free (tmp_atag);
+ 
+   grub_dprintf ("loader", "ATAG updated for Linux boot\n");
+@@ -156,19 +154,19 @@ linux_prepare_atag (void)
+  *   Merges in command line parameters and sets up initrd addresses.
+  */
+ static grub_err_t
+-linux_prepare_fdt (void)
++linux_prepare_fdt (void *target_fdt)
+ {
+   int node;
+   int retval;
+   int tmp_size;
+   void *tmp_fdt;
+ 
+-  tmp_size = grub_fdt_get_totalsize (fdt_addr) + 0x100 + grub_strlen (linux_args);
++  tmp_size = grub_fdt_get_totalsize (current_fdt) + 0x100 + grub_strlen (linux_args);
+   tmp_fdt = grub_malloc (tmp_size);
+   if (!tmp_fdt)
+     return grub_errno;
+ 
+-  grub_memcpy (tmp_fdt, fdt_addr, grub_fdt_get_totalsize (fdt_addr));
++  grub_memcpy (tmp_fdt, current_fdt, grub_fdt_get_totalsize (current_fdt));
+   grub_fdt_set_totalsize (tmp_fdt, tmp_size);
+ 
+   /* Find or create '/chosen' node */
+@@ -209,7 +207,7 @@ linux_prepare_fdt (void)
+     }
+ 
+   /* Copy updated FDT to its launch location */
+-  grub_memcpy (fdt_addr, tmp_fdt, tmp_size);
++  grub_memcpy (target_fdt, tmp_fdt, tmp_size);
+   grub_free (tmp_fdt);
+ 
+   grub_dprintf ("loader", "FDT updated for Linux boot\n");
+@@ -226,16 +224,17 @@ linux_boot (void)
+ {
+   kernel_entry_t linuxmain;
+   int fdt_valid, atag_valid;
++  void *target_fdt = 0;
+ 
+-  fdt_valid = (fdt_addr && grub_fdt_check_header_nosize (fdt_addr) == 0);
+-  atag_valid = ((((grub_uint16_t *) fdt_addr)[3] & ~3) == 0x5440
+-		&& *((grub_uint32_t *) fdt_addr));
++  fdt_valid = (current_fdt && grub_fdt_check_header_nosize (current_fdt) == 0);
++  atag_valid = ((((const grub_uint16_t *) current_fdt)[3] & ~3) == 0x5440
++		&& *((const grub_uint32_t *) current_fdt));
+   grub_dprintf ("loader", "atag: %p, %x, %x, %s, %s\n",
+-		fdt_addr,
+-		((grub_uint16_t *) fdt_addr)[3],
+-		*((grub_uint32_t *) fdt_addr),
+-		(char *) fdt_addr,
+-		(char *) fdt_addr + 1);
++		current_fdt,
++		((const grub_uint16_t *) current_fdt)[3],
++		*((const grub_uint32_t *) current_fdt),
++		(const char *) current_fdt,
++		(const char *) current_fdt + 1);
+ 
+   if (!fdt_valid && machine_type == GRUB_ARM_MACHINE_TYPE_FDT)
+     return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+@@ -245,23 +244,40 @@ linux_boot (void)
+ 
+   grub_dprintf ("loader", "Kernel at: 0x%x\n", linux_addr);
+ 
++  if (fdt_valid || atag_valid)
++    {
++#ifdef GRUB_MACHINE_EFI
++      grub_size_t size;
++      if (fdt_valid)
++	size = grub_fdt_get_totalsize (current_fdt);
++      else
++	size = 4 * get_atag_size (current_fdt);
++      size += grub_strlen (linux_args) + 256;
++      target_fdt = grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size);
++      if (!target_fdt)
++	return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
++#else
++      target_fdt = (void *) LINUX_FDT_ADDRESS;
++#endif
++    }
++
+   if (fdt_valid)
+     {
+       grub_err_t err;
+ 
+-      err = linux_prepare_fdt ();
++      err = linux_prepare_fdt (target_fdt);
+       if (err)
+ 	return err;
+-      grub_dprintf ("loader", "FDT @ 0x%p\n", fdt_addr);
++      grub_dprintf ("loader", "FDT @ %p\n", target_fdt);
+     }
+   else if (atag_valid)
+     {
+       grub_err_t err;
+ 
+-      err = linux_prepare_atag ();
++      err = linux_prepare_atag (target_fdt);
+       if (err)
+ 	return err;
+-      grub_dprintf ("loader", "ATAG @ 0x%p\n", fdt_addr);
++      grub_dprintf ("loader", "ATAG @ %p\n", target_fdt);
+     }
+ 
+   grub_dprintf ("loader", "Jumping to Linux...\n");
+@@ -274,18 +290,9 @@ linux_boot (void)
+    */
+   linuxmain = (kernel_entry_t) linux_addr;
+ 
+-#ifdef GRUB_MACHINE_EFI
+-  {
+-    grub_err_t err;
+-    err = grub_efi_prepare_platform();
+-    if (err != GRUB_ERR_NONE)
+-      return err;
+-  }
+-#endif
+-
+   grub_arm_disable_caches_mmu ();
+ 
+-  linuxmain (0, machine_type, fdt_addr);
++  linuxmain (0, machine_type, target_fdt);
+ 
+   return grub_error (GRUB_ERR_BAD_OS, "Linux call returned");
+ }
+@@ -296,17 +303,12 @@ linux_boot (void)
+ static grub_err_t
+ linux_load (const char *filename, grub_file_t file)
+ {
++  struct linux_arm_kernel_header *lh;
+   int size;
+ 
+   size = grub_file_size (file);
+ 
+-#ifdef GRUB_MACHINE_EFI
+-  linux_addr = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_PHYS_OFFSET, size);
+-  if (!linux_addr)
+-    return grub_errno;
+-#else
+   linux_addr = LINUX_ADDRESS;
+-#endif
+   grub_dprintf ("loader", "Loading Linux to 0x%08x\n",
+ 		(grub_addr_t) linux_addr);
+ 
+@@ -318,9 +320,10 @@ linux_load (const char *filename, grub_file_t file)
+       return grub_errno;
+     }
+ 
+-  if (size > LINUX_ZIMAGE_OFFSET + 4
+-      && *(grub_uint32_t *) (linux_addr + LINUX_ZIMAGE_OFFSET)
+-      == LINUX_ZIMAGE_MAGIC)
++  lh = (void *) linux_addr;
++
++  if ((grub_size_t) size > sizeof (*lh) &&
++      lh->magic == GRUB_LINUX_ARM_MAGIC_SIGNATURE)
+     ;
+   else if (size > 0x8000 && *(grub_uint32_t *) (linux_addr) == 0xea000006
+ 	   && machine_type == GRUB_ARM_MACHINE_TYPE_RASPBERRY_PI)
+@@ -410,20 +413,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ 
+   size = grub_get_initrd_size (&initrd_ctx);
+ 
+-#ifdef GRUB_MACHINE_EFI
+-  if (initrd_start)
+-    grub_efi_free_pages (initrd_start,
+-			 (initrd_end - initrd_start + 0xfff) >> 12);
+-  initrd_start = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_INITRD_PHYS_OFFSET, size);
+-
+-  if (!initrd_start)
+-    {
+-      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+-      goto fail;
+-    }
+-#else
+   initrd_start = LINUX_INITRD_ADDRESS;
+-#endif
+ 
+   grub_dprintf ("loader", "Loading initrd to 0x%08x\n",
+ 		(grub_addr_t) initrd_start);
+@@ -444,11 +434,26 @@ fail:
+ static grub_err_t
+ load_dtb (grub_file_t dtb, int size)
+ {
+-  if ((grub_file_read (dtb, fdt_addr, size) != size)
+-      || (grub_fdt_check_header (fdt_addr, size) != 0))
+-    return grub_error (GRUB_ERR_BAD_OS, N_("invalid device tree"));
++  void *new_fdt = grub_zalloc (size);
++  if (!new_fdt)
++    return grub_errno;
++  grub_dprintf ("loader", "Loading device tree to %p\n",
++		new_fdt);
++  if ((grub_file_read (dtb, new_fdt, size) != size)
++      || (grub_fdt_check_header (new_fdt, size) != 0))
++    {
++      grub_free (new_fdt);
++      return grub_error (GRUB_ERR_BAD_OS, N_("invalid device tree"));
++    }
++
++  grub_fdt_set_totalsize (new_fdt, size);
++  current_fdt = new_fdt;
++  /* 
++   * We've successfully loaded an FDT, so any machine type passed
++   * from firmware is now obsolete.
++   */
++  machine_type = GRUB_ARM_MACHINE_TYPE_FDT;
+ 
+-  grub_fdt_set_totalsize (fdt_addr, size);
+   return GRUB_ERR_NONE;
+ }
+ 
+@@ -464,42 +469,13 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
+ 
+   dtb = grub_file_open (argv[0]);
+   if (!dtb)
+-    goto out;
++    return grub_errno;
+ 
+   size = grub_file_size (dtb);
+   if (size == 0)
+-    {
+-      grub_error (GRUB_ERR_BAD_OS, "empty file");
+-      goto out;
+-    }
+-
+-#ifdef GRUB_MACHINE_EFI
+-  fdt_addr = grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size);
+-  if (!fdt_addr)
+-    {
+-      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+-      goto out;
+-    }
+-#else
+-  fdt_addr = (void *) LINUX_FDT_ADDRESS;
+-#endif
+-
+-  grub_dprintf ("loader", "Loading device tree to 0x%08x\n",
+-		(grub_addr_t) fdt_addr);
+-  load_dtb (dtb, size);
+-  if (grub_errno != GRUB_ERR_NONE)
+-    {
+-      fdt_addr = NULL;
+-      goto out;
+-    }
+-
+-  /* 
+-   * We've successfully loaded an FDT, so any machine type passed
+-   * from firmware is now obsolete.
+-   */
+-  machine_type = GRUB_ARM_MACHINE_TYPE_FDT;
+-
+- out:
++    grub_error (GRUB_ERR_BAD_OS, "empty file");
++  else
++    load_dtb (dtb, size);
+   grub_file_close (dtb);
+ 
+   return grub_errno;
+@@ -517,7 +493,7 @@ GRUB_MOD_INIT (linux)
+ 					  /* TRANSLATORS: DTB stands for device tree blob.  */
+ 					  0, N_("Load DTB file."));
+   my_mod = mod;
+-  fdt_addr = (void *) grub_arm_firmware_get_boot_data ();
++  current_fdt = (const void *) grub_arm_firmware_get_boot_data ();
+   machine_type = grub_arm_firmware_get_machine_type ();
+ }
+ 
+diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
+index 9519d2e4d3ec1229a76eb4bce773c78c7af24a6e..1f86229f86b01e4700bb13c9f936490ea9ac859f 100644
+--- a/grub-core/loader/arm64/linux.c
++++ b/grub-core/loader/arm64/linux.c
+@@ -26,8 +26,9 @@
+ #include <grub/mm.h>
+ #include <grub/types.h>
+ #include <grub/cpu/linux.h>
+-#include <grub/cpu/fdtload.h>
+ #include <grub/efi/efi.h>
++#include <grub/efi/fdtload.h>
++#include <grub/efi/memory.h>
+ #include <grub/efi/pe32.h>
+ #include <grub/i18n.h>
+ #include <grub/lib/cmdline.h>
+@@ -47,18 +48,16 @@ static grub_addr_t initrd_start;
+ static grub_addr_t initrd_end;
+ 
+ grub_err_t
+-grub_arm64_uefi_check_image (struct grub_arm64_linux_kernel_header * lh)
++grub_armxx_efi_linux_check_image (struct linux_armxx_kernel_header * lh)
+ {
+-  if (lh->magic != GRUB_ARM64_LINUX_MAGIC)
++  if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE)
+     return grub_error(GRUB_ERR_BAD_OS, "invalid magic number");
+ 
+-  if ((lh->code0 & 0xffff) != GRUB_EFI_PE_MAGIC)
++  if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC)
+     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ 		       N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled"));
+ 
+   grub_dprintf ("linux", "UEFI stub kernel:\n");
+-  grub_dprintf ("linux", "text_offset = 0x%012llx\n",
+-		(long long unsigned) lh->text_offset);
+   grub_dprintf ("linux", "PE/COFF header @ %08x\n", lh->hdr_offset);
+ 
+   return GRUB_ERR_NONE;
+@@ -86,8 +85,8 @@ finalize_params_linux (void)
+   /* Set initrd info */
+   if (initrd_start && initrd_end > initrd_start)
+     {
+-      grub_dprintf ("linux", "Initrd @ 0x%012lx-0x%012lx\n",
+-		    initrd_start, initrd_end);
++      grub_dprintf ("linux", "Initrd @ %p-%p\n",
++		    (void *) initrd_start, (void *) initrd_end);
+ 
+       retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start",
+ 				    initrd_start);
+@@ -110,7 +109,7 @@ failure:
+ }
+ 
+ grub_err_t
+-grub_arm64_uefi_boot_image (grub_addr_t addr, grub_size_t size, char *args)
++grub_armxx_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args)
+ {
+   grub_efi_memory_mapped_device_path_t *mempath;
+   grub_efi_handle_t image_handle;
+@@ -148,8 +147,7 @@ grub_arm64_uefi_boot_image (grub_addr_t addr, grub_size_t size, char *args)
+   loaded_image->load_options_size = len =
+     (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t);
+   loaded_image->load_options =
+-    grub_efi_allocate_pages (0,
+-			     GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
++    grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
+   if (!loaded_image->load_options)
+     return grub_errno;
+ 
+@@ -162,7 +160,7 @@ grub_arm64_uefi_boot_image (grub_addr_t addr, grub_size_t size, char *args)
+ 
+   /* When successful, not reached */
+   b->unload_image (image_handle);
+-  grub_efi_free_pages ((grub_efi_physical_address_t) loaded_image->load_options,
++  grub_efi_free_pages ((grub_addr_t) loaded_image->load_options,
+ 		       GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
+ 
+   return grub_errno;
+@@ -174,8 +172,8 @@ grub_linux_boot (void)
+   if (finalize_params_linux () != GRUB_ERR_NONE)
+     return grub_errno;
+ 
+-  return (grub_arm64_uefi_boot_image((grub_addr_t)kernel_addr,
+-                                     kernel_size, linux_args));
++  return (grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr,
++                                          kernel_size, linux_args));
+ }
+ 
+ static grub_err_t
+@@ -189,12 +187,48 @@ grub_linux_unload (void)
+   initrd_start = initrd_end = 0;
+   grub_free (linux_args);
+   if (kernel_addr)
+-    grub_efi_free_pages ((grub_efi_physical_address_t) kernel_addr,
++    grub_efi_free_pages ((grub_addr_t) kernel_addr,
+ 			 GRUB_EFI_BYTES_TO_PAGES (kernel_size));
+   grub_fdt_unload ();
+   return GRUB_ERR_NONE;
+ }
+ 
++/*
++ * As per linux/Documentation/arm/Booting
++ * ARM initrd needs to be covered by kernel linear mapping,
++ * so place it in the first 512MB of DRAM.
++ *
++ * As per linux/Documentation/arm64/booting.txt
++ * ARM64 initrd needs to be contained entirely within a 1GB aligned window
++ * of up to 32GB of size that covers the kernel image as well.
++ * Since the EFI stub loader will attempt to load the kernel near start of
++ * RAM, place the buffer in the first 32GB of RAM.
++ */
++#ifdef __arm__
++#define INITRD_MAX_ADDRESS_OFFSET (512U * 1024 * 1024)
++#else /* __aarch64__ */
++#define INITRD_MAX_ADDRESS_OFFSET (32ULL * 1024 * 1024 * 1024)
++#endif
++
++/*
++ * This function returns a pointer to a legally allocated initrd buffer,
++ * or NULL if unsuccessful
++ */
++static void *
++allocate_initrd_mem (int initrd_pages)
++{
++  grub_addr_t max_addr;
++
++  if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE)
++    return NULL;
++
++  max_addr += INITRD_MAX_ADDRESS_OFFSET - 1;
++
++  return grub_efi_allocate_pages_real (max_addr, initrd_pages,
++				       GRUB_EFI_ALLOCATE_MAX_ADDRESS,
++				       GRUB_EFI_LOADER_DATA);
++}
++
+ static grub_err_t
+ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ 		 int argc, char *argv[])
+@@ -223,7 +257,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+   grub_dprintf ("linux", "Loading initrd\n");
+ 
+   initrd_pages = (GRUB_EFI_BYTES_TO_PAGES (initrd_size));
+-  initrd_mem = grub_efi_allocate_pages (0, initrd_pages);
++  initrd_mem = allocate_initrd_mem (initrd_pages);
++
+   if (!initrd_mem)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+@@ -241,8 +276,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+  fail:
+   grub_initrd_close (&initrd_ctx);
+   if (initrd_mem && !initrd_start)
+-    grub_efi_free_pages ((grub_efi_physical_address_t) initrd_mem,
+-			 initrd_pages);
++    grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages);
+ 
+   return grub_errno;
+ }
+@@ -252,7 +286,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 		int argc, char *argv[])
+ {
+   grub_file_t file = 0;
+-  struct grub_arm64_linux_kernel_header lh;
++  struct linux_armxx_kernel_header lh;
+ 
+   grub_dl_ref (my_mod);
+ 
+@@ -271,13 +305,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+   if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh))
+     return grub_errno;
+ 
+-  if (grub_arm64_uefi_check_image (&lh) != GRUB_ERR_NONE)
++  if (grub_armxx_efi_linux_check_image (&lh) != GRUB_ERR_NONE)
+     goto fail;
+ 
+   grub_loader_unset();
+ 
+   grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size);
+-  kernel_addr = grub_efi_allocate_pages (0, GRUB_EFI_BYTES_TO_PAGES (kernel_size));
++  kernel_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size));
+   grub_dprintf ("linux", "kernel numpages: %lld\n",
+ 		(long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size));
+   if (!kernel_addr)
+@@ -329,7 +363,7 @@ fail:
+     grub_free (linux_args);
+ 
+   if (kernel_addr && !loaded)
+-    grub_efi_free_pages ((grub_efi_physical_address_t) kernel_addr,
++    grub_efi_free_pages ((grub_addr_t) kernel_addr,
+ 			 GRUB_EFI_BYTES_TO_PAGES (kernel_size));
+ 
+   return grub_errno;
+diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
+index a914eb8e2df24ebaab41a2eb0ed205bcebafcf5d..1003a0b9997a46ea7e5106da02ef77e9be3a21fc 100644
+--- a/grub-core/loader/arm64/xen_boot.c
++++ b/grub-core/loader/arm64/xen_boot.c
+@@ -27,9 +27,10 @@
+ #include <grub/misc.h>
+ #include <grub/mm.h>
+ #include <grub/types.h>
+-#include <grub/cpu/fdtload.h>
+ #include <grub/cpu/linux.h>
+ #include <grub/efi/efi.h>
++#include <grub/efi/fdtload.h>
++#include <grub/efi/memory.h>
+ #include <grub/efi/pe32.h>	/* required by struct xen_hypervisor_header */
+ #include <grub/i18n.h>
+ #include <grub/lib/cmdline.h>
+@@ -66,7 +67,7 @@ typedef enum module_type module_type_t;
+ 
+ struct xen_hypervisor_header
+ {
+-  struct grub_arm64_linux_kernel_header efi_head;
++  struct linux_arm64_kernel_header efi_head;
+ 
+   /* This is always PE\0\0.  */
+   grub_uint8_t signature[GRUB_PE32_SIGNATURE_SIZE];
+@@ -115,6 +116,17 @@ prepare_xen_hypervisor_params (void *xen_boot_fdt)
+   if (chosen_node < 1)
+     return grub_error (GRUB_ERR_IO, "failed to get chosen node in FDT");
+ 
++  /*
++   * The address and size are always written using 64-bits value. Set
++   * #address-cells and #size-cells accordingly.
++   */
++  retval = grub_fdt_set_prop32 (xen_boot_fdt, chosen_node, "#address-cells", 2);
++  if (retval)
++    return grub_error (GRUB_ERR_IO, "failed to set #address-cells");
++  retval = grub_fdt_set_prop32 (xen_boot_fdt, chosen_node, "#size-cells", 2);
++  if (retval)
++    return grub_error (GRUB_ERR_IO, "failed to set #size-cells");
++
+   grub_dprintf ("xen_loader",
+ 		"Xen Hypervisor cmdline : %s @ %p size:%d\n",
+ 		xen_hypervisor->cmdline, xen_hypervisor->cmdline,
+@@ -156,7 +168,7 @@ prepare_xen_module_params (struct xen_boot_binary *module, void *xen_boot_fdt)
+       grub_fdt_add_subnode (xen_boot_fdt, chosen_node, module_name);
+ 
+   retval = grub_fdt_set_prop (xen_boot_fdt, module_node, "compatible",
+-			      MODULE_CUSTOM_COMPATIBLE, sizeof(MODULE_CUSTOM_COMPATIBLE) - 1);
++			      MODULE_CUSTOM_COMPATIBLE, sizeof(MODULE_CUSTOM_COMPATIBLE));
+   if (retval)
+     return grub_error (GRUB_ERR_IO, "failed to update FDT");
+ 
+@@ -253,9 +265,9 @@ xen_boot (void)
+   if (err)
+     return err;
+ 
+-  return grub_arm64_uefi_boot_image (xen_hypervisor->start,
+-				     xen_hypervisor->size,
+-				     xen_hypervisor->cmdline);
++  return grub_armxx_efi_linux_boot_image (xen_hypervisor->start,
++					  xen_hypervisor->size,
++					  xen_hypervisor->cmdline);
+ }
+ 
+ static void
+@@ -324,10 +336,9 @@ xen_boot_binary_load (struct xen_boot_binary *binary, grub_file_t file,
+   grub_dprintf ("xen_loader", "Xen_boot file size: 0x%lx\n", binary->size);
+ 
+   binary->start
+-    = (grub_addr_t) grub_efi_allocate_pages (0,
+-					     GRUB_EFI_BYTES_TO_PAGES
+-					     (binary->size +
+-					      binary->align));
++    = (grub_addr_t) grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES
++						 (binary->size +
++						  binary->align));
+   if (!binary->start)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+@@ -379,6 +390,20 @@ grub_cmd_xen_module (grub_command_t cmd __attribute__((unused)),
+ 
+   struct xen_boot_binary *module = NULL;
+   grub_file_t file = 0;
++  int nounzip = 0;
++
++  if (!argc)
++    {
++      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
++      goto fail;
++    }
++
++  if (grub_strcmp (argv[0], "--nounzip") == 0)
++    {
++      argv++;
++      argc--;
++      nounzip = 1;
++    }
+ 
+   if (!argc)
+     {
+@@ -403,6 +428,8 @@ grub_cmd_xen_module (grub_command_t cmd __attribute__((unused)),
+ 
+   grub_dprintf ("xen_loader", "Init module and node info\n");
+ 
++  if (nounzip)
++    grub_file_filter_disable_compression ();
+   file = grub_file_open (argv[0]);
+   if (!file)
+     goto fail;
+@@ -441,8 +468,8 @@ grub_cmd_xen_hypervisor (grub_command_t cmd __attribute__ ((unused)),
+ 
+   if (grub_file_read (file, &sh, sizeof (sh)) != (long) sizeof (sh))
+     goto fail;
+-  if (grub_arm64_uefi_check_image
+-      ((struct grub_arm64_linux_kernel_header *) &sh) != GRUB_ERR_NONE)
++  if (grub_armxx_efi_linux_check_image
++      ((struct linux_armxx_kernel_header *) &sh) != GRUB_ERR_NONE)
+     goto fail;
+   grub_file_seek (file, 0);
+ 
+diff --git a/grub-core/loader/arm64/fdt.c b/grub-core/loader/efi/fdt.c
+similarity index 79%
+rename from grub-core/loader/arm64/fdt.c
+rename to grub-core/loader/efi/fdt.c
+index db49cf64991764686c3f643e5289abbd4874a559..a4c6e8036454c1a53deefad791133488281462ea 100644
+--- a/grub-core/loader/arm64/fdt.c
++++ b/grub-core/loader/efi/fdt.c
+@@ -18,26 +18,33 @@
+ 
+ #include <grub/fdt.h>
+ #include <grub/mm.h>
+-#include <grub/cpu/fdtload.h>
+ #include <grub/err.h>
+ #include <grub/dl.h>
+ #include <grub/command.h>
+ #include <grub/file.h>
+ #include <grub/efi/efi.h>
++#include <grub/efi/fdtload.h>
++#include <grub/efi/memory.h>
+ 
+ static void *loaded_fdt;
+ static void *fdt;
+ 
++#define FDT_ADDR_CELLS_STRING "#address-cells"
++#define FDT_SIZE_CELLS_STRING "#size-cells"
++#define FDT_ADDR_SIZE_EXTRA ((2 * grub_fdt_prop_entry_size (sizeof(grub_uint32_t))) + \
++                             sizeof (FDT_ADDR_CELLS_STRING) + \
++                             sizeof (FDT_SIZE_CELLS_STRING))
++
+ void *
+ grub_fdt_load (grub_size_t additional_size)
+ {
+   void *raw_fdt;
+-  grub_size_t size;
++  unsigned int size;
+ 
+   if (fdt)
+     {
+       size = GRUB_EFI_BYTES_TO_PAGES (grub_fdt_get_totalsize (fdt));
+-      grub_efi_free_pages ((grub_efi_physical_address_t) fdt, size);
++      grub_efi_free_pages ((grub_addr_t) fdt, size);
+     }
+ 
+   if (loaded_fdt)
+@@ -45,12 +52,15 @@ grub_fdt_load (grub_size_t additional_size)
+   else
+     raw_fdt = grub_efi_get_firmware_fdt();
+ 
+-  size =
+-    raw_fdt ? grub_fdt_get_totalsize (raw_fdt) : GRUB_FDT_EMPTY_TREE_SZ;
++  if (raw_fdt)
++      size = grub_fdt_get_totalsize (raw_fdt);
++  else
++      size = GRUB_FDT_EMPTY_TREE_SZ + FDT_ADDR_SIZE_EXTRA;
++
+   size += additional_size;
+ 
+-  grub_dprintf ("linux", "allocating %ld bytes for fdt\n", size);
+-  fdt = grub_efi_allocate_pages (0, GRUB_EFI_BYTES_TO_PAGES (size));
++  grub_dprintf ("linux", "allocating %d bytes for fdt\n", size);
++  fdt = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (size));
+   if (!fdt)
+     return NULL;
+ 
+@@ -62,6 +72,8 @@ grub_fdt_load (grub_size_t additional_size)
+   else
+     {
+       grub_fdt_create_empty_tree (fdt, size);
++      grub_fdt_set_prop32 (fdt, 0, FDT_ADDR_CELLS_STRING, 2);
++      grub_fdt_set_prop32 (fdt, 0, FDT_SIZE_CELLS_STRING, 2);
+     }
+   return fdt;
+ }
+@@ -88,7 +100,7 @@ grub_fdt_unload (void) {
+   if (!fdt) {
+     return;
+   }
+-  grub_efi_free_pages ((grub_efi_physical_address_t) fdt,
++  grub_efi_free_pages ((grub_addr_t) fdt,
+ 		       GRUB_EFI_BYTES_TO_PAGES (grub_fdt_get_totalsize (fdt)));
+   fdt = NULL;
+ }
+diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
+index 083f9417cb65e509e673dba09a71616c5661ab05..9b53d3168f9bb78eab7a124518e83915183912b9 100644
+--- a/grub-core/loader/i386/linux.c
++++ b/grub-core/loader/i386/linux.c
+@@ -306,6 +306,12 @@ grub_linux_setup_video (struct linux_kernel_params *params)
+   params->lfb_line_len = mode_info.pitch;
+ 
+   params->lfb_base = (grub_size_t) framebuffer;
++
++#if defined (GRUB_MACHINE_EFI) && defined (__x86_64__)
++  params->ext_lfb_base = (grub_size_t) (((grub_uint64_t)(grub_size_t) framebuffer) >> 32);
++  params->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
++#endif
++
+   params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height, 65536);
+ 
+   params->red_mask_size = mode_info.red_mask_size;
+@@ -678,7 +684,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 		int argc, char *argv[])
+ {
+   grub_file_t file = 0;
+-  struct linux_kernel_header lh;
++  struct linux_i386_kernel_header lh;
+   grub_uint8_t setup_sects;
+   grub_size_t real_size, prot_size, prot_file_size;
+   grub_ssize_t len;
+@@ -721,7 +727,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
+      still not support 32-bit boot.  */
+-  if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_MAGIC_SIGNATURE)
++  if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
+       || grub_le_to_cpu16 (lh.version) < 0x0203)
+     {
+       grub_error (GRUB_ERR_BAD_OS, "version too old for 32-bit boot"
+diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c
+index fd7b41b0cad4f26d1170d70692ac1ac27fd6bd73..dc98dbcae258b340e155c64f1f73213ac724806a 100644
+--- a/grub-core/loader/i386/multiboot_mbi.c
++++ b/grub-core/loader/i386/multiboot_mbi.c
+@@ -239,7 +239,7 @@ grub_multiboot_get_mbi_size (void)
+   ret = sizeof (struct multiboot_info) + ALIGN_UP (cmdline_size, 4)
+     + modcnt * sizeof (struct multiboot_mod_list) + total_modcmd
+     + ALIGN_UP (sizeof(PACKAGE_STRING), 4) 
+-    + grub_get_multiboot_mmap_count () * sizeof (struct multiboot_mmap_entry)
++    + grub_multiboot_get_mmap_count () * sizeof (struct multiboot_mmap_entry)
+     + elf_sec_entsize * elf_sec_num
+     + 256 * sizeof (struct multiboot_color)
+ #if GRUB_MACHINE_HAS_VBE || GRUB_MACHINE_HAS_VGA_TEXT
+@@ -542,7 +542,7 @@ grub_multiboot_make_mbi (grub_uint32_t *target)
+       mbi->mods_count = 0;
+     }
+ 
+-  mmap_size = grub_get_multiboot_mmap_count () 
++  mmap_size = grub_multiboot_get_mmap_count () 
+     * sizeof (struct multiboot_mmap_entry);
+   grub_fill_multiboot_mmap ((struct multiboot_mmap_entry *) ptrorig);
+   mbi->mmap_length = mmap_size;
+diff --git a/grub-core/loader/i386/pc/chainloader.c b/grub-core/loader/i386/pc/chainloader.c
+index c79c4fe0fc99a876b3e92f0a24f16cd636e00a0d..ef3a322b78cf10a406c0420780f821e2e1d1b284 100644
+--- a/grub-core/loader/i386/pc/chainloader.c
++++ b/grub-core/loader/i386/pc/chainloader.c
+@@ -19,6 +19,7 @@
+ 
+ #include <grub/loader.h>
+ #include <grub/machine/chainloader.h>
++#include <grub/machine/biosdisk.h>
+ #include <grub/machine/memory.h>
+ #include <grub/file.h>
+ #include <grub/err.h>
+@@ -86,9 +87,16 @@ grub_chainloader_unload (void)
+ void
+ grub_chainloader_patch_bpb (void *bs, grub_device_t dev, grub_uint8_t dl)
+ {
+-  grub_uint32_t part_start = 0;
++  grub_uint32_t part_start = 0, heads = 0, sectors = 0;
+   if (dev && dev->disk)
+-    part_start = grub_partition_get_start (dev->disk->partition);
++    {
++      part_start = grub_partition_get_start (dev->disk->partition);
++      if (dev->disk->data)
++        {
++          heads = ((struct grub_biosdisk_data *)(dev->disk->data))->heads;
++          sectors = ((struct grub_biosdisk_data *)(dev->disk->data))->sectors;
++        }
++    }
+   if (grub_memcmp ((char *) &((struct grub_ntfs_bpb *) bs)->oem_name,
+ 		   "NTFS", 4) == 0)
+     {
+@@ -117,7 +125,7 @@ grub_chainloader_patch_bpb (void *bs, grub_device_t dev, grub_uint8_t dl)
+ 
+       if (bpb->num_reserved_sectors == 0)
+ 	break;
+-      if (bpb->num_total_sectors_16 == 0 || bpb->num_total_sectors_32 == 0)
++      if (bpb->num_total_sectors_16 == 0 && bpb->num_total_sectors_32 == 0)
+ 	break;
+ 
+       if (bpb->num_fats == 0)
+@@ -127,12 +135,20 @@ grub_chainloader_patch_bpb (void *bs, grub_device_t dev, grub_uint8_t dl)
+ 	{
+ 	  bpb->num_hidden_sectors = grub_cpu_to_le32 (part_start);
+ 	  bpb->version_specific.fat12_or_fat16.num_ph_drive = dl;
++          if (sectors)
++            bpb->sectors_per_track = grub_cpu_to_le16 (sectors);
++          if (heads)
++            bpb->num_heads = grub_cpu_to_le16 (heads);
+ 	  return;
+ 	}
+       if (bpb->version_specific.fat32.sectors_per_fat_32)
+ 	{
+ 	  bpb->num_hidden_sectors = grub_cpu_to_le32 (part_start);
+ 	  bpb->version_specific.fat32.num_ph_drive = dl;
++          if (sectors)
++            bpb->sectors_per_track = grub_cpu_to_le16 (sectors);
++          if (heads)
++            bpb->num_heads = grub_cpu_to_le16 (heads);
+ 	  return;
+ 	}
+       break;
+diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
+index a293b17aa101b308635bbed4086ae1547b91b884..b69cb7a3a7f8a9ca96a91a78c47fa1515e628699 100644
+--- a/grub-core/loader/i386/pc/linux.c
++++ b/grub-core/loader/i386/pc/linux.c
+@@ -121,7 +121,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 		int argc, char *argv[])
+ {
+   grub_file_t file = 0;
+-  struct linux_kernel_header lh;
++  struct linux_i386_kernel_header lh;
+   grub_uint8_t setup_sects;
+   grub_size_t real_size;
+   grub_ssize_t len;
+@@ -169,7 +169,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ 
+   maximal_cmdline_size = 256;
+ 
+-  if (lh.header == grub_cpu_to_le32_compile_time (GRUB_LINUX_MAGIC_SIGNATURE)
++  if (lh.header == grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
+       && grub_le_to_cpu16 (lh.version) >= 0x0200)
+     {
+       grub_linux_is_bzimage = (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL);
+@@ -322,7 +322,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_MAGIC_SIGNATURE)
++  if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
+       || grub_le_to_cpu16 (lh.version) < 0x0200)
+     /* Clear the heap space.  */
+     grub_memset (grub_linux_real_chunk
+@@ -387,7 +387,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ {
+   grub_size_t size = 0;
+   grub_addr_t addr_max, addr_min;
+-  struct linux_kernel_header *lh;
++  struct linux_i386_kernel_header *lh;
+   grub_uint8_t *initrd_chunk;
+   grub_addr_t initrd_addr;
+   grub_err_t err;
+@@ -405,9 +405,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+       goto fail;
+     }
+ 
+-  lh = (struct linux_kernel_header *) grub_linux_real_chunk;
++  lh = (struct linux_i386_kernel_header *) grub_linux_real_chunk;
+ 
+-  if (!(lh->header == grub_cpu_to_le32_compile_time (GRUB_LINUX_MAGIC_SIGNATURE)
++  if (!(lh->header == grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
+ 	&& grub_le_to_cpu16 (lh->version) >= 0x0200))
+     {
+       grub_error (GRUB_ERR_BAD_OS, "the kernel is too old for initrd");
+diff --git a/grub-core/loader/i386/xen_file.c b/grub-core/loader/i386/xen_file.c
+index 99fad4cadae42ab09497babca15cd9606557fcd2..77a93e7b228316e1df731e01e51e67f9225b4482 100644
+--- a/grub-core/loader/i386/xen_file.c
++++ b/grub-core/loader/i386/xen_file.c
+@@ -26,7 +26,7 @@ grub_elf_t
+ grub_xen_file (grub_file_t file)
+ {
+   grub_elf_t elf;
+-  struct linux_kernel_header lh;
++  struct linux_i386_kernel_header lh;
+   grub_file_t off_file;
+   grub_uint32_t payload_offset, payload_length;
+   grub_uint8_t magic[6];
+@@ -43,7 +43,7 @@ grub_xen_file (grub_file_t file)
+     goto fail;
+ 
+   if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55)
+-      || lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_MAGIC_SIGNATURE)
++      || lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
+       || grub_le_to_cpu16 (lh.version) < 0x0208)
+     {
+       grub_error (GRUB_ERR_BAD_OS, "version too old for xen boot");
+diff --git a/grub-core/loader/ia64/efi/linux.c b/grub-core/loader/ia64/efi/linux.c
+index efaa42ccdd2bf74321de20cf5033a80676cc7dc3..750330d4572d0dcd09d02b4b75c1f03045fa897b 100644
+--- a/grub-core/loader/ia64/efi/linux.c
++++ b/grub-core/loader/ia64/efi/linux.c
+@@ -252,7 +252,7 @@ allocate_pages (grub_uint64_t align, grub_uint64_t size_pages,
+ 	aligned_start += align;
+       if (aligned_start + size > end)
+ 	continue;
+-      mem = grub_efi_allocate_pages (aligned_start, size_pages);
++      mem = grub_efi_allocate_fixed (aligned_start, size_pages);
+       if (! mem)
+ 	{
+ 	  grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory");
+@@ -326,7 +326,7 @@ grub_linux_boot (void)
+   mmap_size = find_mmap_size ();
+   if (! mmap_size)
+     return grub_errno;
+-  mmap_buf = grub_efi_allocate_pages (0, page_align (mmap_size) >> 12);
++  mmap_buf = grub_efi_allocate_any_pages (page_align (mmap_size) >> 12);
+   if (! mmap_buf)
+     return grub_error (GRUB_ERR_IO, "cannot allocate memory map");
+   err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, &map_key,
+@@ -422,7 +422,7 @@ grub_load_elf64 (grub_file_t file, void *buffer, const char *filename)
+   relocate = grub_env_get ("linux_relocate");
+   if (!relocate || grub_strcmp (relocate, "force") != 0)
+     {
+-      kernel_mem = grub_efi_allocate_pages (low_addr, kernel_pages);
++      kernel_mem = grub_efi_allocate_fixed (low_addr, kernel_pages);
+       reloc_offset = 0;
+     }
+   /* Try to relocate.  */
+@@ -524,7 +524,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+     len += grub_strlen (argv[i]) + 1;
+   len += sizeof (struct ia64_boot_param) + 512; /* Room for extensions.  */
+   boot_param_pages = page_align (len) >> 12;
+-  boot_param = grub_efi_allocate_pages (0, boot_param_pages);
++  boot_param = grub_efi_allocate_any_pages (boot_param_pages);
+   if (boot_param == 0)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY,
+@@ -589,7 +589,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+   grub_dprintf ("linux", "Loading initrd\n");
+ 
+   initrd_pages = (page_align (initrd_size) >> 12);
+-  initrd_mem = grub_efi_allocate_pages (0, initrd_pages);
++  initrd_mem = grub_efi_allocate_any_pages (initrd_pages);
+   if (! initrd_mem)
+     {
+       grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate pages");
+diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c
+index bd9d5b3e698588db594a2c334d715e0e883bab92..40c67e82489ec3ecf891ae564cde810bf280b242 100644
+--- a/grub-core/loader/multiboot.c
++++ b/grub-core/loader/multiboot.c
+@@ -28,7 +28,15 @@
+ 
+ #include <grub/loader.h>
+ #include <grub/command.h>
++#ifdef GRUB_USE_MULTIBOOT2
++#include <grub/multiboot2.h>
++#define GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER GRUB_MULTIBOOT2_CONSOLE_FRAMEBUFFER
++#define GRUB_MULTIBOOT_CONSOLE_EGA_TEXT GRUB_MULTIBOOT2_CONSOLE_EGA_TEXT
++#define GRUB_MULTIBOOT(x) grub_multiboot2_ ## x
++#else
+ #include <grub/multiboot.h>
++#define GRUB_MULTIBOOT(x) grub_multiboot_ ## x
++#endif
+ #include <grub/cpu/multiboot.h>
+ #include <grub/elf.h>
+ #include <grub/aout.h>
+@@ -49,8 +57,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ #include <grub/efi/efi.h>
+ #endif
+ 
+-struct grub_relocator *grub_multiboot_relocator = NULL;
+-grub_uint32_t grub_multiboot_payload_eip;
++struct grub_relocator *GRUB_MULTIBOOT (relocator) = NULL;
++grub_uint32_t GRUB_MULTIBOOT (payload_eip);
+ #if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
+ #define DEFAULT_VIDEO_MODE "text"
+ #else
+@@ -78,7 +86,7 @@ count_hook (grub_uint64_t addr __attribute__ ((unused)),
+ /* Return the length of the Multiboot mmap that will be needed to allocate
+    our platform's map.  */
+ grub_uint32_t
+-grub_get_multiboot_mmap_count (void)
++GRUB_MULTIBOOT (get_mmap_count) (void)
+ {
+   grub_size_t count = 0;
+ 
+@@ -88,7 +96,7 @@ grub_get_multiboot_mmap_count (void)
+ }
+ 
+ grub_err_t
+-grub_multiboot_set_video_mode (void)
++GRUB_MULTIBOOT (set_video_mode) (void)
+ {
+   grub_err_t err;
+   const char *modevar;
+@@ -130,9 +138,12 @@ static void
+ efi_boot (struct grub_relocator *rel,
+ 	  grub_uint32_t target)
+ {
++#ifdef GRUB_USE_MULTIBOOT2
++  struct grub_relocator_efi_state state_efi = MULTIBOOT2_EFI_INITIAL_STATE;
++#else
+   struct grub_relocator_efi_state state_efi = MULTIBOOT_EFI_INITIAL_STATE;
+-
+-  state_efi.MULTIBOOT_EFI_ENTRY_REGISTER = grub_multiboot_payload_eip;
++#endif
++  state_efi.MULTIBOOT_EFI_ENTRY_REGISTER = GRUB_MULTIBOOT (payload_eip);
+   state_efi.MULTIBOOT_EFI_MBI_REGISTER = target;
+ 
+   grub_relocator_efi_boot (rel, state_efi);
+@@ -164,19 +175,23 @@ static grub_err_t
+ grub_multiboot_boot (void)
+ {
+   grub_err_t err;
++
++#ifdef GRUB_USE_MULTIBOOT2
++  struct grub_relocator32_state state = MULTIBOOT2_INITIAL_STATE;
++#else
+   struct grub_relocator32_state state = MULTIBOOT_INITIAL_STATE;
++#endif
++  state.MULTIBOOT_ENTRY_REGISTER = GRUB_MULTIBOOT (payload_eip);
+ 
+-  state.MULTIBOOT_ENTRY_REGISTER = grub_multiboot_payload_eip;
+-
+-  err = grub_multiboot_make_mbi (&state.MULTIBOOT_MBI_REGISTER);
++  err = GRUB_MULTIBOOT (make_mbi) (&state.MULTIBOOT_MBI_REGISTER);
+ 
+   if (err)
+     return err;
+ 
+   if (grub_efi_is_finished)
+-    normal_boot (grub_multiboot_relocator, state);
++    normal_boot (GRUB_MULTIBOOT (relocator), state);
+   else
+-    efi_boot (grub_multiboot_relocator, state.MULTIBOOT_MBI_REGISTER);
++    efi_boot (GRUB_MULTIBOOT (relocator), state.MULTIBOOT_MBI_REGISTER);
+ 
+   /* Not reached.  */
+   return GRUB_ERR_NONE;
+@@ -185,10 +200,10 @@ grub_multiboot_boot (void)
+ static grub_err_t
+ grub_multiboot_unload (void)
+ {
+-  grub_multiboot_free_mbi ();
++  GRUB_MULTIBOOT (free_mbi) ();
+ 
+-  grub_relocator_unload (grub_multiboot_relocator);
+-  grub_multiboot_relocator = NULL;
++  grub_relocator_unload (GRUB_MULTIBOOT (relocator));
++  GRUB_MULTIBOOT (relocator) = NULL;
+ 
+   grub_dl_unref (my_mod);
+ 
+@@ -207,7 +222,7 @@ static grub_uint64_t highest_load;
+ 
+ /* Load ELF32 or ELF64.  */
+ grub_err_t
+-grub_multiboot_load_elf (mbi_load_data_t *mld)
++GRUB_MULTIBOOT (load_elf) (mbi_load_data_t *mld)
+ {
+   if (grub_multiboot_is_elf32 (mld->buffer))
+     return grub_multiboot_load_elf32 (mld);
+@@ -218,9 +233,9 @@ grub_multiboot_load_elf (mbi_load_data_t *mld)
+ }
+ 
+ grub_err_t
+-grub_multiboot_set_console (int console_type, int accepted_consoles,
+-			    int width, int height, int depth,
+-			    int console_req)
++GRUB_MULTIBOOT (set_console) (int console_type, int accepted_consoles,
++			      int width, int height, int depth,
++			      int console_req)
+ {
+   console_required = console_req;
+   if (!(accepted_consoles 
+@@ -313,19 +328,19 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)),
+   grub_dl_ref (my_mod);
+ 
+   /* Skip filename.  */
+-  grub_multiboot_init_mbi (argc - 1, argv + 1);
++  GRUB_MULTIBOOT (init_mbi) (argc - 1, argv + 1);
+ 
+-  grub_relocator_unload (grub_multiboot_relocator);
+-  grub_multiboot_relocator = grub_relocator_new ();
++  grub_relocator_unload (GRUB_MULTIBOOT (relocator));
++  GRUB_MULTIBOOT (relocator) = grub_relocator_new ();
+ 
+-  if (!grub_multiboot_relocator)
++  if (!GRUB_MULTIBOOT (relocator))
+     goto fail;
+ 
+-  err = grub_multiboot_load (file, argv[0]);
++  err = GRUB_MULTIBOOT (load) (file, argv[0]);
+   if (err)
+     goto fail;
+ 
+-  grub_multiboot_set_bootdev ();
++  GRUB_MULTIBOOT (set_bootdev) ();
+ 
+   grub_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0);
+ 
+@@ -335,8 +350,8 @@ grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)),
+ 
+   if (grub_errno != GRUB_ERR_NONE)
+     {
+-      grub_relocator_unload (grub_multiboot_relocator);
+-      grub_multiboot_relocator = NULL;
++      grub_relocator_unload (GRUB_MULTIBOOT (relocator));
++      GRUB_MULTIBOOT (relocator) = NULL;
+       grub_dl_unref (my_mod);
+     }
+ 
+@@ -368,7 +383,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+   if (argc == 0)
+     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ 
+-  if (!grub_multiboot_relocator)
++  if (!GRUB_MULTIBOOT (relocator))
+     return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ 		       N_("you need to load the kernel first"));
+ 
+@@ -389,7 +404,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+   if (size)
+   {
+     grub_relocator_chunk_t ch;
+-    err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
++    err = grub_relocator_alloc_chunk_align (GRUB_MULTIBOOT (relocator), &ch,
+ 					    lowest_addr, (0xffffffff - size) + 1,
+ 					    size, MULTIBOOT_MOD_ALIGN,
+ 					    GRUB_RELOCATOR_PREFERENCE_NONE, 1);
+@@ -407,7 +422,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+       target = 0;
+     }
+ 
+-  err = grub_multiboot_add_module (target, size, argc - 1, argv + 1);
++  err = GRUB_MULTIBOOT (add_module) (target, size, argc - 1, argv + 1);
+   if (err)
+     {
+       grub_file_close (file);
+diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c
+index 5e649ed2545bee3fbe9602c9d97079160dc6420a..70cd1db513e679f0e02e06dc2de24747a62b88ba 100644
+--- a/grub-core/loader/multiboot_elfxx.c
++++ b/grub-core/loader/multiboot_elfxx.c
+@@ -57,9 +57,9 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
+   char *phdr_base;
+   grub_err_t err;
+   grub_relocator_chunk_t ch;
+-  grub_uint32_t load_offset, load_size;
++  grub_uint32_t load_offset = 0, load_size;
+   int i;
+-  void *source;
++  void *source = NULL;
+ 
+   if (ehdr->e_ident[EI_MAG0] != ELFMAG0
+       || ehdr->e_ident[EI_MAG1] != ELFMAG1
+@@ -97,38 +97,38 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
+     return grub_error (GRUB_ERR_BAD_OS, "segment crosses 4 GiB border");
+ #endif
+ 
+-  load_size = highest_load - mld->link_base_addr;
+-
+   if (mld->relocatable)
+     {
++      load_size = highest_load - mld->link_base_addr;
++
++      grub_dprintf ("multiboot_loader", "align=0x%lx, preference=0x%x, "
++		    "load_size=0x%x, avoid_efi_boot_services=%d\n",
++		    (long) mld->align, mld->preference, load_size,
++		    mld->avoid_efi_boot_services);
++
+       if (load_size > mld->max_addr || mld->min_addr > mld->max_addr - load_size)
+ 	return grub_error (GRUB_ERR_BAD_OS, "invalid min/max address and/or load size");
+ 
+-      err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
++      err = grub_relocator_alloc_chunk_align (GRUB_MULTIBOOT (relocator), &ch,
+ 					      mld->min_addr, mld->max_addr - load_size,
+ 					      load_size, mld->align ? mld->align : 1,
+ 					      mld->preference, mld->avoid_efi_boot_services);
++
++      if (err)
++        {
++          grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS image\n");
++          return err;
++        }
++
++      mld->load_base_addr = get_physical_target_address (ch);
++      source = get_virtual_current_address (ch);
+     }
+   else
+-    err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator, &ch,
+-					   mld->link_base_addr, load_size);
++    mld->load_base_addr = mld->link_base_addr;
+ 
+-  if (err)
+-    {
+-      grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS image\n");
+-      return err;
+-    }
+-
+-  mld->load_base_addr = get_physical_target_address (ch);
+-  source = get_virtual_current_address (ch);
+-
+-  grub_dprintf ("multiboot_loader", "link_base_addr=0x%x, load_base_addr=0x%x, "
+-		"load_size=0x%x, relocatable=%d\n", mld->link_base_addr,
+-		mld->load_base_addr, load_size, mld->relocatable);
+-
+-  if (mld->relocatable)
+-    grub_dprintf ("multiboot_loader", "align=0x%lx, preference=0x%x, avoid_efi_boot_services=%d\n",
+-		  (long) mld->align, mld->preference, mld->avoid_efi_boot_services);
++  grub_dprintf ("multiboot_loader", "relocatable=%d, link_base_addr=0x%x, "
++		"load_base_addr=0x%x\n", mld->relocatable,
++		mld->link_base_addr, mld->load_base_addr);
+ 
+   /* Load every loadable segment in memory.  */
+   for (i = 0; i < ehdr->e_phnum; i++)
+@@ -139,7 +139,24 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
+ 	  grub_dprintf ("multiboot_loader", "segment %d: paddr=0x%lx, memsz=0x%lx, vaddr=0x%lx\n",
+ 			i, (long) phdr(i)->p_paddr, (long) phdr(i)->p_memsz, (long) phdr(i)->p_vaddr);
+ 
+-	  load_offset = phdr(i)->p_paddr - mld->link_base_addr;
++	  if (mld->relocatable)
++	    {
++	      load_offset = phdr(i)->p_paddr - mld->link_base_addr;
++	      grub_dprintf ("multiboot_loader", "segment %d: load_offset=0x%x\n", i, load_offset);
++	    }
++	  else
++	    {
++	      err = grub_relocator_alloc_chunk_addr (GRUB_MULTIBOOT (relocator), &ch,
++	                                             phdr(i)->p_paddr, phdr(i)->p_memsz);
++
++	      if (err)
++		{
++		  grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS image\n");
++		  return err;
++		}
++
++	      source = get_virtual_current_address (ch);
++	    }
+ 
+ 	  if (phdr(i)->p_filesz != 0)
+ 	    {
+@@ -167,7 +184,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
+     if (phdr(i)->p_vaddr <= ehdr->e_entry
+ 	&& phdr(i)->p_vaddr + phdr(i)->p_memsz > ehdr->e_entry)
+       {
+-	grub_multiboot_payload_eip = (ehdr->e_entry - phdr(i)->p_vaddr)
++	GRUB_MULTIBOOT (payload_eip) = (ehdr->e_entry - phdr(i)->p_vaddr)
+ 	  + phdr(i)->p_paddr;
+ #ifdef MULTIBOOT_LOAD_ELF64
+ # ifdef __mips
+@@ -191,7 +208,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
+ #if defined (__i386__) || defined (__x86_64__)
+   
+ #elif defined (__mips)
+-  grub_multiboot_payload_eip |= 0x80000000;
++  GRUB_MULTIBOOT (payload_eip) |= 0x80000000;
+ #else
+ #error Please complete this
+ #endif
+@@ -238,7 +255,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
+ 	  if (sh->sh_size == 0)
+ 	    continue;
+ 
+-	  err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch, 0,
++	  err = grub_relocator_alloc_chunk_align (GRUB_MULTIBOOT (relocator), &ch, 0,
+ 						  (0xffffffff - sh->sh_size) + 1,
+ 						  sh->sh_size, sh->sh_addralign,
+ 						  GRUB_RELOCATOR_PREFERENCE_NONE,
+@@ -264,8 +281,8 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld)
+ 	    }
+ 	  sh->sh_addr = target;
+ 	}
+-      grub_multiboot_add_elfsyms (ehdr->e_shnum, ehdr->e_shentsize,
+-				  ehdr->e_shstrndx, shdr);
++      GRUB_MULTIBOOT (add_elfsyms) (ehdr->e_shnum, ehdr->e_shentsize,
++				    ehdr->e_shstrndx, shdr);
+     }
+ 
+ #undef phdr
+diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c
+index b0679a9f6c9848d81cb74cf799ad3a7b235d937c..4df6595954d889028e4525bb66b42cf391f4c9ce 100644
+--- a/grub-core/loader/multiboot_mbi2.c
++++ b/grub-core/loader/multiboot_mbi2.c
+@@ -22,7 +22,7 @@
+ #include <grub/machine/apm.h>
+ #include <grub/machine/memory.h>
+ #endif
+-#include <grub/multiboot.h>
++#include <grub/multiboot2.h>
+ #include <grub/cpu/multiboot.h>
+ #include <grub/cpu/relocator.h>
+ #include <grub/disk.h>
+@@ -71,7 +71,7 @@ static int keep_bs = 0;
+ static grub_uint32_t load_base_addr;
+ 
+ void
+-grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize,
++grub_multiboot2_add_elfsyms (grub_size_t num, grub_size_t entsize,
+ 			    unsigned shndx, void *data)
+ {
+   elf_sec_num = num;
+@@ -90,17 +90,17 @@ find_header (grub_properly_aligned_t *buffer, grub_ssize_t len)
+        ((char *) header <= (char *) buffer + len - 12);
+        header = (struct multiboot_header *) ((grub_uint32_t *) header + MULTIBOOT_HEADER_ALIGN / 4))
+     {
+-      if (header->magic == MULTIBOOT_HEADER_MAGIC
++      if (header->magic == MULTIBOOT2_HEADER_MAGIC
+ 	  && !(header->magic + header->architecture
+ 	       + header->header_length + header->checksum)
+-	  && header->architecture == MULTIBOOT_ARCHITECTURE_CURRENT)
++	  && header->architecture == MULTIBOOT2_ARCHITECTURE_CURRENT)
+ 	return header;
+     }
+   return NULL;
+ }
+ 
+ grub_err_t
+-grub_multiboot_load (grub_file_t file, const char *filename)
++grub_multiboot2_load (grub_file_t file, const char *filename)
+ {
+   grub_ssize_t len;
+   struct multiboot_header *header;
+@@ -112,7 +112,7 @@ grub_multiboot_load (grub_file_t file, const char *filename)
+   grub_addr_t entry = 0, efi_entry = 0;
+   grub_uint32_t console_required = 0;
+   struct multiboot_header_tag_framebuffer *fbtag = NULL;
+-  int accepted_consoles = GRUB_MULTIBOOT_CONSOLE_EGA_TEXT;
++  int accepted_consoles = GRUB_MULTIBOOT2_CONSOLE_EGA_TEXT;
+   mbi_load_data_t mld;
+ 
+   mld.mbi_ver = 2;
+@@ -210,7 +210,7 @@ grub_multiboot_load (grub_file_t file, const char *filename)
+       case MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS:
+ 	if (!(((struct multiboot_header_tag_console_flags *) tag)->console_flags
+ 	    & MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED))
+-	  accepted_consoles &= ~GRUB_MULTIBOOT_CONSOLE_EGA_TEXT;
++	  accepted_consoles &= ~GRUB_MULTIBOOT2_CONSOLE_EGA_TEXT;
+ 	if (((struct multiboot_header_tag_console_flags *) tag)->console_flags
+ 	    & MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED)
+ 	  console_required = 1;
+@@ -218,7 +218,7 @@ grub_multiboot_load (grub_file_t file, const char *filename)
+ 
+       case MULTIBOOT_HEADER_TAG_FRAMEBUFFER:
+ 	fbtag = (struct multiboot_header_tag_framebuffer *) tag;
+-	accepted_consoles |= GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER;
++	accepted_consoles |= GRUB_MULTIBOOT2_CONSOLE_FRAMEBUFFER;
+ 	break;
+ 
+       case MULTIBOOT_HEADER_TAG_RELOCATABLE:
+@@ -295,13 +295,13 @@ grub_multiboot_load (grub_file_t file, const char *filename)
+ 	      return grub_error (GRUB_ERR_BAD_OS, "invalid min/max address and/or load size");
+ 	    }
+ 
+-	  err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
++	  err = grub_relocator_alloc_chunk_align (grub_multiboot2_relocator, &ch,
+ 						  mld.min_addr, mld.max_addr - code_size,
+ 						  code_size, mld.align ? mld.align : 1,
+ 						  mld.preference, keep_bs);
+ 	}
+       else
+-	err = grub_relocator_alloc_chunk_addr (grub_multiboot_relocator,
++	err = grub_relocator_alloc_chunk_addr (grub_multiboot2_relocator,
+ 					       &ch, load_addr, code_size);
+       if (err)
+ 	{
+@@ -343,7 +343,7 @@ grub_multiboot_load (grub_file_t file, const char *filename)
+       mld.file = file;
+       mld.filename = filename;
+       mld.avoid_efi_boot_services = keep_bs;
+-      err = grub_multiboot_load_elf (&mld);
++      err = grub_multiboot2_load_elf (&mld);
+       if (err)
+ 	{
+ 	  grub_free (mld.buffer);
+@@ -354,9 +354,9 @@ grub_multiboot_load (grub_file_t file, const char *filename)
+   load_base_addr = mld.load_base_addr;
+ 
+   if (keep_bs && efi_entry_specified)
+-    grub_multiboot_payload_eip = efi_entry;
++    grub_multiboot2_payload_eip = efi_entry;
+   else if (entry_specified)
+-    grub_multiboot_payload_eip = entry;
++    grub_multiboot2_payload_eip = entry;
+ 
+   if (mld.relocatable)
+     {
+@@ -370,20 +370,20 @@ grub_multiboot_load (grub_file_t file, const char *filename)
+        * 64-bit int here.
+        */
+       if (mld.load_base_addr >= mld.link_base_addr)
+-	grub_multiboot_payload_eip += mld.load_base_addr - mld.link_base_addr;
++	grub_multiboot2_payload_eip += mld.load_base_addr - mld.link_base_addr;
+       else
+-	grub_multiboot_payload_eip -= mld.link_base_addr - mld.load_base_addr;
++	grub_multiboot2_payload_eip -= mld.link_base_addr - mld.load_base_addr;
+     }
+ 
+   if (fbtag)
+-    err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_FRAMEBUFFER,
+-				      accepted_consoles,
+-				      fbtag->width, fbtag->height,
+-				      fbtag->depth, console_required);
++    err = grub_multiboot2_set_console (GRUB_MULTIBOOT2_CONSOLE_FRAMEBUFFER,
++				       accepted_consoles,
++				       fbtag->width, fbtag->height,
++				       fbtag->depth, console_required);
+   else
+-    err = grub_multiboot_set_console (GRUB_MULTIBOOT_CONSOLE_EGA_TEXT,
+-				      accepted_consoles,
+-				      0, 0, 0, console_required);
++    err = grub_multiboot2_set_console (GRUB_MULTIBOOT2_CONSOLE_EGA_TEXT,
++				       accepted_consoles,
++				       0, 0, 0, console_required);
+   return err;
+ }
+ 
+@@ -459,7 +459,7 @@ net_size (void)
+ }
+ 
+ static grub_size_t
+-grub_multiboot_get_mbi_size (void)
++grub_multiboot2_get_mbi_size (void)
+ {
+ #ifdef GRUB_MACHINE_EFI
+   if (!keep_bs && !efi_mmap_size)
+@@ -478,7 +478,7 @@ grub_multiboot_get_mbi_size (void)
+     + ALIGN_UP (sizeof (struct multiboot_tag_elf_sections), MULTIBOOT_TAG_ALIGN)
+     + ALIGN_UP (elf_sec_entsize * elf_sec_num, MULTIBOOT_TAG_ALIGN)
+     + ALIGN_UP ((sizeof (struct multiboot_tag_mmap)
+-		 + grub_get_multiboot_mmap_count ()
++		 + grub_multiboot2_get_mmap_count ()
+ 		 * sizeof (struct multiboot_mmap_entry)), MULTIBOOT_TAG_ALIGN)
+     + ALIGN_UP (sizeof (struct multiboot_tag_framebuffer), MULTIBOOT_TAG_ALIGN)
+     + ALIGN_UP (sizeof (struct multiboot_tag_old_acpi)
+@@ -522,7 +522,7 @@ grub_fill_multiboot_mmap (struct multiboot_tag_mmap *tag)
+ 
+   tag->type = MULTIBOOT_TAG_TYPE_MMAP;
+   tag->size = sizeof (struct multiboot_tag_mmap)
+-    + sizeof (struct multiboot_mmap_entry) * grub_get_multiboot_mmap_count (); 
++    + sizeof (struct multiboot_mmap_entry) * grub_multiboot2_get_mmap_count (); 
+   tag->entry_size = sizeof (struct multiboot_mmap_entry);
+   tag->entry_version = 0;
+ 
+@@ -588,7 +588,7 @@ retrieve_video_parameters (grub_properly_aligned_t **ptrorig)
+   struct multiboot_tag_framebuffer *tag
+     = (struct multiboot_tag_framebuffer *) *ptrorig;
+ 
+-  err = grub_multiboot_set_video_mode ();
++  err = grub_multiboot2_set_video_mode ();
+   if (err)
+     {
+       grub_print_error ();
+@@ -731,7 +731,7 @@ retrieve_video_parameters (grub_properly_aligned_t **ptrorig)
+ }
+ 
+ grub_err_t
+-grub_multiboot_make_mbi (grub_uint32_t *target)
++grub_multiboot2_make_mbi (grub_uint32_t *target)
+ {
+   grub_properly_aligned_t *ptrorig;
+   grub_properly_aligned_t *mbistart;
+@@ -739,11 +739,11 @@ grub_multiboot_make_mbi (grub_uint32_t *target)
+   grub_size_t bufsize;
+   grub_relocator_chunk_t ch;
+ 
+-  bufsize = grub_multiboot_get_mbi_size ();
++  bufsize = grub_multiboot2_get_mbi_size ();
+ 
+   COMPILE_TIME_ASSERT (MULTIBOOT_TAG_ALIGN % sizeof (grub_properly_aligned_t) == 0);
+ 
+-  err = grub_relocator_alloc_chunk_align (grub_multiboot_relocator, &ch,
++  err = grub_relocator_alloc_chunk_align (grub_multiboot2_relocator, &ch,
+ 					  0, 0xffffffff - bufsize,
+ 					  bufsize, MULTIBOOT_TAG_ALIGN,
+ 					  GRUB_RELOCATOR_PREFERENCE_NONE, 1);
+@@ -1039,7 +1039,7 @@ grub_multiboot_make_mbi (grub_uint32_t *target)
+ }
+ 
+ void
+-grub_multiboot_free_mbi (void)
++grub_multiboot2_free_mbi (void)
+ {
+   struct module *cur, *next;
+ 
+@@ -1061,11 +1061,11 @@ grub_multiboot_free_mbi (void)
+ }
+ 
+ grub_err_t
+-grub_multiboot_init_mbi (int argc, char *argv[])
++grub_multiboot2_init_mbi (int argc, char *argv[])
+ {
+   grub_ssize_t len = 0;
+ 
+-  grub_multiboot_free_mbi ();
++  grub_multiboot2_free_mbi ();
+ 
+   len = grub_loader_cmdline_size (argc, argv);
+ 
+@@ -1081,7 +1081,7 @@ grub_multiboot_init_mbi (int argc, char *argv[])
+ }
+ 
+ grub_err_t
+-grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
++grub_multiboot2_add_module (grub_addr_t start, grub_size_t size,
+ 			   int argc, char *argv[])
+ {
+   struct module *newmod;
+@@ -1119,7 +1119,7 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
+ }
+ 
+ void
+-grub_multiboot_set_bootdev (void)
++grub_multiboot2_set_bootdev (void)
+ {
+   grub_device_t dev;
+ 
+diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c
+index 4b68c4151a11db214602f74e111e7552801d8450..54306e3b16d25fe5d3bdf9502683822237be488d 100644
+--- a/grub-core/net/arp.c
++++ b/grub-core/net/arp.c
+@@ -111,8 +111,8 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
+ }
+ 
+ grub_err_t
+-grub_net_arp_receive (struct grub_net_buff *nb,
+-		      struct grub_net_card *card)
++grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card,
++                      grub_uint16_t *vlantag)
+ {
+   struct arppkt *arp_packet = (struct arppkt *) nb->data;
+   grub_net_network_level_address_t sender_addr, target_addr;
+@@ -138,6 +138,14 @@ grub_net_arp_receive (struct grub_net_buff *nb,
+ 
+   FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
+   {
++    /* Verify vlantag id */
++    if (inf->card == card && inf->vlantag != *vlantag)
++      {
++        grub_dprintf ("net", "invalid vlantag! %x != %x\n",
++                      inf->vlantag, *vlantag);
++        break;
++      }
++
+     /* Am I the protocol address target? */
+     if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
+ 	&& arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
+diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
+index a78d164db1a0abbaf0417f70dc7180b9b2c4df76..002446be1c385934762824a965806ffb75f422a0 100644
+--- a/grub-core/net/drivers/ieee1275/ofnet.c
++++ b/grub-core/net/drivers/ieee1275/ofnet.c
+@@ -153,11 +153,11 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath,
+   char *comma_char = 0;
+   char *equal_char = 0;
+   grub_size_t field_counter = 0;
+-
+   grub_net_network_level_address_t client_addr, gateway_addr, subnet_mask;
+   grub_net_link_level_address_t hw_addr;
+   grub_net_interface_flags_t flags = 0;
+   struct grub_net_network_level_interface *inter = NULL;
++  grub_uint16_t vlantag = 0;
+ 
+   hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
+ 
+@@ -175,6 +175,11 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath,
+           *equal_char = 0;
+           grub_env_set_net_property ((*card)->name, args, equal_char + 1,
+                                      grub_strlen(equal_char + 1));
++
++          if ((grub_strcmp (args, "vtag") == 0) &&
++              (grub_strlen (equal_char + 1) == 8))
++            vlantag = grub_strtoul (equal_char + 1 + 4, 0, 16);
++
+           *equal_char = '=';
+         }
+       else
+@@ -213,8 +218,10 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath,
+                                   hw_addr.mac, sizeof(hw_addr.mac), 0);
+       inter = grub_net_add_addr ((*card)->name, *card, &client_addr, &hw_addr,
+                                  flags);
++      inter->vlantag = vlantag;
+       grub_net_add_ipv4_local (inter,
+                           __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4)));
++
+     }
+ 
+   if (gateway_addr.ipv4 != 0)
+diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c
+index c397b1b348ce559070cabe1e0b6e28e4dbf254d8..4d7ceed6f93c7e87019546b544a4365a504f5f9f 100644
+--- a/grub-core/net/ethernet.c
++++ b/grub-core/net/ethernet.c
+@@ -18,6 +18,7 @@
+ 
+ #include <grub/misc.h>
+ #include <grub/mm.h>
++#include <grub/env.h>
+ #include <grub/net/ethernet.h>
+ #include <grub/net/ip.h>
+ #include <grub/net/arp.h>
+@@ -56,10 +57,17 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
+ {
+   struct etherhdr *eth;
+   grub_err_t err;
++  grub_uint8_t etherhdr_size;
++  grub_uint16_t vlantag_id = VLANTAG_IDENTIFIER;
+ 
+-  COMPILE_TIME_ASSERT (sizeof (*eth) < GRUB_NET_MAX_LINK_HEADER_SIZE);
++  etherhdr_size = sizeof (*eth);
++  COMPILE_TIME_ASSERT (sizeof (*eth) + 4 < GRUB_NET_MAX_LINK_HEADER_SIZE);
+ 
+-  err = grub_netbuff_push (nb, sizeof (*eth));
++  /* Increase ethernet header in case of vlantag */
++  if (inf->vlantag != 0)
++    etherhdr_size += 4;
++
++  err = grub_netbuff_push (nb, etherhdr_size);
+   if (err)
+     return err;
+   eth = (struct etherhdr *) nb->data;
+@@ -76,6 +84,19 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
+ 	return err;
+       inf->card->opened = 1;
+     }
++
++  /* Check and add a vlan-tag if needed. */
++  if (inf->vlantag != 0)
++    {
++      /* Move eth type to the right */
++      grub_memcpy ((char *) nb->data + etherhdr_size - 2,
++                   (char *) nb->data + etherhdr_size - 6, 2);
++
++      /* Add the tag in the middle */
++      grub_memcpy ((char *) nb->data + etherhdr_size - 6, &vlantag_id, 2);
++      grub_memcpy ((char *) nb->data + etherhdr_size - 4, (char *) &(inf->vlantag), 2);
++    }
++
+   return inf->card->driver->send (inf->card, nb);
+ }
+ 
+@@ -90,10 +111,25 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
+   grub_net_link_level_address_t hwaddress;
+   grub_net_link_level_address_t src_hwaddress;
+   grub_err_t err;
++  grub_uint8_t etherhdr_size = sizeof (*eth);
++  grub_uint16_t vlantag = 0;
++
++
++  /* Check if a vlan-tag is present. If so, the ethernet header is 4 bytes */
++  /* longer than the original one. The vlantag id is extracted and the header */
++  /* is reseted to the original size. */
++  if (grub_get_unaligned16 (nb->data + etherhdr_size - 2) == VLANTAG_IDENTIFIER)
++    {
++      vlantag = grub_get_unaligned16 (nb->data + etherhdr_size);
++      etherhdr_size += 4;
++      /* Move eth type to the original position */
++      grub_memcpy((char *) nb->data + etherhdr_size - 6,
++                  (char *) nb->data + etherhdr_size - 2, 2);
++    }
+ 
+   eth = (struct etherhdr *) nb->data;
+   type = grub_be_to_cpu16 (eth->type);
+-  err = grub_netbuff_pull (nb, sizeof (*eth));
++  err = grub_netbuff_pull (nb, etherhdr_size);
+   if (err)
+     return err;
+ 
+@@ -121,13 +157,14 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
+     {
+       /* ARP packet. */
+     case GRUB_NET_ETHERTYPE_ARP:
+-      grub_net_arp_receive (nb, card);
++      grub_net_arp_receive (nb, card, &vlantag);
+       grub_netbuff_free (nb);
+       return GRUB_ERR_NONE;
+       /* IP packet.  */
+     case GRUB_NET_ETHERTYPE_IP:
+     case GRUB_NET_ETHERTYPE_IP6:
+-      return grub_net_recv_ip_packets (nb, card, &hwaddress, &src_hwaddress);
++      return grub_net_recv_ip_packets (nb, card, &hwaddress, &src_hwaddress,
++                                       &vlantag);
+     }
+   grub_netbuff_free (nb);
+   return GRUB_ERR_NONE;
+diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
+index aba4f89087bc14b1fe28a77794dd6792beb0bf36..7c95cc7464a09af4b223c94d6653a03f0dbee062 100644
+--- a/grub-core/net/ip.c
++++ b/grub-core/net/ip.c
+@@ -228,12 +228,13 @@ handle_dgram (struct grub_net_buff *nb,
+ 	      grub_net_ip_protocol_t proto,
+ 	      const grub_net_network_level_address_t *source,
+ 	      const grub_net_network_level_address_t *dest,
++              grub_uint16_t *vlantag,
+ 	      grub_uint8_t ttl)
+ {
+   struct grub_net_network_level_interface *inf = NULL;
+   grub_err_t err;
+   int multicast = 0;
+-  
++
+   /* DHCP needs special treatment since we don't know IP yet.  */
+   {
+     struct udphdr *udph;
+@@ -293,6 +294,15 @@ handle_dgram (struct grub_net_buff *nb,
+ 	&& grub_net_addr_cmp (&inf->address, dest) == 0
+ 	&& grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0)
+       break;
++
++    /* Verify vlantag id */
++    if (inf->card == card && inf->vlantag != *vlantag)
++      {
++        grub_dprintf ("net", "invalid vlantag! %x != %x\n",
++                      inf->vlantag, *vlantag);
++        break;
++      }
++
+     /* Solicited node multicast.  */
+     if (inf->card == card
+ 	&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
+@@ -383,7 +393,8 @@ static grub_err_t
+ grub_net_recv_ip4_packets (struct grub_net_buff *nb,
+ 			   struct grub_net_card *card,
+ 			   const grub_net_link_level_address_t *hwaddress,
+-			   const grub_net_link_level_address_t *src_hwaddress)
++			   const grub_net_link_level_address_t *src_hwaddress,
++                           grub_uint16_t *vlantag)
+ {
+   struct iphdr *iph = (struct iphdr *) nb->data;
+   grub_err_t err;
+@@ -458,7 +469,7 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb,
+       dest.ipv4 = iph->dest;
+ 
+       return handle_dgram (nb, card, src_hwaddress, hwaddress, iph->protocol,
+-			   &source, &dest, iph->ttl);
++			   &source, &dest, vlantag, iph->ttl);
+     }
+ 
+   for (prev = &reassembles, rsm = *prev; rsm; prev = &rsm->next, rsm = *prev)
+@@ -594,7 +605,7 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb,
+       dest.ipv4 = dst;
+ 
+       return handle_dgram (ret, card, src_hwaddress,
+-			   hwaddress, proto, &source, &dest,
++			   hwaddress, proto, &source, &dest, vlantag,
+ 			   ttl);
+     }
+ }
+@@ -652,7 +663,8 @@ static grub_err_t
+ grub_net_recv_ip6_packets (struct grub_net_buff *nb,
+ 			   struct grub_net_card *card,
+ 			   const grub_net_link_level_address_t *hwaddress,
+-			   const grub_net_link_level_address_t *src_hwaddress)
++			   const grub_net_link_level_address_t *src_hwaddress,
++                           grub_uint16_t *vlantag)
+ {
+   struct ip6hdr *iph = (struct ip6hdr *) nb->data;
+   grub_err_t err;
+@@ -703,21 +715,24 @@ grub_net_recv_ip6_packets (struct grub_net_buff *nb,
+   grub_memcpy (dest.ipv6, &iph->dest, sizeof (dest.ipv6));
+ 
+   return handle_dgram (nb, card, src_hwaddress, hwaddress, iph->protocol,
+-		       &source, &dest, iph->ttl);
++		       &source, &dest, vlantag, iph->ttl);
+ }
+ 
+ grub_err_t
+ grub_net_recv_ip_packets (struct grub_net_buff *nb,
+ 			  struct grub_net_card *card,
+ 			  const grub_net_link_level_address_t *hwaddress,
+-			  const grub_net_link_level_address_t *src_hwaddress)
++			  const grub_net_link_level_address_t *src_hwaddress,
++                          grub_uint16_t *vlantag)
+ {
+   struct iphdr *iph = (struct iphdr *) nb->data;
+ 
+   if ((iph->verhdrlen >> 4) == 4)
+-    return grub_net_recv_ip4_packets (nb, card, hwaddress, src_hwaddress);
++    return grub_net_recv_ip4_packets (nb, card, hwaddress, src_hwaddress,
++                                      vlantag);
+   if ((iph->verhdrlen >> 4) == 6)
+-    return grub_net_recv_ip6_packets (nb, card, hwaddress, src_hwaddress);
++    return grub_net_recv_ip6_packets (nb, card, hwaddress, src_hwaddress,
++                                      vlantag);
+   grub_dprintf ("net", "Bad IP version: %d\n", (iph->verhdrlen >> 4));
+   grub_netbuff_free (nb);
+   return GRUB_ERR_NONE;
+diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c
+index 7338f8245e3a9bbe47e821fb43c2b699b9527ffb..6be678c0de1ac236b60f765e767ae43d113b1117 100644
+--- a/grub-core/normal/auth.c
++++ b/grub-core/normal/auth.c
+@@ -166,13 +166,13 @@ grub_username_get (char buf[], unsigned buf_size)
+       if (key == '\n' || key == '\r')
+ 	break;
+ 
+-      if (key == '\e')
++      if (key == GRUB_TERM_ESC)
+ 	{
+ 	  cur_len = 0;
+ 	  break;
+ 	}
+ 
+-      if (key == '\b')
++      if (key == GRUB_TERM_BACKSPACE)
+ 	{
+ 	  if (cur_len)
+ 	    {
+@@ -197,7 +197,7 @@ grub_username_get (char buf[], unsigned buf_size)
+   grub_xputs ("\n");
+   grub_refresh ();
+ 
+-  return (key != '\e');
++  return (key != GRUB_TERM_ESC);
+ }
+ 
+ grub_err_t
+diff --git a/grub-core/normal/cmdline.c b/grub-core/normal/cmdline.c
+index a36180d75305f421e96903a46acb9dd99af06572..c037d5050ed2b34fa3b2ac0c7564e4208ca143c4 100644
+--- a/grub-core/normal/cmdline.c
++++ b/grub-core/normal/cmdline.c
+@@ -626,12 +626,12 @@ grub_cmdline_get (const char *prompt_translated)
+ 	    cl_insert (cl_terms, nterms, &lpos, &llen, &max_len, &buf, kill_buf);
+ 	  break;
+ 
+-	case '\e':
++	case GRUB_TERM_ESC:
+ 	  grub_free (cl_terms);
+ 	  grub_free (buf);
+ 	  return 0;
+ 
+-	case '\b':
++	case GRUB_TERM_BACKSPACE:
+ 	  if (lpos > 0)
+ 	    {
+ 	      lpos--;
+diff --git a/grub-core/normal/crypto.c b/grub-core/normal/crypto.c
+index 2bfd67c8ef388097701a7415df3cd7321c6a1e57..e6d345f33458a167e703235d611afdd8c2a245b0 100644
+--- a/grub-core/normal/crypto.c
++++ b/grub-core/normal/crypto.c
+@@ -147,8 +147,8 @@ read_crypto_list (const char *prefix)
+       if (! cur->modname)
+ 	{
+ 	  grub_errno = GRUB_ERR_NONE;
+-	  grub_free (cur);
+ 	  grub_free (cur->name);
++	  grub_free (cur);
+ 	  continue;
+ 	}
+       cur->next = crypto_specs;
+diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
+index 719e2fb1c260b16d96cea2b787d7f7e592b428b7..e7a83c2d6e2aaa8248ed739b28f2c6be76622eb4 100644
+--- a/grub-core/normal/menu.c
++++ b/grub-core/normal/menu.c
+@@ -763,7 +763,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
+               *auto_boot = 0;
+ 	      return current_entry;
+ 
+-	    case '\e':
++	    case GRUB_TERM_ESC:
+ 	      if (nested)
+ 		{
+ 		  menu_fini ();
+diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c
+index eeeee5580abea9798278ef85cf417366cf4f0e0a..cdf3590a3646ce4be0caf99cafedcbc38cbe51e4 100644
+--- a/grub-core/normal/menu_entry.c
++++ b/grub-core/normal/menu_entry.c
+@@ -1403,7 +1403,7 @@ grub_menu_entry_run (grub_menu_entry_t entry)
+ 	    goto fail;
+ 	  break;
+ 
+-	case '\e':
++	case GRUB_TERM_ESC:
+ 	  destroy_screen (screen);
+ 	  return;
+ 
+diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
+index a79682a5e31e1b4e77d9b99f55cc5a1fca9e159b..a6153d359546d237933cba0f300e7d59fdb1007b 100644
+--- a/grub-core/osdep/linux/ofpath.c
++++ b/grub-core/osdep/linux/ofpath.c
+@@ -38,6 +38,46 @@
+ #include <errno.h>
+ #include <ctype.h>
+ 
++#ifdef __sparc__
++typedef enum
++  {
++    GRUB_OFPATH_SPARC_WWN_ADDR = 1,
++    GRUB_OFPATH_SPARC_TGT_LUN,
++  } ofpath_sparc_addressing;
++
++struct ofpath_sparc_hba
++{
++  grub_uint32_t device_id;
++  ofpath_sparc_addressing addressing;
++};
++
++static struct ofpath_sparc_hba sparc_lsi_hba[] = {
++  /* Rhea, Jasper 320, LSI53C1020/1030. */
++  {0x30, GRUB_OFPATH_SPARC_TGT_LUN},
++  /* SAS-1068E. */
++  {0x50, GRUB_OFPATH_SPARC_TGT_LUN},
++  /* SAS-1064E. */
++  {0x56, GRUB_OFPATH_SPARC_TGT_LUN},
++  /* Pandora SAS-1068E. */
++  {0x58, GRUB_OFPATH_SPARC_TGT_LUN},
++  /* Aspen, Invader, LSI SAS-3108. */
++  {0x5d, GRUB_OFPATH_SPARC_TGT_LUN},
++  /* Niwot, SAS 2108. */
++  {0x79, GRUB_OFPATH_SPARC_TGT_LUN},
++  /* Erie, Falcon, LSI SAS 2008. */
++  {0x72, GRUB_OFPATH_SPARC_WWN_ADDR},
++  /* LSI WarpDrive 6203. */
++  {0x7e, GRUB_OFPATH_SPARC_WWN_ADDR},
++  /* LSI SAS 2308. */
++  {0x87, GRUB_OFPATH_SPARC_WWN_ADDR},
++  /* LSI SAS 3008. */
++  {0x97, GRUB_OFPATH_SPARC_WWN_ADDR},
++  {0, 0}
++};
++
++static const int LSI_VENDOR_ID = 0x1000;
++#endif
++
+ #ifdef OFPATH_STANDALONE
+ #define xmalloc malloc
+ void
+@@ -120,6 +160,8 @@ find_obppath (const char *sysfs_path_orig)
+ #endif
+ 
+       fd = open(path, O_RDONLY);
++
++#ifndef __sparc__
+       if (fd < 0 || fstat (fd, &st) < 0)
+ 	{
+ 	  if (fd >= 0)
+@@ -127,6 +169,7 @@ find_obppath (const char *sysfs_path_orig)
+ 	  snprintf(path, path_size, "%s/devspec", sysfs_path);
+ 	  fd = open(path, O_RDONLY);
+ 	}
++#endif
+ 
+       if (fd < 0 || fstat (fd, &st) < 0)
+ 	{
+@@ -307,6 +350,55 @@ of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *devi
+   return ret;
+ }
+ 
++#ifdef __sparc__
++static char *
++of_path_of_nvme(const char *sys_devname __attribute__((unused)),
++	        const char *device,
++	        const char *devnode __attribute__((unused)),
++	        const char *devicenode)
++{
++  char *sysfs_path, *of_path, disk[MAX_DISK_CAT];
++  const char *digit_string, *part_end;
++
++  digit_string = trailing_digits (device);
++  part_end = devicenode + strlen (devicenode) - 1;
++
++  if ((*digit_string != '\0') && (*part_end == 'p'))
++    {
++      /* We have a partition number, strip it off. */
++      int part;
++      char *nvmedev, *end;
++
++      nvmedev = strdup (devicenode);
++
++      if (!nvmedev)
++        return NULL;
++
++      end = nvmedev + strlen (nvmedev) - 1;
++      /* Remove the p. */
++      *end = '\0';
++      sscanf (digit_string, "%d", &part);
++      snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1));
++      sysfs_path = block_device_get_sysfs_path_and_link (nvmedev);
++      free (nvmedev);
++    }
++  else
++    {
++      /* We do not have the parition. */
++      snprintf (disk, sizeof (disk), "/disk@1");
++      sysfs_path = block_device_get_sysfs_path_and_link (device);
++    }
++
++  of_path = find_obppath (sysfs_path);
++
++  if (of_path)
++    strcat (of_path, disk);
++
++  free (sysfs_path);
++  return of_path;
++}
++#endif
++
+ static int
+ vendor_is_ATA(const char *path)
+ {
+@@ -335,6 +427,64 @@ vendor_is_ATA(const char *path)
+   return (memcmp(bufcont, "ATA", 3) == 0);
+ }
+ 
++#ifdef __sparc__
++static void
++check_hba_identifiers (const char *sysfs_path, int *vendor, int *device_id)
++{
++  char *ed = strstr (sysfs_path, "host");
++  size_t path_size;
++  char *p, *path;
++  char buf[8];
++  int fd;
++
++  if (!ed)
++    return;
++
++  p = xstrdup (sysfs_path);
++  ed = strstr (p, "host");
++
++  *ed = '\0';
++
++  path_size = (strlen (p) + sizeof ("vendor"));
++  path = xmalloc (path_size);
++
++  if (!path)
++    goto out;
++
++  snprintf (path, path_size, "%svendor", p);
++  fd = open (path, O_RDONLY);
++
++  if (fd < 0)
++    goto out;
++
++  memset (buf, 0, sizeof (buf));
++
++  if (read (fd, buf, sizeof (buf) - 1) < 0)
++    goto out;
++
++  close (fd);
++  sscanf (buf, "%x", vendor);
++
++  snprintf (path, path_size, "%sdevice", p);
++  fd = open (path, O_RDONLY);
++
++  if (fd < 0)
++    goto out;
++
++  memset (buf, 0, sizeof (buf));
++
++  if (read (fd, buf, sizeof (buf) - 1) < 0)
++    goto out;
++
++  close (fd);
++  sscanf (buf, "%x", device_id);
++
++ out:
++  free (path);
++  free (p);
++}
++#endif
++
+ static void
+ check_sas (const char *sysfs_path, int *tgt, unsigned long int *sas_address)
+ {
+@@ -396,7 +546,7 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
+ {
+   const char *p, *digit_string, *disk_name;
+   int host, bus, tgt, lun;
+-  unsigned long int sas_address;
++  unsigned long int sas_address = 0;
+   char *sysfs_path, disk[MAX_DISK_CAT - sizeof ("/fp@0,0")];
+   char *of_path;
+ 
+@@ -413,9 +563,8 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
+     }
+ 
+   of_path = find_obppath(sysfs_path);
+-  free (sysfs_path);
+   if (!of_path)
+-    return NULL;
++    goto out;
+ 
+   if (strstr (of_path, "qlc"))
+     strcat (of_path, "/fp@0,0");
+@@ -444,6 +593,46 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
+     }
+   else
+     {
++#ifdef __sparc__
++      ofpath_sparc_addressing addressing = GRUB_OFPATH_SPARC_TGT_LUN;
++      int vendor = 0, device_id = 0;
++      char *optr = disk;
++
++      check_hba_identifiers (sysfs_path, &vendor, &device_id);
++
++      if (vendor == LSI_VENDOR_ID)
++        {
++          struct ofpath_sparc_hba *lsi_hba;
++
++	  /*
++	   * Over time different OF addressing schemes have been supported.
++	   * There is no generic addressing scheme that works across
++	   * every HBA.
++	   */
++          for (lsi_hba = sparc_lsi_hba; lsi_hba->device_id; lsi_hba++)
++            if (lsi_hba->device_id == device_id)
++              {
++                addressing = lsi_hba->addressing;
++                break;
++              }
++        }
++
++      if (addressing == GRUB_OFPATH_SPARC_WWN_ADDR)
++        optr += snprintf (disk, sizeof (disk), "/%s@w%lx,%x", disk_name,
++                          sas_address, lun);
++      else
++        optr += snprintf (disk, sizeof (disk), "/%s@%x,%x", disk_name, tgt,
++                          lun);
++
++      if (*digit_string != '\0')
++        {
++          int part;
++
++          sscanf (digit_string, "%d", &part);
++          snprintf (optr, sizeof (disk) - (optr - disk - 1), ":%c", 'a'
++                    + (part - 1));
++        }
++#else
+       if (lun == 0)
+         {
+           int sas_id = 0;
+@@ -491,8 +680,12 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
+             }
+ 	  free (lunstr);
+         }
++#endif
+     }
+   strcat(of_path, disk);
++
++ out:
++  free (sysfs_path);
+   return of_path;
+ }
+ 
+@@ -537,6 +730,11 @@ grub_util_devname_to_ofpath (const char *sys_devname)
+     /* All the models I've seen have a devalias "floppy".
+        New models have no floppy at all. */
+     ofpath = xstrdup ("floppy");
++#ifdef __sparc__
++  else if (device[0] == 'n' && device[1] == 'v' && device[2] == 'm'
++           && device[3] == 'e')
++    ofpath = of_path_of_nvme (name_buf, device, devnode, devicenode);
++#endif
+   else
+     {
+       grub_util_warn (_("unknown device type %s"), device);
+diff --git a/grub-core/osdep/unix/exec.c b/grub-core/osdep/unix/exec.c
+index 935ff120ebe117f7492715813789db364ef1b12f..db3259f6504d5d5958cfa330bfd4a8b12b64f970 100644
+--- a/grub-core/osdep/unix/exec.c
++++ b/grub-core/osdep/unix/exec.c
+@@ -99,7 +99,7 @@ grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file,
+ 	{
+ 	  fd = open (stdin_file, O_RDONLY);
+ 	  if (fd < 0)
+-	    exit (127);
++	    _exit (127);
+ 	  dup2 (fd, STDIN_FILENO);
+ 	  close (fd);
+ 	}
+@@ -108,7 +108,7 @@ grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file,
+ 	{
+ 	  fd = open (stdout_file, O_WRONLY | O_CREAT, 0700);
+ 	  if (fd < 0)
+-	    exit (127);
++	    _exit (127);
+ 	  dup2 (fd, STDOUT_FILENO);
+ 	  close (fd);
+ 	}
+@@ -117,7 +117,7 @@ grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file,
+ 	{
+ 	  fd = open (stderr_file, O_WRONLY | O_CREAT, 0700);
+ 	  if (fd < 0)
+-	    exit (127);
++	    _exit (127);
+ 	  dup2 (fd, STDERR_FILENO);
+ 	  close (fd);
+ 	}
+@@ -126,7 +126,7 @@ grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file,
+       setenv ("LC_ALL", "C", 1);
+ 
+       execvp ((char *) argv[0], (char **) argv);
+-      exit (127);
++      _exit (127);
+     }
+   waitpid (pid, &status, 0);
+   if (!WIFEXITED (status))
+diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c
+index 4bf37b027be660a14994fb316f08dd478490c4e2..3046e22cc012d1012add87931a018043e3ecc714 100644
+--- a/grub-core/osdep/unix/getroot.c
++++ b/grub-core/osdep/unix/getroot.c
+@@ -428,8 +428,11 @@ grub_find_device (const char *dir, dev_t dev)
+ 	{
+ #ifdef __linux__
+ 	  /* Skip device names like /dev/dm-0, which are short-hand aliases
+-	     to more descriptive device names, e.g. those under /dev/mapper */
+-	  if (ent->d_name[0] == 'd' &&
++	     to more descriptive device names, e.g. those under /dev/mapper.
++	     Also, don't skip devices which names start with dm-[0-9] in
++	     directories below /dev, e.g. /dev/mapper/dm-0-luks. */
++	  if (strcmp (dir, "/dev") == 0 &&
++	      ent->d_name[0] == 'd' &&
+ 	      ent->d_name[1] == 'm' &&
+ 	      ent->d_name[2] == '-' &&
+ 	      ent->d_name[3] >= '0' &&
+diff --git a/grub-core/osdep/unix/hostdisk.c b/grub-core/osdep/unix/hostdisk.c
+index 2a8c5882e3d10b98bc305a116f8cca06acfe89f5..5450cf4166e04c2cfab806e93dfa63c6abdb9698 100644
+--- a/grub-core/osdep/unix/hostdisk.c
++++ b/grub-core/osdep/unix/hostdisk.c
+@@ -77,11 +77,19 @@ grub_util_get_fd_size (grub_util_fd_t fd, const char *name, unsigned *log_secsiz
+ int
+ grub_util_fd_seek (grub_util_fd_t fd, grub_uint64_t off)
+ {
++#if SIZEOF_OFF_T == 8
+   off_t offset = (off_t) off;
+ 
+   if (lseek (fd, offset, SEEK_SET) != offset)
+     return -1;
++#elif SIZEOF_OFF64_T == 8
++  off64_t offset = (off64_t) off;
+ 
++  if (lseek64 (fd, offset, SEEK_SET) != offset)
++    return -1;
++#else
++#error "No large file support"
++#endif
+   return 0;
+ }
+ 
+diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c
+index a3fcfcacaa814d3ab62104f0dd406ef0c2163613..ca448bc11a05b9e0c6203a799ff62ab1dd75274f 100644
+--- a/grub-core/osdep/unix/platform.c
++++ b/grub-core/osdep/unix/platform.c
+@@ -78,19 +78,20 @@ get_ofpathname (const char *dev)
+ 		   dev);
+ }
+ 
+-static void
++static int
+ grub_install_remove_efi_entries_by_distributor (const char *efi_distributor)
+ {
+   int fd;
+   pid_t pid = grub_util_exec_pipe ((const char * []){ "efibootmgr", NULL }, &fd);
+   char *line = NULL;
+   size_t len = 0;
++  int rc;
+ 
+   if (!pid)
+     {
+       grub_util_warn (_("Unable to open stream from %s: %s"),
+ 		      "efibootmgr", strerror (errno));
+-      return;
++      return errno;
+     }
+ 
+   FILE *fp = fdopen (fd, "r");
+@@ -98,7 +99,7 @@ grub_install_remove_efi_entries_by_distributor (const char *efi_distributor)
+     {
+       grub_util_warn (_("Unable to open stream from %s: %s"),
+ 		      "efibootmgr", strerror (errno));
+-      return;
++      return errno;
+     }
+ 
+   line = xmalloc (80);
+@@ -119,23 +120,25 @@ grub_install_remove_efi_entries_by_distributor (const char *efi_distributor)
+       bootnum = line + sizeof ("Boot") - 1;
+       bootnum[4] = '\0';
+       if (!verbosity)
+-	grub_util_exec ((const char * []){ "efibootmgr", "-q",
++	rc = grub_util_exec ((const char * []){ "efibootmgr", "-q",
+ 	      "-b", bootnum,  "-B", NULL });
+       else
+-	grub_util_exec ((const char * []){ "efibootmgr",
++	rc = grub_util_exec ((const char * []){ "efibootmgr",
+ 	      "-b", bootnum, "-B", NULL });
+     }
+ 
+   free (line);
++  return rc;
+ }
+ 
+-void
++int
+ grub_install_register_efi (grub_device_t efidir_grub_dev,
+ 			   const char *efifile_path,
+ 			   const char *efi_distributor)
+ {
+   const char * efidir_disk;
+   int efidir_part;
++  int ret;
+   efidir_disk = grub_util_biosdisk_get_osdev (efidir_grub_dev->disk);
+   efidir_part = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1;
+ 
+@@ -151,23 +154,26 @@ grub_install_register_efi (grub_device_t efidir_grub_dev,
+   grub_util_exec ((const char * []){ "modprobe", "-q", "efivars", NULL });
+ #endif
+   /* Delete old entries from the same distributor.  */
+-  grub_install_remove_efi_entries_by_distributor (efi_distributor);
++  ret = grub_install_remove_efi_entries_by_distributor (efi_distributor);
++  if (ret)
++    return ret;
+ 
+   char *efidir_part_str = xasprintf ("%d", efidir_part);
+ 
+   if (!verbosity)
+-    grub_util_exec ((const char * []){ "efibootmgr", "-q",
++    ret = grub_util_exec ((const char * []){ "efibootmgr", "-q",
+ 	  "-c", "-d", efidir_disk,
+ 	  "-p", efidir_part_str, "-w",
+ 	  "-L", efi_distributor, "-l", 
+ 	  efifile_path, NULL });
+   else
+-    grub_util_exec ((const char * []){ "efibootmgr",
++    ret = grub_util_exec ((const char * []){ "efibootmgr",
+ 	  "-c", "-d", efidir_disk,
+ 	  "-p", efidir_part_str, "-w",
+ 	  "-L", efi_distributor, "-l", 
+ 	  efifile_path, NULL });
+   free (efidir_part_str);
++  return ret;
+ }
+ 
+ void
+diff --git a/grub-core/partmap/gpt.c b/grub-core/partmap/gpt.c
+index 83bcba7791421825da6922a7ee346f4fd5fcd7a4..103f6796f39f38209b0f554842aa6697faa5df2f 100644
+--- a/grub-core/partmap/gpt.c
++++ b/grub-core/partmap/gpt.c
+@@ -33,10 +33,10 @@ static grub_uint8_t grub_gpt_magic[8] =
+     0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54
+   };
+ 
+-static const grub_gpt_part_type_t grub_gpt_partition_type_empty = GRUB_GPT_PARTITION_TYPE_EMPTY;
++static const grub_gpt_part_guid_t grub_gpt_partition_type_empty = GRUB_GPT_PARTITION_TYPE_EMPTY;
+ 
+ #ifdef GRUB_UTIL
+-static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT;
++static const grub_gpt_part_guid_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT;
+ #endif
+ 
+ /* 512 << 7 = 65536 byte sectors.  */
+diff --git a/grub-core/term/arm/cros.c b/grub-core/term/arm/cros.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..1ff9f8ccfb8270884ba962a05ca99df4c6ed1f41
+--- /dev/null
++++ b/grub-core/term/arm/cros.c
+@@ -0,0 +1,125 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *
++ *  Copyright (C) 2012  Google Inc.
++ *  Copyright (C) 2016  Free Software Foundation, Inc.
++ *
++ *  This is based on depthcharge code.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/ps2.h>
++#include <grub/fdtbus.h>
++#include <grub/err.h>
++#include <grub/machine/kernel.h>
++#include <grub/misc.h>
++#include <grub/term.h>
++#include <grub/time.h>
++#include <grub/fdtbus.h>
++#include <grub/arm/cros_ec.h>
++
++struct grub_ps2_state ps2_state;
++
++struct grub_cros_ec_keyscan old_scan;
++
++static const struct grub_fdtbus_dev *cros_ec;
++
++static grub_uint8_t map_code[GRUB_CROS_EC_KEYSCAN_COLS][GRUB_CROS_EC_KEYSCAN_ROWS];
++
++static grub_uint8_t e0_translate[16] =
++  {
++    0x1c, 0x1d, 0x35, 0x00,
++    0x38, 0x00, 0x47, 0x48,
++    0x49, 0x4b, 0x4d, 0x4f,
++    0x50, 0x51, 0x52, 0x53,
++  };
++
++/* If there is a character pending, return it;
++   otherwise return GRUB_TERM_NO_KEY.  */
++static int
++grub_cros_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
++{
++  struct grub_cros_ec_keyscan scan;
++  int i, j;
++  if (grub_cros_ec_scan_keyboard (cros_ec, &scan) < 0)
++    return GRUB_TERM_NO_KEY;
++  for (i = 0; i < GRUB_CROS_EC_KEYSCAN_COLS; i++)
++    if (scan.data[i] ^ old_scan.data[i])
++      for (j = 0; j < GRUB_CROS_EC_KEYSCAN_ROWS; j++)
++	if ((scan.data[i] ^ old_scan.data[i]) & (1 << j))
++	  {
++	    grub_uint8_t code = map_code[i][j];
++	    int ret;
++	    grub_uint8_t brk = 0;
++	    if (!(scan.data[i] & (1 << j)))
++	      brk = 0x80;
++	    grub_dprintf ("cros_keyboard", "key <%d, %d> code %x\n", i, j, code);
++	    if (code < 0x60)
++	      ret = grub_ps2_process_incoming_byte (&ps2_state, code | brk);
++	    else if (code >= 0x60 && code < 0x70 && e0_translate[code - 0x60])
++	      {
++		grub_ps2_process_incoming_byte (&ps2_state, 0xe0);
++		ret = grub_ps2_process_incoming_byte (&ps2_state, e0_translate[code - 0x60] | brk);
++	      }
++	    else
++	      ret = GRUB_TERM_NO_KEY;
++	    old_scan.data[i] ^= (1 << j);
++	    if (ret != GRUB_TERM_NO_KEY)
++	      return ret;
++	  }
++  return GRUB_TERM_NO_KEY;
++}
++
++static struct grub_term_input grub_cros_keyboard_term =
++  {
++    .name = "cros_keyboard",
++    .getkey = grub_cros_keyboard_getkey
++  };
++
++static grub_err_t
++cros_attach (const struct grub_fdtbus_dev *dev)
++{
++  grub_size_t keymap_size, i;
++  const grub_uint8_t *keymap = grub_fdtbus_get_prop (dev, "linux,keymap", &keymap_size);
++
++  if (!dev->parent || !grub_cros_ec_validate (dev->parent))
++    return GRUB_ERR_IO;
++
++  if (keymap)
++    {
++      for (i = 0; i + 3 < keymap_size; i += 4)
++	if (keymap[i+1] < GRUB_CROS_EC_KEYSCAN_COLS && keymap[i] < GRUB_CROS_EC_KEYSCAN_ROWS
++	    && keymap[i+2] == 0 && keymap[i+3] < 0x80)
++	  map_code[keymap[i+1]][keymap[i]] = keymap[i+3];
++    }
++
++  cros_ec = dev->parent;
++  ps2_state.current_set = 1;
++  ps2_state.at_keyboard_status = 0;
++  grub_term_register_input ("cros_keyboard", &grub_cros_keyboard_term);
++  return GRUB_ERR_NONE;
++}
++
++static struct grub_fdtbus_driver cros =
++{
++  .compatible = "google,cros-ec-keyb",
++  .attach = cros_attach
++};
++
++void
++grub_cros_init (void)
++{
++  grub_fdtbus_register (&cros);
++}
+diff --git a/grub-core/term/arm/cros_ec.c b/grub-core/term/arm/cros_ec.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..f4144818b5bfdb9a512316ccc321586d539653ac
+--- /dev/null
++++ b/grub-core/term/arm/cros_ec.c
+@@ -0,0 +1,238 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *
++ *  Copyright (C) 2012  Google Inc.
++ *  Copyright (C) 2016  Free Software Foundation, Inc.
++ *
++ *  This is based on depthcharge code.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/mm.h>
++#include <grub/time.h>
++#include <grub/misc.h>
++#include <grub/arm/cros_ec.h>
++#include <grub/fdtbus.h>
++
++static const grub_uint64_t FRAMING_TIMEOUT_MS = 300;
++
++static const grub_uint8_t EC_FRAMING_BYTE = 0xec;
++
++#define EC_CMD_MKBP_STATE 0x60
++#define EC_CMD_VERSION0 0xdc
++
++static grub_uint64_t last_transfer;
++
++static void
++stop_bus (const struct grub_fdtbus_dev *spi)
++{
++  spi->driver->stop (spi);
++  last_transfer = grub_get_time_ms ();
++}
++
++static int
++wait_for_frame (const struct grub_fdtbus_dev *spi)
++{
++  grub_uint64_t start = grub_get_time_ms ();
++  grub_uint8_t byte;
++  do
++    {
++      if (spi->driver->receive (spi, &byte, 1))
++	return -1;
++      if (byte != EC_FRAMING_BYTE &&
++	  grub_get_time_ms () - start > FRAMING_TIMEOUT_MS)
++	{
++	  grub_dprintf ("cros", "Timeout waiting for framing byte.\n");
++	  return -1;
++	}
++    }
++  while (byte != EC_FRAMING_BYTE);
++  return 0;
++}
++
++/*
++ * Calculate a simple 8-bit checksum of a data block
++ *
++ * @param data	Data block to checksum
++ * @param size	Size of data block in bytes
++ * @return checksum value (0 to 255)
++ */
++static grub_uint8_t
++cros_ec_calc_checksum (const void *data, int size)
++{
++  grub_uint8_t csum;
++  const grub_uint8_t *bytes = data;
++  int i;
++
++  for (i = csum = 0; i < size; i++)
++    csum += bytes[i];
++  return csum & 0xff;
++}
++
++enum
++{
++  /* response, arglen */
++  CROS_EC_SPI_IN_HDR_SIZE = 2,
++  /* version, cmd, arglen */
++  CROS_EC_SPI_OUT_HDR_SIZE = 3
++};
++
++static grub_uint8_t busbuf[256];
++#define MSG_BYTES ((int)sizeof (busbuf))
++
++static int
++ec_command (const struct grub_fdtbus_dev *dev, int cmd, int cmd_version,
++	    const void *dout, int dout_len, void *din, int din_len)
++{
++  const struct grub_fdtbus_dev *spi = dev->parent;
++  grub_uint8_t *bytes;
++
++  /* Header + data + checksum. */
++  grub_uint32_t out_bytes = CROS_EC_SPI_OUT_HDR_SIZE + dout_len + 1;
++  grub_uint32_t in_bytes = CROS_EC_SPI_IN_HDR_SIZE + din_len + 1;
++
++  /*
++   * Sanity-check I/O sizes given transaction overhead in internal
++   * buffers.
++   */
++  if (out_bytes > MSG_BYTES)
++    {
++      grub_dprintf ("cros", "Cannot send %d bytes\n", dout_len);
++      return -1;
++    }
++  if (in_bytes > MSG_BYTES)
++    {
++      grub_dprintf ("cros", "Cannot receive %d bytes\n", din_len);
++      return -1;
++    }
++
++  /* Prepare the output. */
++  bytes = busbuf;
++  *bytes++ = EC_CMD_VERSION0 + cmd_version;
++  *bytes++ = cmd;
++  *bytes++ = dout_len;
++  grub_memcpy (bytes, dout, dout_len);
++  bytes += dout_len;
++
++  *bytes++ = cros_ec_calc_checksum (busbuf,
++				    CROS_EC_SPI_OUT_HDR_SIZE + dout_len);
++
++  /* Depthcharge uses 200 us here but GRUB timer resolution is only 1ms,
++     decrease this when we increase timer resolution.  */
++  while (grub_get_time_ms () - last_transfer < 1)
++    ;
++
++  if (spi->driver->start (spi))
++    return -1;
++
++  /* Allow EC to ramp up clock after being awoken. */
++  /* Depthcharge only waits 100 us here but GRUB timer resolution is only 1ms,
++     decrease this when we increase timer resolution.  */
++  grub_millisleep (1);
++
++  if (spi->driver->send (spi, busbuf, out_bytes))
++    {
++      stop_bus (spi);
++      return -1;
++    }
++
++  /* Wait until the EC is ready. */
++  if (wait_for_frame (spi))
++    {
++      stop_bus (spi);
++      return -1;
++    }
++
++  /* Read the response code and the data length. */
++  bytes = busbuf;
++  if (spi->driver->receive (spi, bytes, 2))
++    {
++      stop_bus (spi);
++      return -1;
++    }
++  grub_uint8_t result = *bytes++;
++  grub_uint8_t length = *bytes++;
++
++  /* Make sure there's enough room for the data. */
++  if (CROS_EC_SPI_IN_HDR_SIZE + length + 1 > MSG_BYTES)
++    {
++      grub_dprintf ("cros", "Received length %#02x too large\n", length);
++      stop_bus (spi);
++      return -1;
++    }
++
++  /* Read the data and the checksum, and finish up. */
++  if (spi->driver->receive (spi, bytes, length + 1))
++    {
++      stop_bus (spi);
++      return -1;
++    }
++  bytes += length;
++  int expected = *bytes++;
++  stop_bus (spi);
++
++  /* Check the integrity of the response. */
++  if (result != 0)
++    {
++      grub_dprintf ("cros", "Received bad result code %d\n", result);
++      return -result;
++    }
++
++  int csum = cros_ec_calc_checksum (busbuf,
++				    CROS_EC_SPI_IN_HDR_SIZE + length);
++
++  if (csum != expected)
++    {
++      grub_dprintf ("cros", "Invalid checksum rx %#02x, calced %#02x\n",
++		    expected, csum);
++      return -1;
++    }
++
++  /* If the caller wants the response, copy it out for them. */
++  if (length < din_len)
++    din_len = length;
++  if (din)
++    {
++      grub_memcpy (din, (grub_uint8_t *) busbuf + CROS_EC_SPI_IN_HDR_SIZE, din_len);
++    }
++
++  return din_len;
++}
++
++int
++grub_cros_ec_scan_keyboard (const struct grub_fdtbus_dev *dev, struct grub_cros_ec_keyscan *scan)
++{
++  if (ec_command (dev, EC_CMD_MKBP_STATE, 0, NULL, 0, scan,
++		  sizeof (*scan)) < (int) sizeof (*scan))
++    return -1;
++
++  return 0;
++}
++
++int
++grub_cros_ec_validate (const struct grub_fdtbus_dev *dev)
++{
++  if (!grub_fdtbus_is_compatible("google,cros-ec-spi", dev))
++    return 0;
++  if (!dev->parent)
++    return 0;
++  if (!dev->parent->driver)
++    return 0;
++  if (!dev->parent->driver->send
++      || !dev->parent->driver->receive)
++    return 0;
++  return 1;
++}
++
+diff --git a/grub-core/term/arm/pl050.c b/grub-core/term/arm/pl050.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..e4cda305666df20eba26e10d74b879361e83d6ea
+--- /dev/null
++++ b/grub-core/term/arm/pl050.c
+@@ -0,0 +1,189 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2007,2008,2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/ps2.h>
++#include <grub/fdtbus.h>
++#include <grub/err.h>
++#include <grub/machine/kernel.h>
++#include <grub/at_keyboard.h>
++#include <grub/misc.h>
++#include <grub/term.h>
++#include <grub/time.h>
++#include <grub/ps2.h>
++#include <grub/fdtbus.h>
++
++static volatile grub_uint32_t *pl050_regs;
++
++struct grub_ps2_state ps2_state;
++
++static void
++keyboard_controller_wait_until_ready (void)
++{
++  while (! (pl050_regs[1] & 0x40));
++}
++
++static grub_uint8_t
++wait_ack (void)
++{
++  grub_uint64_t endtime;
++  grub_uint8_t ack;
++
++  endtime = grub_get_time_ms () + 20;
++  do
++    ack = pl050_regs[2];
++  while (ack != GRUB_AT_ACK && ack != GRUB_AT_NACK
++	 && grub_get_time_ms () < endtime);
++  return ack;
++}
++
++
++static int
++write_mode (int mode)
++{
++  unsigned i;
++  for (i = 0; i < GRUB_AT_TRIES; i++)
++    {
++      grub_uint8_t ack;
++      keyboard_controller_wait_until_ready ();
++      pl050_regs[2] = 0xf0;
++      keyboard_controller_wait_until_ready ();
++      pl050_regs[2] = mode;
++      keyboard_controller_wait_until_ready ();
++      ack = wait_ack ();
++      if (ack == GRUB_AT_NACK)
++	continue;
++      if (ack == GRUB_AT_ACK)
++	break;
++      return 0;
++    }
++
++  return (i != GRUB_AT_TRIES);
++}
++
++static int
++query_mode (void)
++{
++  grub_uint8_t ret;
++  int e;
++
++  e = write_mode (0);
++  if (!e)
++    return 0;
++
++  keyboard_controller_wait_until_ready ();
++
++  do
++    ret = pl050_regs[2];
++  while (ret == GRUB_AT_ACK);
++
++  /* QEMU translates the set even in no-translate mode.  */
++  if (ret == 0x43 || ret == 1)
++    return 1;
++  if (ret == 0x41 || ret == 2)
++    return 2;
++  if (ret == 0x3f || ret == 3)
++    return 3;
++  return 0;
++}
++
++static void
++set_scancodes (void)
++{
++  write_mode (2);
++  ps2_state.current_set = query_mode ();
++  grub_dprintf ("atkeyb", "returned set %d\n", ps2_state.current_set);
++  if (ps2_state.current_set == 2)
++    return;
++
++  write_mode (1);
++  ps2_state.current_set = query_mode ();
++  grub_dprintf ("atkeyb", "returned set %d\n", ps2_state.current_set);
++  if (ps2_state.current_set == 1)
++    return;
++  grub_dprintf ("atkeyb", "no supported scancode set found\n");
++}
++
++static void
++keyboard_controller_led (grub_uint8_t leds)
++{
++  keyboard_controller_wait_until_ready ();
++  pl050_regs[2] = 0xed;
++  keyboard_controller_wait_until_ready ();
++  pl050_regs[2] = leds & 0x7;
++}
++
++/* If there is a character pending, return it;
++   otherwise return GRUB_TERM_NO_KEY.  */
++static int
++grub_pl050_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
++{
++  grub_uint8_t at_key;
++  int ret;
++  grub_uint8_t old_led;
++
++  if (!(pl050_regs[1] & 0x10))
++    return -1;
++  at_key = pl050_regs[2];
++  old_led = ps2_state.led_status;
++
++  ret = grub_ps2_process_incoming_byte (&ps2_state, at_key);
++  if (old_led != ps2_state.led_status)
++    keyboard_controller_led (ps2_state.led_status);
++  return ret;
++}
++
++static struct grub_term_input grub_pl050_keyboard_term =
++  {
++    .name = "pl050_keyboard",
++    .getkey = grub_pl050_keyboard_getkey
++  };
++
++static grub_err_t
++pl050_attach(const struct grub_fdtbus_dev *dev)
++{
++  const grub_uint32_t *reg;
++  reg = grub_fdtbus_get_prop (dev, "reg", 0);
++
++  /* Mouse.  Nothing to do.  */
++  if (grub_be_to_cpu32 (*reg) == 0x7000)
++    return 0;
++
++  pl050_regs = grub_fdtbus_map_reg (dev, 0, 0);
++
++  if (!grub_fdtbus_is_mapping_valid (pl050_regs))
++    return grub_error (GRUB_ERR_IO, "could not map pl050");
++
++  ps2_state.at_keyboard_status = 0;
++  set_scancodes ();
++  keyboard_controller_led (ps2_state.led_status);
++
++  grub_term_register_input ("pl050_keyboard", &grub_pl050_keyboard_term);
++  return GRUB_ERR_NONE;
++}
++
++struct grub_fdtbus_driver pl050 =
++{
++  .compatible = "arm,pl050",
++  .attach = pl050_attach
++};
++
++void
++grub_pl050_init (void)
++{
++  grub_fdtbus_register (&pl050);
++}
+diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c
+index b4ea9ff7e637f59c653b86cea79d4d664c78af84..f0a986eb176aef6c4fe3f5a65c646756e5bbde56 100644
+--- a/grub-core/term/at_keyboard.c
++++ b/grub-core/term/at_keyboard.c
+@@ -22,215 +22,26 @@
+ #include <grub/cpu/io.h>
+ #include <grub/misc.h>
+ #include <grub/term.h>
+-#include <grub/keyboard_layouts.h>
+ #include <grub/time.h>
+ #include <grub/loader.h>
++#include <grub/ps2.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+-static short at_keyboard_status = 0;
+-static int e0_received = 0;
+-static int f0_received = 0;
+-
+-static grub_uint8_t led_status;
+-
+-#define KEYBOARD_LED_SCROLL		(1 << 0)
+-#define KEYBOARD_LED_NUM		(1 << 1)
+-#define KEYBOARD_LED_CAPS		(1 << 2)
+-
+ static grub_uint8_t grub_keyboard_controller_orig;
+ static grub_uint8_t grub_keyboard_orig_set;
+-static grub_uint8_t current_set; 
+-
+-static void
+-grub_keyboard_controller_init (void);
+-
+-static const grub_uint8_t set1_mapping[128] =
+-  {
+-    /* 0x00 */ 0 /* Unused  */,               GRUB_KEYBOARD_KEY_ESCAPE, 
+-    /* 0x02 */ GRUB_KEYBOARD_KEY_1,           GRUB_KEYBOARD_KEY_2, 
+-    /* 0x04 */ GRUB_KEYBOARD_KEY_3,           GRUB_KEYBOARD_KEY_4, 
+-    /* 0x06 */ GRUB_KEYBOARD_KEY_5,           GRUB_KEYBOARD_KEY_6, 
+-    /* 0x08 */ GRUB_KEYBOARD_KEY_7,           GRUB_KEYBOARD_KEY_8, 
+-    /* 0x0a */ GRUB_KEYBOARD_KEY_9,           GRUB_KEYBOARD_KEY_0, 
+-    /* 0x0c */ GRUB_KEYBOARD_KEY_DASH,        GRUB_KEYBOARD_KEY_EQUAL, 
+-    /* 0x0e */ GRUB_KEYBOARD_KEY_BACKSPACE,   GRUB_KEYBOARD_KEY_TAB, 
+-    /* 0x10 */ GRUB_KEYBOARD_KEY_Q,           GRUB_KEYBOARD_KEY_W, 
+-    /* 0x12 */ GRUB_KEYBOARD_KEY_E,           GRUB_KEYBOARD_KEY_R, 
+-    /* 0x14 */ GRUB_KEYBOARD_KEY_T,           GRUB_KEYBOARD_KEY_Y, 
+-    /* 0x16 */ GRUB_KEYBOARD_KEY_U,           GRUB_KEYBOARD_KEY_I, 
+-    /* 0x18 */ GRUB_KEYBOARD_KEY_O,           GRUB_KEYBOARD_KEY_P, 
+-    /* 0x1a */ GRUB_KEYBOARD_KEY_LBRACKET,    GRUB_KEYBOARD_KEY_RBRACKET, 
+-    /* 0x1c */ GRUB_KEYBOARD_KEY_ENTER,       GRUB_KEYBOARD_KEY_LEFT_CTRL, 
+-    /* 0x1e */ GRUB_KEYBOARD_KEY_A,           GRUB_KEYBOARD_KEY_S, 
+-    /* 0x20 */ GRUB_KEYBOARD_KEY_D,           GRUB_KEYBOARD_KEY_F, 
+-    /* 0x22 */ GRUB_KEYBOARD_KEY_G,           GRUB_KEYBOARD_KEY_H, 
+-    /* 0x24 */ GRUB_KEYBOARD_KEY_J,           GRUB_KEYBOARD_KEY_K, 
+-    /* 0x26 */ GRUB_KEYBOARD_KEY_L,           GRUB_KEYBOARD_KEY_SEMICOLON, 
+-    /* 0x28 */ GRUB_KEYBOARD_KEY_DQUOTE,      GRUB_KEYBOARD_KEY_RQUOTE, 
+-    /* 0x2a */ GRUB_KEYBOARD_KEY_LEFT_SHIFT,  GRUB_KEYBOARD_KEY_BACKSLASH, 
+-    /* 0x2c */ GRUB_KEYBOARD_KEY_Z,           GRUB_KEYBOARD_KEY_X, 
+-    /* 0x2e */ GRUB_KEYBOARD_KEY_C,           GRUB_KEYBOARD_KEY_V, 
+-    /* 0x30 */ GRUB_KEYBOARD_KEY_B,           GRUB_KEYBOARD_KEY_N, 
+-    /* 0x32 */ GRUB_KEYBOARD_KEY_M,           GRUB_KEYBOARD_KEY_COMMA, 
+-    /* 0x34 */ GRUB_KEYBOARD_KEY_DOT,         GRUB_KEYBOARD_KEY_SLASH, 
+-    /* 0x36 */ GRUB_KEYBOARD_KEY_RIGHT_SHIFT, GRUB_KEYBOARD_KEY_NUMMUL, 
+-    /* 0x38 */ GRUB_KEYBOARD_KEY_LEFT_ALT,    GRUB_KEYBOARD_KEY_SPACE, 
+-    /* 0x3a */ GRUB_KEYBOARD_KEY_CAPS_LOCK,   GRUB_KEYBOARD_KEY_F1, 
+-    /* 0x3c */ GRUB_KEYBOARD_KEY_F2,          GRUB_KEYBOARD_KEY_F3, 
+-    /* 0x3e */ GRUB_KEYBOARD_KEY_F4,          GRUB_KEYBOARD_KEY_F5, 
+-    /* 0x40 */ GRUB_KEYBOARD_KEY_F6,          GRUB_KEYBOARD_KEY_F7, 
+-    /* 0x42 */ GRUB_KEYBOARD_KEY_F8,          GRUB_KEYBOARD_KEY_F9, 
+-    /* 0x44 */ GRUB_KEYBOARD_KEY_F10,         GRUB_KEYBOARD_KEY_NUM_LOCK, 
+-    /* 0x46 */ GRUB_KEYBOARD_KEY_SCROLL_LOCK, GRUB_KEYBOARD_KEY_NUM7, 
+-    /* 0x48 */ GRUB_KEYBOARD_KEY_NUM8,        GRUB_KEYBOARD_KEY_NUM9, 
+-    /* 0x4a */ GRUB_KEYBOARD_KEY_NUMMINUS,    GRUB_KEYBOARD_KEY_NUM4, 
+-    /* 0x4c */ GRUB_KEYBOARD_KEY_NUM5,        GRUB_KEYBOARD_KEY_NUM6, 
+-    /* 0x4e */ GRUB_KEYBOARD_KEY_NUMPLUS,     GRUB_KEYBOARD_KEY_NUM1, 
+-    /* 0x50 */ GRUB_KEYBOARD_KEY_NUM2,        GRUB_KEYBOARD_KEY_NUM3, 
+-    /* 0x52 */ GRUB_KEYBOARD_KEY_NUM0,        GRUB_KEYBOARD_KEY_NUMDOT, 
+-    /* 0x54 */ 0,                             0, 
+-    /* 0x56 */ GRUB_KEYBOARD_KEY_102ND,       GRUB_KEYBOARD_KEY_F11, 
+-    /* 0x58 */ GRUB_KEYBOARD_KEY_F12,         0,
+-    /* 0x5a */ 0,                             0,
+-    /* 0x5c */ 0,                             0,
+-    /* 0x5e */ 0,                             0,
+-    /* 0x60 */ 0,                             0,
+-    /* 0x62 */ 0,                             0,
+-    /* OLPC keys. Just mapped to normal keys.  */
+-    /* 0x64 */ 0,                             GRUB_KEYBOARD_KEY_UP,
+-    /* 0x66 */ GRUB_KEYBOARD_KEY_DOWN,        GRUB_KEYBOARD_KEY_LEFT,
+-    /* 0x68 */ GRUB_KEYBOARD_KEY_RIGHT,       0,
+-    /* 0x6a */ 0,                             0,
+-    /* 0x6c */ 0,                             0,
+-    /* 0x6e */ 0,                             0,
+-    /* 0x70 */ 0,                             0,
+-    /* 0x72 */ 0,                             GRUB_KEYBOARD_KEY_JP_RO,
+-    /* 0x74 */ 0,                             0,
+-    /* 0x76 */ 0,                             0,
+-    /* 0x78 */ 0,                             0,
+-    /* 0x7a */ 0,                             0,
+-    /* 0x7c */ 0,                             GRUB_KEYBOARD_KEY_JP_YEN,
+-    /* 0x7e */ GRUB_KEYBOARD_KEY_KPCOMMA
+-  };
+-
+-static const struct
+-{
+-  grub_uint8_t from, to;
+-} set1_e0_mapping[] = 
+-  {
+-    {0x1c, GRUB_KEYBOARD_KEY_NUMENTER},
+-    {0x1d, GRUB_KEYBOARD_KEY_RIGHT_CTRL},
+-    {0x35, GRUB_KEYBOARD_KEY_NUMSLASH }, 
+-    {0x38, GRUB_KEYBOARD_KEY_RIGHT_ALT},
+-    {0x47, GRUB_KEYBOARD_KEY_HOME}, 
+-    {0x48, GRUB_KEYBOARD_KEY_UP},
+-    {0x49, GRUB_KEYBOARD_KEY_PPAGE}, 
+-    {0x4b, GRUB_KEYBOARD_KEY_LEFT},
+-    {0x4d, GRUB_KEYBOARD_KEY_RIGHT},
+-    {0x4f, GRUB_KEYBOARD_KEY_END}, 
+-    {0x50, GRUB_KEYBOARD_KEY_DOWN},
+-    {0x51, GRUB_KEYBOARD_KEY_NPAGE},
+-    {0x52, GRUB_KEYBOARD_KEY_INSERT},
+-    {0x53, GRUB_KEYBOARD_KEY_DELETE}, 
+-  };
+-
+-static const grub_uint8_t set2_mapping[256] =
+-  {
+-    /* 0x00 */ 0,                             GRUB_KEYBOARD_KEY_F9,
+-    /* 0x02 */ 0,                             GRUB_KEYBOARD_KEY_F5,
+-    /* 0x04 */ GRUB_KEYBOARD_KEY_F3,          GRUB_KEYBOARD_KEY_F1,
+-    /* 0x06 */ GRUB_KEYBOARD_KEY_F2,          GRUB_KEYBOARD_KEY_F12,
+-    /* 0x08 */ 0,                             GRUB_KEYBOARD_KEY_F10,
+-    /* 0x0a */ GRUB_KEYBOARD_KEY_F8,          GRUB_KEYBOARD_KEY_F6,
+-    /* 0x0c */ GRUB_KEYBOARD_KEY_F4,          GRUB_KEYBOARD_KEY_TAB,
+-    /* 0x0e */ GRUB_KEYBOARD_KEY_RQUOTE,      0,
+-    /* 0x10 */ 0,                             GRUB_KEYBOARD_KEY_LEFT_ALT,
+-    /* 0x12 */ GRUB_KEYBOARD_KEY_LEFT_SHIFT,  0,
+-    /* 0x14 */ GRUB_KEYBOARD_KEY_LEFT_CTRL,   GRUB_KEYBOARD_KEY_Q,
+-    /* 0x16 */ GRUB_KEYBOARD_KEY_1,           0,
+-    /* 0x18 */ 0,                             0,
+-    /* 0x1a */ GRUB_KEYBOARD_KEY_Z,           GRUB_KEYBOARD_KEY_S,
+-    /* 0x1c */ GRUB_KEYBOARD_KEY_A,           GRUB_KEYBOARD_KEY_W,
+-    /* 0x1e */ GRUB_KEYBOARD_KEY_2,           0,
+-    /* 0x20 */ 0,                             GRUB_KEYBOARD_KEY_C,
+-    /* 0x22 */ GRUB_KEYBOARD_KEY_X,           GRUB_KEYBOARD_KEY_D,
+-    /* 0x24 */ GRUB_KEYBOARD_KEY_E,           GRUB_KEYBOARD_KEY_4,
+-    /* 0x26 */ GRUB_KEYBOARD_KEY_3,           0,
+-    /* 0x28 */ 0,                             GRUB_KEYBOARD_KEY_SPACE,
+-    /* 0x2a */ GRUB_KEYBOARD_KEY_V,           GRUB_KEYBOARD_KEY_F,
+-    /* 0x2c */ GRUB_KEYBOARD_KEY_T,           GRUB_KEYBOARD_KEY_R,
+-    /* 0x2e */ GRUB_KEYBOARD_KEY_5,           0,
+-    /* 0x30 */ 0,                             GRUB_KEYBOARD_KEY_N,
+-    /* 0x32 */ GRUB_KEYBOARD_KEY_B,           GRUB_KEYBOARD_KEY_H,
+-    /* 0x34 */ GRUB_KEYBOARD_KEY_G,           GRUB_KEYBOARD_KEY_Y,
+-    /* 0x36 */ GRUB_KEYBOARD_KEY_6,           0,
+-    /* 0x38 */ 0,                             0,
+-    /* 0x3a */ GRUB_KEYBOARD_KEY_M,           GRUB_KEYBOARD_KEY_J,
+-    /* 0x3c */ GRUB_KEYBOARD_KEY_U,           GRUB_KEYBOARD_KEY_7,
+-    /* 0x3e */ GRUB_KEYBOARD_KEY_8,           0,
+-    /* 0x40 */ 0,                             GRUB_KEYBOARD_KEY_COMMA,
+-    /* 0x42 */ GRUB_KEYBOARD_KEY_K,           GRUB_KEYBOARD_KEY_I,
+-    /* 0x44 */ GRUB_KEYBOARD_KEY_O,           GRUB_KEYBOARD_KEY_0,
+-    /* 0x46 */ GRUB_KEYBOARD_KEY_9,           0,
+-    /* 0x48 */ 0,                             GRUB_KEYBOARD_KEY_DOT,
+-    /* 0x4a */ GRUB_KEYBOARD_KEY_SLASH,       GRUB_KEYBOARD_KEY_L,
+-    /* 0x4c */ GRUB_KEYBOARD_KEY_SEMICOLON,   GRUB_KEYBOARD_KEY_P,
+-    /* 0x4e */ GRUB_KEYBOARD_KEY_DASH,        0,
+-    /* 0x50 */ 0,                             GRUB_KEYBOARD_KEY_JP_RO,
+-    /* 0x52 */ GRUB_KEYBOARD_KEY_DQUOTE,      0,
+-    /* 0x54 */ GRUB_KEYBOARD_KEY_LBRACKET,    GRUB_KEYBOARD_KEY_EQUAL,
+-    /* 0x56 */ 0,                             0,
+-    /* 0x58 */ GRUB_KEYBOARD_KEY_CAPS_LOCK,   GRUB_KEYBOARD_KEY_RIGHT_SHIFT,
+-    /* 0x5a */ GRUB_KEYBOARD_KEY_ENTER,       GRUB_KEYBOARD_KEY_RBRACKET,
+-    /* 0x5c */ 0,                             GRUB_KEYBOARD_KEY_BACKSLASH,
+-    /* 0x5e */ 0,                             0,
+-    /* 0x60 */ 0,                             GRUB_KEYBOARD_KEY_102ND,
+-    /* 0x62 */ 0,                             0,
+-    /* 0x64 */ 0,                             0,
+-    /* 0x66 */ GRUB_KEYBOARD_KEY_BACKSPACE,   0,
+-    /* 0x68 */ 0,                             GRUB_KEYBOARD_KEY_NUM1,
+-    /* 0x6a */ GRUB_KEYBOARD_KEY_JP_YEN,      GRUB_KEYBOARD_KEY_NUM4,
+-    /* 0x6c */ GRUB_KEYBOARD_KEY_NUM7,        GRUB_KEYBOARD_KEY_KPCOMMA,
+-    /* 0x6e */ 0,                             0,
+-    /* 0x70 */ GRUB_KEYBOARD_KEY_NUM0,        GRUB_KEYBOARD_KEY_NUMDOT,
+-    /* 0x72 */ GRUB_KEYBOARD_KEY_NUM2,        GRUB_KEYBOARD_KEY_NUM5,
+-    /* 0x74 */ GRUB_KEYBOARD_KEY_NUM6,        GRUB_KEYBOARD_KEY_NUM8,
+-    /* 0x76 */ GRUB_KEYBOARD_KEY_ESCAPE,      GRUB_KEYBOARD_KEY_NUM_LOCK,
+-    /* 0x78 */ GRUB_KEYBOARD_KEY_F11,         GRUB_KEYBOARD_KEY_NUMPLUS,
+-    /* 0x7a */ GRUB_KEYBOARD_KEY_NUM3,        GRUB_KEYBOARD_KEY_NUMMINUS,
+-    /* 0x7c */ GRUB_KEYBOARD_KEY_NUMMUL,      GRUB_KEYBOARD_KEY_NUM9,
+-    /* 0x7e */ GRUB_KEYBOARD_KEY_SCROLL_LOCK, 0,
+-    /* 0x80 */ 0,                             0, 
+-    /* 0x82 */ 0,                             GRUB_KEYBOARD_KEY_F7,
+-  };
+-
+-static const struct
+-{
+-  grub_uint8_t from, to;
+-} set2_e0_mapping[] = 
+-  {
+-    {0x11, GRUB_KEYBOARD_KEY_RIGHT_ALT},
+-    {0x14, GRUB_KEYBOARD_KEY_RIGHT_CTRL},
+-    {0x4a, GRUB_KEYBOARD_KEY_NUMSLASH},
+-    {0x5a, GRUB_KEYBOARD_KEY_NUMENTER},
+-    {0x69, GRUB_KEYBOARD_KEY_END},
+-    {0x6b, GRUB_KEYBOARD_KEY_LEFT},
+-    {0x6c, GRUB_KEYBOARD_KEY_HOME},
+-    {0x70, GRUB_KEYBOARD_KEY_INSERT},
+-    {0x71, GRUB_KEYBOARD_KEY_DELETE},
+-    {0x72, GRUB_KEYBOARD_KEY_DOWN},
+-    {0x74, GRUB_KEYBOARD_KEY_RIGHT},
+-    {0x75, GRUB_KEYBOARD_KEY_UP},
+-    {0x7a, GRUB_KEYBOARD_KEY_NPAGE},
+-    {0x7d, GRUB_KEYBOARD_KEY_PPAGE},
+-  };
++struct grub_ps2_state ps2_state;
+ 
+ static int ping_sent;
+ 
++static void
++grub_keyboard_controller_init (void);
++
+ static void
+ keyboard_controller_wait_until_ready (void)
+ {
++  /* 50 us would be enough but our current time resolution is 1ms.  */
++  grub_millisleep (1);
+   while (! KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS)));
+ }
+ 
+@@ -241,10 +52,11 @@ wait_ack (void)
+   grub_uint8_t ack;
+ 
+   endtime = grub_get_time_ms () + 20;
+-  do
++  do {
++    keyboard_controller_wait_until_ready ();
+     ack = grub_inb (KEYBOARD_REG_DATA);
+-  while (ack != GRUB_AT_ACK && ack != GRUB_AT_NACK
+-	 && grub_get_time_ms () < endtime);
++  } while (ack != GRUB_AT_ACK && ack != GRUB_AT_NACK
++	   && grub_get_time_ms () < endtime);
+   return ack;
+ }
+ 
+@@ -326,12 +138,10 @@ query_mode (void)
+   if (!e)
+     return 0;
+ 
+-  keyboard_controller_wait_until_ready ();
+-
+-  do
++  do {
++    keyboard_controller_wait_until_ready ();
+     ret = grub_inb (KEYBOARD_REG_DATA);
+-  while (ret == GRUB_AT_ACK);
+-
++  } while (ret == GRUB_AT_ACK);
+   /* QEMU translates the set even in no-translate mode.  */
+   if (ret == 0x43 || ret == 1)
+     return 1;
+@@ -350,28 +160,32 @@ set_scancodes (void)
+   if (!grub_keyboard_orig_set)
+     {
+       grub_dprintf ("atkeyb", "No sets support assumed\n");
+-      current_set = 1;
++      ps2_state.current_set = 1;
+       return;
+     }
+ 
+ #if !USE_SCANCODE_SET
+-  current_set = 1;
++  ps2_state.current_set = 1;
+   return;
+ #else
+ 
+   grub_keyboard_controller_write (grub_keyboard_controller_orig
+-				  & ~KEYBOARD_AT_TRANSLATE);
++				  & ~KEYBOARD_AT_TRANSLATE
++				  & ~KEYBOARD_AT_DISABLE);
++
++  keyboard_controller_wait_until_ready ();
++  grub_outb (KEYBOARD_COMMAND_ENABLE, KEYBOARD_REG_DATA);
+ 
+   write_mode (2);
+-  current_set = query_mode ();
+-  grub_dprintf ("atkeyb", "returned set %d\n", current_set);
+-  if (current_set == 2)
++  ps2_state.current_set = query_mode ();
++  grub_dprintf ("atkeyb", "returned set %d\n", ps2_state.current_set);
++  if (ps2_state.current_set == 2)
+     return;
+ 
+   write_mode (1);
+-  current_set = query_mode ();
+-  grub_dprintf ("atkeyb", "returned set %d\n", current_set);
+-  if (current_set == 1)
++  ps2_state.current_set = query_mode ();
++  grub_dprintf ("atkeyb", "returned set %d\n", ps2_state.current_set);
++  if (ps2_state.current_set == 1)
+     return;
+   grub_dprintf ("atkeyb", "no supported scancode set found\n");
+ #endif
+@@ -386,164 +200,10 @@ keyboard_controller_led (grub_uint8_t leds)
+   grub_outb (leds & 0x7, KEYBOARD_REG_DATA);
+ }
+ 
+-static int
+-fetch_key (int *is_break)
+-{
+-  int was_ext = 0;
+-  grub_uint8_t at_key;
+-  int ret = 0;
+-
+-  if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS)))
+-    return -1;
+-  at_key = grub_inb (KEYBOARD_REG_DATA);
+-  /* May happen if no keyboard is connected. Just ignore this.  */
+-  if (at_key == 0xff)
+-    return -1;
+-  if (at_key == 0xe0)
+-    {
+-      e0_received = 1;
+-      return -1;
+-    }
+-
+-  if ((current_set == 2 || current_set == 3) && at_key == 0xf0)
+-    {
+-      f0_received = 1;
+-      return -1;
+-    }
+-
+-  /* Setting LEDs may generate ACKs.  */
+-  if (at_key == GRUB_AT_ACK)
+-    return -1;
+-
+-  was_ext = e0_received;
+-  e0_received = 0;
+-
+-  switch (current_set)
+-    {
+-    case 1:
+-      *is_break = !!(at_key & 0x80);
+-      if (!was_ext)
+-	ret = set1_mapping[at_key & 0x7f];
+-      else
+-	{
+-	  unsigned i;
+-	  for (i = 0; i < ARRAY_SIZE (set1_e0_mapping); i++)
+-	    if (set1_e0_mapping[i].from == (at_key & 0x7f))
+-	      {
+-		ret = set1_e0_mapping[i].to;
+-		break;
+-	      }
+-	}
+-      break;
+-    case 2:
+-      *is_break = f0_received;
+-      f0_received = 0;
+-      if (!was_ext)
+-	ret = set2_mapping[at_key];
+-      else
+-	{
+-	  unsigned i;
+-	  for (i = 0; i < ARRAY_SIZE (set2_e0_mapping); i++)
+-	    if (set2_e0_mapping[i].from == at_key)
+-	      {
+-		ret = set2_e0_mapping[i].to;
+-		break;
+-	      }
+-	}	
+-      break;
+-    default:
+-      return -1;
+-    }
+-  if (!ret)
+-    {
+-      if (was_ext)
+-	grub_dprintf ("atkeyb", "Unknown key 0xe0+0x%02x from set %d\n",
+-		      at_key, current_set);
+-      else
+-	grub_dprintf ("atkeyb", "Unknown key 0x%02x from set %d\n",
+-		      at_key, current_set);
+-      return -1;
+-    }
+-  return ret;
+-}
+-
+-/* FIXME: This should become an interrupt service routine.  For now
+-   it's just used to catch events from control keys.  */
+-static int
+-grub_keyboard_isr (grub_keyboard_key_t key, int is_break)
+-{
+-  if (!is_break)
+-    switch (key)
+-      {
+-      case GRUB_KEYBOARD_KEY_LEFT_SHIFT:
+-	at_keyboard_status |= GRUB_TERM_STATUS_LSHIFT;
+-	return 1;
+-      case GRUB_KEYBOARD_KEY_RIGHT_SHIFT:
+-	at_keyboard_status |= GRUB_TERM_STATUS_RSHIFT;
+-	return 1;
+-      case GRUB_KEYBOARD_KEY_LEFT_CTRL:
+-	at_keyboard_status |= GRUB_TERM_STATUS_LCTRL;
+-	return 1;
+-      case GRUB_KEYBOARD_KEY_RIGHT_CTRL:
+-	at_keyboard_status |= GRUB_TERM_STATUS_RCTRL;
+-	return 1;
+-      case GRUB_KEYBOARD_KEY_RIGHT_ALT:
+-	at_keyboard_status |= GRUB_TERM_STATUS_RALT;
+-	return 1;
+-      case GRUB_KEYBOARD_KEY_LEFT_ALT:
+-	at_keyboard_status |= GRUB_TERM_STATUS_LALT;
+-	return 1;
+-      default:
+-	return 0;
+-      }
+-  else
+-    switch (key)
+-      {
+-      case GRUB_KEYBOARD_KEY_LEFT_SHIFT:
+-	at_keyboard_status &= ~GRUB_TERM_STATUS_LSHIFT;
+-	return 1;
+-      case GRUB_KEYBOARD_KEY_RIGHT_SHIFT:
+-	at_keyboard_status &= ~GRUB_TERM_STATUS_RSHIFT;
+-	return 1;
+-      case GRUB_KEYBOARD_KEY_LEFT_CTRL:
+-	at_keyboard_status &= ~GRUB_TERM_STATUS_LCTRL;
+-	return 1;
+-      case GRUB_KEYBOARD_KEY_RIGHT_CTRL:
+-	at_keyboard_status &= ~GRUB_TERM_STATUS_RCTRL;
+-	return 1;
+-      case GRUB_KEYBOARD_KEY_RIGHT_ALT:
+-	at_keyboard_status &= ~GRUB_TERM_STATUS_RALT;
+-	return 1;
+-      case GRUB_KEYBOARD_KEY_LEFT_ALT:
+-	at_keyboard_status &= ~GRUB_TERM_STATUS_LALT;
+-	return 1;
+-      default:
+-	return 0;
+-      }
+-}
+-
+-/* If there is a raw key pending, return it; otherwise return -1.  */
+-static int
+-grub_keyboard_getkey (void)
+-{
+-  int key;
+-  int is_break = 0;
+-
+-  key = fetch_key (&is_break);
+-  if (key == -1)
+-    return -1;
+-
+-  if (grub_keyboard_isr (key, is_break))
+-    return -1;
+-  if (is_break)
+-    return -1;
+-  return key;
+-}
+-
+ int
+ grub_at_keyboard_is_alive (void)
+ {
+-  if (current_set != 0)
++  if (ps2_state.current_set != 0)
+     return 1;
+   if (ping_sent
+       && KEYBOARD_COMMAND_ISREADY (grub_inb (KEYBOARD_REG_STATUS))
+@@ -566,51 +226,28 @@ grub_at_keyboard_is_alive (void)
+ static int
+ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
+ {
+-  int code;
++  grub_uint8_t at_key;
++  int ret;
++  grub_uint8_t old_led;
+ 
+   if (!grub_at_keyboard_is_alive ())
+     return GRUB_TERM_NO_KEY;
+ 
+-  code = grub_keyboard_getkey ();
+-  if (code == -1)
+-    return GRUB_TERM_NO_KEY;
+-#ifdef DEBUG_AT_KEYBOARD
+-  grub_dprintf ("atkeyb", "Detected key 0x%x\n", code);
+-#endif
+-  switch (code)
+-    {
+-      case GRUB_KEYBOARD_KEY_CAPS_LOCK:
+-	at_keyboard_status ^= GRUB_TERM_STATUS_CAPS;
+-	led_status ^= KEYBOARD_LED_CAPS;
+-	keyboard_controller_led (led_status);
++  if (! KEYBOARD_ISREADY (grub_inb (KEYBOARD_REG_STATUS)))
++    return -1;
++  at_key = grub_inb (KEYBOARD_REG_DATA);
++  old_led = ps2_state.led_status;
+ 
+-#ifdef DEBUG_AT_KEYBOARD
+-	grub_dprintf ("atkeyb", "caps_lock = %d\n", !!(at_keyboard_status & GRUB_KEYBOARD_STATUS_CAPS_LOCK));
+-#endif
+-	return GRUB_TERM_NO_KEY;
+-      case GRUB_KEYBOARD_KEY_NUM_LOCK:
+-	at_keyboard_status ^= GRUB_TERM_STATUS_NUM;
+-	led_status ^= KEYBOARD_LED_NUM;
+-	keyboard_controller_led (led_status);
+-
+-#ifdef DEBUG_AT_KEYBOARD
+-	grub_dprintf ("atkeyb", "num_lock = %d\n", !!(at_keyboard_status & GRUB_KEYBOARD_STATUS_NUM_LOCK));
+-#endif
+-	return GRUB_TERM_NO_KEY;
+-      case GRUB_KEYBOARD_KEY_SCROLL_LOCK:
+-	at_keyboard_status ^= GRUB_TERM_STATUS_SCROLL;
+-	led_status ^= KEYBOARD_LED_SCROLL;
+-	keyboard_controller_led (led_status);
+-	return GRUB_TERM_NO_KEY;
+-      default:
+-	return grub_term_map_key (code, at_keyboard_status);
+-    }
++  ret = grub_ps2_process_incoming_byte (&ps2_state, at_key);
++  if (old_led != ps2_state.led_status)
++    keyboard_controller_led (ps2_state.led_status);
++  return ret;
+ }
+ 
+ static void
+ grub_keyboard_controller_init (void)
+ {
+-  at_keyboard_status = 0;
++  ps2_state.at_keyboard_status = 0;
+   /* Drain input buffer. */
+   while (1)
+     {
+@@ -632,13 +269,13 @@ grub_keyboard_controller_init (void)
+   grub_keyboard_orig_set = query_mode ();
+ #endif
+   set_scancodes ();
+-  keyboard_controller_led (led_status);
++  keyboard_controller_led (ps2_state.led_status);
+ }
+ 
+ static grub_err_t
+ grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused)))
+ {
+-  if (current_set == 0)
++  if (ps2_state.current_set == 0)
+     return GRUB_ERR_NONE;
+   if (grub_keyboard_orig_set)
+     write_mode (grub_keyboard_orig_set);
+@@ -655,7 +292,7 @@ grub_at_fini_hw (int noreturn __attribute__ ((unused)))
+ static grub_err_t
+ grub_at_restore_hw (void)
+ {
+-  if (current_set == 0)
++  if (ps2_state.current_set == 0)
+     return GRUB_ERR_NONE;
+ 
+   /* Drain input buffer. */
+@@ -668,7 +305,7 @@ grub_at_restore_hw (void)
+       grub_inb (KEYBOARD_REG_DATA);
+     }
+   set_scancodes ();
+-  keyboard_controller_led (led_status);
++  keyboard_controller_led (ps2_state.led_status);
+ 
+   return GRUB_ERR_NONE;
+ }
+diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
+index 7d31095b1ef8d01886a0516343f2e5c5601265dd..4840cc59d3f68944fb2ca6b40cc6488e74b5da02 100644
+--- a/grub-core/term/efi/console.c
++++ b/grub-core/term/efi/console.c
+@@ -104,7 +104,7 @@ const unsigned efi_codes[] =
+     GRUB_TERM_KEY_DC, GRUB_TERM_KEY_PPAGE, GRUB_TERM_KEY_NPAGE, GRUB_TERM_KEY_F1,
+     GRUB_TERM_KEY_F2, GRUB_TERM_KEY_F3, GRUB_TERM_KEY_F4, GRUB_TERM_KEY_F5,
+     GRUB_TERM_KEY_F6, GRUB_TERM_KEY_F7, GRUB_TERM_KEY_F8, GRUB_TERM_KEY_F9,
+-    GRUB_TERM_KEY_F10, GRUB_TERM_KEY_F11, GRUB_TERM_KEY_F12, '\e'
++    GRUB_TERM_KEY_F10, GRUB_TERM_KEY_F11, GRUB_TERM_KEY_F12, GRUB_TERM_ESC
+   };
+ 
+ static int
+@@ -122,6 +122,9 @@ grub_efi_translate_key (grub_efi_input_key_t key)
+       else
+ 	return key.unicode_char;
+     }
++  /* Some devices send enter with scan_code 0x0d (F3) and unicode_char 0x0d. */
++  else if (key.scan_code == '\r' && key.unicode_char == '\r')
++    return key.unicode_char;
+   else if (key.scan_code < ARRAY_SIZE (efi_codes))
+     return efi_codes[key.scan_code];
+ 
+diff --git a/grub-core/term/i386/coreboot/cbmemc.c b/grub-core/term/i386/coreboot/cbmemc.c
+index 25e64a05c03286f644b39398e9e68cbdde333510..cea9b84315bdaf3b1238acc915f35ba6148ffbcf 100644
+--- a/grub-core/term/i386/coreboot/cbmemc.c
++++ b/grub-core/term/i386/coreboot/cbmemc.c
+@@ -23,17 +23,20 @@
+ #include <grub/time.h>
+ #include <grub/terminfo.h>
+ #include <grub/dl.h>
+-#include <grub/i386/coreboot/lbio.h>
++#include <grub/coreboot/lbio.h>
+ #include <grub/command.h>
+ #include <grub/normal.h>
+ 
+ GRUB_MOD_LICENSE ("GPLv3+");
+ 
++#define CURSOR_MASK ((1 << 28) - 1)
++#define OVERFLOW (1 << 31)
++
+ struct grub_linuxbios_cbmemc
+ {
+   grub_uint32_t size;
+-  grub_uint32_t pointer;
+-  char data[0];
++  grub_uint32_t cursor;
++  char body[0];
+ };
+ 
+ static struct grub_linuxbios_cbmemc *cbmemc;
+@@ -41,11 +44,20 @@ static struct grub_linuxbios_cbmemc *cbmemc;
+ static void
+ put (struct grub_term_output *term __attribute__ ((unused)), const int c)
+ {
++  grub_uint32_t flags, cursor;
+   if (!cbmemc)
+     return;
+-  if (cbmemc->pointer < cbmemc->size)
+-    cbmemc->data[cbmemc->pointer] = c;
+-  cbmemc->pointer++;
++  flags = cbmemc->cursor & ~CURSOR_MASK;
++  cursor = cbmemc->cursor & CURSOR_MASK;
++  if (cursor >= cbmemc->size)
++    return;
++  cbmemc->body[cursor++] = c;
++  if (cursor >= cbmemc->size)
++    {
++      cursor = 0;
++      flags |= OVERFLOW;
++    }
++  cbmemc->cursor = flags | cursor;
+ }
+ 
+ struct grub_terminfo_output_state grub_cbmemc_terminfo_output =
+@@ -87,21 +99,29 @@ grub_cmd_cbmemc (struct grub_command *cmd __attribute__ ((unused)),
+ 		 int argc __attribute__ ((unused)),
+ 		 char *argv[] __attribute__ ((unused)))
+ {
+-  grub_size_t len;
+-  char *str;
+-  struct grub_linuxbios_cbmemc *cbmemc_saved;
++  grub_size_t size, cursor;
++  struct grub_linuxbios_cbmemc *real_cbmemc;
+ 
+   if (!cbmemc)
+     return grub_error (GRUB_ERR_IO, "no CBMEM console found");
+ 
+-  len = cbmemc->pointer;
+-  if (len > cbmemc->size)
+-    len = cbmemc->size;
+-  str = cbmemc->data;
+-  cbmemc_saved = cbmemc;
++  real_cbmemc = cbmemc;
+   cbmemc = 0;
+-  grub_xnputs (str, len);
+-  cbmemc = cbmemc_saved;
++  cursor = real_cbmemc->cursor & CURSOR_MASK;
++  if (!(real_cbmemc->cursor & OVERFLOW) && cursor < real_cbmemc->size)
++    size = cursor;
++  else
++    size = real_cbmemc->size;
++  if (real_cbmemc->cursor & OVERFLOW)
++    {
++      if (cursor > size)
++        cursor = 0;
++      grub_xnputs(real_cbmemc->body + cursor, size - cursor);
++      grub_xnputs(real_cbmemc->body, cursor);
++    }
++  else
++    grub_xnputs(real_cbmemc->body, size);
++  cbmemc = real_cbmemc;
+   return 0;
+ }
+ 
+diff --git a/grub-core/term/i386/pc/console.c b/grub-core/term/i386/pc/console.c
+index 28de46b576a667fd40c5852b16a4bcc3ea681849..f6142a2dea8036f5301c81a9e2fbd5ddbff5fd90 100644
+--- a/grub-core/term/i386/pc/console.c
++++ b/grub-core/term/i386/pc/console.c
+@@ -204,7 +204,7 @@ static int
+ grub_console_getkey (struct grub_term_input *term __attribute__ ((unused)))
+ {
+   const grub_uint16_t bypass_table[] = {
+-    0x0100 | '\e', 0x0f00 | '\t', 0x0e00 | '\b', 0x1c00 | '\r', 0x1c00 | '\n'
++    0x0100 | GRUB_TERM_ESC, 0x0f00 | GRUB_TERM_TAB, 0x0e00 | GRUB_TERM_BACKSPACE, 0x1c00 | '\r', 0x1c00 | '\n'
+   };
+   struct grub_bios_int_registers regs;
+   unsigned i;
+diff --git a/grub-core/term/ps2.c b/grub-core/term/ps2.c
+new file mode 100644
+index 0000000000000000000000000000000000000000..7ae4e9f2f8cd4a0ba4405c21581f906f7b458379
+--- /dev/null
++++ b/grub-core/term/ps2.c
+@@ -0,0 +1,387 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2007,2008,2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/dl.h>
++#include <grub/misc.h>
++#include <grub/term.h>
++#include <grub/keyboard_layouts.h>
++#include <grub/ps2.h>
++
++#define KEYBOARD_LED_SCROLL		(1 << 0)
++#define KEYBOARD_LED_NUM		(1 << 1)
++#define KEYBOARD_LED_CAPS		(1 << 2)
++
++static const grub_uint8_t set1_mapping[128] =
++  {
++    /* 0x00 */ 0 /* Unused  */,               GRUB_KEYBOARD_KEY_ESCAPE, 
++    /* 0x02 */ GRUB_KEYBOARD_KEY_1,           GRUB_KEYBOARD_KEY_2, 
++    /* 0x04 */ GRUB_KEYBOARD_KEY_3,           GRUB_KEYBOARD_KEY_4, 
++    /* 0x06 */ GRUB_KEYBOARD_KEY_5,           GRUB_KEYBOARD_KEY_6, 
++    /* 0x08 */ GRUB_KEYBOARD_KEY_7,           GRUB_KEYBOARD_KEY_8, 
++    /* 0x0a */ GRUB_KEYBOARD_KEY_9,           GRUB_KEYBOARD_KEY_0, 
++    /* 0x0c */ GRUB_KEYBOARD_KEY_DASH,        GRUB_KEYBOARD_KEY_EQUAL, 
++    /* 0x0e */ GRUB_KEYBOARD_KEY_BACKSPACE,   GRUB_KEYBOARD_KEY_TAB, 
++    /* 0x10 */ GRUB_KEYBOARD_KEY_Q,           GRUB_KEYBOARD_KEY_W, 
++    /* 0x12 */ GRUB_KEYBOARD_KEY_E,           GRUB_KEYBOARD_KEY_R, 
++    /* 0x14 */ GRUB_KEYBOARD_KEY_T,           GRUB_KEYBOARD_KEY_Y, 
++    /* 0x16 */ GRUB_KEYBOARD_KEY_U,           GRUB_KEYBOARD_KEY_I, 
++    /* 0x18 */ GRUB_KEYBOARD_KEY_O,           GRUB_KEYBOARD_KEY_P, 
++    /* 0x1a */ GRUB_KEYBOARD_KEY_LBRACKET,    GRUB_KEYBOARD_KEY_RBRACKET, 
++    /* 0x1c */ GRUB_KEYBOARD_KEY_ENTER,       GRUB_KEYBOARD_KEY_LEFT_CTRL, 
++    /* 0x1e */ GRUB_KEYBOARD_KEY_A,           GRUB_KEYBOARD_KEY_S, 
++    /* 0x20 */ GRUB_KEYBOARD_KEY_D,           GRUB_KEYBOARD_KEY_F, 
++    /* 0x22 */ GRUB_KEYBOARD_KEY_G,           GRUB_KEYBOARD_KEY_H, 
++    /* 0x24 */ GRUB_KEYBOARD_KEY_J,           GRUB_KEYBOARD_KEY_K, 
++    /* 0x26 */ GRUB_KEYBOARD_KEY_L,           GRUB_KEYBOARD_KEY_SEMICOLON, 
++    /* 0x28 */ GRUB_KEYBOARD_KEY_DQUOTE,      GRUB_KEYBOARD_KEY_RQUOTE, 
++    /* 0x2a */ GRUB_KEYBOARD_KEY_LEFT_SHIFT,  GRUB_KEYBOARD_KEY_BACKSLASH, 
++    /* 0x2c */ GRUB_KEYBOARD_KEY_Z,           GRUB_KEYBOARD_KEY_X, 
++    /* 0x2e */ GRUB_KEYBOARD_KEY_C,           GRUB_KEYBOARD_KEY_V, 
++    /* 0x30 */ GRUB_KEYBOARD_KEY_B,           GRUB_KEYBOARD_KEY_N, 
++    /* 0x32 */ GRUB_KEYBOARD_KEY_M,           GRUB_KEYBOARD_KEY_COMMA, 
++    /* 0x34 */ GRUB_KEYBOARD_KEY_DOT,         GRUB_KEYBOARD_KEY_SLASH, 
++    /* 0x36 */ GRUB_KEYBOARD_KEY_RIGHT_SHIFT, GRUB_KEYBOARD_KEY_NUMMUL, 
++    /* 0x38 */ GRUB_KEYBOARD_KEY_LEFT_ALT,    GRUB_KEYBOARD_KEY_SPACE, 
++    /* 0x3a */ GRUB_KEYBOARD_KEY_CAPS_LOCK,   GRUB_KEYBOARD_KEY_F1, 
++    /* 0x3c */ GRUB_KEYBOARD_KEY_F2,          GRUB_KEYBOARD_KEY_F3, 
++    /* 0x3e */ GRUB_KEYBOARD_KEY_F4,          GRUB_KEYBOARD_KEY_F5, 
++    /* 0x40 */ GRUB_KEYBOARD_KEY_F6,          GRUB_KEYBOARD_KEY_F7, 
++    /* 0x42 */ GRUB_KEYBOARD_KEY_F8,          GRUB_KEYBOARD_KEY_F9, 
++    /* 0x44 */ GRUB_KEYBOARD_KEY_F10,         GRUB_KEYBOARD_KEY_NUM_LOCK, 
++    /* 0x46 */ GRUB_KEYBOARD_KEY_SCROLL_LOCK, GRUB_KEYBOARD_KEY_NUM7, 
++    /* 0x48 */ GRUB_KEYBOARD_KEY_NUM8,        GRUB_KEYBOARD_KEY_NUM9, 
++    /* 0x4a */ GRUB_KEYBOARD_KEY_NUMMINUS,    GRUB_KEYBOARD_KEY_NUM4, 
++    /* 0x4c */ GRUB_KEYBOARD_KEY_NUM5,        GRUB_KEYBOARD_KEY_NUM6, 
++    /* 0x4e */ GRUB_KEYBOARD_KEY_NUMPLUS,     GRUB_KEYBOARD_KEY_NUM1, 
++    /* 0x50 */ GRUB_KEYBOARD_KEY_NUM2,        GRUB_KEYBOARD_KEY_NUM3, 
++    /* 0x52 */ GRUB_KEYBOARD_KEY_NUM0,        GRUB_KEYBOARD_KEY_NUMDOT, 
++    /* 0x54 */ 0,                             0, 
++    /* 0x56 */ GRUB_KEYBOARD_KEY_102ND,       GRUB_KEYBOARD_KEY_F11, 
++    /* 0x58 */ GRUB_KEYBOARD_KEY_F12,         0,
++    /* 0x5a */ 0,                             0,
++    /* 0x5c */ 0,                             0,
++    /* 0x5e */ 0,                             0,
++    /* 0x60 */ 0,                             0,
++    /* 0x62 */ 0,                             0,
++    /* OLPC keys. Just mapped to normal keys.  */
++    /* 0x64 */ 0,                             GRUB_KEYBOARD_KEY_UP,
++    /* 0x66 */ GRUB_KEYBOARD_KEY_DOWN,        GRUB_KEYBOARD_KEY_LEFT,
++    /* 0x68 */ GRUB_KEYBOARD_KEY_RIGHT,       0,
++    /* 0x6a */ 0,                             0,
++    /* 0x6c */ 0,                             0,
++    /* 0x6e */ 0,                             0,
++    /* 0x70 */ 0,                             0,
++    /* 0x72 */ 0,                             GRUB_KEYBOARD_KEY_JP_RO,
++    /* 0x74 */ 0,                             0,
++    /* 0x76 */ 0,                             0,
++    /* 0x78 */ 0,                             0,
++    /* 0x7a */ 0,                             0,
++    /* 0x7c */ 0,                             GRUB_KEYBOARD_KEY_JP_YEN,
++    /* 0x7e */ GRUB_KEYBOARD_KEY_KPCOMMA
++  };
++
++static const struct
++{
++  grub_uint8_t from, to;
++} set1_e0_mapping[] = 
++  {
++    {0x1c, GRUB_KEYBOARD_KEY_NUMENTER},
++    {0x1d, GRUB_KEYBOARD_KEY_RIGHT_CTRL},
++    {0x35, GRUB_KEYBOARD_KEY_NUMSLASH }, 
++    {0x38, GRUB_KEYBOARD_KEY_RIGHT_ALT},
++    {0x47, GRUB_KEYBOARD_KEY_HOME}, 
++    {0x48, GRUB_KEYBOARD_KEY_UP},
++    {0x49, GRUB_KEYBOARD_KEY_PPAGE}, 
++    {0x4b, GRUB_KEYBOARD_KEY_LEFT},
++    {0x4d, GRUB_KEYBOARD_KEY_RIGHT},
++    {0x4f, GRUB_KEYBOARD_KEY_END}, 
++    {0x50, GRUB_KEYBOARD_KEY_DOWN},
++    {0x51, GRUB_KEYBOARD_KEY_NPAGE},
++    {0x52, GRUB_KEYBOARD_KEY_INSERT},
++    {0x53, GRUB_KEYBOARD_KEY_DELETE}, 
++  };
++
++static const grub_uint8_t set2_mapping[256] =
++  {
++    /* 0x00 */ 0,                             GRUB_KEYBOARD_KEY_F9,
++    /* 0x02 */ 0,                             GRUB_KEYBOARD_KEY_F5,
++    /* 0x04 */ GRUB_KEYBOARD_KEY_F3,          GRUB_KEYBOARD_KEY_F1,
++    /* 0x06 */ GRUB_KEYBOARD_KEY_F2,          GRUB_KEYBOARD_KEY_F12,
++    /* 0x08 */ 0,                             GRUB_KEYBOARD_KEY_F10,
++    /* 0x0a */ GRUB_KEYBOARD_KEY_F8,          GRUB_KEYBOARD_KEY_F6,
++    /* 0x0c */ GRUB_KEYBOARD_KEY_F4,          GRUB_KEYBOARD_KEY_TAB,
++    /* 0x0e */ GRUB_KEYBOARD_KEY_RQUOTE,      0,
++    /* 0x10 */ 0,                             GRUB_KEYBOARD_KEY_LEFT_ALT,
++    /* 0x12 */ GRUB_KEYBOARD_KEY_LEFT_SHIFT,  0,
++    /* 0x14 */ GRUB_KEYBOARD_KEY_LEFT_CTRL,   GRUB_KEYBOARD_KEY_Q,
++    /* 0x16 */ GRUB_KEYBOARD_KEY_1,           0,
++    /* 0x18 */ 0,                             0,
++    /* 0x1a */ GRUB_KEYBOARD_KEY_Z,           GRUB_KEYBOARD_KEY_S,
++    /* 0x1c */ GRUB_KEYBOARD_KEY_A,           GRUB_KEYBOARD_KEY_W,
++    /* 0x1e */ GRUB_KEYBOARD_KEY_2,           0,
++    /* 0x20 */ 0,                             GRUB_KEYBOARD_KEY_C,
++    /* 0x22 */ GRUB_KEYBOARD_KEY_X,           GRUB_KEYBOARD_KEY_D,
++    /* 0x24 */ GRUB_KEYBOARD_KEY_E,           GRUB_KEYBOARD_KEY_4,
++    /* 0x26 */ GRUB_KEYBOARD_KEY_3,           0,
++    /* 0x28 */ 0,                             GRUB_KEYBOARD_KEY_SPACE,
++    /* 0x2a */ GRUB_KEYBOARD_KEY_V,           GRUB_KEYBOARD_KEY_F,
++    /* 0x2c */ GRUB_KEYBOARD_KEY_T,           GRUB_KEYBOARD_KEY_R,
++    /* 0x2e */ GRUB_KEYBOARD_KEY_5,           0,
++    /* 0x30 */ 0,                             GRUB_KEYBOARD_KEY_N,
++    /* 0x32 */ GRUB_KEYBOARD_KEY_B,           GRUB_KEYBOARD_KEY_H,
++    /* 0x34 */ GRUB_KEYBOARD_KEY_G,           GRUB_KEYBOARD_KEY_Y,
++    /* 0x36 */ GRUB_KEYBOARD_KEY_6,           0,
++    /* 0x38 */ 0,                             0,
++    /* 0x3a */ GRUB_KEYBOARD_KEY_M,           GRUB_KEYBOARD_KEY_J,
++    /* 0x3c */ GRUB_KEYBOARD_KEY_U,           GRUB_KEYBOARD_KEY_7,
++    /* 0x3e */ GRUB_KEYBOARD_KEY_8,           0,
++    /* 0x40 */ 0,                             GRUB_KEYBOARD_KEY_COMMA,
++    /* 0x42 */ GRUB_KEYBOARD_KEY_K,           GRUB_KEYBOARD_KEY_I,
++    /* 0x44 */ GRUB_KEYBOARD_KEY_O,           GRUB_KEYBOARD_KEY_0,
++    /* 0x46 */ GRUB_KEYBOARD_KEY_9,           0,
++    /* 0x48 */ 0,                             GRUB_KEYBOARD_KEY_DOT,
++    /* 0x4a */ GRUB_KEYBOARD_KEY_SLASH,       GRUB_KEYBOARD_KEY_L,
++    /* 0x4c */ GRUB_KEYBOARD_KEY_SEMICOLON,   GRUB_KEYBOARD_KEY_P,
++    /* 0x4e */ GRUB_KEYBOARD_KEY_DASH,        0,
++    /* 0x50 */ 0,                             GRUB_KEYBOARD_KEY_JP_RO,
++    /* 0x52 */ GRUB_KEYBOARD_KEY_DQUOTE,      0,
++    /* 0x54 */ GRUB_KEYBOARD_KEY_LBRACKET,    GRUB_KEYBOARD_KEY_EQUAL,
++    /* 0x56 */ 0,                             0,
++    /* 0x58 */ GRUB_KEYBOARD_KEY_CAPS_LOCK,   GRUB_KEYBOARD_KEY_RIGHT_SHIFT,
++    /* 0x5a */ GRUB_KEYBOARD_KEY_ENTER,       GRUB_KEYBOARD_KEY_RBRACKET,
++    /* 0x5c */ 0,                             GRUB_KEYBOARD_KEY_BACKSLASH,
++    /* 0x5e */ 0,                             0,
++    /* 0x60 */ 0,                             GRUB_KEYBOARD_KEY_102ND,
++    /* 0x62 */ 0,                             0,
++    /* 0x64 */ 0,                             0,
++    /* 0x66 */ GRUB_KEYBOARD_KEY_BACKSPACE,   0,
++    /* 0x68 */ 0,                             GRUB_KEYBOARD_KEY_NUM1,
++    /* 0x6a */ GRUB_KEYBOARD_KEY_JP_YEN,      GRUB_KEYBOARD_KEY_NUM4,
++    /* 0x6c */ GRUB_KEYBOARD_KEY_NUM7,        GRUB_KEYBOARD_KEY_KPCOMMA,
++    /* 0x6e */ 0,                             0,
++    /* 0x70 */ GRUB_KEYBOARD_KEY_NUM0,        GRUB_KEYBOARD_KEY_NUMDOT,
++    /* 0x72 */ GRUB_KEYBOARD_KEY_NUM2,        GRUB_KEYBOARD_KEY_NUM5,
++    /* 0x74 */ GRUB_KEYBOARD_KEY_NUM6,        GRUB_KEYBOARD_KEY_NUM8,
++    /* 0x76 */ GRUB_KEYBOARD_KEY_ESCAPE,      GRUB_KEYBOARD_KEY_NUM_LOCK,
++    /* 0x78 */ GRUB_KEYBOARD_KEY_F11,         GRUB_KEYBOARD_KEY_NUMPLUS,
++    /* 0x7a */ GRUB_KEYBOARD_KEY_NUM3,        GRUB_KEYBOARD_KEY_NUMMINUS,
++    /* 0x7c */ GRUB_KEYBOARD_KEY_NUMMUL,      GRUB_KEYBOARD_KEY_NUM9,
++    /* 0x7e */ GRUB_KEYBOARD_KEY_SCROLL_LOCK, 0,
++    /* 0x80 */ 0,                             0, 
++    /* 0x82 */ 0,                             GRUB_KEYBOARD_KEY_F7,
++  };
++
++static const struct
++{
++  grub_uint8_t from, to;
++} set2_e0_mapping[] = 
++  {
++    {0x11, GRUB_KEYBOARD_KEY_RIGHT_ALT},
++    {0x14, GRUB_KEYBOARD_KEY_RIGHT_CTRL},
++    {0x4a, GRUB_KEYBOARD_KEY_NUMSLASH},
++    {0x5a, GRUB_KEYBOARD_KEY_NUMENTER},
++    {0x69, GRUB_KEYBOARD_KEY_END},
++    {0x6b, GRUB_KEYBOARD_KEY_LEFT},
++    {0x6c, GRUB_KEYBOARD_KEY_HOME},
++    {0x70, GRUB_KEYBOARD_KEY_INSERT},
++    {0x71, GRUB_KEYBOARD_KEY_DELETE},
++    {0x72, GRUB_KEYBOARD_KEY_DOWN},
++    {0x74, GRUB_KEYBOARD_KEY_RIGHT},
++    {0x75, GRUB_KEYBOARD_KEY_UP},
++    {0x7a, GRUB_KEYBOARD_KEY_NPAGE},
++    {0x7d, GRUB_KEYBOARD_KEY_PPAGE},
++  };
++
++static int
++fetch_key (struct grub_ps2_state *ps2_state, grub_uint8_t at_key, int *is_break)
++{
++  int was_ext = 0;
++  int ret = 0;
++
++  /* May happen if no keyboard is connected. Just ignore this.  */
++  if (at_key == 0xff)
++    return -1;
++  if (at_key == 0xe0)
++    {
++      ps2_state->e0_received = 1;
++      return -1;
++    }
++
++  if ((ps2_state->current_set == 2 || ps2_state->current_set == 3) && at_key == 0xf0)
++    {
++      ps2_state->f0_received = 1;
++      return -1;
++    }
++
++  /* Setting LEDs may generate ACKs.  */
++  if (at_key == GRUB_AT_ACK)
++    return -1;
++
++  was_ext = ps2_state->e0_received;
++  ps2_state->e0_received = 0;
++
++  switch (ps2_state->current_set)
++    {
++    case 1:
++      *is_break = !!(at_key & 0x80);
++      if (!was_ext)
++	ret = set1_mapping[at_key & 0x7f];
++      else
++	{
++	  unsigned i;
++	  for (i = 0; i < ARRAY_SIZE (set1_e0_mapping); i++)
++	    if (set1_e0_mapping[i].from == (at_key & 0x7f))
++	      {
++		ret = set1_e0_mapping[i].to;
++		break;
++	      }
++	}
++      break;
++    case 2:
++      *is_break = ps2_state->f0_received;
++      ps2_state->f0_received = 0;
++      if (!was_ext)
++	ret = set2_mapping[at_key];
++      else
++	{
++	  unsigned i;
++	  for (i = 0; i < ARRAY_SIZE (set2_e0_mapping); i++)
++	    if (set2_e0_mapping[i].from == at_key)
++	      {
++		ret = set2_e0_mapping[i].to;
++		break;
++	      }
++	}	
++      break;
++    default:
++      return -1;
++    }
++  if (!ret)
++    {
++      if (was_ext)
++	grub_dprintf ("atkeyb", "Unknown key 0xe0+0x%02x from set %d\n",
++		      at_key, ps2_state->current_set);
++      else
++	grub_dprintf ("atkeyb", "Unknown key 0x%02x from set %d\n",
++		      at_key, ps2_state->current_set);
++      return -1;
++    }
++  return ret;
++}
++
++/* FIXME: This should become an interrupt service routine.  For now
++   it's just used to catch events from control keys.  */
++static int
++grub_keyboard_isr (struct grub_ps2_state *ps2_state,
++		   grub_keyboard_key_t key, int is_break)
++{
++  if (!is_break)
++    switch (key)
++      {
++      case GRUB_KEYBOARD_KEY_LEFT_SHIFT:
++	ps2_state->at_keyboard_status |= GRUB_TERM_STATUS_LSHIFT;
++	return 1;
++      case GRUB_KEYBOARD_KEY_RIGHT_SHIFT:
++	ps2_state->at_keyboard_status |= GRUB_TERM_STATUS_RSHIFT;
++	return 1;
++      case GRUB_KEYBOARD_KEY_LEFT_CTRL:
++	ps2_state->at_keyboard_status |= GRUB_TERM_STATUS_LCTRL;
++	return 1;
++      case GRUB_KEYBOARD_KEY_RIGHT_CTRL:
++	ps2_state->at_keyboard_status |= GRUB_TERM_STATUS_RCTRL;
++	return 1;
++      case GRUB_KEYBOARD_KEY_RIGHT_ALT:
++	ps2_state->at_keyboard_status |= GRUB_TERM_STATUS_RALT;
++	return 1;
++      case GRUB_KEYBOARD_KEY_LEFT_ALT:
++	ps2_state->at_keyboard_status |= GRUB_TERM_STATUS_LALT;
++	return 1;
++      default:
++	return 0;
++      }
++  else
++    switch (key)
++      {
++      case GRUB_KEYBOARD_KEY_LEFT_SHIFT:
++	ps2_state->at_keyboard_status &= ~GRUB_TERM_STATUS_LSHIFT;
++	return 1;
++      case GRUB_KEYBOARD_KEY_RIGHT_SHIFT:
++	ps2_state->at_keyboard_status &= ~GRUB_TERM_STATUS_RSHIFT;
++	return 1;
++      case GRUB_KEYBOARD_KEY_LEFT_CTRL:
++	ps2_state->at_keyboard_status &= ~GRUB_TERM_STATUS_LCTRL;
++	return 1;
++      case GRUB_KEYBOARD_KEY_RIGHT_CTRL:
++	ps2_state->at_keyboard_status &= ~GRUB_TERM_STATUS_RCTRL;
++	return 1;
++      case GRUB_KEYBOARD_KEY_RIGHT_ALT:
++	ps2_state->at_keyboard_status &= ~GRUB_TERM_STATUS_RALT;
++	return 1;
++      case GRUB_KEYBOARD_KEY_LEFT_ALT:
++	ps2_state->at_keyboard_status &= ~GRUB_TERM_STATUS_LALT;
++	return 1;
++      default:
++	return 0;
++      }
++}
++
++/* If there is a key pending, return it; otherwise return GRUB_TERM_NO_KEY.  */
++int
++grub_ps2_process_incoming_byte (struct grub_ps2_state *ps2_state,
++				grub_uint8_t at_key)
++{
++  int code;
++  int is_break = 0;
++
++  code = fetch_key (ps2_state, at_key, &is_break);
++  if (code == -1)
++    return GRUB_TERM_NO_KEY;
++
++  if (grub_keyboard_isr (ps2_state, code, is_break))
++    return GRUB_TERM_NO_KEY;
++  if (is_break)
++    return GRUB_TERM_NO_KEY;
++#ifdef DEBUG_AT_KEYBOARD
++  grub_dprintf ("atkeyb", "Detected key 0x%x\n", code);
++#endif
++  switch (code)
++    {
++      case GRUB_KEYBOARD_KEY_CAPS_LOCK:
++	ps2_state->at_keyboard_status ^= GRUB_TERM_STATUS_CAPS;
++	ps2_state->led_status ^= KEYBOARD_LED_CAPS;
++
++#ifdef DEBUG_AT_KEYBOARD
++	grub_dprintf ("atkeyb", "caps_lock = %d\n", !!(ps2_state->at_keyboard_status & GRUB_KEYBOARD_STATUS_CAPS_LOCK));
++#endif
++	return GRUB_TERM_NO_KEY;
++      case GRUB_KEYBOARD_KEY_NUM_LOCK:
++	ps2_state->at_keyboard_status ^= GRUB_TERM_STATUS_NUM;
++	ps2_state->led_status ^= KEYBOARD_LED_NUM;
++
++#ifdef DEBUG_AT_KEYBOARD
++	grub_dprintf ("atkeyb", "num_lock = %d\n", !!(ps2_state->at_keyboard_status & GRUB_KEYBOARD_STATUS_NUM_LOCK));
++#endif
++	return GRUB_TERM_NO_KEY;
++      case GRUB_KEYBOARD_KEY_SCROLL_LOCK:
++	ps2_state->at_keyboard_status ^= GRUB_TERM_STATUS_SCROLL;
++	ps2_state->led_status ^= KEYBOARD_LED_SCROLL;
++	return GRUB_TERM_NO_KEY;
++      default:
++	return grub_term_map_key (code, ps2_state->at_keyboard_status);
++    }
++}
+diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c
+index f0d3e3debc60aa8dd04a5643a8a0537ffb88ec26..d317efa368d846963743a243fd672026a2221933 100644
+--- a/grub-core/term/terminfo.c
++++ b/grub-core/term/terminfo.c
+@@ -426,12 +426,12 @@ grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len,
+     }
+   *len = 1;
+   keys[0] = c;
+-  if (c != ANSI_CSI && c != '\e')
++  if (c != ANSI_CSI && c != GRUB_TERM_ESC)
+     {
+       /* Backspace: Ctrl-h.  */
+       if (c == 0x7f)
+-	c = '\b'; 
+-      if (c < 0x20 && c != '\t' && c!= '\b' && c != '\n' && c != '\r')
++	c = GRUB_TERM_BACKSPACE;
++      if (c < 0x20 && c != GRUB_TERM_TAB && c!= GRUB_TERM_BACKSPACE && c != '\n' && c != '\r')
+ 	c = GRUB_TERM_CTRL | (c - 1 + 'a');
+       *len = 1;
+       keys[0] = c;
+@@ -487,7 +487,7 @@ grub_terminfo_readkey (struct grub_term_input *term, int *keys, int *len,
+ 	  GRUB_TERM_KEY_HOME, GRUB_TERM_KEY_END };
+     unsigned i;
+ 
+-    if (c == '\e')
++    if (c == GRUB_TERM_ESC)
+       {
+ 	CONTINUE_READ;
+ 
+@@ -606,7 +606,7 @@ grub_terminfo_getkey (struct grub_term_input *termi)
+ 			 &data->npending, data->readkey);
+ 
+ #if defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)
+-  if (data->npending == 1 && data->input_buf[0] == '\e'
++  if (data->npending == 1 && data->input_buf[0] == GRUB_TERM_ESC
+       && grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_REPEAT)
+       && grub_get_time_ms () - data->last_key_time < 1000
+       && (data->last_key & GRUB_TERM_EXTENDED))
+diff --git a/grub-core/tests/cmdline_cat_test.c b/grub-core/tests/cmdline_cat_test.c
+index f1e21439e2be229d386cb310d62164fc9a5f4f92..baea7688a1d3c49d37a2c03e585109ccd04328f8 100644
+--- a/grub-core/tests/cmdline_cat_test.c
++++ b/grub-core/tests/cmdline_cat_test.c
+@@ -103,7 +103,7 @@ cmdline_cat_test (void)
+ 					     '/', 't', 'e', 's', 't', '.',
+ 					     't', 'x', 't', '\n',
+ 					     GRUB_TERM_NO_KEY,
+-					     GRUB_TERM_NO_KEY, '\e'},
++					     GRUB_TERM_NO_KEY, GRUB_TERM_ESC},
+ 					 23);
+ 
+       grub_video_checksum ("cmdline_cat");
+diff --git a/grub-core/tests/gfxterm_menu.c b/grub-core/tests/gfxterm_menu.c
+index 8f63dc27a35bd769ecb5d94599de3ba9e97cf5dc..12836fb96598d98b5cbf371a953e6ec702eb50de 100644
+--- a/grub-core/tests/gfxterm_menu.c
++++ b/grub-core/tests/gfxterm_menu.c
+@@ -146,7 +146,7 @@ gfxterm_menu (void)
+ 	    return;
+ 	  }
+ 	grub_terminal_input_fake_sequence ((int []) { -1, -1, -1, GRUB_TERM_KEY_DOWN, -1, 'e',
+-	      -1, GRUB_TERM_KEY_RIGHT, -1, 'x', -1,  '\e', -1, '\e' }, 14);
++	      -1, GRUB_TERM_KEY_RIGHT, -1, 'x', -1,  GRUB_TERM_ESC, -1, GRUB_TERM_ESC }, 14);
+ 
+ 	grub_video_checksum (tests[j].name);
+ 
+diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c
+index d4822a12456525e4abc5f587bc897364db4e52b7..96781fb39b5f37b201345f60fe4297629bb672cf 100644
+--- a/grub-core/tests/lib/functional_test.c
++++ b/grub-core/tests/lib/functional_test.c
+@@ -26,14 +26,23 @@ GRUB_MOD_LICENSE ("GPLv3+");
+ 
+ static grub_err_t
+ grub_functional_test (grub_extcmd_context_t ctxt __attribute__ ((unused)),
+-		      int argc __attribute__ ((unused)),
+-		      char **args __attribute__ ((unused)))
++		      int argc,
++		      char **args)
+ {
+   grub_test_t test;
+   int ok = 1;
++  int i;
+ 
+   FOR_LIST_ELEMENTS (test, grub_test_list)
+     {
++      if (argc != 0)
++	{
++	  for (i = 0; i < argc; i++)
++	    if (grub_strcmp(args[i], test->name) == 0)
++	      break;
++	  if (i == argc)
++	    continue;
++	}
+       grub_errno = 0;
+       ok = ok && !grub_test_run (test);
+       grub_errno = 0;
+diff --git a/grub-core/video/i386/coreboot/cbfb.c b/grub-core/video/coreboot/cbfb.c
+similarity index 99%
+rename from grub-core/video/i386/coreboot/cbfb.c
+rename to grub-core/video/coreboot/cbfb.c
+index dede0c37ea3e8a8948cd6535d26d008e117206bc..9af81fa5b01b63677d97ba9a242e60080df84e5a 100644
+--- a/grub-core/video/i386/coreboot/cbfb.c
++++ b/grub-core/video/coreboot/cbfb.c
+@@ -25,7 +25,7 @@
+ #include <grub/mm.h>
+ #include <grub/video.h>
+ #include <grub/video_fb.h>
+-#include <grub/machine/lbio.h>
++#include <grub/coreboot/lbio.h>
+ #include <grub/machine/console.h>
+ 
+ struct grub_linuxbios_table_framebuffer *grub_video_coreboot_fbtable;
+diff --git a/grub-core/video/efi_uga.c b/grub-core/video/efi_uga.c
+index 464ede874daff480fb4199927cb30d48f0558e8b..044af1d20d38f08e3b5c5dcec4281c0b452cf8ea 100644
+--- a/grub-core/video/efi_uga.c
++++ b/grub-core/video/efi_uga.c
+@@ -94,10 +94,19 @@ static int
+ find_card (grub_pci_device_t dev, grub_pci_id_t pciid, void *data)
+ {
+   struct find_framebuf_ctx *ctx = data;
+-  grub_pci_address_t addr;
++  grub_pci_address_t addr, rcaddr;
++  grub_uint32_t subclass;
+ 
+   addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
+-  if (grub_pci_read (addr) >> 24 == 0x3)
++  subclass = (grub_pci_read (addr) >> 16) & 0xffff;
++
++  if (subclass != GRUB_PCI_CLASS_SUBCLASS_VGA)
++    return 0;
++
++  /* Enable MEM address spaces */
++  rcaddr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
++  grub_pci_write_word (rcaddr, grub_pci_read_word (rcaddr) | GRUB_PCI_COMMAND_MEM_ENABLED);
++
+     {
+       int i;
+ 
+diff --git a/tests/printf_unit_test.c b/tests/printf_unit_test.c
+index d7b12c6dbee6e84ace9d9f81d476622194810b26..098c29fd9ce2d28a5b83b74afc0f9e40b7c401ec 100644
+--- a/tests/printf_unit_test.c
++++ b/tests/printf_unit_test.c
+@@ -23,6 +23,10 @@
+ 
+ #define MSG "printf test failed: %s, %s", real, expected
+ 
++#if defined(__GNUC__) && __GNUC__ >= 7
++#pragma GCC diagnostic ignored "-Wformat-truncation="
++#endif
++
+ static void
+ printf_test (void)
+ {
+diff --git a/util/grub-install-common.c b/util/grub-install-common.c
+index 452b230daedc3db0296cab014e89ddacf1c21347..0a2e24a79f11916527650d124e38c6184c4ceb93 100644
+--- a/util/grub-install-common.c
++++ b/util/grub-install-common.c
+@@ -73,6 +73,7 @@ grub_install_help_filter (int key, const char *text,
+ 
+ static int (*compress_func) (const char *src, const char *dest) = NULL;
+ char *grub_install_copy_buffer;
++static char *dtb;
+ 
+ int
+ grub_install_copy_file (const char *src,
+@@ -364,6 +365,11 @@ grub_install_parse (int key, char *arg)
+     case GRUB_INSTALL_OPTIONS_INSTALL_FONTS:
+       handle_install_list (&install_fonts, arg, 0);
+       return 1;
++    case GRUB_INSTALL_OPTIONS_DTB:
++      if (dtb)
++	free (dtb);
++      dtb = xstrdup (arg);
++      return 1;
+     case GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS:
+       if (strcmp (arg, "no") == 0
+ 	  || strcmp (arg, "none") == 0)
+@@ -486,9 +492,10 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
+ 
+   grub_util_info ("grub-mkimage --directory '%s' --prefix '%s'"
+ 		  " --output '%s' "
++		  " --dtb '%s' "
+ 		  "--format '%s' --compression '%s' %s %s\n",
+ 		  dir, prefix,
+-		  outname, mkimage_target,
++		  outname, dtb ? : "", mkimage_target,
+ 		  compnames[compression], note ? "--note" : "", s);
+   free (s);
+ 
+@@ -499,7 +506,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
+   grub_install_generate_image (dir, prefix, fp, outname,
+ 			       modules.entries, memdisk_path,
+ 			       pubkeys, npubkeys, config_path, tgt,
+-			       note, compression);
++			       note, compression, dtb);
+   while (dc--)
+     grub_install_pop_module ();
+ }
+@@ -585,6 +592,7 @@ copy_all (const char *srcd,
+   grub_util_fd_closedir (d);
+ }
+ 
++#if !(defined (GRUB_UTIL) && defined(ENABLE_NLS) && ENABLE_NLS)
+ static const char *
+ get_localedir (void)
+ {
+@@ -639,6 +647,59 @@ copy_locales (const char *dstd)
+     }
+   grub_util_fd_closedir (d);
+ }
++#endif
++
++static void
++grub_install_copy_nls(const char *src __attribute__ ((unused)),
++                      const char *dst __attribute__ ((unused)))
++{
++#if !(defined (GRUB_UTIL) && defined(ENABLE_NLS) && ENABLE_NLS)
++  char *dst_locale;
++
++  dst_locale = grub_util_path_concat (2, dst, "locale");
++  grub_install_mkdir_p (dst_locale);
++  clean_grub_dir (dst_locale);
++
++  if (install_locales.is_default)
++    {
++      char *srcd = grub_util_path_concat (2, src, "po");
++      copy_by_ext (srcd, dst_locale, ".mo", 0);
++      copy_locales (dst_locale);
++      free (srcd);
++    }
++  else
++    {
++      size_t i;
++      const char *locale_dir = get_localedir ();
++
++      for (i = 0; i < install_locales.n_entries; i++)
++      {
++        char *srcf = grub_util_path_concat_ext (3, src, "po",
++                                                install_locales.entries[i],
++                                                ".mo");
++        char *dstf = grub_util_path_concat_ext (2, dst_locale,
++                                                install_locales.entries[i],
++                                                ".mo");
++        if (grub_install_compress_file (srcf, dstf, 0))
++          {
++            free (srcf);
++            free (dstf);
++            continue;
++          }
++        free (srcf);
++        srcf = grub_util_path_concat_ext (4, locale_dir,
++                                          install_locales.entries[i],
++                                          "LC_MESSAGES", PACKAGE, ".mo");
++        if (grub_install_compress_file (srcf, dstf, 0) == 0)
++          grub_util_error (_("cannot find locale `%s'"),
++                           install_locales.entries[i]);
++        free (srcf);
++        free (dstf);
++      }
++    }
++  free (dst_locale);
++#endif
++}
+ 
+ static struct
+ {
+@@ -666,6 +727,7 @@ static struct
+     [GRUB_INSTALL_PLATFORM_ARM_EFI] =          { "arm",     "efi"       },
+     [GRUB_INSTALL_PLATFORM_ARM64_EFI] =        { "arm64",   "efi"       },
+     [GRUB_INSTALL_PLATFORM_ARM_UBOOT] =        { "arm",     "uboot"     },
++    [GRUB_INSTALL_PLATFORM_ARM_COREBOOT] =     { "arm",     "coreboot"  },
+   }; 
+ 
+ char *
+@@ -723,7 +785,7 @@ grub_install_copy_files (const char *src,
+ 			 const char *dst,
+ 			 enum grub_install_plat platid)
+ {
+-  char *dst_platform, *dst_locale, *dst_fonts;
++  char *dst_platform, *dst_fonts;
+   const char *pkgdatadir = grub_util_get_pkgdatadir ();
+   char *themes_dir;
+ 
+@@ -734,13 +796,12 @@ grub_install_copy_files (const char *src,
+     dst_platform = grub_util_path_concat (2, dst, platform);
+     free (platform);
+   }
+-  dst_locale = grub_util_path_concat (2, dst, "locale");
+   dst_fonts = grub_util_path_concat (2, dst, "fonts");
+   grub_install_mkdir_p (dst_platform);
+-  grub_install_mkdir_p (dst_locale);
+   clean_grub_dir (dst);
+   clean_grub_dir (dst_platform);
+-  clean_grub_dir (dst_locale);
++
++  grub_install_copy_nls(src, dst);
+ 
+   if (install_modules.is_default)
+     copy_by_ext (src, dst_platform, ".mod", 1);
+@@ -789,50 +850,6 @@ grub_install_copy_files (const char *src,
+       free (dstf);
+     }
+ 
+-  if (install_locales.is_default)
+-    {
+-      char *srcd = grub_util_path_concat (2, src, "po");
+-      copy_by_ext (srcd, dst_locale, ".mo", 0);
+-      copy_locales (dst_locale);
+-      free (srcd);
+-    }
+-  else
+-    {
+-      const char *locale_dir = get_localedir ();
+-
+-      for (i = 0; i < install_locales.n_entries; i++)
+-	{
+-	  char *srcf = grub_util_path_concat_ext (3, src,
+-						"po",
+-						install_locales.entries[i],
+-						".mo");
+-	  char *dstf = grub_util_path_concat_ext (2, dst_locale,
+-						install_locales.entries[i],
+-						".mo");
+-	  if (grub_install_compress_file (srcf, dstf, 0))
+-	    {
+-	      free (srcf);
+-	      free (dstf);
+-	      continue;
+-	    }
+-	  free (srcf);
+-	  srcf = grub_util_path_concat_ext (4,
+-						 locale_dir,
+-						 install_locales.entries[i],
+-						 "LC_MESSAGES",
+-						 PACKAGE,
+-						 ".mo");
+-	  if (grub_install_compress_file (srcf, dstf, 0))
+-	    {
+-	      free (srcf);
+-	      free (dstf);
+-	      continue;
+-	    }
+-	  grub_util_error (_("cannot find locale `%s'"),
+-			   install_locales.entries[i]);
+-	}
+-    }
+-
+   if (install_themes.is_default)
+     {
+       install_themes.is_default = 0;
+@@ -895,7 +912,6 @@ grub_install_copy_files (const char *src,
+     }
+ 
+   free (dst_platform);
+-  free (dst_locale);
+   free (dst_fonts);
+ }
+ 
+diff --git a/util/grub-install.c b/util/grub-install.c
+index 9074d3e9e52d2a2e215a10b2f8b3cf627ca80db3..78d0138cb0a8c891f8140f1804d68d275eb690f6 100644
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -486,6 +486,7 @@ have_bootdev (enum grub_install_plat pl)
+ 
+     case GRUB_INSTALL_PLATFORM_I386_QEMU:
+     case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
++    case GRUB_INSTALL_PLATFORM_ARM_COREBOOT:
+     case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+     case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+     case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+@@ -713,7 +714,7 @@ is_prep_partition (grub_device_t dev)
+       if (grub_disk_read (dev->disk, p->offset, p->index,
+ 			  sizeof (gptdata), &gptdata) == 0)
+ 	{
+-	  const grub_gpt_part_type_t template = {
++	  const grub_gpt_part_guid_t template = {
+ 	    grub_cpu_to_le32_compile_time (0x9e1a2d38),
+ 	    grub_cpu_to_le16_compile_time (0xc612),
+ 	    grub_cpu_to_le16_compile_time (0x4316),
+@@ -911,6 +912,7 @@ main (int argc, char *argv[])
+ 
+     case GRUB_INSTALL_PLATFORM_I386_QEMU:
+     case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
++    case GRUB_INSTALL_PLATFORM_ARM_COREBOOT:
+     case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+     case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+     case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+@@ -946,6 +948,7 @@ main (int argc, char *argv[])
+     case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+     case GRUB_INSTALL_PLATFORM_I386_QEMU:
+     case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
++    case GRUB_INSTALL_PLATFORM_ARM_COREBOOT:
+     case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+     case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+     case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+@@ -1448,6 +1451,7 @@ main (int argc, char *argv[])
+ 		  case GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON:
+ 		  case GRUB_INSTALL_PLATFORM_I386_QEMU:
+ 		  case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
++		  case GRUB_INSTALL_PLATFORM_ARM_COREBOOT:
+ 		  case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+ 		  case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+ 		  case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+@@ -1468,6 +1472,7 @@ main (int argc, char *argv[])
+ 		{
+ 		  grub_util_fprint_full_disk_name (load_cfg_f, g, dev);
+ 		  fprintf (load_cfg_f, " ");
++		  free (g);
+ 		}
+ 	      if (dev != grub_dev)
+ 		grub_device_close (dev);
+@@ -1542,6 +1547,7 @@ main (int argc, char *argv[])
+       break;
+ 
+     case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
++    case GRUB_INSTALL_PLATFORM_ARM_COREBOOT:
+     case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+     case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
+     case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
+@@ -1629,6 +1635,7 @@ main (int argc, char *argv[])
+     case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+     case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+     case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
++    case GRUB_INSTALL_PLATFORM_ARM_COREBOOT:
+     case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+     case GRUB_INSTALL_PLATFORM_I386_PC:
+     case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+@@ -1841,9 +1848,13 @@ main (int argc, char *argv[])
+ 	  if (!removable && update_nvram)
+ 	    {
+ 	      /* Try to make this image bootable using the EFI Boot Manager, if available.  */
+-	      grub_install_register_efi (efidir_grub_dev,
+-					 "\\System\\Library\\CoreServices",
+-					 efi_distributor);
++	      int ret;
++	      ret = grub_install_register_efi (efidir_grub_dev,
++					       "\\System\\Library\\CoreServices",
++					       efi_distributor);
++	      if (ret)
++	        grub_util_error (_("efibootmgr failed to register the boot entry: %s"),
++				 strerror (ret));
+ 	    }
+ 
+ 	  grub_device_close (ins_dev);
+@@ -1864,6 +1875,7 @@ main (int argc, char *argv[])
+ 	{
+ 	  char * efifile_path;
+ 	  char * part;
++	  int ret;
+ 
+ 	  /* Try to make this image bootable using the EFI Boot Manager, if available.  */
+ 	  if (!efi_distributor || efi_distributor[0] == '\0')
+@@ -1880,8 +1892,11 @@ main (int argc, char *argv[])
+ 			  efidir_grub_dev->disk->name,
+ 			  (part ? ",": ""), (part ? : ""));
+ 	  grub_free (part);
+-	  grub_install_register_efi (efidir_grub_dev,
+-				     efifile_path, efi_distributor);
++	  ret = grub_install_register_efi (efidir_grub_dev,
++					   efifile_path, efi_distributor);
++	  if (ret)
++	    grub_util_error (_("efibootmgr failed to register the boot entry: %s"),
++			     strerror (ret));
+ 	}
+       break;
+ 
+@@ -1889,6 +1904,7 @@ main (int argc, char *argv[])
+     case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
+     case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
+     case GRUB_INSTALL_PLATFORM_I386_COREBOOT:
++    case GRUB_INSTALL_PLATFORM_ARM_COREBOOT:
+     case GRUB_INSTALL_PLATFORM_I386_MULTIBOOT:
+     case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
+     case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
+diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
+index aba19d21b9a774e63ad49f166554d90f8c667e36..98d24cc06ea57b88a4f02f38f177f44ec4f38f3f 100644
+--- a/util/grub-mkimage.c
++++ b/util/grub-mkimage.c
+@@ -71,6 +71,7 @@ static struct argp_option options[] = {
+    N_("embed FILE as a memdisk image\n"
+       "Implies `-p (memdisk)/boot/grub' and overrides any prefix supplied previously,"
+       " but the prefix itself can be overridden by later options"), 0},
++  {"dtb",  'D', N_("FILE"), 0, N_("embed FILE as a device tree (DTB)\n"), 0},
+    /* TRANSLATORS: "embed" is a verb (command description).  "*/
+   {"config",   'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0},
+    /* TRANSLATORS: "embed" is a verb (command description).  "*/
+@@ -117,6 +118,7 @@ struct arguments
+   char *dir;
+   char *prefix;
+   char *memdisk;
++  char *dtb;
+   char **pubkeys;
+   size_t npubkeys;
+   char *font;
+@@ -176,6 +178,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
+       arguments->prefix = xstrdup ("(memdisk)/boot/grub");
+       break;
+ 
++    case 'D':
++      if (arguments->dtb)
++	free (arguments->dtb);
++
++      arguments->dtb = xstrdup (arg);
++      break;
++
+     case 'k':
+       arguments->pubkeys = xrealloc (arguments->pubkeys,
+ 				     sizeof (arguments->pubkeys[0])
+@@ -300,7 +309,7 @@ main (int argc, char *argv[])
+ 			       arguments.memdisk, arguments.pubkeys,
+ 			       arguments.npubkeys, arguments.config,
+ 			       arguments.image_target, arguments.note,
+-			       arguments.comp);
++			       arguments.comp, arguments.dtb);
+ 
+   grub_util_file_sync  (fp);
+   fclose (fp);
+diff --git a/util/grub-mkimage32.c b/util/grub-mkimage32.c
+index 9b31397bc40b95b69a1edc4f2d4c4b5d6eaa63cd..1f2ccccd225bbbb32e7e38801ddafeb90d9a69bb 100644
+--- a/util/grub-mkimage32.c
++++ b/util/grub-mkimage32.c
+@@ -19,4 +19,6 @@
+ # define ELF_ST_TYPE(val)		ELF32_ST_TYPE(val)
+ #define XEN_NOTE_SIZE 132
+ 
++#ifndef GRUB_MKIMAGEXX
+ #include "grub-mkimagexx.c"
++#endif
+diff --git a/util/grub-mkimage64.c b/util/grub-mkimage64.c
+index d83345924705353b3c20a1e4dd087371ec5383ec..4ff72a625e0030d05cee0675a481b0803cda081e 100644
+--- a/util/grub-mkimage64.c
++++ b/util/grub-mkimage64.c
+@@ -19,4 +19,6 @@
+ # define ELF_ST_TYPE(val)		ELF64_ST_TYPE(val)
+ #define XEN_NOTE_SIZE 120
+ 
++#ifndef GRUB_MKIMAGEXX
+ #include "grub-mkimagexx.c"
++#endif
+diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
+index e63f148e48cf6f66852b15063405f81371d95ae9..a483c674c4908bca02ecda73de78d04456667a37 100644
+--- a/util/grub-mkimagexx.c
++++ b/util/grub-mkimagexx.c
+@@ -50,6 +50,15 @@
+ 
+ #pragma GCC diagnostic ignored "-Wcast-align"
+ 
++#define GRUB_MKIMAGEXX
++#if !defined(MKIMAGE_ELF32) && !defined(MKIMAGE_ELF64)
++#if __SIZEOF_POINTER__ == 8
++#include "grub-mkimage64.c"
++#else
++#include "grub-mkimage32.c"
++#endif
++#endif
++
+ /* These structures are defined according to the CHRP binding to IEEE1275,
+    "Client Program Format" section.  */
+ 
+@@ -84,10 +93,22 @@ struct fixup_block_list
+ 
+ #define ALIGN_ADDR(x) (ALIGN_UP((x), image_target->voidp_sizeof))
+ 
++struct section_metadata
++{
++  Elf_Half num_sections;
++  Elf_Shdr *sections;
++  Elf_Addr *addrs;
++  Elf_Addr *vaddrs;
++  Elf_Half section_entsize;
++  Elf_Shdr *symtab;
++  const char *strtab;
++};
++
+ static int
+ is_relocatable (const struct grub_install_image_target_desc *image_target)
+ {
+-  return image_target->id == IMAGE_EFI || image_target->id == IMAGE_UBOOT;
++  return image_target->id == IMAGE_EFI || image_target->id == IMAGE_UBOOT
++    || (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM);
+ }
+ 
+ #ifdef MKIMAGE_ELF32
+@@ -185,8 +206,8 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
+ void
+ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target,
+ 				    int note, char **core_img, size_t *core_size,
+-				    Elf_Addr target_addr, grub_size_t align,
+-				    size_t kernel_size, size_t bss_size)
++				    Elf_Addr target_addr,
++				    struct grub_mkimage_layout *layout)
+ {
+   char *elf_img;
+   size_t program_size;
+@@ -214,7 +235,7 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
+       footer_size += XEN_NOTE_SIZE;
+     }
+   header_size = ALIGN_UP (sizeof (*ehdr) + phnum * sizeof (*phdr)
+-			  + shnum * sizeof (*shdr) + string_size, align);
++			  + shnum * sizeof (*shdr) + string_size, layout->align);
+ 
+   program_size = ALIGN_ADDR (*core_size);
+ 
+@@ -258,7 +279,8 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
+   ehdr->e_entry = grub_host_to_target32 (target_addr);
+   phdr->p_vaddr = grub_host_to_target32 (target_addr);
+   phdr->p_paddr = grub_host_to_target32 (target_addr);
+-  phdr->p_align = grub_host_to_target32 (align > image_target->link_align ? align : image_target->link_align);
++  phdr->p_align = grub_host_to_target32 (layout->align > image_target->link_align ?
++					 layout->align : image_target->link_align);
+   if (image_target->id == IMAGE_LOONGSON_ELF)
+     ehdr->e_flags = grub_host_to_target32 (0x1000 | EF_MIPS_NOREORDER 
+ 					   | EF_MIPS_PIC | EF_MIPS_CPIC);
+@@ -272,27 +294,34 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
+   else
+     {
+       grub_uint32_t target_addr_mods;
+-      phdr->p_filesz = grub_host_to_target32 (kernel_size);
+-      phdr->p_memsz = grub_host_to_target32 (kernel_size + bss_size);
++      phdr->p_filesz = grub_host_to_target32 (layout->kernel_size);
++      if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM)
++	phdr->p_memsz = grub_host_to_target32 (layout->kernel_size);
++      else
++	phdr->p_memsz = grub_host_to_target32 (layout->kernel_size + layout->bss_size);
+ 
+       phdr++;
+       phdr->p_type = grub_host_to_target32 (PT_GNU_STACK);
+-      phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
++      phdr->p_offset = grub_host_to_target32 (header_size + layout->kernel_size);
+       phdr->p_paddr = phdr->p_vaddr = phdr->p_filesz = phdr->p_memsz = 0;
+       phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
+       phdr->p_align = grub_host_to_target32 (image_target->link_align);
+ 
+       phdr++;
+       phdr->p_type = grub_host_to_target32 (PT_LOAD);
+-      phdr->p_offset = grub_host_to_target32 (header_size + kernel_size);
++      phdr->p_offset = grub_host_to_target32 (header_size + layout->kernel_size);
+       phdr->p_flags = grub_host_to_target32 (PF_R | PF_W | PF_X);
+       phdr->p_filesz = phdr->p_memsz
+-	= grub_host_to_target32 (*core_size - kernel_size);
++	= grub_host_to_target32 (*core_size - layout->kernel_size);
+ 
+-      if (image_target->id == IMAGE_COREBOOT)
++      if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_386)
+ 	target_addr_mods = GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR;
++      else if (image_target->id == IMAGE_COREBOOT && image_target->elf_target == EM_ARM)
++	target_addr_mods = ALIGN_UP (target_addr + layout->end
++				     + image_target->mod_gap,
++				     image_target->mod_align);
+       else
+-	target_addr_mods = ALIGN_UP (target_addr + kernel_size + bss_size
++	target_addr_mods = ALIGN_UP (target_addr + layout->kernel_size + layout->bss_size
+ 				     + image_target->mod_gap,
+ 				     image_target->mod_align);
+       phdr->p_vaddr = grub_host_to_target_addr (target_addr_mods);
+@@ -434,7 +463,7 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
+     shdr->sh_size = grub_host_to_target32 (string_size);
+     shdr->sh_link = grub_host_to_target32 (0);
+     shdr->sh_info = grub_host_to_target32 (0);
+-    shdr->sh_addralign = grub_host_to_target32 (align);
++    shdr->sh_addralign = grub_host_to_target32 (layout->align);
+     shdr->sh_entsize = grub_host_to_target32 (0);
+     shdr++;
+ 
+@@ -445,10 +474,10 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
+     shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
+     shdr->sh_addr = grub_host_to_target_addr (target_addr);
+     shdr->sh_offset = grub_host_to_target_addr (header_size);
+-    shdr->sh_size = grub_host_to_target32 (kernel_size);
++    shdr->sh_size = grub_host_to_target32 (layout->kernel_size);
+     shdr->sh_link = grub_host_to_target32 (0);
+     shdr->sh_info = grub_host_to_target32 (0);
+-    shdr->sh_addralign = grub_host_to_target32 (align);
++    shdr->sh_addralign = grub_host_to_target32 (layout->align);
+     shdr->sh_entsize = grub_host_to_target32 (0);
+     shdr++;
+ 
+@@ -456,9 +485,9 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
+     shdr->sh_name = grub_host_to_target32 (ptr - str_start);
+     ptr += sizeof ("mods");
+     shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
+-    shdr->sh_addr = grub_host_to_target_addr (target_addr + kernel_size);
+-    shdr->sh_offset = grub_host_to_target_addr (header_size + kernel_size);
+-    shdr->sh_size = grub_host_to_target32 (*core_size - kernel_size);
++    shdr->sh_addr = grub_host_to_target_addr (target_addr + layout->kernel_size);
++    shdr->sh_offset = grub_host_to_target_addr (header_size + layout->kernel_size);
++    shdr->sh_size = grub_host_to_target32 (*core_size - layout->kernel_size);
+     shdr->sh_link = grub_host_to_target32 (0);
+     shdr->sh_info = grub_host_to_target32 (0);
+     shdr->sh_addralign = grub_host_to_target32 (image_target->voidp_sizeof);
+@@ -471,7 +500,7 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
+ 	shdr->sh_name = grub_host_to_target32 (ptr - str_start);
+ 	ptr += sizeof (".xen");
+ 	shdr->sh_type = grub_host_to_target32 (SHT_PROGBITS);
+-	shdr->sh_addr = grub_host_to_target_addr (target_addr + kernel_size);
++	shdr->sh_addr = grub_host_to_target_addr (target_addr + layout->kernel_size);
+ 	shdr->sh_offset = grub_host_to_target_addr (program_size + header_size);
+ 	shdr->sh_size = grub_host_to_target32 (XEN_NOTE_SIZE);
+ 	shdr->sh_link = grub_host_to_target32 (0);
+@@ -490,9 +519,7 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
+ /* Relocate symbols; note that this function overwrites the symbol table.
+    Return the address of a start symbol.  */
+ static Elf_Addr
+-SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
+-			   Elf_Shdr *symtab_section, Elf_Addr *section_addresses,
+-			   Elf_Half section_entsize, Elf_Half num_sections,
++SUFFIX (relocate_symbols) (Elf_Ehdr *e, struct section_metadata *smd,
+ 			   void *jumpers, Elf_Addr jumpers_addr,
+ 			   Elf_Addr bss_start, Elf_Addr end,
+ 			   const struct grub_install_image_target_desc *image_target)
+@@ -502,19 +529,18 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
+   Elf_Addr start_address = (Elf_Addr) -1;
+   Elf_Sym *sym;
+   Elf_Word i;
+-  Elf_Shdr *strtab_section;
+-  const char *strtab;
++  Elf_Shdr *symtab_section;
++  const char *symtab;
+   grub_uint64_t *jptr = jumpers;
+ 
+-  strtab_section
+-    = (Elf_Shdr *) ((char *) sections
+-		      + (grub_target_to_host32 (symtab_section->sh_link)
+-			 * section_entsize));
+-  strtab = (char *) e + grub_target_to_host (strtab_section->sh_offset);
++  symtab_section = (Elf_Shdr *) ((char *) smd->sections
++				 + grub_target_to_host32 (smd->symtab->sh_link)
++				   * smd->section_entsize);
++  symtab = (char *) e + grub_target_to_host (symtab_section->sh_offset);
+ 
+-  symtab_size = grub_target_to_host (symtab_section->sh_size);
+-  sym_size = grub_target_to_host (symtab_section->sh_entsize);
+-  symtab_offset = grub_target_to_host (symtab_section->sh_offset);
++  symtab_size = grub_target_to_host (smd->symtab->sh_size);
++  sym_size = grub_target_to_host (smd->symtab->sh_entsize);
++  symtab_offset = grub_target_to_host (smd->symtab->sh_offset);
+   num_syms = symtab_size / sym_size;
+ 
+   for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
+@@ -524,7 +550,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
+       Elf_Section cur_index;
+       const char *name;
+ 
+-      name = strtab + grub_target_to_host32 (sym->st_name);
++      name = symtab + grub_target_to_host32 (sym->st_name);
+ 
+       cur_index = grub_target_to_host16 (sym->st_shndx);
+       if (cur_index == STN_ABS)
+@@ -542,12 +568,12 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
+ 	  else
+ 	    continue;
+ 	}
+-      else if (cur_index >= num_sections)
++      else if (cur_index >= smd->num_sections)
+ 	grub_util_error ("section %d does not exist", cur_index);
+       else
+ 	{
+ 	  sym->st_value = (grub_target_to_host (sym->st_value)
+-			   + section_addresses[cur_index]);
++			   + smd->vaddrs[cur_index]);
+ 	}
+ 
+       if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info)
+@@ -562,7 +588,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
+       grub_util_info ("locating %s at 0x%"  GRUB_HOST_PRIxLONG_LONG
+ 		      " (0x%"  GRUB_HOST_PRIxLONG_LONG ")", name,
+ 		      (unsigned long long) sym->st_value,
+-		      (unsigned long long) section_addresses[cur_index]);
++		      (unsigned long long) smd->vaddrs[cur_index]);
+ 
+       if (start_address == (Elf_Addr)-1)
+ 	if (strcmp (name, "_start") == 0 || strcmp (name, "start") == 0)
+@@ -699,17 +725,19 @@ arm_get_trampoline_size (Elf_Ehdr *e,
+ }
+ #endif
+ 
++static int
++SUFFIX (is_kept_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target);
++static int
++SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target,
++				struct section_metadata *smd);
++
+ /* Deal with relocation information. This function relocates addresses
+    within the virtual address space starting from 0. So only relative
+    addresses can be fully resolved. Absolute addresses must be relocated
+    again by a PE32 relocator when loaded.  */
+ static void
+-SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
+-			     Elf_Addr *section_addresses,
+-			     Elf_Half section_entsize, Elf_Half num_sections,
+-			     const char *strtab,
+-			     char *pe_target, Elf_Addr tramp_off,
+-			     Elf_Addr got_off,
++SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd,
++			     char *pe_target, Elf_Addr tramp_off, Elf_Addr got_off,
+ 			     const struct grub_install_image_target_desc *image_target)
+ {
+   Elf_Half i;
+@@ -723,33 +751,37 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
+   grub_uint32_t *tr = (void *) (pe_target + tramp_off);
+ #endif
+ 
+-  for (i = 0, s = sections;
+-       i < num_sections;
+-       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
++  for (i = 0, s = smd->sections;
++       i < smd->num_sections;
++       i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
+     if ((s->sh_type == grub_host_to_target32 (SHT_REL)) ||
+         (s->sh_type == grub_host_to_target32 (SHT_RELA)))
+       {
+ 	Elf_Rela *r;
+ 	Elf_Word rtab_size, r_size, num_rs;
+ 	Elf_Off rtab_offset;
+-	Elf_Shdr *symtab_section;
+ 	Elf_Word target_section_index;
+ 	Elf_Addr target_section_addr;
+ 	Elf_Shdr *target_section;
+ 	Elf_Word j;
+ 
+-	symtab_section = (Elf_Shdr *) ((char *) sections
+-					 + (grub_target_to_host32 (s->sh_link)
+-					    * section_entsize));
++	if (!SUFFIX (is_kept_section) (s, image_target) &&
++	    !SUFFIX (is_kept_reloc_section) (s, image_target, smd))
++	  {
++	    grub_util_info ("not translating relocations for omitted section %s",
++			smd->strtab + grub_le_to_cpu32 (s->sh_name));
++	    continue;
++	  }
++
+ 	target_section_index = grub_target_to_host32 (s->sh_info);
+-	target_section_addr = section_addresses[target_section_index];
+-	target_section = (Elf_Shdr *) ((char *) sections
++	target_section_addr = smd->addrs[target_section_index];
++	target_section = (Elf_Shdr *) ((char *) smd->sections
+ 					 + (target_section_index
+-					    * section_entsize));
++					    * smd->section_entsize));
+ 
+ 	grub_util_info ("dealing with the relocation section %s for %s",
+-			strtab + grub_target_to_host32 (s->sh_name),
+-			strtab + grub_target_to_host32 (target_section->sh_name));
++			smd->strtab + grub_target_to_host32 (s->sh_name),
++			smd->strtab + grub_target_to_host32 (target_section->sh_name));
+ 
+ 	rtab_size = grub_target_to_host (s->sh_size);
+ 	r_size = grub_target_to_host (s->sh_entsize);
+@@ -770,7 +802,7 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
+ 	    target = SUFFIX (get_target_address) (e, target_section,
+ 						  offset, image_target);
+ 	    info = grub_target_to_host (r->r_info);
+-	    sym_addr = SUFFIX (get_symbol_address) (e, symtab_section,
++	    sym_addr = SUFFIX (get_symbol_address) (e, smd->symtab,
+ 						    ELF_R_SYM (info), image_target);
+ 
+             addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
+@@ -832,6 +864,7 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
+ 		  break;
+ 
+ 		case R_X86_64_PC32:
++		case R_X86_64_PLT32:
+ 		  {
+ 		    grub_uint32_t *t32 = (grub_uint32_t *) target;
+ 		    *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32)
+@@ -900,8 +933,8 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
+ 		    Elf_Sym *sym;
+ 
+ 		    sym = (Elf_Sym *) ((char *) e
+-				       + grub_target_to_host (symtab_section->sh_offset)
+-				       + ELF_R_SYM (info) * grub_target_to_host (symtab_section->sh_entsize));
++				       + grub_target_to_host (smd->symtab->sh_offset)
++				       + ELF_R_SYM (info) * grub_target_to_host (smd->symtab->sh_entsize));
+ 		    if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
+ 		      sym_addr = grub_target_to_host64 (*(grub_uint64_t *) (pe_target
+ 									    + sym->st_value
+@@ -1086,8 +1119,8 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
+ 							- (char *) e),
+ 				       sym_addr);
+ 		       sym = (Elf_Sym *) ((char *) e
+-					  + grub_target_to_host (symtab_section->sh_offset)
+-					  + ELF_R_SYM (info) * grub_target_to_host (symtab_section->sh_entsize));
++					  + grub_target_to_host (smd->symtab->sh_offset)
++					  + ELF_R_SYM (info) * grub_target_to_host (smd->symtab->sh_entsize));
+ 		       if (ELF_ST_TYPE (sym->st_info) != STT_FUNC)
+ 			 sym_addr |= 1;
+ 		       if (!(sym_addr & 1))
+@@ -1625,9 +1658,7 @@ create_u64_fixups (struct translate_context *ctx,
+ /* Make a .reloc section.  */
+ static void
+ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout,
+-		    Elf_Addr *section_addresses, Elf_Shdr *sections,
+-		    Elf_Half section_entsize, Elf_Half num_sections,
+-		    const char *strtab,
++		    struct section_metadata *smd,
+ 		    const struct grub_install_image_target_desc *image_target)
+ {
+   unsigned i;
+@@ -1636,8 +1667,8 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout,
+ 
+   translate_reloc_start (&ctx, image_target);
+ 
+-  for (i = 0, s = sections; i < num_sections;
+-       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
++  for (i = 0, s = smd->sections; i < smd->num_sections;
++       i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
+     if ((grub_target_to_host32 (s->sh_type) == SHT_REL) ||
+         (grub_target_to_host32 (s->sh_type) == SHT_RELA))
+       {
+@@ -1647,15 +1678,22 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout,
+ 	Elf_Addr section_address;
+ 	Elf_Word j;
+ 
++	if (!SUFFIX (is_kept_reloc_section) (s, image_target, smd))
++	  {
++	    grub_util_info ("not translating the skipped relocation section %s",
++			    smd->strtab + grub_le_to_cpu32 (s->sh_name));
++	    continue;
++	  }
++
+ 	grub_util_info ("translating the relocation section %s",
+-			strtab + grub_le_to_cpu32 (s->sh_name));
++			smd->strtab + grub_le_to_cpu32 (s->sh_name));
+ 
+ 	rtab_size = grub_target_to_host (s->sh_size);
+ 	r_size = grub_target_to_host (s->sh_entsize);
+ 	rtab_offset = grub_target_to_host (s->sh_offset);
+ 	num_rs = rtab_size / r_size;
+ 
+-	section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)];
++	section_address = smd->vaddrs[grub_le_to_cpu32 (s->sh_info)];
+ 
+ 	for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset);
+ 	     j < num_rs;
+@@ -1722,6 +1760,56 @@ SUFFIX (is_bss_section) (Elf_Shdr *s, const struct grub_install_image_target_des
+ 	  == SHF_ALLOC) && (grub_target_to_host32 (s->sh_type) == SHT_NOBITS);
+ }
+ 
++/* Determine if a section is going to be in the final output */
++static int
++SUFFIX (is_kept_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target)
++{
++  /* We keep .text and .data */
++  if (SUFFIX (is_text_section) (s, image_target)
++      || SUFFIX (is_data_section) (s, image_target))
++    return 1;
++
++  /*
++   * And we keep .bss if we're producing PE binaries or the target doesn't
++   * have a relocating loader.  Platforms other than EFI and U-boot shouldn't
++   * have .bss in their binaries as we build with -Wl,-Ttext.
++   */
++  if (SUFFIX (is_bss_section) (s, image_target)
++      && (image_target->id == IMAGE_EFI || !is_relocatable (image_target)))
++    return 1;
++
++  /* Otherwise this is not a section we're keeping in the final output. */
++  return 0;
++}
++
++static int
++SUFFIX (is_kept_reloc_section) (Elf_Shdr *s, const struct grub_install_image_target_desc *image_target,
++				struct section_metadata *smd)
++{
++  int i;
++  int r = 0;
++  const char *name = smd->strtab + grub_host_to_target32 (s->sh_name);
++
++  if (!strncmp (name, ".rela.", 6))
++    name += 5;
++  else if (!strncmp (name, ".rel.", 5))
++    name += 4;
++  else
++    return 1;
++
++  for (i = 0, s = smd->sections; i < smd->num_sections;
++       i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
++    {
++      const char *sname = smd->strtab + grub_host_to_target32 (s->sh_name);
++      if (strcmp (sname, name))
++	continue;
++
++      return SUFFIX (is_kept_section) (s, image_target);
++    }
++
++  return r;
++}
++
+ /* Return if the ELF header is valid.  */
+ static int
+ SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_image_target_desc *image_target)
+@@ -1742,12 +1830,11 @@ SUFFIX (check_elf_header) (Elf_Ehdr *e, size_t size, const struct grub_install_i
+ static Elf_Addr
+ SUFFIX (put_section) (Elf_Shdr *s, int i,
+ 		      Elf_Addr current_address,
+-		      Elf_Addr *section_addresses,
+-		      const char *strtab,
++		      struct section_metadata *smd,
+ 		      const struct grub_install_image_target_desc *image_target)
+ {
+ 	Elf_Word align = grub_host_to_target_addr (s->sh_addralign);
+-	const char *name = strtab + grub_host_to_target32 (s->sh_name);
++	const char *name = smd->strtab + grub_host_to_target32 (s->sh_name);
+ 
+ 	if (align)
+ 	  current_address = ALIGN_UP (current_address + image_target->vaddr_offset,
+@@ -1759,24 +1846,23 @@ SUFFIX (put_section) (Elf_Shdr *s, int i,
+ 			name, (unsigned long long) current_address);
+ 	if (!is_relocatable (image_target))
+ 	  current_address = grub_host_to_target_addr (s->sh_addr)
+-	    - image_target->link_addr;
+-	section_addresses[i] = current_address;
++			    - image_target->link_addr;
++	smd->addrs[i] = current_address;
+ 	current_address += grub_host_to_target_addr (s->sh_size);
+ 	return current_address;
+ }
+ 
+-/* Locate section addresses by merging code sections and data sections
+-   into .text and .data, respectively. Return the array of section
+-   addresses.  */
+-static Elf_Addr *
++/*
++ * Locate section addresses by merging code sections and data sections
++ * into .text and .data, respectively.
++ */
++static void
+ SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path,
+-			  Elf_Shdr *sections, Elf_Half section_entsize,
+-			  Elf_Half num_sections, const char *strtab,
++			  struct section_metadata *smd,
+ 			  struct grub_mkimage_layout *layout,
+ 			  const struct grub_install_image_target_desc *image_target)
+ {
+   int i;
+-  Elf_Addr *section_addresses;
+   Elf_Shdr *s;
+ 
+   layout->align = 1;
+@@ -1784,30 +1870,23 @@ SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path,
+   if (image_target->elf_target == EM_AARCH64)
+     layout->align = 4096;
+ 
+-  section_addresses = xmalloc (sizeof (*section_addresses) * num_sections);
+-  memset (section_addresses, 0, sizeof (*section_addresses) * num_sections);
+-
+   layout->kernel_size = 0;
+ 
+-  for (i = 0, s = sections;
+-       i < num_sections;
+-       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+-    if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC) 
++  for (i = 0, s = smd->sections;
++       i < smd->num_sections;
++       i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
++    if ((grub_target_to_host (s->sh_flags) & SHF_ALLOC)
+ 	&& grub_host_to_target32 (s->sh_addralign) > layout->align)
+       layout->align = grub_host_to_target32 (s->sh_addralign);
+ 
+-
+   /* .text */
+-  for (i = 0, s = sections;
+-       i < num_sections;
+-       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
++  for (i = 0, s = smd->sections;
++       i < smd->num_sections;
++       i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
+     if (SUFFIX (is_text_section) (s, image_target))
+       {
+-	layout->kernel_size = SUFFIX (put_section) (s, i,
+-						layout->kernel_size,
+-						section_addresses,
+-						strtab,
+-						image_target);
++	layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size,
++						smd, image_target);
+ 	if (!is_relocatable (image_target) &&
+ 	    grub_host_to_target_addr (s->sh_addr) != image_target->link_addr)
+ 	  {
+@@ -1827,15 +1906,12 @@ SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path,
+   layout->exec_size = layout->kernel_size;
+ 
+   /* .data */
+-  for (i = 0, s = sections;
+-       i < num_sections;
+-       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
++  for (i = 0, s = smd->sections;
++       i < smd->num_sections;
++       i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
+     if (SUFFIX (is_data_section) (s, image_target))
+-      layout->kernel_size = SUFFIX (put_section) (s, i,
+-					      layout->kernel_size,
+-					      section_addresses,
+-					      strtab,
+-					      image_target);
++      layout->kernel_size = SUFFIX (put_section) (s, i, layout->kernel_size, smd,
++						  image_target);
+ 
+ #ifdef MKIMAGE_ELF32
+   if (image_target->elf_target == EM_ARM)
+@@ -1846,8 +1922,8 @@ SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path,
+ 
+       layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
+ 
+-      tramp = arm_get_trampoline_size (e, sections, section_entsize,
+-				       num_sections, image_target);
++      tramp = arm_get_trampoline_size (e, smd->sections, smd->section_entsize,
++				       smd->num_sections, image_target);
+ 
+       layout->tramp_off = layout->kernel_size;
+       layout->kernel_size += ALIGN_UP (tramp, 16);
+@@ -1858,15 +1934,18 @@ SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path,
+   layout->end = layout->kernel_size;
+   
+   /* .bss */
+-  for (i = 0, s = sections;
+-       i < num_sections;
+-       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+-    if (SUFFIX (is_bss_section) (s, image_target))
+-      layout->end = SUFFIX (put_section) (s, i,
+-					  layout->end,
+-					  section_addresses,
+-					  strtab,
+-					  image_target);
++  for (i = 0, s = smd->sections;
++       i < smd->num_sections;
++       i++, s = (Elf_Shdr *) ((char *) s + smd->section_entsize))
++    {
++      if (SUFFIX (is_bss_section) (s, image_target))
++	layout->end = SUFFIX (put_section) (s, i, layout->end, smd, image_target);
++
++      /*
++       * This must to be in the last time this function passes through the loop.
++       */
++      smd->vaddrs[i] = smd->addrs[i] + image_target->vaddr_offset;
++    }
+ 
+   layout->end = ALIGN_UP (layout->end + image_target->vaddr_offset,
+ 			      image_target->section_align) - image_target->vaddr_offset;
+@@ -1875,10 +1954,8 @@ SUFFIX (locate_sections) (Elf_Ehdr *e, const char *kernel_path,
+      Platforms other than EFI and U-boot shouldn't have .bss in
+      their binaries as we build with -Wl,-Ttext.
+   */
+-  if (image_target->id != IMAGE_UBOOT)
++  if (image_target->id == IMAGE_EFI || !is_relocatable (image_target))
+     layout->kernel_size = layout->end;
+-
+-  return section_addresses;
+ }
+ 
+ char *
+@@ -1888,18 +1965,12 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
+ 				  const struct grub_install_image_target_desc *image_target)
+ {
+   char *kernel_img, *out_img;
+-  const char *strtab;
++  struct section_metadata smd = { 0, 0, 0, 0, 0, 0, 0 };
+   Elf_Ehdr *e;
+-  Elf_Shdr *sections;
+-  Elf_Addr *section_addresses;
+-  Elf_Addr *section_vaddresses;
+   int i;
+   Elf_Shdr *s;
+-  Elf_Half num_sections;
+   Elf_Off section_offset;
+-  Elf_Half section_entsize;
+   grub_size_t kernel_size;
+-  Elf_Shdr *symtab_section = 0;
+ 
+   grub_memset (layout, 0, sizeof (*layout));
+ 
+@@ -1914,48 +1985,45 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
+     grub_util_error ("invalid ELF header");
+ 
+   section_offset = grub_target_to_host (e->e_shoff);
+-  section_entsize = grub_target_to_host16 (e->e_shentsize);
+-  num_sections = grub_target_to_host16 (e->e_shnum);
++  smd.section_entsize = grub_target_to_host16 (e->e_shentsize);
++  smd.num_sections = grub_target_to_host16 (e->e_shnum);
+ 
+-  if (kernel_size < section_offset + (grub_uint32_t) section_entsize * num_sections)
++  if (kernel_size < section_offset
++		    + (grub_uint32_t) smd.section_entsize * smd.num_sections)
+     grub_util_error (_("premature end of file %s"), kernel_path);
+ 
+-  sections = (Elf_Shdr *) (kernel_img + section_offset);
++  smd.sections = (Elf_Shdr *) (kernel_img + section_offset);
+ 
+   /* Relocate sections then symbols in the virtual address space.  */
+-  s = (Elf_Shdr *) ((char *) sections
+-		      + grub_host_to_target16 (e->e_shstrndx) * section_entsize);
+-  strtab = (char *) e + grub_host_to_target_addr (s->sh_offset);
++  s = (Elf_Shdr *) ((char *) smd.sections
++		      + grub_host_to_target16 (e->e_shstrndx) * smd.section_entsize);
++  smd.strtab = (char *) e + grub_host_to_target_addr (s->sh_offset);
+ 
+-  section_addresses = SUFFIX (locate_sections) (e, kernel_path,
+-						sections, section_entsize,
+-						num_sections, strtab,
+-						layout,
+-						image_target);
++  smd.addrs = xmalloc (sizeof (*smd.addrs) * smd.num_sections);
++  memset (smd.addrs, 0, sizeof (*smd.addrs) * smd.num_sections);
++  smd.vaddrs = xmalloc (sizeof (*smd.vaddrs) * smd.num_sections);
++  memset (smd.vaddrs, 0, sizeof (*smd.vaddrs) * smd.num_sections);
+ 
+-  section_vaddresses = xmalloc (sizeof (*section_addresses) * num_sections);
+-
+-  for (i = 0; i < num_sections; i++)
+-    section_vaddresses[i] = section_addresses[i] + image_target->vaddr_offset;
++  SUFFIX (locate_sections) (e, kernel_path, &smd, layout, image_target);
+ 
+   if (!is_relocatable (image_target))
+     {
+       Elf_Addr current_address = layout->kernel_size;
+ 
+-      for (i = 0, s = sections;
+-	   i < num_sections;
+-	   i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
++      for (i = 0, s = smd.sections;
++	   i < smd.num_sections;
++	   i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize))
+ 	if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
+ 	  {
+ 	    Elf_Word sec_align = grub_host_to_target_addr (s->sh_addralign);
+-	    const char *name = strtab + grub_host_to_target32 (s->sh_name);
++	    const char *name = smd.strtab + grub_host_to_target32 (s->sh_name);
+ 
+ 	    if (sec_align)
+ 	      current_address = ALIGN_UP (current_address
+ 					  + image_target->vaddr_offset,
+ 					  sec_align)
+ 		- image_target->vaddr_offset;
+-	
++
+ 	    grub_util_info ("locating the section %s at 0x%"
+ 			    GRUB_HOST_PRIxLONG_LONG,
+ 			    name, (unsigned long long) current_address);
+@@ -1963,7 +2031,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
+ 	      current_address = grub_host_to_target_addr (s->sh_addr)
+ 		- image_target->link_addr;
+ 
+-	    section_vaddresses[i] = current_address
++	    smd.vaddrs[i] = current_address
+ 	      + image_target->vaddr_offset;
+ 	    current_address += grub_host_to_target_addr (s->sh_size);
+ 	  }
+@@ -1978,21 +2046,22 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
+   if (image_target->id == IMAGE_SPARC64_AOUT
+       || image_target->id == IMAGE_SPARC64_RAW
+       || image_target->id == IMAGE_UBOOT
++      || image_target->id == IMAGE_COREBOOT
+       || image_target->id == IMAGE_SPARC64_CDCORE)
+     layout->kernel_size = ALIGN_UP (layout->kernel_size, image_target->mod_align);
+ 
+   if (is_relocatable (image_target))
+     {
+-      symtab_section = NULL;
+-      for (i = 0, s = sections;
+-	   i < num_sections;
+-	   i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
++      smd.symtab = NULL;
++      for (i = 0, s = smd.sections;
++	   i < smd.num_sections;
++	   i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize))
+ 	if (s->sh_type == grub_host_to_target32 (SHT_SYMTAB))
+ 	  {
+-	    symtab_section = s;
++	    smd.symtab = s;
+ 	    break;
+ 	  }
+-      if (! symtab_section)
++      if (! smd.symtab)
+ 	grub_util_error ("%s", _("no symbol table"));
+ #ifdef MKIMAGE_ELF64
+       if (image_target->elf_target == EM_IA_64)
+@@ -2007,7 +2076,7 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
+ 	  layout->kernel_size += ALIGN_UP (tramp, 16);
+ 
+ 	  layout->ia64jmp_off = layout->kernel_size;
+-	  layout->ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section,
++	  layout->ia64jmpnum = SUFFIX (count_funcs) (e, smd.symtab,
+ 						     image_target);
+ 	  layout->kernel_size += 16 * layout->ia64jmpnum;
+ 
+@@ -2038,31 +2107,19 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
+ 
+   if (is_relocatable (image_target))
+     {
+-      layout->start_address = SUFFIX (relocate_symbols) (e, sections, symtab_section,
+-					  section_vaddresses, section_entsize,
+-					  num_sections, 
+-					  (char *) out_img + layout->ia64jmp_off, 
+-					  layout->ia64jmp_off 
+-					  + image_target->vaddr_offset,
+-							 layout->bss_start,
+-							 layout->end,
+-					  image_target);
++      layout->start_address = SUFFIX (relocate_symbols) (e, &smd,
++				  (char *) out_img + layout->ia64jmp_off,
++				  layout->ia64jmp_off + image_target->vaddr_offset,
++				  layout->bss_start, layout->end, image_target);
++
+       if (layout->start_address == (Elf_Addr) -1)
+ 	grub_util_error ("start symbol is not defined");
+ 
+-      /* Resolve addresses in the virtual address space.  */
+-      SUFFIX (relocate_addresses) (e, sections, section_addresses, 
+-				   section_entsize,
+-				   num_sections, strtab,
+-				   out_img, layout->tramp_off,
+-				   layout->got_off,
+-				   image_target);
++      /* Resolve addrs in the virtual address space.  */
++      SUFFIX (relocate_addrs) (e, &smd, out_img, layout->tramp_off,
++				   layout->got_off, image_target);
+ 
+-      make_reloc_section (e, layout,
+-			  section_vaddresses, sections,
+-			  section_entsize, num_sections,
+-			  strtab,
+-			  image_target);
++      make_reloc_section (e, layout, &smd, image_target);
+       if (image_target->id != IMAGE_EFI)
+ 	{
+ 	  out_img = xrealloc (out_img, layout->kernel_size + total_module_size
+@@ -2074,30 +2131,25 @@ SUFFIX (grub_mkimage_load_image) (const char *kernel_path,
+ 	}
+     }
+ 
+-  for (i = 0, s = sections;
+-       i < num_sections;
+-       i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+-    if (SUFFIX (is_data_section) (s, image_target)
+-	/* Explicitly initialize BSS
+-	   when producing PE32 to avoid a bug in EFI implementations.
+-	   Platforms other than EFI and U-boot shouldn't have .bss in
+-	   their binaries as we build with -Wl,-Ttext.
+-	*/
+-	|| (SUFFIX (is_bss_section) (s, image_target) && (image_target->id != IMAGE_UBOOT))
+-	|| SUFFIX (is_text_section) (s, image_target))
++  for (i = 0, s = smd.sections;
++       i < smd.num_sections;
++       i++, s = (Elf_Shdr *) ((char *) s + smd.section_entsize))
++    if (SUFFIX (is_kept_section) (s, image_target))
+       {
+ 	if (grub_target_to_host32 (s->sh_type) == SHT_NOBITS)
+-	  memset (out_img + section_addresses[i], 0,
++	  memset (out_img + smd.addrs[i], 0,
+ 		  grub_host_to_target_addr (s->sh_size));
+ 	else
+-	  memcpy (out_img + section_addresses[i],
++	  memcpy (out_img + smd.addrs[i],
+ 		  kernel_img + grub_host_to_target_addr (s->sh_offset),
+ 		  grub_host_to_target_addr (s->sh_size));
+       }
+   free (kernel_img);
+ 
+-  free (section_vaddresses);
+-  free (section_addresses);
++  free (smd.vaddrs);
++  smd.vaddrs = NULL;
++  free (smd.addrs);
++  smd.addrs = NULL;
+ 
+   return out_img;
+ }
+diff --git a/util/grub-mkrescue.c b/util/grub-mkrescue.c
+index 238d4840e2f9613c6392e16cb88e7f413cae41c4..9545945d8f3b1a85dea8404fe1a0c9b3a3b84ba1 100644
+--- a/util/grub-mkrescue.c
++++ b/util/grub-mkrescue.c
+@@ -323,6 +323,7 @@ check_xorriso (const char *val)
+   char *buf = NULL;
+   size_t len = 0;
+   int ret = 0;
++  int wstatus = 0;
+ 
+   argv[0] = xorriso;
+   argv[1] = "-as";
+@@ -347,8 +348,10 @@ check_xorriso (const char *val)
+     }
+ 
+   close (fd);
+-  waitpid (pid, NULL, 0);
++  waitpid (pid, &wstatus, 0);
+   free (buf);
++  if (!WIFEXITED (wstatus) || WEXITSTATUS(wstatus) != 0)
++    return 0;
+   return ret;
+ }
+ 
+@@ -426,6 +429,7 @@ main (int argc, char *argv[])
+   char **argp_argv;
+   int xorriso_tail_argc;
+   char **xorriso_tail_argv;
++  int rv;
+ 
+   grub_util_host_init (&argc, &argv);
+   grub_util_disable_fd_syncs ();
+@@ -478,6 +482,10 @@ main (int argc, char *argv[])
+   if (!output_image)
+     grub_util_error ("%s", _("output file must be specified"));
+ 
++  if (!check_xorriso ("graft-points")) {
++    grub_util_error ("%s", _("xorriso not found"));
++  }
++
+   grub_init_all ();
+   grub_hostfs_init ();
+   grub_host_init ();
+@@ -787,7 +795,6 @@ main (int argc, char *argv[])
+       free (efidir_efi_boot);
+ 
+       efiimgfat = grub_util_path_concat (2, iso9660_dir, "efi.img");
+-      int rv;
+       rv = grub_util_exec ((const char * []) { "mformat", "-C", "-f", "2880", "-L", "16", "-i",
+ 	    efiimgfat, "::", NULL });
+       if (rv != 0)
+@@ -960,7 +967,9 @@ main (int argc, char *argv[])
+ 
+   xorriso_argv[xorriso_argc] = NULL;
+ 
+-  grub_util_exec ((const char *const *)xorriso_argv);
++  rv = grub_util_exec ((const char *const *)xorriso_argv);
++  if (rv != 0)
++    grub_util_error ("`%s` invocation failed\n", "xorriso");
+ 
+   grub_util_unlink_recursive (iso9660_dir);
+ 
+diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c
+index 9179285a5ffe5d641a4c2726ce8367dba623d29e..a79271f663166f4d302e1f73d1bcd400c9e8604e 100644
+--- a/util/grub-module-verifier.c
++++ b/util/grub-module-verifier.c
+@@ -19,6 +19,7 @@ struct grub_module_verifier_arch archs[] = {
+       -1
+     }, (int[]){
+       R_X86_64_PC32,
++      R_X86_64_PLT32,
+       -1
+     }
+   },
+diff --git a/util/grub-probe.c b/util/grub-probe.c
+index 8ac527d2f2a17142c5cf873d27c5818477d2c1a4..e45dbf9e049bd41f3122793330b2d0f7bcc844f8 100644
+--- a/util/grub-probe.c
++++ b/util/grub-probe.c
+@@ -28,6 +28,7 @@
+ #include <grub/partition.h>
+ #include <grub/msdos_partition.h>
+ #include <grub/gpt_partition.h>
++#include <grub/i386/pc/boot.h>
+ #include <grub/emu/hostdisk.h>
+ #include <grub/emu/getroot.h>
+ #include <grub/term.h>
+@@ -62,6 +63,7 @@ enum {
+   PRINT_DRIVE,
+   PRINT_DEVICE,
+   PRINT_PARTMAP,
++  PRINT_PARTUUID,
+   PRINT_ABSTRACTION,
+   PRINT_CRYPTODISK_UUID,
+   PRINT_HINT_STR,
+@@ -85,6 +87,7 @@ static const char *targets[] =
+     [PRINT_DRIVE]              = "drive",
+     [PRINT_DEVICE]             = "device",
+     [PRINT_PARTMAP]            = "partmap",
++    [PRINT_PARTUUID]           = "partuuid",
+     [PRINT_ABSTRACTION]        = "abstraction",
+     [PRINT_CRYPTODISK_UUID]    = "cryptodisk_uuid",
+     [PRINT_HINT_STR]           = "hints_string",
+@@ -129,6 +132,20 @@ get_targets_string (void)
+   return str;
+ }
+ 
++static int
++print_gpt_guid (grub_gpt_part_guid_t guid)
++{
++  guid.data1 = grub_le_to_cpu32 (guid.data1);
++  guid.data2 = grub_le_to_cpu16 (guid.data2);
++  guid.data3 = grub_le_to_cpu16 (guid.data3);
++
++  return grub_printf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
++		      guid.data1, guid.data2, guid.data3, guid.data4[0],
++		      guid.data4[1], guid.data4[2], guid.data4[3],
++		      guid.data4[4], guid.data4[5], guid.data4[6],
++		      guid.data4[7]);
++}
++
+ static void
+ do_print (const char *x, void *data)
+ {
+@@ -167,6 +184,45 @@ probe_partmap (grub_disk_t disk, char delim)
+     }
+ }
+ 
++static void
++probe_partuuid (grub_disk_t disk, char delim)
++{
++  grub_partition_t p = disk->partition;
++
++  /*
++   * Nested partitions not supported for now.
++   * Non-nested partitions must have disk->partition->parent == NULL
++   */
++  if (p && p->parent == NULL)
++    {
++      disk->partition = p->parent;
++
++      if (strcmp(p->partmap->name, "msdos") == 0)
++	{
++	    /*
++	     * The partition GUID for MSDOS is the partition number (starting
++	     * with 1) prepended with the NT disk signature.
++	     */
++	    grub_uint32_t nt_disk_sig;
++
++	    if (grub_disk_read (disk, 0, GRUB_BOOT_MACHINE_WINDOWS_NT_MAGIC,
++				sizeof(nt_disk_sig), &nt_disk_sig) == 0)
++	      grub_printf ("%08x-%02x",
++			   grub_le_to_cpu32(nt_disk_sig), 1 + p->number);
++	}
++      else if (strcmp(p->partmap->name, "gpt") == 0)
++	{
++	  struct grub_gpt_partentry gptdata;
++
++	  if (grub_disk_read (disk, p->offset, p->index,
++			      sizeof(gptdata), &gptdata) == 0)
++	    print_gpt_guid(gptdata.guid);
++	}
++
++      disk->partition = p;
++    }
++}
++
+ static void
+ probe_cryptodisk_uuid (grub_disk_t disk, char delim)
+ {
+@@ -621,6 +677,12 @@ probe (const char *path, char **device_names, char delim)
+ 	/* Check if dev->disk itself is contained in a partmap.  */
+ 	probe_partmap (dev->disk, delim);
+ 
++      else if (print == PRINT_PARTUUID)
++	{
++	  probe_partuuid (dev->disk, delim);
++	  putchar (delim);
++	}
++
+       else if (print == PRINT_MSDOS_PARTTYPE)
+ 	{
+ 	  if (dev->disk->partition
+@@ -641,21 +703,7 @@ probe (const char *path, char **device_names, char delim)
+ 
+               if (grub_disk_read (dev->disk, p->offset, p->index,
+                                   sizeof (gptdata), &gptdata) == 0)
+-                {
+-                  grub_gpt_part_type_t gpttype;
+-                  gpttype.data1 = grub_le_to_cpu32 (gptdata.type.data1);
+-                  gpttype.data2 = grub_le_to_cpu16 (gptdata.type.data2);
+-                  gpttype.data3 = grub_le_to_cpu16 (gptdata.type.data3);
+-                  grub_memcpy (gpttype.data4, gptdata.type.data4, 8);
+-
+-                  grub_printf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+-                               gpttype.data1, gpttype.data2,
+-                               gpttype.data3, gpttype.data4[0], 
+-                               gpttype.data4[1], gpttype.data4[2],
+-                               gpttype.data4[3], gpttype.data4[4],
+-                               gpttype.data4[5], gpttype.data4[6],
+-                               gpttype.data4[7]);
+-                }
++		print_gpt_guid(gptdata.type);
+               dev->disk->partition = p;
+             }
+           putchar (delim);
+diff --git a/util/ieee1275/grub-ofpathname.c b/util/ieee1275/grub-ofpathname.c
+index 8e5d766cb63871c1479a42626c8cfa7fddd6f771..300fbddad7c54e2b52d90a7de5eb868a9a1ae705 100644
+--- a/util/ieee1275/grub-ofpathname.c
++++ b/util/ieee1275/grub-ofpathname.c
+@@ -46,7 +46,9 @@ int main(int argc, char **argv)
+     }
+ 
+   of_path = grub_util_devname_to_ofpath (argv[1]);
+-  printf("%s\n", of_path);
++
++  if (of_path)
++    printf ("%s\n", of_path);
+ 
+   free (of_path);
+ 
+diff --git a/util/mkimage.c b/util/mkimage.c
+index 9ad4cfe4223b661c11ab9d3783cb13c88100631c..e22d82afa61a6aa4209c7ab6d2aa5b58f95e1bfe 100644
+--- a/util/mkimage.c
++++ b/util/mkimage.c
+@@ -533,6 +533,45 @@ static const struct grub_install_image_target_desc image_targets[] =
+       .mod_align = GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN,
+       .link_align = 4
+     },
++    /* For coreboot versions that don't support self-relocating images. */
++    {
++      .dirname = "arm-coreboot-vexpress",
++      .names = { "arm-coreboot-vexpress", NULL },
++      .voidp_sizeof = 4,
++      .bigendian = 0,
++      .id = IMAGE_COREBOOT,
++      .flags = PLATFORM_FLAGS_NONE,
++      .total_module_size = GRUB_KERNEL_ARM_COREBOOT_TOTAL_MODULE_SIZE,
++      .decompressor_compressed_size = TARGET_NO_FIELD,
++      .decompressor_uncompressed_size = TARGET_NO_FIELD,
++      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
++      .section_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN,
++      .vaddr_offset = 0,
++      .elf_target = EM_ARM,
++      .mod_gap = GRUB_KERNEL_ARM_COREBOOT_MOD_GAP,
++      .mod_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN,
++      .link_align = 4,
++      .link_addr = 0x62000000,
++    },
++    {
++      .dirname = "arm-coreboot-veyron",
++      .names = { "arm-coreboot-veyron", NULL },
++      .voidp_sizeof = 4,
++      .bigendian = 0,
++      .id = IMAGE_COREBOOT,
++      .flags = PLATFORM_FLAGS_NONE,
++      .total_module_size = GRUB_KERNEL_ARM_COREBOOT_TOTAL_MODULE_SIZE,
++      .decompressor_compressed_size = TARGET_NO_FIELD,
++      .decompressor_uncompressed_size = TARGET_NO_FIELD,
++      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
++      .section_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN,
++      .vaddr_offset = 0,
++      .elf_target = EM_ARM,
++      .mod_gap = GRUB_KERNEL_ARM_COREBOOT_MOD_GAP,
++      .mod_align = GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN,
++      .link_align = 4,
++      .link_addr = 0x43000000,
++    },
+     {
+       .dirname = "arm-efi",
+       .names = { "arm-efi", NULL },
+@@ -738,13 +777,12 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ 			     char *memdisk_path, char **pubkey_paths,
+ 			     size_t npubkeys, char *config_path,
+ 			     const struct grub_install_image_target_desc *image_target,
+-			     int note,
+-			     grub_compression_t comp)
++			     int note, grub_compression_t comp, const char *dtb_path)
+ {
+   char *kernel_img, *core_img;
+   size_t total_module_size, core_size;
+   size_t memdisk_size = 0, config_size = 0;
+-  size_t prefix_size = 0;
++  size_t prefix_size = 0, dtb_size = 0;
+   char *kernel_path;
+   size_t offset;
+   struct grub_util_path_list *path_list, *p;
+@@ -789,6 +827,12 @@ grub_install_generate_image (const char *dir, const char *prefix,
+       total_module_size += memdisk_size + sizeof (struct grub_module_header);
+     }
+ 
++  if (dtb_path)
++    {
++      dtb_size = ALIGN_UP(grub_util_get_image_size (dtb_path), 4);
++      total_module_size += dtb_size + sizeof (struct grub_module_header);
++    }
++
+   if (config_path)
+     {
+       config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1);
+@@ -911,6 +955,19 @@ grub_install_generate_image (const char *dir, const char *prefix,
+       offset += memdisk_size;
+     }
+ 
++  if (dtb_path)
++    {
++      struct grub_module_header *header;
++
++      header = (struct grub_module_header *) (kernel_img + offset);
++      header->type = grub_host_to_target32 (OBJ_TYPE_DTB);
++      header->size = grub_host_to_target32 (dtb_size + sizeof (*header));
++      offset += sizeof (*header);
++
++      grub_util_load_image (dtb_path, kernel_img + offset);
++      offset += dtb_size;
++    }
++
+   if (config_path)
+     {
+       struct grub_module_header *header;
+@@ -1033,7 +1090,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ 	/* fallthrough */
+     case IMAGE_COREBOOT:
+     case IMAGE_QEMU:
+-	if (layout.kernel_size + layout.bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000)
++	if (image_target->elf_target != EM_ARM && layout.kernel_size + layout.bss_size + GRUB_KERNEL_I386_PC_LINK_ADDR > 0x68000)
+ 	  grub_util_error (_("kernel image is too big (0x%x > 0x%x)"),
+ 			   (unsigned) layout.kernel_size + (unsigned) layout.bss_size
+ 			   + GRUB_KERNEL_I386_PC_LINK_ADDR,
+@@ -1638,10 +1695,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ 	  target_addr = image_target->link_addr;
+ 	if (image_target->voidp_sizeof == 4)
+ 	  grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size,
+-				       target_addr, layout.align, layout.kernel_size, layout.bss_size);
++				       target_addr, &layout);
+ 	else
+ 	  grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size,
+-				       target_addr, layout.align, layout.kernel_size, layout.bss_size);
++				       target_addr, &layout);
+       }
+       break;
+     }
+diff --git a/util/setup.c b/util/setup.c
+index 8aa5a39a79465c33b0ff6a5a6b1bc82128df2e18..9c1e1b7da6a85ea7aece6433f2eaf81a6ccde451 100644
+--- a/util/setup.c
++++ b/util/setup.c
+@@ -137,6 +137,9 @@ struct blocklists
+   struct grub_boot_blocklist *first_block, *block;
+ #ifdef GRUB_SETUP_BIOS
+   grub_uint16_t current_segment;
++#endif
++#ifdef GRUB_SETUP_SPARC64
++  grub_uint64_t gpt_offset;
+ #endif
+   grub_uint16_t last_length;
+   grub_disk_addr_t first_sector;
+@@ -151,6 +154,10 @@ save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length,
+   struct grub_boot_blocklist *prev = bl->block + 1;
+   grub_uint64_t seclen;
+ 
++#ifdef GRUB_SETUP_SPARC64
++  sector -= bl->gpt_offset;
++#endif
++
+   grub_util_info ("saving <%"  GRUB_HOST_PRIuLONG_LONG ",%u,%u>",
+ 		  (unsigned long long) sector, offset, length);
+ 
+@@ -298,9 +305,8 @@ SETUP (const char *dir,
+   bl.first_block = (struct grub_boot_blocklist *) (core_img
+ 						   + GRUB_DISK_SECTOR_SIZE
+ 						   - sizeof (*bl.block));
+-  grub_util_info ("root is `%s', dest is `%s'", root, dest);
+ 
+-  grub_util_info ("Opening dest");
++  grub_util_info ("Opening dest `%s'", dest);
+   dest_dev = grub_device_open (dest);
+   if (! dest_dev)
+     grub_util_error ("%s", grub_errmsg);
+@@ -662,6 +668,16 @@ unable_to_embed:
+ 
+   bl.block = bl.first_block;
+ 
++#ifdef GRUB_SETUP_SPARC64
++  {
++    grub_partition_t container = root_dev->disk->partition;
++    bl.gpt_offset = 0;
++
++    if (grub_strstr (container->partmap->name, "gpt"))
++      bl.gpt_offset = grub_partition_get_start (container);
++  }
++#endif
++
+   grub_install_get_blocklist (root_dev, core_path, core_img, core_size,
+ 			      save_blocklists, &bl);
+ 
+@@ -721,15 +737,18 @@ unable_to_embed:
+   {
+     char *buf, *ptr = core_img;
+     size_t len = core_size;
+-    grub_uint64_t blk;
++    grub_uint64_t blk, offset = 0;
+     grub_partition_t container = core_dev->disk->partition;
+     grub_err_t err;
+ 
+     core_dev->disk->partition = 0;
++#ifdef GRUB_SETUP_SPARC64
++    offset = bl.gpt_offset;
++#endif
+ 
+     buf = xmalloc (core_size);
+     blk = bl.first_sector;
+-    err = grub_disk_read (core_dev->disk, blk, 0, GRUB_DISK_SECTOR_SIZE, buf);
++    err = grub_disk_read (core_dev->disk, blk + offset, 0, GRUB_DISK_SECTOR_SIZE, buf);
+     if (err)
+       grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
+ 		       grub_errmsg);
+@@ -748,7 +767,7 @@ unable_to_embed:
+ 	if (cur > len)
+ 	  cur = len;
+ 
+-	err = grub_disk_read (core_dev->disk, blk, 0, cur, buf);
++	err = grub_disk_read (core_dev->disk, blk + offset, 0, cur, buf);
+ 	if (err)
+ 	  grub_util_error (_("cannot read `%s': %s"), core_dev->disk->name,
+ 			   grub_errmsg);
+diff --git a/grub-core/lib/libgcrypt/cipher/bufhelp.h b/grub-core/lib/libgcrypt/cipher/bufhelp.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..df3559472312d8c6c0c038e27571c546ce489283
+--- /dev/null
++++ b/grub-core/lib/libgcrypt/cipher/bufhelp.h
+@@ -0,0 +1,432 @@
++/* bufhelp.h  -  Some buffer manipulation helpers
++ * Copyright (C) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
++ *
++ * This file is part of Libgcrypt.
++ *
++ * Libgcrypt is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as
++ * published by the Free Software Foundation; either version 2.1 of
++ * the License, or (at your option) any later version.
++ *
++ * Libgcrypt 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++#ifndef GCRYPT_BUFHELP_H
++#define GCRYPT_BUFHELP_H
++
++
++#include "bithelp.h"
++
++
++#undef BUFHELP_FAST_UNALIGNED_ACCESS
++#if defined(HAVE_GCC_ATTRIBUTE_PACKED) && \
++    defined(HAVE_GCC_ATTRIBUTE_ALIGNED) && \
++    (defined(__i386__) || defined(__x86_64__) || \
++     (defined(__arm__) && defined(__ARM_FEATURE_UNALIGNED)) || \
++     defined(__aarch64__))
++/* These architectures are able of unaligned memory accesses and can
++   handle those fast.
++ */
++# define BUFHELP_FAST_UNALIGNED_ACCESS 1
++#endif
++
++
++#ifdef BUFHELP_FAST_UNALIGNED_ACCESS
++/* Define type with one-byte alignment on architectures with fast unaligned
++   memory accesses.
++ */
++typedef struct bufhelp_int_s
++{
++  uintptr_t a;
++} __attribute__((packed, aligned(1))) bufhelp_int_t;
++#else
++/* Define type with default alignment for other architectures (unaligned
++   accessed handled in per byte loops).
++ */
++typedef struct bufhelp_int_s
++{
++  uintptr_t a;
++} bufhelp_int_t;
++#endif
++
++
++/* Optimized function for small buffer copying */
++static inline void
++buf_cpy(void *_dst, const void *_src, size_t len)
++{
++#if __GNUC__ >= 4 && (defined(__x86_64__) || defined(__i386__))
++  /* For AMD64 and i386, memcpy is faster.  */
++  memcpy(_dst, _src, len);
++#else
++  byte *dst = _dst;
++  const byte *src = _src;
++  bufhelp_int_t *ldst;
++  const bufhelp_int_t *lsrc;
++#ifndef BUFHELP_FAST_UNALIGNED_ACCESS
++  const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
++
++  /* Skip fast processing if buffers are unaligned.  */
++  if (((uintptr_t)dst | (uintptr_t)src) & longmask)
++    goto do_bytes;
++#endif
++
++  ldst = (bufhelp_int_t *)(void *)dst;
++  lsrc = (const bufhelp_int_t *)(const void *)src;
++
++  for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
++    (ldst++)->a = (lsrc++)->a;
++
++  dst = (byte *)ldst;
++  src = (const byte *)lsrc;
++
++#ifndef BUFHELP_FAST_UNALIGNED_ACCESS
++do_bytes:
++#endif
++  /* Handle tail.  */
++  for (; len; len--)
++    *dst++ = *src++;
++#endif /*__GNUC__ >= 4 && (__x86_64__ || __i386__)*/
++}
++
++
++/* Optimized function for buffer xoring */
++static inline void
++buf_xor(void *_dst, const void *_src1, const void *_src2, size_t len)
++{
++  byte *dst = _dst;
++  const byte *src1 = _src1;
++  const byte *src2 = _src2;
++  bufhelp_int_t *ldst;
++  const bufhelp_int_t *lsrc1, *lsrc2;
++#ifndef BUFHELP_FAST_UNALIGNED_ACCESS
++  const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
++
++  /* Skip fast processing if buffers are unaligned.  */
++  if (((uintptr_t)dst | (uintptr_t)src1 | (uintptr_t)src2) & longmask)
++    goto do_bytes;
++#endif
++
++  ldst = (bufhelp_int_t *)(void *)dst;
++  lsrc1 = (const bufhelp_int_t *)(const void *)src1;
++  lsrc2 = (const bufhelp_int_t *)(const void *)src2;
++
++  for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
++    (ldst++)->a = (lsrc1++)->a ^ (lsrc2++)->a;
++
++  dst = (byte *)ldst;
++  src1 = (const byte *)lsrc1;
++  src2 = (const byte *)lsrc2;
++
++#ifndef BUFHELP_FAST_UNALIGNED_ACCESS
++do_bytes:
++#endif
++  /* Handle tail.  */
++  for (; len; len--)
++    *dst++ = *src1++ ^ *src2++;
++}
++
++
++/* Optimized function for in-place buffer xoring. */
++static inline void
++buf_xor_1(void *_dst, const void *_src, size_t len)
++{
++  byte *dst = _dst;
++  const byte *src = _src;
++  bufhelp_int_t *ldst;
++  const bufhelp_int_t *lsrc;
++#ifndef BUFHELP_FAST_UNALIGNED_ACCESS
++  const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
++
++  /* Skip fast processing if buffers are unaligned.  */
++  if (((uintptr_t)dst | (uintptr_t)src) & longmask)
++    goto do_bytes;
++#endif
++
++  ldst = (bufhelp_int_t *)(void *)dst;
++  lsrc = (const bufhelp_int_t *)(const void *)src;
++
++  for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
++    (ldst++)->a ^= (lsrc++)->a;
++
++  dst = (byte *)ldst;
++  src = (const byte *)lsrc;
++
++#ifndef BUFHELP_FAST_UNALIGNED_ACCESS
++do_bytes:
++#endif
++  /* Handle tail.  */
++  for (; len; len--)
++    *dst++ ^= *src++;
++}
++
++
++/* Optimized function for buffer xoring with two destination buffers.  Used
++   mainly by CFB mode encryption.  */
++static inline void
++buf_xor_2dst(void *_dst1, void *_dst2, const void *_src, size_t len)
++{
++  byte *dst1 = _dst1;
++  byte *dst2 = _dst2;
++  const byte *src = _src;
++  bufhelp_int_t *ldst1, *ldst2;
++  const bufhelp_int_t *lsrc;
++#ifndef BUFHELP_FAST_UNALIGNED_ACCESS
++  const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
++
++  /* Skip fast processing if buffers are unaligned.  */
++  if (((uintptr_t)src | (uintptr_t)dst1 | (uintptr_t)dst2) & longmask)
++    goto do_bytes;
++#endif
++
++  ldst1 = (bufhelp_int_t *)(void *)dst1;
++  ldst2 = (bufhelp_int_t *)(void *)dst2;
++  lsrc = (const bufhelp_int_t *)(const void *)src;
++
++  for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
++    (ldst1++)->a = ((ldst2++)->a ^= (lsrc++)->a);
++
++  dst1 = (byte *)ldst1;
++  dst2 = (byte *)ldst2;
++  src = (const byte *)lsrc;
++
++#ifndef BUFHELP_FAST_UNALIGNED_ACCESS
++do_bytes:
++#endif
++  /* Handle tail.  */
++  for (; len; len--)
++    *dst1++ = (*dst2++ ^= *src++);
++}
++
++
++/* Optimized function for combined buffer xoring and copying.  Used by mainly
++   CBC mode decryption.  */
++static inline void
++buf_xor_n_copy_2(void *_dst_xor, const void *_src_xor, void *_srcdst_cpy,
++		 const void *_src_cpy, size_t len)
++{
++  byte *dst_xor = _dst_xor;
++  byte *srcdst_cpy = _srcdst_cpy;
++  const byte *src_xor = _src_xor;
++  const byte *src_cpy = _src_cpy;
++  byte temp;
++  bufhelp_int_t *ldst_xor, *lsrcdst_cpy;
++  const bufhelp_int_t *lsrc_cpy, *lsrc_xor;
++  uintptr_t ltemp;
++#ifndef BUFHELP_FAST_UNALIGNED_ACCESS
++  const unsigned int longmask = sizeof(bufhelp_int_t) - 1;
++
++  /* Skip fast processing if buffers are unaligned.  */
++  if (((uintptr_t)src_cpy | (uintptr_t)src_xor | (uintptr_t)dst_xor |
++       (uintptr_t)srcdst_cpy) & longmask)
++    goto do_bytes;
++#endif
++
++  ldst_xor = (bufhelp_int_t *)(void *)dst_xor;
++  lsrc_xor = (const bufhelp_int_t *)(void *)src_xor;
++  lsrcdst_cpy = (bufhelp_int_t *)(void *)srcdst_cpy;
++  lsrc_cpy = (const bufhelp_int_t *)(const void *)src_cpy;
++
++  for (; len >= sizeof(bufhelp_int_t); len -= sizeof(bufhelp_int_t))
++    {
++      ltemp = (lsrc_cpy++)->a;
++      (ldst_xor++)->a = (lsrcdst_cpy)->a ^ (lsrc_xor++)->a;
++      (lsrcdst_cpy++)->a = ltemp;
++    }
++
++  dst_xor = (byte *)ldst_xor;
++  src_xor = (const byte *)lsrc_xor;
++  srcdst_cpy = (byte *)lsrcdst_cpy;
++  src_cpy = (const byte *)lsrc_cpy;
++
++#ifndef BUFHELP_FAST_UNALIGNED_ACCESS
++do_bytes:
++#endif
++  /* Handle tail.  */
++  for (; len; len--)
++    {
++      temp = *src_cpy++;
++      *dst_xor++ = *srcdst_cpy ^ *src_xor++;
++      *srcdst_cpy++ = temp;
++    }
++}
++
++
++/* Optimized function for combined buffer xoring and copying.  Used by mainly
++   CFB mode decryption.  */
++static inline void
++buf_xor_n_copy(void *_dst_xor, void *_srcdst_cpy, const void *_src, size_t len)
++{
++  buf_xor_n_copy_2(_dst_xor, _src, _srcdst_cpy, _src, len);
++}
++
++
++/* Constant-time compare of two buffers.  Returns 1 if buffers are equal,
++   and 0 if buffers differ.  */
++static inline int
++buf_eq_const(const void *_a, const void *_b, size_t len)
++{
++  const byte *a = _a;
++  const byte *b = _b;
++  size_t diff, i;
++
++  /* Constant-time compare. */
++  for (i = 0, diff = 0; i < len; i++)
++    diff -= !!(a[i] - b[i]);
++
++  return !diff;
++}
++
++
++#ifndef BUFHELP_FAST_UNALIGNED_ACCESS
++
++/* Functions for loading and storing unaligned u32 values of different
++   endianness.  */
++static inline u32 buf_get_be32(const void *_buf)
++{
++  const byte *in = _buf;
++  return ((u32)in[0] << 24) | ((u32)in[1] << 16) | \
++         ((u32)in[2] << 8) | (u32)in[3];
++}
++
++static inline u32 buf_get_le32(const void *_buf)
++{
++  const byte *in = _buf;
++  return ((u32)in[3] << 24) | ((u32)in[2] << 16) | \
++         ((u32)in[1] << 8) | (u32)in[0];
++}
++
++static inline void buf_put_be32(void *_buf, u32 val)
++{
++  byte *out = _buf;
++  out[0] = val >> 24;
++  out[1] = val >> 16;
++  out[2] = val >> 8;
++  out[3] = val;
++}
++
++static inline void buf_put_le32(void *_buf, u32 val)
++{
++  byte *out = _buf;
++  out[3] = val >> 24;
++  out[2] = val >> 16;
++  out[1] = val >> 8;
++  out[0] = val;
++}
++
++
++/* Functions for loading and storing unaligned u64 values of different
++   endianness.  */
++static inline u64 buf_get_be64(const void *_buf)
++{
++  const byte *in = _buf;
++  return ((u64)in[0] << 56) | ((u64)in[1] << 48) | \
++         ((u64)in[2] << 40) | ((u64)in[3] << 32) | \
++         ((u64)in[4] << 24) | ((u64)in[5] << 16) | \
++         ((u64)in[6] << 8) | (u64)in[7];
++}
++
++static inline u64 buf_get_le64(const void *_buf)
++{
++  const byte *in = _buf;
++  return ((u64)in[7] << 56) | ((u64)in[6] << 48) | \
++         ((u64)in[5] << 40) | ((u64)in[4] << 32) | \
++         ((u64)in[3] << 24) | ((u64)in[2] << 16) | \
++         ((u64)in[1] << 8) | (u64)in[0];
++}
++
++static inline void buf_put_be64(void *_buf, u64 val)
++{
++  byte *out = _buf;
++  out[0] = val >> 56;
++  out[1] = val >> 48;
++  out[2] = val >> 40;
++  out[3] = val >> 32;
++  out[4] = val >> 24;
++  out[5] = val >> 16;
++  out[6] = val >> 8;
++  out[7] = val;
++}
++
++static inline void buf_put_le64(void *_buf, u64 val)
++{
++  byte *out = _buf;
++  out[7] = val >> 56;
++  out[6] = val >> 48;
++  out[5] = val >> 40;
++  out[4] = val >> 32;
++  out[3] = val >> 24;
++  out[2] = val >> 16;
++  out[1] = val >> 8;
++  out[0] = val;
++}
++
++#else /*BUFHELP_FAST_UNALIGNED_ACCESS*/
++
++typedef struct bufhelp_u32_s
++{
++  u32 a;
++} __attribute__((packed, aligned(1))) bufhelp_u32_t;
++
++/* Functions for loading and storing unaligned u32 values of different
++   endianness.  */
++static inline u32 buf_get_be32(const void *_buf)
++{
++  return be_bswap32(((const bufhelp_u32_t *)_buf)->a);
++}
++
++static inline u32 buf_get_le32(const void *_buf)
++{
++  return le_bswap32(((const bufhelp_u32_t *)_buf)->a);
++}
++
++static inline void buf_put_be32(void *_buf, u32 val)
++{
++  bufhelp_u32_t *out = _buf;
++  out->a = be_bswap32(val);
++}
++
++static inline void buf_put_le32(void *_buf, u32 val)
++{
++  bufhelp_u32_t *out = _buf;
++  out->a = le_bswap32(val);
++}
++
++
++typedef struct bufhelp_u64_s
++{
++  u64 a;
++} __attribute__((packed, aligned(1))) bufhelp_u64_t;
++
++/* Functions for loading and storing unaligned u64 values of different
++   endianness.  */
++static inline u64 buf_get_be64(const void *_buf)
++{
++  return be_bswap64(((const bufhelp_u64_t *)_buf)->a);
++}
++
++static inline u64 buf_get_le64(const void *_buf)
++{
++  return le_bswap64(((const bufhelp_u64_t *)_buf)->a);
++}
++
++static inline void buf_put_be64(void *_buf, u64 val)
++{
++  bufhelp_u64_t *out = _buf;
++  out->a = be_bswap64(val);
++}
++
++static inline void buf_put_le64(void *_buf, u64 val)
++{
++  bufhelp_u64_t *out = _buf;
++  out->a = le_bswap64(val);
++}
++
++
++#endif /*BUFHELP_FAST_UNALIGNED_ACCESS*/
++
++#endif /*GCRYPT_BUFHELP_H*/
+diff --git a/grub-core/tests/checksums.h b/grub-core/tests/checksums.h
+index 68d8ce7c7753ff721ab0d5a12d40b2aff20c694c..8273bd105deec0bf21f507e0eddb867f104afc5d 100644
+--- a/grub-core/tests/checksums.h
++++ b/grub-core/tests/checksums.h
+@@ -1,129 +1,129 @@
+-  { "cmdline_cat", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xcd5fc34e, 0xcd5fc34e, 0xeabbecab, 0xeabbecab, 0xc9950151, 0xc9950151, 0x2be222b6, 0x2be222b6, 0xe88c769e, 0xe88c769e, 0x6be4910e, 0x6be4910e, 0x1dc1fe4f, 0x1dc1fe4f, 0xd7613e8f, 0xd7613e8f, 0xf8124196, 0xf8124196, 0x130f5935, 0x130f5935, 0x2872330e, 0x2872330e, 0xaa7b7868, 0xaa7b7868, 0x558eaeea, 0x558eaeea, 0x92f7960f, 0x92f7960f, 0xc5bfc709, 0xc5bfc709, 0x699732fe, 0x699732fe, 0xc859125f, 0xc859125f, 0xfc6ac729, 0xfc6ac729, 0xcdab6cd4, 0xcdab6cd4, 0x58a8b7f8, 0x58a8b7f8, 0xc0e73385, 0x6560d6ef, 0x3be8bb5d, 0x3be8bb5d, }, 45 },
+-  { "cmdline_cat", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x13029f94, 0x13029f94, 0x7785fdab, 0x7785fdab, 0x95a7c1e8, 0x95a7c1e8, 0x315ab3e3, 0x315ab3e3, 0x6787f012, 0x6787f012, 0x79b1ecdc, 0x79b1ecdc, 0xdbc67810, 0xdbc67810, 0xafaa982e, 0xafaa982e, 0xc5cd0157, 0xc5cd0157, 0x3c50dd64, 0x3c50dd64, 0x1056cac0, 0x1056cac0, 0x1d7a41fa, 0x1d7a41fa, 0x5690b1e8, 0x5690b1e8, 0x616831d6, 0x616831d6, 0xfaf8e726, 0xfaf8e726, 0xd1ec5e26, 0xd1ec5e26, 0x3c269e1f, 0x3c269e1f, 0x1aa7952d, 0x1aa7952d, 0x6e7e2f99, 0x6e7e2f99, 0x98f4c02, 0x98f4c02, 0xc3f1abf2, 0xe348bb73, 0xea53cd60, 0xea53cd60, }, 45 },
+-  { "cmdline_cat", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x8fbb4f4c, 0x8fbb4f4c, 0x5dc00167, 0x5dc00167, 0xbc124df8, 0xbc124df8, 0x31cf0f8e, 0x31cf0f8e, 0x798cc4ed, 0x798cc4ed, 0xc5d2a091, 0xc5d2a091, 0xb58a0591, 0xb58a0591, 0x4d118aca, 0x4d118aca, 0xbb06c7ee, 0xbb06c7ee, 0x42179db7, 0x42179db7, 0x65f2d81e, 0x65f2d81e, 0xa2628bcb, 0xa2628bcb, 0xbdb7f4b, 0xbdb7f4b, 0x66b10309, 0x66b10309, 0x1a550ea9, 0x1a550ea9, 0x377a297d, 0x377a297d, 0x2ea99015, 0x2ea99015, 0x4e20d7bc, 0x4e20d7bc, 0x8ecbde02, 0x8ecbde02, 0xdfa2195a, 0xdfa2195a, 0xe113d2a, 0xe204ee5b, 0x734679c1, 0x734679c1, }, 45 },
+-  { "cmdline_cat", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0xe2f6bfe1, 0xe2f6bfe1, 0xf18aee15, 0xf18aee15, 0x5e83b689, 0x5e83b689, 0xb7e8b42c, 0xb7e8b42c, 0x85d78f92, 0x85d78f92, 0xd56fadae, 0xd56fadae, 0x7632f5bf, 0x7632f5bf, 0x2769a748, 0x2769a748, 0x4a6112cd, 0x4a6112cd, 0x4f9b66a4, 0x4f9b66a4, 0x70457d38, 0x70457d38, 0x8cadb1a7, 0x8cadb1a7, 0x451341f, 0x451341f, 0x8a62e741, 0x8a62e741, 0x1b1f9031, 0x1b1f9031, 0x75ab630e, 0x75ab630e, 0xd5ff53ac, 0xd5ff53ac, 0x73a2b3c7, 0x73a2b3c7, 0x7b52acd5, 0x7b52acd5, 0xf6f3e48c, 0xf6f3e48c, 0x8d0db133, 0x8db24310, 0x7aef56d4, 0x7aef56d4, }, 45 },
+-  { "cmdline_cat", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x838a3f40, 0x838a3f40, 0x7351ba96, 0x7351ba96, 0x660963bb, 0x660963bb, 0x6f3362a6, 0x6f3362a6, 0x915d35d9, 0x915d35d9, 0xc7edaee9, 0xc7edaee9, 0xbc8ec24c, 0xbc8ec24c, 0xeb120ffd, 0xeb120ffd, 0x8f6d8232, 0x8f6d8232, 0x2de5d515, 0x2de5d515, 0x4f2ecd91, 0x4f2ecd91, 0x555a9b90, 0x555a9b90, 0x8f7b0d77, 0x8f7b0d77, 0x5f9536af, 0x5f9536af, 0x3dd79dbe, 0x3dd79dbe, 0xb555a0, 0xb555a0, 0x75aec882, 0x75aec882, 0xd5da89cb, 0xd5da89cb, 0xb47b3257, 0xb47b3257, 0x7c97c046, 0x7c97c046, 0x726a7abe, 0x4c8b8a56, 0xcffa0854, 0xcffa0854, }, 45 },
+-  { "cmdline_cat", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x7bf761e, 0x7bf761e, 0xaf0b6dae, 0xaf0b6dae, 0x7db15930, 0x7db15930, 0xc9720d56, 0xc9720d56, 0x55590d6c, 0x55590d6c, 0xa0d193d9, 0xa0d193d9, 0x728987b2, 0x728987b2, 0x28aecde6, 0x28aecde6, 0xa59bb094, 0xa59bb094, 0x2d0b049d, 0x2d0b049d, 0xd8421240, 0xd8421240, 0x51fa339, 0x51fa339, 0xc625cc46, 0xc625cc46, 0x2c9e6fcc, 0x2c9e6fcc, 0x3d06ffd5, 0x3d06ffd5, 0x8dd72816, 0x8dd72816, 0xfcf2a982, 0xfcf2a982, 0x6ef2870f, 0x6ef2870f, 0xba2caab7, 0xba2caab7, 0x8e5a5872, 0x8e5a5872, 0x62b2fedc, 0x2bd3b588, 0x34ebdb15, 0x34ebdb15, }, 45 },
+-  { "cmdline_cat", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0xa133280a, 0xa133280a, 0x1e8f4227, 0x1e8f4227, 0xa01cd911, 0xa01cd911, 0xdcb3d617, 0xdcb3d617, 0x51200351, 0x51200351, 0x609ba305, 0x609ba305, 0x5d96abfd, 0x5d96abfd, 0xd855cc70, 0xd855cc70, 0xdbfaf18d, 0xdbfaf18d, 0x84814843, 0x84814843, 0x4b00e630, 0x4b00e630, 0xd362b0f5, 0xd362b0f5, 0xec863355, 0xec863355, 0x195898d0, 0x195898d0, 0xe8c698c7, 0xe8c698c7, 0x884229e7, 0x884229e7, 0xb41ed3a9, 0xb41ed3a9, 0x2be1ce40, 0x2be1ce40, 0x8c33eb7c, 0x8c33eb7c, 0xbbce1da, 0xbbce1da, 0xef9415fa, 0x22fbc0d, 0xd82c182c, 0xd82c182c, }, 45 },
+-  { "gfxterm_menu", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xbe029c, 0x6671ee1f, 0xbe029c, 0x4348cfdb, 0x59c36f00, 0x59c36f00, 0x3ad73295, 0x3ad73295, 0x3ad73295, 0x44575ff3, 0x44575ff3, 0x44575ff3, 0x26a14a21, 0x26a14a21, 0x26a14a21, 0x59c36f00, 0x4348cfdb, 0x4348cfdb, 0x59c36f00, }, 20 },
+-  { "gfxterm_menu", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x14e228ef, 0xb0c8af57, 0x14e228ef, 0x3ae7ad90, 0xaa4593fe, 0xaa4593fe, 0xbec19c1b, 0xbec19c1b, 0xbec19c1b, 0x1834917c, 0x1834917c, 0x1834917c, 0x350c3a04, 0x350c3a04, 0x350c3a04, 0xaa4593fe, 0x3ae7ad90, 0x3ae7ad90, 0xaa4593fe, }, 20 },
+-  { "gfxterm_menu", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x651fb144, 0xdf93ee9c, 0x651fb144, 0x3808dcc0, 0xc9cbf769, 0xc9cbf769, 0xe4861949, 0xe4861949, 0xe4861949, 0x1a5ed885, 0x1a5ed885, 0x1a5ed885, 0xf314678d, 0xf314678d, 0xf314678d, 0xc9cbf769, 0x3808dcc0, 0x3808dcc0, 0xc9cbf769, }, 20 },
+-  { "gfxterm_menu", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0xdfd0119e, 0x6c7018a9, 0xdfd0119e, 0x71865846, 0x9813a416, 0x9813a416, 0xb5e8801c, 0xb5e8801c, 0xb5e8801c, 0x2433062f, 0x2433062f, 0x2433062f, 0x3d893bff, 0x3d893bff, 0x3d893bff, 0x9813a416, 0x71865846, 0x71865846, 0x9813a416, }, 20 },
+-  { "gfxterm_menu", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x4e4844e0, 0x5ebe5f81, 0x4e4844e0, 0x38ee7153, 0x5fcf013d, 0x5fcf013d, 0x819b5c4e, 0x819b5c4e, 0x819b5c4e, 0x538b4438, 0x538b4438, 0x538b4438, 0x45f87ba7, 0x45f87ba7, 0x45f87ba7, 0x5fcf013d, 0x38ee7153, 0x38ee7153, 0x5fcf013d, }, 20 },
+-  { "gfxterm_menu", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x701427d4, 0x246c830a, 0x701427d4, 0x6b11fdd3, 0xdd28f52b, 0xdd28f52b, 0xcd83646c, 0xcd83646c, 0xcd83646c, 0xecbf9d88, 0xecbf9d88, 0xecbf9d88, 0x91075604, 0x91075604, 0x91075604, 0xdd28f52b, 0x6b11fdd3, 0x6b11fdd3, 0xdd28f52b, }, 20 },
+-  { "gfxterm_menu", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x7b5bd4c, 0xac246af1, 0x7b5bd4c, 0xf80aa6cc, 0x43d1f34, 0x43d1f34, 0xb200c08a, 0xb200c08a, 0xb200c08a, 0xcd0a6922, 0xcd0a6922, 0xcd0a6922, 0x545b6ca4, 0x545b6ca4, 0x545b6ca4, 0x43d1f34, 0xf80aa6cc, 0xf80aa6cc, 0x43d1f34, }, 20 },
+-  { "gfxmenu", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x1027210c, 0x64e51c81, 0x1027210c, 0x45ca4a8a, 0x9a2e0d26, 0x12fd0f21, 0x12fd0f21, 0x12fd0f21, 0x4e25f9e1, 0x4e25f9e1, 0x4e25f9e1, 0x67bd3773, 0x67bd3773, 0x67bd3773, 0x59c36f00, 0x45ca4a8a, 0x45ca4a8a, }, 18 },
+-  { "gfxmenu", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x8d12f697, 0xc5b32248, 0x8d12f697, 0x56720aa4, 0xa9d58ccd, 0xf766a14d, 0xf766a14d, 0xf766a14d, 0xa2390b47, 0xa2390b47, 0xa2390b47, 0xcb0ac30e, 0xcb0ac30e, 0xcb0ac30e, 0xaa4593fe, 0x56720aa4, 0x56720aa4, }, 18 },
+-  { "gfxmenu", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xa5ec9f45, 0xdb7085d8, 0xa5ec9f45, 0x9caf1d3f, 0x5411be8b, 0xedc0ad83, 0xedc0ad83, 0xedc0ad83, 0x927e0b17, 0x927e0b17, 0x927e0b17, 0xd00a6b6f, 0xd00a6b6f, 0xd00a6b6f, 0xc9cbf769, 0x9caf1d3f, 0x9caf1d3f, }, 18 },
+-  { "gfxmenu", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x1c3742c9, 0xce8e83bf, 0xeb96c838, 0xce8e83bf, 0x73cb3bc1, 0x740d78cf, 0xb35c7e64, 0xb35c7e64, 0xb35c7e64, 0x58f99418, 0x58f99418, 0x58f99418, 0x5eb294e8, 0x5eb294e8, 0x5eb294e8, 0x1c3742c9, 0x73cb3bc1, 0x73cb3bc1, }, 18 },
+-  { "gfxmenu", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0xcc5a7bed, 0x56a03e51, 0xee7d8d4b, 0x56a03e51, 0x5bdf9413, 0xbcda144c, 0x220f7a5e, 0x220f7a5e, 0x220f7a5e, 0x4d46a64f, 0x4d46a64f, 0x4d46a64f, 0x40b0384c, 0x40b0384c, 0x40b0384c, 0xcc5a7bed, 0x5bdf9413, 0x5bdf9413, }, 18 },
+-  { "gfxmenu", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xef4a3312, 0xea8a9cf0, 0x8929e522, 0xea8a9cf0, 0x78f3dfbc, 0x5d55a141, 0x377f1aeb, 0x377f1aeb, 0x377f1aeb, 0xf1cd5ef5, 0xf1cd5ef5, 0xf1cd5ef5, 0xe5a88e4a, 0xe5a88e4a, 0xe5a88e4a, 0xef4a3312, 0x78f3dfbc, 0x78f3dfbc, }, 18 },
+-  { "gfxmenu", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x54e48d80, 0x6dcf1d57, 0x925a4c8f, 0x6dcf1d57, 0x69005b38, 0x6d6bb4bc, 0x756a36b9, 0x756a36b9, 0x756a36b9, 0xf499c068, 0xf499c068, 0xf499c068, 0x623d7907, 0x623d7907, 0x623d7907, 0x54e48d80, 0x69005b38, 0x69005b38, }, 18 },
+-  { "gfxterm_ar", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xa49d26b0, 0xaa7d9b28, 0xa49d26b0, 0xe76bebf7, 0x59c36f00, 0x59c36f00, 0xea6ab252, 0xea6ab252, 0xea6ab252, 0x94eadf34, 0x94eadf34, 0x94eadf34, 0xf61ccae6, 0xf61ccae6, 0xf61ccae6, 0x59c36f00, 0xe76bebf7, 0xe76bebf7, 0x59c36f00, }, 20 },
+-  { "gfxterm_ar", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x7a277db, 0xf3bf80f7, 0x7a277db, 0x29a7f2a4, 0xaa4593fe, 0xaa4593fe, 0xf1cd57e3, 0xf1cd57e3, 0xf1cd57e3, 0x57385a84, 0x57385a84, 0x57385a84, 0x7a00f1fc, 0x7a00f1fc, 0x7a00f1fc, 0xaa4593fe, 0x29a7f2a4, 0x29a7f2a4, 0xaa4593fe, }, 20 },
+-  { "gfxterm_ar", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x631edf85, 0x71926408, 0x631edf85, 0x3e09b201, 0xc9cbf769, 0xc9cbf769, 0xf224ab3, 0xf224ab3, 0xf224ab3, 0xf1fa8b7f, 0xf1fa8b7f, 0xf1fa8b7f, 0x18b03477, 0x18b03477, 0x18b03477, 0xc9cbf769, 0x3e09b201, 0x3e09b201, 0xc9cbf769, }, 20 },
+-  { "gfxterm_ar", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0xfbaf4635, 0xe69ef474, 0xfbaf4635, 0x55f90fed, 0x9813a416, 0x9813a416, 0x3aad8f41, 0x3aad8f41, 0x3aad8f41, 0xab760972, 0xab760972, 0xab760972, 0xb2cc34a2, 0xb2cc34a2, 0xb2cc34a2, 0x9813a416, 0x55f90fed, 0x55f90fed, 0x9813a416, }, 20 },
+-  { "gfxterm_ar", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xdce50745, 0x1d8009e4, 0xdce50745, 0xaa4332f6, 0x5fcf013d, 0x5fcf013d, 0x354e5749, 0x354e5749, 0x354e5749, 0xe75e4f3f, 0xe75e4f3f, 0xe75e4f3f, 0xf12d70a0, 0xf12d70a0, 0xf12d70a0, 0x5fcf013d, 0xaa4332f6, 0xaa4332f6, 0x5fcf013d, }, 20 },
+-  { "gfxterm_ar", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x3efebeff, 0xf101dfe2, 0x3efebeff, 0x25fb64f8, 0xdd28f52b, 0xdd28f52b, 0x70c69ebd, 0x70c69ebd, 0x70c69ebd, 0x51fa6759, 0x51fa6759, 0x51fa6759, 0x2c42acd5, 0x2c42acd5, 0x2c42acd5, 0xdd28f52b, 0x25fb64f8, 0x25fb64f8, 0xdd28f52b, }, 20 },
+-  { "gfxterm_ar", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x59a34c64, 0x281cca78, 0x59a34c64, 0xa61c57e4, 0x43d1f34, 0x43d1f34, 0x95131d4, 0x95131d4, 0x95131d4, 0x765b987c, 0x765b987c, 0x765b987c, 0xef0a9dfa, 0xef0a9dfa, 0xef0a9dfa, 0x43d1f34, 0xa61c57e4, 0xa61c57e4, 0x43d1f34, }, 20 },
+-  { "gfxterm_cyr", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xa37c165, 0x72063383, 0xa37c165, 0x49c10c22, 0x59c36f00, 0x59c36f00, 0x4e53de8e, 0x4e53de8e, 0x4e53de8e, 0x30d3b3e8, 0x30d3b3e8, 0x30d3b3e8, 0x5225a63a, 0x5225a63a, 0x5225a63a, 0x59c36f00, 0x49c10c22, 0x49c10c22, 0x59c36f00, }, 20 },
+-  { "gfxterm_cyr", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x45bba0ba, 0xe60fd0b6, 0x45bba0ba, 0x6bbe25c5, 0xaa4593fe, 0xaa4593fe, 0x28de2b41, 0x28de2b41, 0x28de2b41, 0x8e2b2626, 0x8e2b2626, 0x8e2b2626, 0xa3138d5e, 0xa3138d5e, 0xa3138d5e, 0xaa4593fe, 0x6bbe25c5, 0x6bbe25c5, 0xaa4593fe, }, 20 },
+-  { "gfxterm_cyr", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xb43d4e9d, 0x16f88820, 0xb43d4e9d, 0xe92a2319, 0xc9cbf769, 0xc9cbf769, 0xb8959ec7, 0xb8959ec7, 0xb8959ec7, 0x464d5f0b, 0x464d5f0b, 0x464d5f0b, 0xaf07e003, 0xaf07e003, 0xaf07e003, 0xc9cbf769, 0xe92a2319, 0xe92a2319, 0xc9cbf769, }, 20 },
+-  { "gfxterm_cyr", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x46760365, 0x685ae30e, 0x46760365, 0xe8204abd, 0x9813a416, 0x9813a416, 0x8896050a, 0x8896050a, 0x8896050a, 0x194d8339, 0x194d8339, 0x194d8339, 0xf7bee9, 0xf7bee9, 0xf7bee9, 0x9813a416, 0xe8204abd, 0xe8204abd, 0x9813a416, }, 20 },
+-  { "gfxterm_cyr", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x6859aa86, 0xf3f11deb, 0x6859aa86, 0x1eff9f35, 0x5fcf013d, 0x5fcf013d, 0xd72b1482, 0xd72b1482, 0xd72b1482, 0x53b0cf4, 0x53b0cf4, 0x53b0cf4, 0x1348336b, 0x1348336b, 0x1348336b, 0x5fcf013d, 0x1eff9f35, 0x1eff9f35, 0x5fcf013d, }, 20 },
+-  { "gfxterm_cyr", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x688451e7, 0xf6936b72, 0x688451e7, 0x73818be0, 0xdd28f52b, 0xdd28f52b, 0xf12a65ac, 0xf12a65ac, 0xf12a65ac, 0xd0169c48, 0xd0169c48, 0xd0169c48, 0xadae57c4, 0xadae57c4, 0xadae57c4, 0xdd28f52b, 0x73818be0, 0x73818be0, 0xdd28f52b, }, 20 },
+-  { "gfxterm_cyr", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x9616af94, 0xd466be40, 0x9616af94, 0x69a9b414, 0x43d1f34, 0x43d1f34, 0xf3bb3240, 0xf3bb3240, 0xf3bb3240, 0x8cb19be8, 0x8cb19be8, 0x8cb19be8, 0x15e09e6e, 0x15e09e6e, 0x15e09e6e, 0x43d1f34, 0x69a9b414, 0x69a9b414, 0x43d1f34, }, 20 },
+-  { "gfxterm_heb", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x8708d1bd, 0x85dd5e9c, 0x8708d1bd, 0xc4fe1cfa, 0x59c36f00, 0x59c36f00, 0x7ae8aced, 0x7ae8aced, 0x7ae8aced, 0x468c18b, 0x468c18b, 0x468c18b, 0x669ed459, 0x669ed459, 0x669ed459, 0x59c36f00, 0xc4fe1cfa, 0xc4fe1cfa, 0x59c36f00, }, 20 },
+-  { "gfxterm_heb", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0xa72b1043, 0x147d4ce0, 0xa72b1043, 0x892e953c, 0xaa4593fe, 0xaa4593fe, 0xb7b1dd40, 0xb7b1dd40, 0xb7b1dd40, 0x1144d027, 0x1144d027, 0x1144d027, 0x3c7c7b5f, 0x3c7c7b5f, 0x3c7c7b5f, 0xaa4593fe, 0x892e953c, 0x892e953c, 0xaa4593fe, }, 20 },
+-  { "gfxterm_heb", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xc5fb1817, 0x745fb26c, 0xc5fb1817, 0x98ec7593, 0xc9cbf769, 0xc9cbf769, 0xf5f17e2d, 0xf5f17e2d, 0xf5f17e2d, 0xb29bfe1, 0xb29bfe1, 0xb29bfe1, 0xe26300e9, 0xe26300e9, 0xe26300e9, 0xc9cbf769, 0x98ec7593, 0x98ec7593, 0xc9cbf769, }, 20 },
+-  { "gfxterm_heb", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x4be837e1, 0xbf4963ca, 0x4be837e1, 0xe5be7e39, 0x9813a416, 0x9813a416, 0xd886fca0, 0xd886fca0, 0xd886fca0, 0x495d7a93, 0x495d7a93, 0x495d7a93, 0x50e74743, 0x50e74743, 0x50e74743, 0x9813a416, 0xe5be7e39, 0xe5be7e39, 0x9813a416, }, 20 },
+-  { "gfxterm_heb", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x21a8ccb8, 0x17719be, 0x21a8ccb8, 0x570ef90b, 0x5fcf013d, 0x5fcf013d, 0x2a7b5333, 0x2a7b5333, 0x2a7b5333, 0xf86b4b45, 0xf86b4b45, 0xf86b4b45, 0xee1874da, 0xee1874da, 0xee1874da, 0x5fcf013d, 0x570ef90b, 0x570ef90b, 0x5fcf013d, }, 20 },
+-  { "gfxterm_heb", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x7001fe50, 0x4798153f, 0x7001fe50, 0x6b042457, 0xdd28f52b, 0xdd28f52b, 0x46489369, 0x46489369, 0x46489369, 0x67746a8d, 0x67746a8d, 0x67746a8d, 0x1acca101, 0x1acca101, 0x1acca101, 0xdd28f52b, 0x6b042457, 0x6b042457, 0xdd28f52b, }, 20 },
+-  { "gfxterm_heb", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x6e10591c, 0x48bd926e, 0x6e10591c, 0x91af429c, 0x43d1f34, 0x43d1f34, 0x59cb829, 0x59cb829, 0x59cb829, 0x7a961181, 0x7a961181, 0x7a961181, 0xe3c71407, 0xe3c71407, 0xe3c71407, 0x43d1f34, 0x91af429c, 0x91af429c, 0x43d1f34, }, 20 },
+-  { "gfxterm_gre", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x67627ed5, 0xdb276cef, 0x67627ed5, 0x2494b392, 0x59c36f00, 0x59c36f00, 0x43f511f3, 0x43f511f3, 0x43f511f3, 0x3d757c95, 0x3d757c95, 0x3d757c95, 0x5f836947, 0x5f836947, 0x5f836947, 0x59c36f00, 0x2494b392, 0x2494b392, 0x59c36f00, }, 20 },
+-  { "gfxterm_gre", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x987cbf71, 0x6e4c645c, 0x987cbf71, 0xb6793a0e, 0xaa4593fe, 0xaa4593fe, 0xb943d716, 0xb943d716, 0xb943d716, 0x1fb6da71, 0x1fb6da71, 0x1fb6da71, 0x328e7109, 0x328e7109, 0x328e7109, 0xaa4593fe, 0xb6793a0e, 0xb6793a0e, 0xaa4593fe, }, 20 },
+-  { "gfxterm_gre", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xf9987c07, 0x4a92eed9, 0xf9987c07, 0xa48f1183, 0xc9cbf769, 0xc9cbf769, 0x5eb3ddf4, 0x5eb3ddf4, 0x5eb3ddf4, 0xa06b1c38, 0xa06b1c38, 0xa06b1c38, 0x4921a330, 0x4921a330, 0x4921a330, 0xc9cbf769, 0xa48f1183, 0xa48f1183, 0xc9cbf769, }, 20 },
+-  { "gfxterm_gre", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0xccd804e2, 0xb99e8d91, 0xccd804e2, 0x628e4d3a, 0x9813a416, 0x9813a416, 0x5aec5acc, 0x5aec5acc, 0x5aec5acc, 0xcb37dcff, 0xcb37dcff, 0xcb37dcff, 0xd28de12f, 0xd28de12f, 0xd28de12f, 0x9813a416, 0x628e4d3a, 0x628e4d3a, 0x9813a416, }, 20 },
+-  { "gfxterm_gre", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x4990d896, 0x2b3aa242, 0x4990d896, 0x3f36ed25, 0x5fcf013d, 0x5fcf013d, 0x3cc6048d, 0x3cc6048d, 0x3cc6048d, 0xeed61cfb, 0xeed61cfb, 0xeed61cfb, 0xf8a52364, 0xf8a52364, 0xf8a52364, 0x5fcf013d, 0x3f36ed25, 0x3f36ed25, 0x5fcf013d, }, 20 },
+-  { "gfxterm_gre", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x4ff5c69f, 0x66586489, 0x4ff5c69f, 0x54f01c98, 0xdd28f52b, 0xdd28f52b, 0xc3ff0bf5, 0xc3ff0bf5, 0xc3ff0bf5, 0xe2c3f211, 0xe2c3f211, 0xe2c3f211, 0x9f7b399d, 0x9f7b399d, 0x9f7b399d, 0xdd28f52b, 0x54f01c98, 0x54f01c98, 0xdd28f52b, }, 20 },
+-  { "gfxterm_gre", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x909b7bb4, 0x2bb2a58c, 0x909b7bb4, 0x6f246034, 0x43d1f34, 0x43d1f34, 0x2df40751, 0x2df40751, 0x2df40751, 0x52feaef9, 0x52feaef9, 0x52feaef9, 0xcbafab7f, 0xcbafab7f, 0xcbafab7f, 0x43d1f34, 0x6f246034, 0x6f246034, 0x43d1f34, }, 20 },
+-  { "gfxterm_ru", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xc77bfcc6, 0xffcdf45d, 0xc77bfcc6, 0x848d3181, 0x59c36f00, 0x59c36f00, 0xd79cd5e, 0xd79cd5e, 0xd79cd5e, 0x73f9a038, 0x73f9a038, 0x73f9a038, 0x110fb5ea, 0x110fb5ea, 0x110fb5ea, 0x59c36f00, 0x848d3181, 0x848d3181, 0x59c36f00, }, 20 },
+-  { "gfxterm_ru", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0xd5494aa5, 0xa0924ec, 0xd5494aa5, 0xfb4ccfda, 0xaa4593fe, 0xaa4593fe, 0x8692c636, 0x8692c636, 0x8692c636, 0x2067cb51, 0x2067cb51, 0x2067cb51, 0xd5f6029, 0xd5f6029, 0xd5f6029, 0xaa4593fe, 0xfb4ccfda, 0xfb4ccfda, 0xaa4593fe, }, 20 },
+-  { "gfxterm_ru", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x2436c4f, 0x2cde4e0c, 0x2436c4f, 0x5f5401cb, 0xc9cbf769, 0xc9cbf769, 0x558f50ae, 0x558f50ae, 0x558f50ae, 0xab579162, 0xab579162, 0xab579162, 0x421d2e6a, 0x421d2e6a, 0x421d2e6a, 0xc9cbf769, 0x5f5401cb, 0x5f5401cb, 0xc9cbf769, }, 20 },
+-  { "gfxterm_ru", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x86f8a68c, 0xf4116451, 0x86f8a68c, 0x28aeef54, 0x9813a416, 0x9813a416, 0x7befbe43, 0x7befbe43, 0x7befbe43, 0xea343870, 0xea343870, 0xea343870, 0xf38e05a0, 0xf38e05a0, 0xf38e05a0, 0x9813a416, 0x28aeef54, 0x28aeef54, 0x9813a416, }, 20 },
+-  { "gfxterm_ru", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x156c292f, 0x3c8eb473, 0x156c292f, 0x63ca1c9c, 0x5fcf013d, 0x5fcf013d, 0x895ea16b, 0x895ea16b, 0x895ea16b, 0x5b4eb91d, 0x5b4eb91d, 0x5b4eb91d, 0x4d3d8682, 0x4d3d8682, 0x4d3d8682, 0x5fcf013d, 0x63ca1c9c, 0x63ca1c9c, 0x5fcf013d, }, 20 },
+-  { "gfxterm_ru", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xf57ebf12, 0x798b299b, 0xf57ebf12, 0xee7b6515, 0xdd28f52b, 0xdd28f52b, 0x22563fc6, 0x22563fc6, 0x22563fc6, 0x36ac622, 0x36ac622, 0x36ac622, 0x7ed20dae, 0x7ed20dae, 0x7ed20dae, 0xdd28f52b, 0xee7b6515, 0xee7b6515, 0xdd28f52b, }, 20 },
+-  { "gfxterm_ru", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x2bc82eb1, 0x94064cc8, 0x2bc82eb1, 0xd4773531, 0x43d1f34, 0x43d1f34, 0x44cbf2f0, 0x44cbf2f0, 0x44cbf2f0, 0x3bc15b58, 0x3bc15b58, 0x3bc15b58, 0xa2905ede, 0xa2905ede, 0xa2905ede, 0x43d1f34, 0xd4773531, 0xd4773531, 0x43d1f34, }, 20 },
+-  { "gfxterm_fr", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x7f6dd146, 0x548af474, 0x7f6dd146, 0x3c9b1c01, 0x59c36f00, 0x59c36f00, 0x7d913e8d, 0x7d913e8d, 0x7d913e8d, 0x31153eb, 0x31153eb, 0x31153eb, 0x61e74639, 0x61e74639, 0x61e74639, 0x59c36f00, 0x3c9b1c01, 0x3c9b1c01, 0x59c36f00, }, 20 },
+-  { "gfxterm_fr", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0xf29ad079, 0x50d47c0, 0xf29ad079, 0xdc9f5506, 0xaa4593fe, 0xaa4593fe, 0x6bcf4c90, 0x6bcf4c90, 0x6bcf4c90, 0xcd3a41f7, 0xcd3a41f7, 0xcd3a41f7, 0xe002ea8f, 0xe002ea8f, 0xe002ea8f, 0xaa4593fe, 0xdc9f5506, 0xdc9f5506, 0xaa4593fe, }, 20 },
+-  { "gfxterm_fr", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xb25e3082, 0x2ed845dd, 0xb25e3082, 0xef495d06, 0xc9cbf769, 0xc9cbf769, 0xd5322575, 0xd5322575, 0xd5322575, 0x2beae4b9, 0x2beae4b9, 0x2beae4b9, 0xc2a05bb1, 0xc2a05bb1, 0xc2a05bb1, 0xc9cbf769, 0xef495d06, 0xef495d06, 0xc9cbf769, }, 20 },
+-  { "gfxterm_fr", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x4cdfcd2e, 0x8bf091f, 0x4cdfcd2e, 0xe28984f6, 0x9813a416, 0x9813a416, 0x8217f630, 0x8217f630, 0x8217f630, 0x13cc7003, 0x13cc7003, 0x13cc7003, 0xa764dd3, 0xa764dd3, 0xa764dd3, 0x9813a416, 0xe28984f6, 0xe28984f6, 0x9813a416, }, 20 },
+-  { "gfxterm_fr", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xf2b49f88, 0x2eff252d, 0xf2b49f88, 0x8412aa3b, 0x5fcf013d, 0x5fcf013d, 0x5d3b9fe7, 0x5d3b9fe7, 0x5d3b9fe7, 0x8f2b8791, 0x8f2b8791, 0x8f2b8791, 0x9958b80e, 0x9958b80e, 0x9958b80e, 0x5fcf013d, 0x8412aa3b, 0x8412aa3b, 0x5fcf013d, }, 20 },
+-  { "gfxterm_fr", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x786673be, 0x536f1359, 0x786673be, 0x6363a9b9, 0xdd28f52b, 0xdd28f52b, 0x38653b12, 0x38653b12, 0x38653b12, 0x1959c2f6, 0x1959c2f6, 0x1959c2f6, 0x64e1097a, 0x64e1097a, 0x64e1097a, 0xdd28f52b, 0x6363a9b9, 0x6363a9b9, 0xdd28f52b, }, 20 },
+-  { "gfxterm_fr", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0xac4a1127, 0x699c2ad8, 0xac4a1127, 0x53f50aa7, 0x43d1f34, 0x43d1f34, 0xfa47dfba, 0xfa47dfba, 0xfa47dfba, 0x854d7612, 0x854d7612, 0x854d7612, 0x1c1c7394, 0x1c1c7394, 0x1c1c7394, 0x43d1f34, 0x53f50aa7, 0x53f50aa7, 0x43d1f34, }, 20 },
+-  { "gfxterm_quot", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xbc5f6633, 0xda908ab0, 0xbc5f6633, 0xffa9ab74, 0x59c36f00, 0x59c36f00, 0x3ad73295, 0x3ad73295, 0x3ad73295, 0x44575ff3, 0x44575ff3, 0x44575ff3, 0x26a14a21, 0x26a14a21, 0x26a14a21, 0x59c36f00, 0xffa9ab74, 0xffa9ab74, 0x59c36f00, }, 20 },
+-  { "gfxterm_quot", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0xad820d6b, 0x9a88ad3, 0xad820d6b, 0x83878814, 0xaa4593fe, 0xaa4593fe, 0xbec19c1b, 0xbec19c1b, 0xbec19c1b, 0x1834917c, 0x1834917c, 0x1834917c, 0x350c3a04, 0x350c3a04, 0x350c3a04, 0xaa4593fe, 0x83878814, 0x83878814, 0xaa4593fe, }, 20 },
+-  { "gfxterm_quot", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xe5774112, 0x5ffb1eca, 0xe5774112, 0xb8602c96, 0xc9cbf769, 0xc9cbf769, 0xe4861949, 0xe4861949, 0xe4861949, 0x1a5ed885, 0x1a5ed885, 0x1a5ed885, 0xf314678d, 0xf314678d, 0xf314678d, 0xc9cbf769, 0xb8602c96, 0xb8602c96, 0xc9cbf769, }, 20 },
+-  { "gfxterm_quot", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x6af1a2bc, 0xd951ab8b, 0x6af1a2bc, 0xc4a7eb64, 0x9813a416, 0x9813a416, 0xb5e8801c, 0xb5e8801c, 0xb5e8801c, 0x2433062f, 0x2433062f, 0x2433062f, 0x3d893bff, 0x3d893bff, 0x3d893bff, 0x9813a416, 0xc4a7eb64, 0xc4a7eb64, 0x9813a416, }, 20 },
+-  { "gfxterm_quot", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xc6baa18, 0x1c9db179, 0xc6baa18, 0x7acd9fab, 0x5fcf013d, 0x5fcf013d, 0x819b5c4e, 0x819b5c4e, 0x819b5c4e, 0x538b4438, 0x538b4438, 0x538b4438, 0x45f87ba7, 0x45f87ba7, 0x45f87ba7, 0x5fcf013d, 0x7acd9fab, 0x7acd9fab, 0x5fcf013d, }, 20 },
+-  { "gfxterm_quot", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xe424a6ab, 0xb05c0275, 0xe424a6ab, 0xff217cac, 0xdd28f52b, 0xdd28f52b, 0xcd83646c, 0xcd83646c, 0xcd83646c, 0xecbf9d88, 0xecbf9d88, 0xecbf9d88, 0x91075604, 0x91075604, 0x91075604, 0xdd28f52b, 0xff217cac, 0xff217cac, 0xdd28f52b, }, 20 },
+-  { "gfxterm_quot", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x4a7dff41, 0xe1ec28fc, 0x4a7dff41, 0xb5c2e4c1, 0x43d1f34, 0x43d1f34, 0xb200c08a, 0xb200c08a, 0xb200c08a, 0xcd0a6922, 0xcd0a6922, 0xcd0a6922, 0x545b6ca4, 0x545b6ca4, 0x545b6ca4, 0x43d1f34, 0xb5c2e4c1, 0xb5c2e4c1, 0x43d1f34, }, 20 },
+-  { "gfxterm_piglatin", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xd3d3e4a2, 0x9c635046, 0xd3d3e4a2, 0x902529e5, 0x59c36f00, 0x59c36f00, 0x85e713, 0x85e713, 0x85e713, 0x7e058a75, 0x7e058a75, 0x7e058a75, 0x1cf39fa7, 0x1cf39fa7, 0x1cf39fa7, 0x59c36f00, 0x902529e5, 0x902529e5, 0x59c36f00, }, 20 },
+-  { "gfxterm_piglatin", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0xd61c80f5, 0xdf78b496, 0xd61c80f5, 0xf819058a, 0xaa4593fe, 0xaa4593fe, 0xefc0f7e7, 0xefc0f7e7, 0xefc0f7e7, 0x4935fa80, 0x4935fa80, 0x4935fa80, 0x640d51f8, 0x640d51f8, 0x640d51f8, 0xaa4593fe, 0xf819058a, 0xf819058a, 0xaa4593fe, }, 20 },
+-  { "gfxterm_piglatin", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x936bc89d, 0x523a3e80, 0x936bc89d, 0xce7ca519, 0xc9cbf769, 0xc9cbf769, 0xaa99ffb1, 0xaa99ffb1, 0xaa99ffb1, 0x54413e7d, 0x54413e7d, 0x54413e7d, 0xbd0b8175, 0xbd0b8175, 0xbd0b8175, 0xc9cbf769, 0xce7ca519, 0xce7ca519, 0xc9cbf769, }, 20 },
+-  { "gfxterm_piglatin", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x4fdd0291, 0x133fa83d, 0x4fdd0291, 0xe18b4b49, 0x9813a416, 0x9813a416, 0x74c38e90, 0x74c38e90, 0x74c38e90, 0xe51808a3, 0xe51808a3, 0xe51808a3, 0xfca23573, 0xfca23573, 0xfca23573, 0x9813a416, 0xe18b4b49, 0xe18b4b49, 0x9813a416, }, 20 },
+-  { "gfxterm_piglatin", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x538203b0, 0x2a92e789, 0x538203b0, 0x25243603, 0x5fcf013d, 0x5fcf013d, 0x5e4d3dd8, 0x5e4d3dd8, 0x5e4d3dd8, 0x8c5d25ae, 0x8c5d25ae, 0x8c5d25ae, 0x9a2e1a31, 0x9a2e1a31, 0x9a2e1a31, 0x5fcf013d, 0x25243603, 0x25243603, 0x5fcf013d, }, 20 },
+-  { "gfxterm_piglatin", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xcfc85125, 0xa5b0e11b, 0xcfc85125, 0xd4cd8b22, 0xdd28f52b, 0xdd28f52b, 0x1af8cddc, 0x1af8cddc, 0x1af8cddc, 0x3bc43438, 0x3bc43438, 0x3bc43438, 0x467cffb4, 0x467cffb4, 0x467cffb4, 0xdd28f52b, 0xd4cd8b22, 0xd4cd8b22, 0xdd28f52b, }, 20 },
+-  { "gfxterm_piglatin", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0xf2469ffb, 0x1d0c1d2, 0xf2469ffb, 0xdf9847b, 0x43d1f34, 0x43d1f34, 0xa2837c7a, 0xa2837c7a, 0xa2837c7a, 0xdd89d5d2, 0xdd89d5d2, 0xdd89d5d2, 0x44d8d054, 0x44d8d054, 0x44d8d054, 0x43d1f34, 0xdf9847b, 0xdf9847b, 0x43d1f34, }, 20 },
+-  { "gfxterm_ch", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x27851cc1, 0x15f731b5, 0x27851cc1, 0x6473d186, 0x59c36f00, 0x59c36f00, 0x125bcddf, 0x125bcddf, 0x125bcddf, 0x6cdba0b9, 0x6cdba0b9, 0x6cdba0b9, 0xe2db56b, 0xe2db56b, 0xe2db56b, 0x59c36f00, 0x6473d186, 0x6473d186, 0x59c36f00, }, 20 },
+-  { "gfxterm_ch", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0xfcb223c, 0x2c2e18b9, 0xfcb223c, 0x21cea743, 0xaa4593fe, 0xaa4593fe, 0xd700be1a, 0xd700be1a, 0xd700be1a, 0x71f5b37d, 0x71f5b37d, 0x71f5b37d, 0x5ccd1805, 0x5ccd1805, 0x5ccd1805, 0xaa4593fe, 0x21cea743, 0x21cea743, 0xaa4593fe, }, 20 },
+-  { "gfxterm_ch", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x807efaa5, 0xb673036a, 0x807efaa5, 0xdd699721, 0xc9cbf769, 0xc9cbf769, 0xdca3ed4b, 0xdca3ed4b, 0xdca3ed4b, 0x227b2c87, 0x227b2c87, 0x227b2c87, 0xcb31938f, 0xcb31938f, 0xcb31938f, 0xc9cbf769, 0xdd699721, 0xdd699721, 0xc9cbf769, }, 20 },
+-  { "gfxterm_ch", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x651d0d50, 0xf0dc38fc, 0x651d0d50, 0xcb4b4488, 0x9813a416, 0x9813a416, 0x80d03ee8, 0x80d03ee8, 0x80d03ee8, 0x110bb8db, 0x110bb8db, 0x110bb8db, 0x8b1850b, 0x8b1850b, 0x8b1850b, 0x9813a416, 0xcb4b4488, 0xcb4b4488, 0x9813a416, }, 20 },
+-  { "gfxterm_ch", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xb9b068f, 0xdc68ac3c, 0xb9b068f, 0x7d3d333c, 0x5fcf013d, 0x5fcf013d, 0xa1f0a6e4, 0xa1f0a6e4, 0xa1f0a6e4, 0x73e0be92, 0x73e0be92, 0x73e0be92, 0x6593810d, 0x6593810d, 0x6593810d, 0x5fcf013d, 0x7d3d333c, 0x7d3d333c, 0x5fcf013d, }, 20 },
+-  { "gfxterm_ch", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xf0789d7e, 0x6f2f2b61, 0xf0789d7e, 0xeb7d4779, 0xdd28f52b, 0xdd28f52b, 0xb995630, 0xb995630, 0xb995630, 0x2aa5afd4, 0x2aa5afd4, 0x2aa5afd4, 0x571d6458, 0x571d6458, 0x571d6458, 0xdd28f52b, 0xeb7d4779, 0xeb7d4779, 0xdd28f52b, }, 20 },
+-  { "gfxterm_ch", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x819821ff, 0xdd19128c, 0x819821ff, 0x7e273a7f, 0x43d1f34, 0x43d1f34, 0xf35981d3, 0xf35981d3, 0xf35981d3, 0x8c53287b, 0x8c53287b, 0x8c53287b, 0x15022dfd, 0x15022dfd, 0x15022dfd, 0x43d1f34, 0x7e273a7f, 0x7e273a7f, 0x43d1f34, }, 20 },
+-  { "gfxterm_red", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xa99604d1, 0xcf59e852, 0xa99604d1, 0xfebbba0f, 0x59c36f00, 0x59c36f00, 0x53767ce3, 0x53767ce3, 0x53767ce3, 0x2df61185, 0x2df61185, 0x2df61185, 0x4f000457, 0x4f000457, 0x4f000457, 0x59c36f00, 0xfebbba0f, 0xfebbba0f, 0x59c36f00, }, 20 },
+-  { "gfxterm_red", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x7d0a218, 0xa3fa25a0, 0x7d0a218, 0xb777784e, 0xaa4593fe, 0xaa4593fe, 0x35db26e1, 0x35db26e1, 0x35db26e1, 0x932e2b86, 0x932e2b86, 0x932e2b86, 0xbe1680fe, 0xbe1680fe, 0xbe1680fe, 0xaa4593fe, 0xb777784e, 0xb777784e, 0xaa4593fe, }, 20 },
+-  { "gfxterm_red", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x63be90f4, 0xd932cf2c, 0x63be90f4, 0x739b8e5a, 0xc9cbf769, 0xc9cbf769, 0x70a00efe, 0x70a00efe, 0x70a00efe, 0x8e78cf32, 0x8e78cf32, 0x8e78cf32, 0x6732703a, 0x6732703a, 0x6732703a, 0xc9cbf769, 0x739b8e5a, 0x739b8e5a, 0xc9cbf769, }, 20 },
+-  { "gfxterm_red", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x53460c90, 0xe0e605a7, 0x53460c90, 0x6337f0bf, 0x9813a416, 0x9813a416, 0x4161864c, 0x4161864c, 0x4161864c, 0xd0ba007f, 0xd0ba007f, 0xd0ba007f, 0xc9003daf, 0xc9003daf, 0xc9003daf, 0x9813a416, 0x6337f0bf, 0x6337f0bf, 0x9813a416, }, 20 },
+-  { "gfxterm_red", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xf54761a0, 0xe5b17ac1, 0xf54761a0, 0x5b408e55, 0x5fcf013d, 0x5fcf013d, 0x580fda0e, 0x580fda0e, 0x580fda0e, 0x8a1fc278, 0x8a1fc278, 0x8a1fc278, 0x9c6cfde7, 0x9c6cfde7, 0x9c6cfde7, 0x5fcf013d, 0x5b408e55, 0x5b408e55, 0x5fcf013d, }, 20 },
+-  { "gfxterm_red", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xec78b0c1, 0xb800141f, 0xec78b0c1, 0x621c7b1b, 0xdd28f52b, 0xdd28f52b, 0x8f60179, 0x8f60179, 0x8f60179, 0x29caf89d, 0x29caf89d, 0x29caf89d, 0x54723311, 0x54723311, 0x54723311, 0xdd28f52b, 0x621c7b1b, 0x621c7b1b, 0xdd28f52b, }, 20 },
+-  { "gfxterm_red", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0xf209411b, 0x599896a6, 0xf209411b, 0x6551c7bb, 0x43d1f34, 0x43d1f34, 0x5ac6bb4a, 0x5ac6bb4a, 0x5ac6bb4a, 0x25cc12e2, 0x25cc12e2, 0x25cc12e2, 0xbc9d1764, 0xbc9d1764, 0xbc9d1764, 0x43d1f34, 0x6551c7bb, 0x6551c7bb, 0x43d1f34, }, 20 },
+-  { "gfxterm_high", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x93b4fcd8, 0xf57b105b, 0x93b4fcd8, 0x2bfe5312, 0x59c36f00, 0x59c36f00, 0x3ad73295, 0x3ad73295, 0x3ad73295, 0x44575ff3, 0x44575ff3, 0x44575ff3, 0x26a14a21, 0x26a14a21, 0x26a14a21, 0x59c36f00, 0x2bfe5312, 0x2bfe5312, 0x59c36f00, }, 20 },
+-  { "gfxterm_high", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x656c9044, 0xc14617fc, 0x656c9044, 0xa6ea58cb, 0xaa4593fe, 0xaa4593fe, 0xbec19c1b, 0xbec19c1b, 0xbec19c1b, 0x1834917c, 0x1834917c, 0x1834917c, 0x350c3a04, 0x350c3a04, 0x350c3a04, 0xaa4593fe, 0xa6ea58cb, 0xa6ea58cb, 0xaa4593fe, }, 20 },
+-  { "gfxterm_high", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xa11479ed, 0x1b982635, 0xa11479ed, 0xe37185d0, 0xc9cbf769, 0xc9cbf769, 0xe4861949, 0xe4861949, 0xe4861949, 0x1a5ed885, 0x1a5ed885, 0x1a5ed885, 0xf314678d, 0xf314678d, 0xf314678d, 0xc9cbf769, 0xe37185d0, 0xe37185d0, 0xc9cbf769, }, 20 },
+-  { "gfxterm_high", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x244770a7, 0x97e77990, 0x244770a7, 0x6a54d2ee, 0x9813a416, 0x9813a416, 0xb5e8801c, 0xb5e8801c, 0xb5e8801c, 0x2433062f, 0x2433062f, 0x2433062f, 0x3d893bff, 0x3d893bff, 0x3d893bff, 0x9813a416, 0x6a54d2ee, 0x6a54d2ee, 0x9813a416, }, 20 },
+-  { "gfxterm_high", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x8ca34476, 0x9c555f17, 0x8ca34476, 0x1fc54b41, 0x5fcf013d, 0x5fcf013d, 0x819b5c4e, 0x819b5c4e, 0x819b5c4e, 0x538b4438, 0x538b4438, 0x538b4438, 0x45f87ba7, 0x45f87ba7, 0x45f87ba7, 0x5fcf013d, 0x1fc54b41, 0x1fc54b41, 0x5fcf013d, }, 20 },
+-  { "gfxterm_high", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xf19f6af8, 0xa5e7ce26, 0xf19f6af8, 0x1619aea6, 0xdd28f52b, 0xdd28f52b, 0xcd83646c, 0xcd83646c, 0xcd83646c, 0xecbf9d88, 0xecbf9d88, 0xecbf9d88, 0x91075604, 0x91075604, 0x91075604, 0xdd28f52b, 0x1619aea6, 0x1619aea6, 0xdd28f52b, }, 20 },
+-  { "gfxterm_high", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x5f75414f, 0xf4e496f2, 0x5f75414f, 0x27fd1fe0, 0x43d1f34, 0x43d1f34, 0xb200c08a, 0xb200c08a, 0xb200c08a, 0xcd0a6922, 0xcd0a6922, 0xcd0a6922, 0x545b6ca4, 0x545b6ca4, 0x545b6ca4, 0x43d1f34, 0x27fd1fe0, 0x27fd1fe0, 0x43d1f34, }, 20 },
+-  { "videotest", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x1368a483, 0x1368a483, 0x1368a483, 0x1368a483, 0x1368a483, }, 5 },
+-  { "videotest", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0x7033079c, 0x7033079c, 0x7033079c, 0x7033079c, 0x7033079c, }, 5 },
+-  { "videotest", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xff583fbf, 0xff583fbf, 0xff583fbf, 0xff583fbf, 0xff583fbf, }, 5 },
+-  { "videotest", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x4c2cef83, 0x1b215a88, 0xe2378595, 0xb53a309e, 0x15f64d5e, }, 5 },
+-  { "videotest", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x758f388c, 0xd4442397, 0x33f5784b, 0x923e6350, 0xf97bb902, }, 5 },
+-  { "videotest", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xb9f6f52a, 0x4e24e8b7, 0x53beb8e1, 0xa46ca57c, 0x688a184d, }, 5 },
+-  { "videotest", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x5bd98ce3, 0x15df7962, 0xc7d467e1, 0x89d29260, 0x662e2c16, }, 5 },
+-  { "videotest", 640, 480, 0x2, 256, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi256 */, (grub_uint32_t []) { 0xf9847b65, 0xf9847b65, 0xf9847b65, 0xf9847b65, 0xf9847b65, }, 5 },
+-  { "videotest", 800, 600, 0x2, 256, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi256 */, (grub_uint32_t []) { 0xc421716d, 0xc421716d, 0xc421716d, 0xc421716d, 0xc421716d, }, 5 },
+-  { "videotest", 1024, 768, 0x2, 256, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi256 */, (grub_uint32_t []) { 0x5d46f2a8, 0x5d46f2a8, 0x5d46f2a8, 0x5d46f2a8, 0x5d46f2a8, }, 5 },
+-  { "videotest", 640, 480, 0x1, 256, 15, 2, 10, 5, 5, 5, 0, 5, 0, 0 /* 640x480xrgba5550 */, (grub_uint32_t []) { 0x25690db2, 0x25690db2, 0x25690db2, 0x25690db2, 0x25690db2, }, 5 },
+-  { "videotest", 800, 600, 0x1, 256, 15, 2, 10, 5, 5, 5, 0, 5, 0, 0 /* 800x600xrgba5550 */, (grub_uint32_t []) { 0x7333f220, 0x7333f220, 0x7333f220, 0x7333f220, 0x7333f220, }, 5 },
+-  { "videotest", 1024, 768, 0x1, 256, 15, 2, 10, 5, 5, 5, 0, 5, 0, 0 /* 1024x768xrgba5550 */, (grub_uint32_t []) { 0xac52d537, 0xac52d537, 0xac52d537, 0xac52d537, 0xac52d537, }, 5 },
+-  { "videotest", 640, 480, 0x1, 256, 16, 2, 11, 5, 5, 6, 0, 5, 0, 0 /* 640x480xrgba5650 */, (grub_uint32_t []) { 0xd4cbcd66, 0xd4cbcd66, 0xd4cbcd66, 0xd4cbcd66, 0xd4cbcd66, }, 5 },
+-  { "videotest", 800, 600, 0x1, 256, 16, 2, 11, 5, 5, 6, 0, 5, 0, 0 /* 800x600xrgba5650 */, (grub_uint32_t []) { 0x9d23f9d1, 0x9d23f9d1, 0x9d23f9d1, 0x9d23f9d1, 0x9d23f9d1, }, 5 },
+-  { "videotest", 1024, 768, 0x1, 256, 16, 2, 11, 5, 5, 6, 0, 5, 0, 0 /* 1024x768xrgba5650 */, (grub_uint32_t []) { 0x89acbf88, 0x89acbf88, 0x89acbf88, 0x89acbf88, 0x89acbf88, }, 5 },
+-  { "videotest", 640, 480, 0x1, 256, 24, 3, 16, 8, 8, 8, 0, 8, 0, 0 /* 640x480xrgba8880 */, (grub_uint32_t []) { 0x335fadcb, 0x1f517b5c, 0x6b4200e5, 0x474cd672, 0x8364f797, }, 5 },
+-  { "videotest", 800, 600, 0x1, 256, 24, 3, 16, 8, 8, 8, 0, 8, 0, 0 /* 800x600xrgba8880 */, (grub_uint32_t []) { 0xcf9985f8, 0x1d92c7fc, 0x6e637701, 0xbc683505, 0x898016fb, }, 5 },
+-  { "videotest", 1024, 768, 0x1, 256, 24, 3, 16, 8, 8, 8, 0, 8, 0, 0 /* 1024x768xrgba8880 */, (grub_uint32_t []) { 0xdb824190, 0x378d05dc, 0x670bff9, 0xea7ffbb5, 0x658bcbb3, }, 5 },
+-  { "videotest", 640, 480, 0x1, 256, 15, 2, 0, 5, 5, 5, 10, 5, 0, 0 /* 640x480xbgra5550 */, (grub_uint32_t []) { 0x18ed532e, 0x18ed532e, 0x18ed532e, 0x18ed532e, 0x18ed532e, }, 5 },
+-  { "videotest", 800, 600, 0x1, 256, 15, 2, 0, 5, 5, 5, 10, 5, 0, 0 /* 800x600xbgra5550 */, (grub_uint32_t []) { 0x2b35b09f, 0x2b35b09f, 0x2b35b09f, 0x2b35b09f, 0x2b35b09f, }, 5 },
+-  { "videotest", 1024, 768, 0x1, 256, 15, 2, 0, 5, 5, 5, 10, 5, 0, 0 /* 1024x768xbgra5550 */, (grub_uint32_t []) { 0xa24c4d98, 0xa24c4d98, 0xa24c4d98, 0xa24c4d98, 0xa24c4d98, }, 5 },
+-  { "videotest", 640, 480, 0x1, 256, 16, 2, 0, 5, 5, 6, 11, 5, 0, 0 /* 640x480xbgra5650 */, (grub_uint32_t []) { 0xc07dde33, 0xc07dde33, 0xc07dde33, 0xc07dde33, 0xc07dde33, }, 5 },
+-  { "videotest", 800, 600, 0x1, 256, 16, 2, 0, 5, 5, 6, 11, 5, 0, 0 /* 800x600xbgra5650 */, (grub_uint32_t []) { 0x7e6ed757, 0x7e6ed757, 0x7e6ed757, 0x7e6ed757, 0x7e6ed757, }, 5 },
+-  { "videotest", 1024, 768, 0x1, 256, 16, 2, 0, 5, 5, 6, 11, 5, 0, 0 /* 1024x768xbgra5650 */, (grub_uint32_t []) { 0x700255dd, 0x700255dd, 0x700255dd, 0x700255dd, 0x700255dd, }, 5 },
+-  { "videotest", 640, 480, 0x1, 256, 24, 3, 0, 8, 8, 8, 16, 8, 0, 0 /* 640x480xbgra8880 */, (grub_uint32_t []) { 0x157232bd, 0x5e6bdacd, 0x8341e25d, 0xc8580a2d, 0x3cf9e58c, }, 5 },
+-  { "videotest", 800, 600, 0x1, 256, 24, 3, 0, 8, 8, 8, 16, 8, 0, 0 /* 800x600xbgra8880 */, (grub_uint32_t []) { 0xbfafd7cd, 0x51650951, 0x67d61c04, 0x891cc298, 0xab036ae, }, 5 },
+-  { "videotest", 1024, 768, 0x1, 256, 24, 3, 0, 8, 8, 8, 16, 8, 0, 0 /* 1024x768xbgra8880 */, (grub_uint32_t []) { 0x760580c9, 0xdc6d8205, 0x2739f3a0, 0x8d51f16c, 0xd47d661b, }, 5 },
+-  { "videotest", 640, 480, 0x1, 256, 32, 4, 0, 8, 8, 8, 16, 8, 24, 8 /* 640x480xbgra8888 */, (grub_uint32_t []) { 0xada3b5f, 0x24cd61a6, 0x56f48ead, 0x78e3d454, 0xb28750bb, }, 5 },
+-  { "videotest", 800, 600, 0x1, 256, 32, 4, 0, 8, 8, 8, 16, 8, 24, 8 /* 800x600xbgra8888 */, (grub_uint32_t []) { 0x827694e2, 0x9d97c3dd, 0xbdb43a9c, 0xa2556da3, 0xfdf3c81e, }, 5 },
+-  { "videotest", 1024, 768, 0x1, 256, 32, 4, 0, 8, 8, 8, 16, 8, 24, 8 /* 1024x768xbgra8888 */, (grub_uint32_t []) { 0x664534a5, 0xcd0979a0, 0x3531d85e, 0x9e7d955b, 0xc0aced53, }, 5 },
++  { "cmdline_cat", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xc69be699, 0xc69be699, 0xe17fc97c, 0xe17fc97c, 0xc2512486, 0xc2512486, 0x20260761, 0x20260761, 0xe3485349, 0xe3485349, 0x6020b4d9, 0x6020b4d9, 0x1605db98, 0x1605db98, 0xdca51b58, 0xdca51b58, 0xf3d66441, 0xf3d66441, 0x18cb7ce2, 0x18cb7ce2, 0x23b616d9, 0x23b616d9, 0xa1bf5dbf, 0xa1bf5dbf, 0x5e4a8b3d, 0x5e4a8b3d, 0x9933b3d8, 0x9933b3d8, 0xce7be2de, 0xce7be2de, 0x62531729, 0x62531729, 0xc39d3788, 0xc39d3788, 0xf7aee2fe, 0xf7aee2fe, 0xc66f4903, 0xc66f4903, 0x536c922f, 0x536c922f, 0xcb231652, 0x4ae07b67, 0x146816d5, 0x146816d5, }, 45 },
++  { "cmdline_cat", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x29d0cfb7, 0x29d0cfb7, 0x4d57ad88, 0x4d57ad88, 0xaf7591cb, 0xaf7591cb, 0xb88e3c0, 0xb88e3c0, 0x5d55a031, 0x5d55a031, 0x4363bcff, 0x4363bcff, 0xe1142833, 0xe1142833, 0x9578c80d, 0x9578c80d, 0xff1f5174, 0xff1f5174, 0x6828d47, 0x6828d47, 0x2a849ae3, 0x2a849ae3, 0x27a811d9, 0x27a811d9, 0x6c42e1cb, 0x6c42e1cb, 0x5bba61f5, 0x5bba61f5, 0xc02ab705, 0xc02ab705, 0xeb3e0e05, 0xeb3e0e05, 0x6f4ce3c, 0x6f4ce3c, 0x2075c50e, 0x2075c50e, 0x54ac7fba, 0x54ac7fba, 0x335d1c21, 0x335d1c21, 0xf923fbd1, 0x1b489d4d, 0x1253eb5e, 0x1253eb5e, }, 45 },
++  { "cmdline_cat", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x6ff92a98, 0x6ff92a98, 0xbd8264b3, 0xbd8264b3, 0x5c50282c, 0x5c50282c, 0xd18d6a5a, 0xd18d6a5a, 0x99cea139, 0x99cea139, 0x2590c545, 0x2590c545, 0x55c86045, 0x55c86045, 0xad53ef1e, 0xad53ef1e, 0x5b44a23a, 0x5b44a23a, 0xa255f863, 0xa255f863, 0x85b0bdca, 0x85b0bdca, 0x4220ee1f, 0x4220ee1f, 0xeb991a9f, 0xeb991a9f, 0x86f366dd, 0x86f366dd, 0xfa176b7d, 0xfa176b7d, 0xd7384ca9, 0xd7384ca9, 0xceebf5c1, 0xceebf5c1, 0xae62b268, 0xae62b268, 0x6e89bbd6, 0x6e89bbd6, 0x3fe07c8e, 0x3fe07c8e, 0xee5358fe, 0x162d1a8a, 0x876f8d10, 0x876f8d10, }, 45 },
++  { "cmdline_cat", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0xb96afaea, 0xb96afaea, 0xaa16ab1e, 0xaa16ab1e, 0x51ff382, 0x51ff382, 0xec74f127, 0xec74f127, 0xde4bca99, 0xde4bca99, 0x8ef3e8a5, 0x8ef3e8a5, 0x2daeb0b4, 0x2daeb0b4, 0x7cf5e243, 0x7cf5e243, 0x11fd57c6, 0x11fd57c6, 0x140723af, 0x140723af, 0x2bd93833, 0x2bd93833, 0xd731f4ac, 0xd731f4ac, 0x5fcd7114, 0x5fcd7114, 0xd1fea24a, 0xd1fea24a, 0x4083d53a, 0x4083d53a, 0x2e372605, 0x2e372605, 0x8e6316a7, 0x8e6316a7, 0x283ef6cc, 0x283ef6cc, 0x20cee9de, 0x20cee9de, 0xad6fa187, 0xad6fa187, 0xd691f438, 0xf3257e63, 0x4786ba7, 0x4786ba7, }, 45 },
++  { "cmdline_cat", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x48acf1bf, 0x48acf1bf, 0xb8777469, 0xb8777469, 0xad2fad44, 0xad2fad44, 0xa415ac59, 0xa415ac59, 0x5a7bfb26, 0x5a7bfb26, 0xccb6016, 0xccb6016, 0x77a80cb3, 0x77a80cb3, 0x2034c102, 0x2034c102, 0x444b4ccd, 0x444b4ccd, 0xe6c31bea, 0xe6c31bea, 0x8408036e, 0x8408036e, 0x9e7c556f, 0x9e7c556f, 0x445dc388, 0x445dc388, 0x94b3f850, 0x94b3f850, 0xf6f15341, 0xf6f15341, 0xcb939b5f, 0xcb939b5f, 0xbe88067d, 0xbe88067d, 0x1efc4734, 0x1efc4734, 0x7f5dfca8, 0x7f5dfca8, 0xb7b10eb9, 0xb7b10eb9, 0xb94cb441, 0x9571329, 0x8a26912b, 0x8a26912b, }, 45 },
++  { "cmdline_cat", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xc508d04e, 0xc508d04e, 0x6dbccbfe, 0x6dbccbfe, 0xbf06ff60, 0xbf06ff60, 0xbc5ab06, 0xbc5ab06, 0x97eeab3c, 0x97eeab3c, 0x62663589, 0x62663589, 0xb03e21e2, 0xb03e21e2, 0xea196bb6, 0xea196bb6, 0x672c16c4, 0x672c16c4, 0xefbca2cd, 0xefbca2cd, 0x1af5b410, 0x1af5b410, 0xc7a80569, 0xc7a80569, 0x4926a16, 0x4926a16, 0xee29c99c, 0xee29c99c, 0xffb15985, 0xffb15985, 0x4f608e46, 0x4f608e46, 0x3e450fd2, 0x3e450fd2, 0xac45215f, 0xac45215f, 0x789b0ce7, 0x789b0ce7, 0x4cedfe22, 0x4cedfe22, 0xa005588c, 0x701da05c, 0x6f25cec1, 0x6f25cec1, }, 45 },
++  { "cmdline_cat", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x29e7a7f, 0x29e7a7f, 0xbd221052, 0xbd221052, 0x3b18b64, 0x3b18b64, 0x7f1e8462, 0x7f1e8462, 0xf28d5124, 0xf28d5124, 0xc336f170, 0xc336f170, 0xfe3bf988, 0xfe3bf988, 0x7bf89e05, 0x7bf89e05, 0x7857a3f8, 0x7857a3f8, 0x272c1a36, 0x272c1a36, 0xe8adb445, 0xe8adb445, 0x70cfe280, 0x70cfe280, 0x4f2b6120, 0x4f2b6120, 0xbaf5caa5, 0xbaf5caa5, 0x4b6bcab2, 0x4b6bcab2, 0x2bef7b92, 0x2bef7b92, 0x17b381dc, 0x17b381dc, 0x884c9c35, 0x884c9c35, 0x2f9eb909, 0x2f9eb909, 0xa811b3af, 0xa811b3af, 0x4c39478f, 0x5a72c3ab, 0x8071678a, 0x8071678a, }, 45 },
++  { "gfxterm_menu", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xd9f04953, 0xbf3fa5d0, 0xd9f04953, 0x9a068414, 0x59c36f00, 0x59c36f00, 0x620c0067, 0x620c0067, 0x620c0067, 0x1c8c6d01, 0x1c8c6d01, 0x1c8c6d01, 0xc3269013, 0xc3269013, 0xc3269013, 0x59c36f00, 0x9a068414, 0x9a068414, 0x59c36f00, }, 20 },
++  { "gfxterm_menu", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x9254157f, 0x367e92c7, 0x9254157f, 0xbc519000, 0xaa4593fe, 0xaa4593fe, 0xa8a596c8, 0xa8a596c8, 0xa8a596c8, 0xe509baf, 0xe509baf, 0xe509baf, 0x16f0dc06, 0x16f0dc06, 0x16f0dc06, 0xaa4593fe, 0xbc519000, 0xbc519000, 0xaa4593fe, }, 20 },
++  { "gfxterm_menu", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x354b1976, 0x8fc746ae, 0x354b1976, 0x685c74f2, 0xc9cbf769, 0xc9cbf769, 0x3ce35e1d, 0x3ce35e1d, 0x3ce35e1d, 0xc23b9fd1, 0xc23b9fd1, 0xc23b9fd1, 0x5b18528e, 0x5b18528e, 0x5b18528e, 0xc9cbf769, 0x685c74f2, 0x685c74f2, 0xc9cbf769, }, 20 },
++  { "gfxterm_menu", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x1c9ec014, 0xaf3ec923, 0x1c9ec014, 0x43f5296, 0x9813a416, 0x9813a416, 0x43fda3fa, 0x43fda3fa, 0x43fda3fa, 0xd22625c9, 0xd22625c9, 0xd22625c9, 0x76a62c0a, 0x76a62c0a, 0x76a62c0a, 0x9813a416, 0x43f5296, 0x43f5296, 0x9813a416, }, 20 },
++  { "gfxterm_menu", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xa704f7ea, 0xb7f2ec8b, 0xa704f7ea, 0xb279bf59, 0x5fcf013d, 0x5fcf013d, 0xf3582c48, 0xf3582c48, 0xf3582c48, 0x2148343e, 0x2148343e, 0x2148343e, 0x9c719024, 0x9c719024, 0x9c719024, 0x5fcf013d, 0xb279bf59, 0xb279bf59, 0x5fcf013d, }, 20 },
++  { "gfxterm_menu", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xf293ce36, 0xa6eb6ae8, 0xf293ce36, 0xcd87647e, 0xdd28f52b, 0xdd28f52b, 0xb3c7ef80, 0xb3c7ef80, 0xb3c7ef80, 0x92fb1664, 0x92fb1664, 0x92fb1664, 0xd15b5e2e, 0xd15b5e2e, 0xd15b5e2e, 0xdd28f52b, 0xcd87647e, 0xcd87647e, 0xdd28f52b, }, 20 },
++  { "gfxterm_menu", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x31e75bd7, 0x9a768c6a, 0x31e75bd7, 0xa8fc31a6, 0x43d1f34, 0x43d1f34, 0xa0717008, 0xa0717008, 0xa0717008, 0xdf7bd9a0, 0xdf7bd9a0, 0xdf7bd9a0, 0x8e5a9312, 0x8e5a9312, 0x8e5a9312, 0x43d1f34, 0xa8fc31a6, 0xa8fc31a6, 0x43d1f34, }, 20 },
++  { "gfxmenu", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x1ce7bd78, 0x682580f5, 0x1ce7bd78, 0x490ad6fe, 0x9a2e0d26, 0x64eb71ba, 0x64eb71ba, 0x64eb71ba, 0x3833877a, 0x3833877a, 0x3833877a, 0xcfc14f0a, 0xcfc14f0a, 0xcfc14f0a, 0x59c36f00, 0x490ad6fe, 0x490ad6fe, }, 18 },
++  { "gfxmenu", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x2b6ff87d, 0x63ce2ca2, 0x2b6ff87d, 0xf00f044e, 0xa9d58ccd, 0xe2c46577, 0xe2c46577, 0xe2c46577, 0xb79bcf7d, 0xb79bcf7d, 0xb79bcf7d, 0xbc30ed71, 0xbc30ed71, 0xbc30ed71, 0xaa4593fe, 0xf00f044e, 0xf00f044e, }, 18 },
++  { "gfxmenu", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xe61cadba, 0x9880b727, 0xe61cadba, 0xdf5f2fc0, 0x5411be8b, 0x4449774e, 0x4449774e, 0x4449774e, 0x3bf7d1da, 0x3bf7d1da, 0x3bf7d1da, 0xd2ddee01, 0xd2ddee01, 0xd2ddee01, 0xc9cbf769, 0xdf5f2fc0, 0xdf5f2fc0, }, 18 },
++  { "gfxmenu", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x1c3742c9, 0xbe54acf7, 0x9b4ce770, 0xbe54acf7, 0x3111489, 0x740d78cf, 0x314c4c59, 0x314c4c59, 0x314c4c59, 0xdae9a625, 0xdae9a625, 0xdae9a625, 0xcbf8af57, 0xcbf8af57, 0xcbf8af57, 0x1c3742c9, 0x3111489, 0x3111489, }, 18 },
++  { "gfxmenu", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0xcc5a7bed, 0xee571de5, 0x568aaeff, 0xee571de5, 0xe328b7a7, 0xbcda144c, 0xf56e1b60, 0xf56e1b60, 0xf56e1b60, 0x9a27c771, 0x9a27c771, 0x9a27c771, 0xd6d05397, 0xd6d05397, 0xd6d05397, 0xcc5a7bed, 0xe328b7a7, 0xe328b7a7, }, 18 },
++  { "gfxmenu", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xef4a3312, 0x1db9877c, 0x7e1afeae, 0x1db9877c, 0x8fc0c430, 0x5d55a141, 0x96f335c6, 0x96f335c6, 0x96f335c6, 0x504171d8, 0x504171d8, 0x504171d8, 0x69f71c0, 0x69f71c0, 0x69f71c0, 0xef4a3312, 0x8fc0c430, 0x8fc0c430, }, 18 },
++  { "gfxmenu", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x54e48d80, 0x151819bd, 0xea8d4865, 0x151819bd, 0x11d75fd2, 0x6d6bb4bc, 0x650ccd09, 0x650ccd09, 0x650ccd09, 0xe4ff3bd8, 0xe4ff3bd8, 0xe4ff3bd8, 0xc5308b73, 0xc5308b73, 0xc5308b73, 0x54e48d80, 0x11d75fd2, 0x11d75fd2, }, 18 },
++  { "gfxterm_ar", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xd0b06c3d, 0xde50d1a5, 0xd0b06c3d, 0x9346a17a, 0x59c36f00, 0x59c36f00, 0xacff5d47, 0xacff5d47, 0xacff5d47, 0xd27f3021, 0xd27f3021, 0xd27f3021, 0xdd5cd33, 0xdd5cd33, 0xdd5cd33, 0x59c36f00, 0x9346a17a, 0x9346a17a, 0x59c36f00, }, 20 },
++  { "gfxterm_ar", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0xf32d50c1, 0x730a7ed, 0xf32d50c1, 0xdd28d5be, 0xaa4593fe, 0xaa4593fe, 0xba8a2d4c, 0xba8a2d4c, 0xba8a2d4c, 0x1c7f202b, 0x1c7f202b, 0x1c7f202b, 0x4df6782, 0x4df6782, 0x4df6782, 0xaa4593fe, 0xdd28d5be, 0xdd28d5be, 0xaa4593fe, }, 20 },
++  { "gfxterm_ar", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x711a4ac1, 0x6396f14c, 0x711a4ac1, 0x2c0d2745, 0xc9cbf769, 0xc9cbf769, 0x6b6ccbb0, 0x6b6ccbb0, 0x6b6ccbb0, 0x95b40a7c, 0x95b40a7c, 0x95b40a7c, 0xc97c723, 0xc97c723, 0xc97c723, 0xc9cbf769, 0x2c0d2745, 0x2c0d2745, 0xc9cbf769, }, 20 },
++  { "gfxterm_ar", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x29baad6a, 0x348b1f2b, 0x29baad6a, 0x311b3fe8, 0x9813a416, 0x9813a416, 0xe8e982cc, 0xe8e982cc, 0xe8e982cc, 0x793204ff, 0x793204ff, 0x793204ff, 0xddb20d3c, 0xddb20d3c, 0xddb20d3c, 0x9813a416, 0x311b3fe8, 0x311b3fe8, 0x9813a416, }, 20 },
++  { "gfxterm_ar", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xf834b3bb, 0x3951bd1a, 0xf834b3bb, 0xed49fb08, 0x5fcf013d, 0x5fcf013d, 0x5aefa2a7, 0x5aefa2a7, 0x5aefa2a7, 0x88ffbad1, 0x88ffbad1, 0x88ffbad1, 0x35c61ecb, 0x35c61ecb, 0x35c61ecb, 0x5fcf013d, 0xed49fb08, 0xed49fb08, 0x5fcf013d, }, 20 },
++  { "gfxterm_ar", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x7e9a7a47, 0xb1651b5a, 0x7e9a7a47, 0x418ed00f, 0xdd28f52b, 0xdd28f52b, 0x83f9db69, 0x83f9db69, 0x83f9db69, 0xa2c5228d, 0xa2c5228d, 0xa2c5228d, 0xe1656ac7, 0xe1656ac7, 0xe1656ac7, 0xdd28f52b, 0x418ed00f, 0x418ed00f, 0xdd28f52b, }, 20 },
++  { "gfxterm_ar", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0xc6a0340, 0x7dd5855c, 0xc6a0340, 0x95716931, 0x43d1f34, 0x43d1f34, 0x5f1c24c0, 0x5f1c24c0, 0x5f1c24c0, 0x20168d68, 0x20168d68, 0x20168d68, 0x7137c7da, 0x7137c7da, 0x7137c7da, 0x43d1f34, 0x95716931, 0x95716931, 0x43d1f34, }, 20 },
++  { "gfxterm_cyr", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xd3798aaa, 0xab48784c, 0xd3798aaa, 0x908f47ed, 0x59c36f00, 0x59c36f00, 0x1688ec7c, 0x1688ec7c, 0x1688ec7c, 0x6808811a, 0x6808811a, 0x6808811a, 0xb7a27c08, 0xb7a27c08, 0xb7a27c08, 0x59c36f00, 0x908f47ed, 0x908f47ed, 0x59c36f00, }, 20 },
++  { "gfxterm_cyr", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0xc30d9d2a, 0x60b9ed26, 0xc30d9d2a, 0xed081855, 0xaa4593fe, 0xaa4593fe, 0x3eba2192, 0x3eba2192, 0x3eba2192, 0x984f2cf5, 0x984f2cf5, 0x984f2cf5, 0x80ef6b5c, 0x80ef6b5c, 0x80ef6b5c, 0xaa4593fe, 0xed081855, 0xed081855, 0xaa4593fe, }, 20 },
++  { "gfxterm_cyr", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xe469e6af, 0x46ac2012, 0xe469e6af, 0xb97e8b2b, 0xc9cbf769, 0xc9cbf769, 0x60f0d993, 0x60f0d993, 0x60f0d993, 0x9e28185f, 0x9e28185f, 0x9e28185f, 0x70bd500, 0x70bd500, 0x70bd500, 0xc9cbf769, 0xb97e8b2b, 0xb97e8b2b, 0xc9cbf769, }, 20 },
++  { "gfxterm_cyr", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x8538d2ef, 0xab143284, 0x8538d2ef, 0x9d99406d, 0x9813a416, 0x9813a416, 0x7e8326ec, 0x7e8326ec, 0x7e8326ec, 0xef58a0df, 0xef58a0df, 0xef58a0df, 0x4bd8a91c, 0x4bd8a91c, 0x4bd8a91c, 0x9813a416, 0x9d99406d, 0x9d99406d, 0x9813a416, }, 20 },
++  { "gfxterm_cyr", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x8115198c, 0x1abdaee1, 0x8115198c, 0x9468513f, 0x5fcf013d, 0x5fcf013d, 0xa5e86484, 0xa5e86484, 0xa5e86484, 0x77f87cf2, 0x77f87cf2, 0x77f87cf2, 0xcac1d8e8, 0xcac1d8e8, 0xcac1d8e8, 0x5fcf013d, 0x9468513f, 0x9468513f, 0x5fcf013d, }, 20 },
++  { "gfxterm_cyr", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xea03b805, 0x74148290, 0xea03b805, 0xd517124d, 0xdd28f52b, 0xdd28f52b, 0x8f6eee40, 0x8f6eee40, 0x8f6eee40, 0xae5217a4, 0xae5217a4, 0xae5217a4, 0xedf25fee, 0xedf25fee, 0xedf25fee, 0xdd28f52b, 0xd517124d, 0xd517124d, 0xdd28f52b, }, 20 },
++  { "gfxterm_cyr", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0xa044490f, 0xe23458db, 0xa044490f, 0x395f237e, 0x43d1f34, 0x43d1f34, 0xe1ca82c2, 0xe1ca82c2, 0xe1ca82c2, 0x9ec02b6a, 0x9ec02b6a, 0x9ec02b6a, 0xcfe161d8, 0xcfe161d8, 0xcfe161d8, 0x43d1f34, 0x395f237e, 0x395f237e, 0x43d1f34, }, 20 },
++  { "gfxterm_heb", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xf3259b30, 0xf1f01411, 0xf3259b30, 0xb0d35677, 0x59c36f00, 0x59c36f00, 0x97895f8e, 0x97895f8e, 0x97895f8e, 0xe90932e8, 0xe90932e8, 0xe90932e8, 0x36a3cffa, 0x36a3cffa, 0x36a3cffa, 0x59c36f00, 0xb0d35677, 0xb0d35677, 0x59c36f00, }, 20 },
++  { "gfxterm_heb", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x53a43759, 0xe0f26bfa, 0x53a43759, 0x7da1b226, 0xaa4593fe, 0xaa4593fe, 0xbf482a4e, 0xbf482a4e, 0xbf482a4e, 0x19bd2729, 0x19bd2729, 0x19bd2729, 0x11d6080, 0x11d6080, 0x11d6080, 0xaa4593fe, 0x7da1b226, 0x7da1b226, 0xaa4593fe, }, 20 },
++  { "gfxterm_heb", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xd7ff8d53, 0x665b2728, 0xd7ff8d53, 0x8ae8e0d7, 0xc9cbf769, 0xc9cbf769, 0x5a693e73, 0x5a693e73, 0x5a693e73, 0xa4b1ffbf, 0xa4b1ffbf, 0xa4b1ffbf, 0x3d9232e0, 0x3d9232e0, 0x3d9232e0, 0xc9cbf769, 0x8ae8e0d7, 0x8ae8e0d7, 0xc9cbf769, }, 20 },
++  { "gfxterm_heb", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x99fddcbe, 0x6d5c8895, 0x99fddcbe, 0x815c4e3c, 0x9813a416, 0x9813a416, 0x9bcf9821, 0x9bcf9821, 0x9bcf9821, 0xa141e12, 0xa141e12, 0xa141e12, 0xae9417d1, 0xae9417d1, 0xae9417d1, 0x9813a416, 0x815c4e3c, 0x815c4e3c, 0x9813a416, }, 20 },
++  { "gfxterm_heb", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x5797846, 0x25a6ad40, 0x5797846, 0x100430f5, 0x5fcf013d, 0x5fcf013d, 0xddc86daf, 0xddc86daf, 0xddc86daf, 0xfd875d9, 0xfd875d9, 0xfd875d9, 0xb2e1d1c3, 0xb2e1d1c3, 0xb2e1d1c3, 0x5fcf013d, 0x100430f5, 0x100430f5, 0x5fcf013d, }, 20 },
++  { "gfxterm_heb", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x30653ae8, 0x7fcd187, 0x30653ae8, 0xf7190a0, 0xdd28f52b, 0xdd28f52b, 0x24c3d325, 0x24c3d325, 0x24c3d325, 0x5ff2ac1, 0x5ff2ac1, 0x5ff2ac1, 0x465f628b, 0x465f628b, 0x465f628b, 0xdd28f52b, 0xf7190a0, 0xf7190a0, 0xdd28f52b, }, 20 },
++  { "gfxterm_heb", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x3bd91638, 0x1d74dd4a, 0x3bd91638, 0xa2c27c49, 0x43d1f34, 0x43d1f34, 0x53d1ad3d, 0x53d1ad3d, 0x53d1ad3d, 0x2cdb0495, 0x2cdb0495, 0x2cdb0495, 0x7dfa4e27, 0x7dfa4e27, 0x7dfa4e27, 0x43d1f34, 0xa2c27c49, 0xa2c27c49, 0x43d1f34, }, 20 },
++  { "gfxterm_gre", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xbe2c351a, 0x2692720, 0xbe2c351a, 0xfddaf85d, 0x59c36f00, 0x59c36f00, 0x1b2e2301, 0x1b2e2301, 0x1b2e2301, 0x65ae4e67, 0x65ae4e67, 0x65ae4e67, 0xba04b375, 0xba04b375, 0xba04b375, 0x59c36f00, 0xfddaf85d, 0xfddaf85d, 0x59c36f00, }, 20 },
++  { "gfxterm_gre", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x1eca82e1, 0xe8fa59cc, 0x1eca82e1, 0x30cf079e, 0xaa4593fe, 0xaa4593fe, 0xaf27ddc5, 0xaf27ddc5, 0xaf27ddc5, 0x9d2d0a2, 0x9d2d0a2, 0x9d2d0a2, 0x1172970b, 0x1172970b, 0x1172970b, 0xaa4593fe, 0x30cf079e, 0x30cf079e, 0xaa4593fe, }, 20 },
++  { "gfxterm_gre", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xa9ccd435, 0x1ac646eb, 0xa9ccd435, 0xf4dbb9b1, 0xc9cbf769, 0xc9cbf769, 0x86d69aa0, 0x86d69aa0, 0x86d69aa0, 0x780e5b6c, 0x780e5b6c, 0x780e5b6c, 0xe12d9633, 0xe12d9633, 0xe12d9633, 0xc9cbf769, 0xf4dbb9b1, 0xf4dbb9b1, 0xc9cbf769, }, 20 },
++  { "gfxterm_gre", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0xf96d568, 0x7ad05c1b, 0xf96d568, 0x173747ea, 0x9813a416, 0x9813a416, 0xacf9792a, 0xacf9792a, 0xacf9792a, 0x3d22ff19, 0x3d22ff19, 0x3d22ff19, 0x99a2f6da, 0x99a2f6da, 0x99a2f6da, 0x9813a416, 0x173747ea, 0x173747ea, 0x9813a416, }, 20 },
++  { "gfxterm_gre", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xa0dc6b9c, 0xc2761148, 0xa0dc6b9c, 0xb5a1232f, 0x5fcf013d, 0x5fcf013d, 0x4e05748b, 0x4e05748b, 0x4e05748b, 0x9c156cfd, 0x9c156cfd, 0x9c156cfd, 0x212cc8e7, 0x212cc8e7, 0x212cc8e7, 0x5fcf013d, 0xb5a1232f, 0xb5a1232f, 0x5fcf013d, }, 20 },
++  { "gfxterm_gre", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xcd722f7d, 0xe4df8d6b, 0xcd722f7d, 0xf2668535, 0xdd28f52b, 0xdd28f52b, 0xbdbb8019, 0xbdbb8019, 0xbdbb8019, 0x9c8779fd, 0x9c8779fd, 0x9c8779fd, 0xdf2731b7, 0xdf2731b7, 0xdf2731b7, 0xdd28f52b, 0xf2668535, 0xf2668535, 0xdd28f52b, }, 20 },
++  { "gfxterm_gre", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0xa6c99d2f, 0x1de04317, 0xa6c99d2f, 0x3fd2f75e, 0x43d1f34, 0x43d1f34, 0x3f85b7d3, 0x3f85b7d3, 0x3f85b7d3, 0x408f1e7b, 0x408f1e7b, 0x408f1e7b, 0x11ae54c9, 0x11ae54c9, 0x11ae54c9, 0x43d1f34, 0x3fd2f75e, 0x3fd2f75e, 0x43d1f34, }, 20 },
++  { "gfxterm_ru", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x1e35b709, 0x2683bf92, 0x1e35b709, 0x5dc37a4e, 0x59c36f00, 0x59c36f00, 0xd697967f, 0xd697967f, 0xd697967f, 0xa817fb19, 0xa817fb19, 0xa817fb19, 0x77bd060b, 0x77bd060b, 0x77bd060b, 0x59c36f00, 0x5dc37a4e, 0x5dc37a4e, 0x59c36f00, }, 20 },
++  { "gfxterm_ru", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x53ff7735, 0x8cbf197c, 0x53ff7735, 0x7dfaf24a, 0xaa4593fe, 0xaa4593fe, 0x389a922, 0x389a922, 0x389a922, 0xa57ca445, 0xa57ca445, 0xa57ca445, 0xbddce3ec, 0xbddce3ec, 0xbddce3ec, 0xaa4593fe, 0x7dfaf24a, 0x7dfaf24a, 0xaa4593fe, }, 20 },
++  { "gfxterm_ru", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x5217c47d, 0x7c8ae63e, 0x5217c47d, 0xf00a9f9, 0xc9cbf769, 0xc9cbf769, 0x3995409, 0x3995409, 0x3995409, 0xfd4195c5, 0xfd4195c5, 0xfd4195c5, 0x6462589a, 0x6462589a, 0x6462589a, 0xc9cbf769, 0xf00a9f9, 0xf00a9f9, 0xc9cbf769, }, 20 },
++  { "gfxterm_ru", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x45b67706, 0x375fb5db, 0x45b67706, 0x5d17e584, 0x9813a416, 0x9813a416, 0x8195719b, 0x8195719b, 0x8195719b, 0x104ef7a8, 0x104ef7a8, 0x104ef7a8, 0xb4cefe6b, 0xb4cefe6b, 0xb4cefe6b, 0x9813a416, 0x5d17e584, 0x5d17e584, 0x9813a416, }, 20 },
++  { "gfxterm_ru", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xfc209a25, 0xd5c20779, 0xfc209a25, 0xe95dd296, 0x5fcf013d, 0x5fcf013d, 0xe5699efe, 0xe5699efe, 0xe5699efe, 0x37798688, 0x37798688, 0x37798688, 0x8a402292, 0x8a402292, 0x8a402292, 0x5fcf013d, 0xe95dd296, 0xe95dd296, 0x5fcf013d, }, 20 },
++  { "gfxterm_ru", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x77f956f0, 0xfb0cc079, 0x77f956f0, 0x48edfcb8, 0xdd28f52b, 0xdd28f52b, 0xd51b1dc9, 0xd51b1dc9, 0xd51b1dc9, 0xf427e42d, 0xf427e42d, 0xf427e42d, 0xb787ac67, 0xb787ac67, 0xb787ac67, 0xdd28f52b, 0x48edfcb8, 0x48edfcb8, 0xdd28f52b, }, 20 },
++  { "gfxterm_ru", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x1d9ac82a, 0xa254aa53, 0x1d9ac82a, 0x8481a25b, 0x43d1f34, 0x43d1f34, 0xc304df68, 0xc304df68, 0xc304df68, 0xbc0e76c0, 0xbc0e76c0, 0xbc0e76c0, 0xed2f3c72, 0xed2f3c72, 0xed2f3c72, 0x43d1f34, 0x8481a25b, 0x8481a25b, 0x43d1f34, }, 20 },
++  { "gfxterm_fr", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xa6239a89, 0x8dc4bfbb, 0xa6239a89, 0xe5d557ce, 0x59c36f00, 0x59c36f00, 0x244cf807, 0x244cf807, 0x244cf807, 0x5acc9561, 0x5acc9561, 0x5acc9561, 0x85666873, 0x85666873, 0x85666873, 0x59c36f00, 0xe5d557ce, 0xe5d557ce, 0x59c36f00, }, 20 },
++  { "gfxterm_fr", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x742cede9, 0x83bb7a50, 0x742cede9, 0x5a296896, 0xaa4593fe, 0xaa4593fe, 0xd83f8aeb, 0xd83f8aeb, 0xd83f8aeb, 0x7eca878c, 0x7eca878c, 0x7eca878c, 0x666ac025, 0x666ac025, 0x666ac025, 0xaa4593fe, 0x5a296896, 0x5a296896, 0xaa4593fe, }, 20 },
++  { "gfxterm_fr", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xe20a98b0, 0x7e8cedef, 0xe20a98b0, 0xbf1df534, 0xc9cbf769, 0xc9cbf769, 0x2748b88c, 0x2748b88c, 0x2748b88c, 0xd9907940, 0xd9907940, 0xd9907940, 0x40b3b41f, 0x40b3b41f, 0x40b3b41f, 0xc9cbf769, 0xbf1df534, 0xbf1df534, 0xc9cbf769, }, 20 },
++  { "gfxterm_fr", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x8f911ca4, 0xcbf1d895, 0x8f911ca4, 0x97308e26, 0x9813a416, 0x9813a416, 0x5b359bf4, 0x5b359bf4, 0x5b359bf4, 0xcaee1dc7, 0xcaee1dc7, 0xcaee1dc7, 0x6e6e1404, 0x6e6e1404, 0x6e6e1404, 0x9813a416, 0x97308e26, 0x97308e26, 0x9813a416, }, 20 },
++  { "gfxterm_fr", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x1bf82c82, 0xc7b39627, 0x1bf82c82, 0xe856431, 0x5fcf013d, 0x5fcf013d, 0xa9dbae99, 0xa9dbae99, 0xa9dbae99, 0x7bcbb6ef, 0x7bcbb6ef, 0x7bcbb6ef, 0xc6f212f5, 0xc6f212f5, 0xc6f212f5, 0x5fcf013d, 0xe856431, 0xe856431, 0x5fcf013d, }, 20 },
++  { "gfxterm_fr", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xfae19a5c, 0xd1e8fabb, 0xfae19a5c, 0xc5f53014, 0xdd28f52b, 0xdd28f52b, 0xfa2c5565, 0xfa2c5565, 0xfa2c5565, 0xdb10ac81, 0xdb10ac81, 0xdb10ac81, 0x98b0e4cb, 0x98b0e4cb, 0x98b0e4cb, 0xdd28f52b, 0xc5f53014, 0xc5f53014, 0xdd28f52b, }, 20 },
++  { "gfxterm_fr", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x9a18f7bc, 0x5fcecc43, 0x9a18f7bc, 0x3039dcd, 0x43d1f34, 0x43d1f34, 0x287a2b96, 0x287a2b96, 0x287a2b96, 0x5770823e, 0x5770823e, 0x5770823e, 0x651c88c, 0x651c88c, 0x651c88c, 0x43d1f34, 0x3039dcd, 0x3039dcd, 0x43d1f34, }, 20 },
++  { "gfxterm_quot", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x65112dfc, 0x3dec17f, 0x65112dfc, 0x26e7e0bb, 0x59c36f00, 0x59c36f00, 0x620c0067, 0x620c0067, 0x620c0067, 0x1c8c6d01, 0x1c8c6d01, 0x1c8c6d01, 0xc3269013, 0xc3269013, 0xc3269013, 0x59c36f00, 0x26e7e0bb, 0x26e7e0bb, 0x59c36f00, }, 20 },
++  { "gfxterm_quot", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x2b3430fb, 0x8f1eb743, 0x2b3430fb, 0x531b584, 0xaa4593fe, 0xaa4593fe, 0xa8a596c8, 0xa8a596c8, 0xa8a596c8, 0xe509baf, 0xe509baf, 0xe509baf, 0x16f0dc06, 0x16f0dc06, 0x16f0dc06, 0xaa4593fe, 0x531b584, 0x531b584, 0xaa4593fe, }, 20 },
++  { "gfxterm_quot", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xb523e920, 0xfafb6f8, 0xb523e920, 0xe83484a4, 0xc9cbf769, 0xc9cbf769, 0x3ce35e1d, 0x3ce35e1d, 0x3ce35e1d, 0xc23b9fd1, 0xc23b9fd1, 0xc23b9fd1, 0x5b18528e, 0x5b18528e, 0x5b18528e, 0xc9cbf769, 0xe83484a4, 0xe83484a4, 0xc9cbf769, }, 20 },
++  { "gfxterm_quot", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0xa9bf7336, 0x1a1f7a01, 0xa9bf7336, 0xb11ee1b4, 0x9813a416, 0x9813a416, 0x43fda3fa, 0x43fda3fa, 0x43fda3fa, 0xd22625c9, 0xd22625c9, 0xd22625c9, 0x76a62c0a, 0x76a62c0a, 0x76a62c0a, 0x9813a416, 0xb11ee1b4, 0xb11ee1b4, 0x9813a416, }, 20 },
++  { "gfxterm_quot", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xe5271912, 0xf5d10273, 0xe5271912, 0xf05a51a1, 0x5fcf013d, 0x5fcf013d, 0xf3582c48, 0xf3582c48, 0xf3582c48, 0x2148343e, 0x2148343e, 0x2148343e, 0x9c719024, 0x9c719024, 0x9c719024, 0x5fcf013d, 0xf05a51a1, 0xf05a51a1, 0x5fcf013d, }, 20 },
++  { "gfxterm_quot", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x66a34f49, 0x32dbeb97, 0x66a34f49, 0x59b7e501, 0xdd28f52b, 0xdd28f52b, 0xb3c7ef80, 0xb3c7ef80, 0xb3c7ef80, 0x92fb1664, 0x92fb1664, 0x92fb1664, 0xd15b5e2e, 0xd15b5e2e, 0xd15b5e2e, 0xdd28f52b, 0x59b7e501, 0x59b7e501, 0xdd28f52b, }, 20 },
++  { "gfxterm_quot", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x7c2f19da, 0xd7bece67, 0x7c2f19da, 0xe53473ab, 0x43d1f34, 0x43d1f34, 0xa0717008, 0xa0717008, 0xa0717008, 0xdf7bd9a0, 0xdf7bd9a0, 0xdf7bd9a0, 0x8e5a9312, 0x8e5a9312, 0x8e5a9312, 0x43d1f34, 0xe53473ab, 0xe53473ab, 0x43d1f34, }, 20 },
++  { "gfxterm_piglatin", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x37943894, 0x78248c70, 0x37943894, 0x7462f5d3, 0x59c36f00, 0x59c36f00, 0xf4be229a, 0xf4be229a, 0xf4be229a, 0x8a3e4ffc, 0x8a3e4ffc, 0x8a3e4ffc, 0x5594b2ee, 0x5594b2ee, 0x5594b2ee, 0x59c36f00, 0x7462f5d3, 0x7462f5d3, 0x59c36f00, }, 20 },
++  { "gfxterm_piglatin", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0xd5158e6c, 0xdc71ba0f, 0xd5158e6c, 0xfb100b13, 0xaa4593fe, 0xaa4593fe, 0xd3ed72a3, 0xd3ed72a3, 0xd3ed72a3, 0x75187fc4, 0x75187fc4, 0x75187fc4, 0x6db8386d, 0x6db8386d, 0x6db8386d, 0xaa4593fe, 0xfb100b13, 0xfb100b13, 0xaa4593fe, }, 20 },
++  { "gfxterm_piglatin", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0x6277a9e6, 0xa3265ffb, 0x6277a9e6, 0x3f60c462, 0xc9cbf769, 0xc9cbf769, 0x2dcf8a8d, 0x2dcf8a8d, 0x2dcf8a8d, 0xd3174b41, 0xd3174b41, 0xd3174b41, 0x4a34861e, 0x4a34861e, 0x4a34861e, 0xc9cbf769, 0x3f60c462, 0x3f60c462, 0xc9cbf769, }, 20 },
++  { "gfxterm_piglatin", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0x81115dc4, 0xddf3f768, 0x81115dc4, 0x99b0cf46, 0x9813a416, 0x9813a416, 0x9b9d96df, 0x9b9d96df, 0x9b9d96df, 0xa4610ec, 0xa4610ec, 0xa4610ec, 0xaec6192f, 0xaec6192f, 0xaec6192f, 0x9813a416, 0x99b0cf46, 0x99b0cf46, 0x9813a416, }, 20 },
++  { "gfxterm_piglatin", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x5e96a904, 0x27864d3d, 0x5e96a904, 0x4bebe1b7, 0x5fcf013d, 0x5fcf013d, 0x18cae7f4, 0x18cae7f4, 0x18cae7f4, 0xcadaff82, 0xcadaff82, 0xcadaff82, 0x77e35b98, 0x77e35b98, 0x77e35b98, 0x5fcf013d, 0x4bebe1b7, 0x4bebe1b7, 0x5fcf013d, }, 20 },
++  { "gfxterm_piglatin", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0xd00b19f8, 0xba73a9c6, 0xd00b19f8, 0xef1fb3b0, 0xdd28f52b, 0xdd28f52b, 0xb660046d, 0xb660046d, 0xb660046d, 0x975cfd89, 0x975cfd89, 0x975cfd89, 0xd4fcb5c3, 0xd4fcb5c3, 0xd4fcb5c3, 0xdd28f52b, 0xef1fb3b0, 0xef1fb3b0, 0xdd28f52b, }, 20 },
++  { "gfxterm_piglatin", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x8b4b98cd, 0x78ddc6e4, 0x8b4b98cd, 0x1250f2bc, 0x43d1f34, 0x43d1f34, 0x4889d3fd, 0x4889d3fd, 0x4889d3fd, 0x37837a55, 0x37837a55, 0x37837a55, 0x66a230e7, 0x66a230e7, 0x66a230e7, 0x43d1f34, 0x1250f2bc, 0x1250f2bc, 0x43d1f34, }, 20 },
++  { "gfxterm_ch", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0xfecb570e, 0xccb97a7a, 0xfecb570e, 0xbd3d9a49, 0x59c36f00, 0x59c36f00, 0x40281258, 0x40281258, 0x40281258, 0x3ea87f3e, 0x3ea87f3e, 0x3ea87f3e, 0xe102822c, 0xe102822c, 0xe102822c, 0x59c36f00, 0xbd3d9a49, 0xbd3d9a49, 0x59c36f00, }, 20 },
++  { "gfxterm_ch", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0x897d1fac, 0xaa982529, 0x897d1fac, 0xa7789ad3, 0xaa4593fe, 0xaa4593fe, 0xa482510, 0xa482510, 0xa482510, 0xacbd2877, 0xacbd2877, 0xacbd2877, 0xb41d6fde, 0xb41d6fde, 0xb41d6fde, 0xaa4593fe, 0xa7789ad3, 0xa7789ad3, 0xaa4593fe, }, 20 },
++  { "gfxterm_ch", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xd02a5297, 0xe627ab58, 0xd02a5297, 0x8d3d3f13, 0xc9cbf769, 0xc9cbf769, 0xbf0a8b7f, 0xbf0a8b7f, 0xbf0a8b7f, 0x41d24ab3, 0x41d24ab3, 0x41d24ab3, 0xd8f187ec, 0xd8f187ec, 0xd8f187ec, 0xc9cbf769, 0x8d3d3f13, 0x8d3d3f13, 0xc9cbf769, }, 20 },
++  { "gfxterm_ch", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0xa653dcda, 0x3392e976, 0xa653dcda, 0xbef24e58, 0x9813a416, 0x9813a416, 0x4f2bc106, 0x4f2bc106, 0x4f2bc106, 0xdef04735, 0xdef04735, 0xdef04735, 0x7a704ef6, 0x7a704ef6, 0x7a704ef6, 0x9813a416, 0xbef24e58, 0xbef24e58, 0x9813a416, }, 20 },
++  { "gfxterm_ch", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xe2d7b585, 0x35241f36, 0xe2d7b585, 0xf7aafd36, 0x5fcf013d, 0x5fcf013d, 0xf2bd04db, 0xf2bd04db, 0xf2bd04db, 0x20ad1cad, 0x20ad1cad, 0x20ad1cad, 0x9d94b8b7, 0x9d94b8b7, 0x9d94b8b7, 0x5fcf013d, 0xf7aafd36, 0xf7aafd36, 0x5fcf013d, }, 20 },
++  { "gfxterm_ch", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x72ff749c, 0xeda8c283, 0x72ff749c, 0x4debded4, 0xdd28f52b, 0xdd28f52b, 0xb8c9cc22, 0xb8c9cc22, 0xb8c9cc22, 0x99f535c6, 0x99f535c6, 0x99f535c6, 0xda557d8c, 0xda557d8c, 0xda557d8c, 0xdd28f52b, 0x4debded4, 0x4debded4, 0xdd28f52b, }, 20 },
++  { "gfxterm_ch", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0xb7cac764, 0xeb4bf417, 0xb7cac764, 0x2ed1ad15, 0x43d1f34, 0x43d1f34, 0xce718801, 0xce718801, 0xce718801, 0xb17b21a9, 0xb17b21a9, 0xb17b21a9, 0xe05a6b1b, 0xe05a6b1b, 0xe05a6b1b, 0x43d1f34, 0x2ed1ad15, 0x2ed1ad15, 0x43d1f34, }, 20 },
++  { "gfxterm_red", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x930e8e13, 0xf5c16290, 0x930e8e13, 0x27f5f1c0, 0x59c36f00, 0x59c36f00, 0xbad4e11, 0xbad4e11, 0xbad4e11, 0x752d2377, 0x752d2377, 0x752d2377, 0xaa87de65, 0xaa87de65, 0xaa87de65, 0x59c36f00, 0x27f5f1c0, 0x27f5f1c0, 0x59c36f00, }, 20 },
++  { "gfxterm_red", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0xff9301f2, 0x5bb9864a, 0xff9301f2, 0x31c145de, 0xaa4593fe, 0xaa4593fe, 0x23bf2c32, 0x23bf2c32, 0x23bf2c32, 0x854a2155, 0x854a2155, 0x854a2155, 0x9dea66fc, 0x9dea66fc, 0x9dea66fc, 0xaa4593fe, 0x31c145de, 0x31c145de, 0xaa4593fe, }, 20 },
++  { "gfxterm_red", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xfc5938ef, 0x46d56737, 0xfc5938ef, 0x23cf2668, 0xc9cbf769, 0xc9cbf769, 0xa8c549aa, 0xa8c549aa, 0xa8c549aa, 0x561d8866, 0x561d8866, 0x561d8866, 0xcf3e4539, 0xcf3e4539, 0xcf3e4539, 0xc9cbf769, 0x23cf2668, 0x23cf2668, 0xc9cbf769, }, 20 },
++  { "gfxterm_red", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0xe7160822, 0x54b60115, 0xe7160822, 0x168efa6f, 0x9813a416, 0x9813a416, 0xb774a5aa, 0xb774a5aa, 0xb774a5aa, 0x26af2399, 0x26af2399, 0x26af2399, 0x822f2a5a, 0x822f2a5a, 0x822f2a5a, 0x9813a416, 0x168efa6f, 0x168efa6f, 0x9813a416, }, 20 },
++  { "gfxterm_red", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0xf655f9b2, 0xe6a3e2d3, 0xf655f9b2, 0xd1d7405f, 0x5fcf013d, 0x5fcf013d, 0x2accaa08, 0x2accaa08, 0x2accaa08, 0xf8dcb27e, 0xf8dcb27e, 0xf8dcb27e, 0x45e51664, 0x45e51664, 0x45e51664, 0x5fcf013d, 0xd1d7405f, 0xd1d7405f, 0x5fcf013d, }, 20 },
++  { "gfxterm_red", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x2d85ebdc, 0x79fd4f02, 0x2d85ebdc, 0xc48ae2b6, 0xdd28f52b, 0xdd28f52b, 0x76b28a95, 0x76b28a95, 0x76b28a95, 0x578e7371, 0x578e7371, 0x578e7371, 0x142e3b3b, 0x142e3b3b, 0x142e3b3b, 0xdd28f52b, 0xc48ae2b6, 0xc48ae2b6, 0xdd28f52b, }, 20 },
++  { "gfxterm_red", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x29c00f98, 0x8251d825, 0x29c00f98, 0x35a750d1, 0x43d1f34, 0x43d1f34, 0x48b70bc8, 0x48b70bc8, 0x48b70bc8, 0x37bda260, 0x37bda260, 0x37bda260, 0x669ce8d2, 0x669ce8d2, 0x669ce8d2, 0x43d1f34, 0x35a750d1, 0x35a750d1, 0x43d1f34, }, 20 },
++  { "gfxterm_high", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0x59c36f00, 0x4afab717, 0x2c355b94, 0x4afab717, 0x1166d9d0, 0x59c36f00, 0x59c36f00, 0x620c0067, 0x620c0067, 0x620c0067, 0x1c8c6d01, 0x1c8c6d01, 0x1c8c6d01, 0xc3269013, 0xc3269013, 0xc3269013, 0x59c36f00, 0x1166d9d0, 0x1166d9d0, 0x59c36f00, }, 20 },
++  { "gfxterm_high", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xaa4593fe, 0xe3daadd4, 0x47f02a6c, 0xe3daadd4, 0x5ea9fb21, 0xaa4593fe, 0xaa4593fe, 0xa8a596c8, 0xa8a596c8, 0xa8a596c8, 0xe509baf, 0xe509baf, 0xe509baf, 0x16f0dc06, 0x16f0dc06, 0x16f0dc06, 0xaa4593fe, 0x5ea9fb21, 0x5ea9fb21, 0xaa4593fe, }, 20 },
++  { "gfxterm_high", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0xc9cbf769, 0xf140d1df, 0x4bcc8e07, 0xf140d1df, 0x7c962dcb, 0xc9cbf769, 0xc9cbf769, 0x3ce35e1d, 0x3ce35e1d, 0x3ce35e1d, 0xc23b9fd1, 0xc23b9fd1, 0xc23b9fd1, 0x5b18528e, 0x5b18528e, 0x5b18528e, 0xc9cbf769, 0x7c962dcb, 0x7c962dcb, 0xc9cbf769, }, 20 },
++  { "gfxterm_high", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x9813a416, 0xe709a12d, 0x54a9a81a, 0xe709a12d, 0xde04d65c, 0x9813a416, 0x9813a416, 0x43fda3fa, 0x43fda3fa, 0x43fda3fa, 0xd22625c9, 0xd22625c9, 0xd22625c9, 0x76a62c0a, 0x76a62c0a, 0x76a62c0a, 0x9813a416, 0xde04d65c, 0xde04d65c, 0x9813a416, }, 20 },
++  { "gfxterm_high", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0x5fcf013d, 0x65eff77c, 0x7519ec1d, 0x65eff77c, 0x1cd7d353, 0x5fcf013d, 0x5fcf013d, 0xf3582c48, 0xf3582c48, 0xf3582c48, 0x2148343e, 0x2148343e, 0x2148343e, 0x9c719024, 0x9c719024, 0x9c719024, 0x5fcf013d, 0x1cd7d353, 0x1cd7d353, 0x5fcf013d, }, 20 },
++  { "gfxterm_high", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0xdd28f52b, 0x7318831a, 0x276027c4, 0x7318831a, 0xd7e4f5bb, 0xdd28f52b, 0xdd28f52b, 0xb3c7ef80, 0xb3c7ef80, 0xb3c7ef80, 0x92fb1664, 0x92fb1664, 0x92fb1664, 0xd15b5e2e, 0xd15b5e2e, 0xd15b5e2e, 0xdd28f52b, 0xd7e4f5bb, 0xd7e4f5bb, 0xdd28f52b, }, 20 },
++  { "gfxterm_high", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x43d1f34, 0x6927a7d4, 0xc2b67069, 0x6927a7d4, 0xfc345163, 0x43d1f34, 0x43d1f34, 0xa0717008, 0xa0717008, 0xa0717008, 0xdf7bd9a0, 0xdf7bd9a0, 0xdf7bd9a0, 0x8e5a9312, 0x8e5a9312, 0x8e5a9312, 0x43d1f34, 0xfc345163, 0xfc345163, 0x43d1f34, }, 20 },
++  { "videotest", 640, 480, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi16 */, (grub_uint32_t []) { 0xe6012f70, 0xe6012f70, 0xe6012f70, 0xe6012f70, 0xe6012f70, }, 5 },
++  { "videotest", 800, 600, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi16 */, (grub_uint32_t []) { 0xfb6be77b, 0xfb6be77b, 0xfb6be77b, 0xfb6be77b, 0xfb6be77b, }, 5 },
++  { "videotest", 1024, 768, 0x2, 16, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi16 */, (grub_uint32_t []) { 0x67c0629f, 0x67c0629f, 0x67c0629f, 0x67c0629f, 0x67c0629f, }, 5 },
++  { "videotest", 640, 480, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 640x480xrgba8888 */, (grub_uint32_t []) { 0x8f20afbb, 0xd8f7abc, 0x8f937344, 0xd3ca643, 0x8e471645, }, 5 },
++  { "videotest", 800, 600, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 800x600xrgba8888 */, (grub_uint32_t []) { 0xdca764da, 0x9f76da9a, 0x5b04185a, 0x18d5a61a, 0xd60deb2b, }, 5 },
++  { "videotest", 1024, 768, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 1024x768xrgba8888 */, (grub_uint32_t []) { 0x7b87af36, 0x7cb96093, 0x75fa307c, 0x72c4ffd9, 0x677c91a2, }, 5 },
++  { "videotest", 2560, 1440, 0x1, 256, 32, 4, 16, 8, 8, 8, 0, 8, 24, 8 /* 2560x1440xrgba8888 */, (grub_uint32_t []) { 0x72981c65, 0x50120635, 0x378c28c5, 0x15063295, 0xf8b07525, }, 5 },
++  { "videotest", 640, 480, 0x2, 256, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 640x480xi256 */, (grub_uint32_t []) { 0xc8f64b58, 0xc8f64b58, 0xc8f64b58, 0xc8f64b58, 0xc8f64b58, }, 5 },
++  { "videotest", 800, 600, 0x2, 256, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 800x600xi256 */, (grub_uint32_t []) { 0x2b499dfa, 0x2b499dfa, 0x2b499dfa, 0x2b499dfa, 0x2b499dfa, }, 5 },
++  { "videotest", 1024, 768, 0x2, 256, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0 /* 1024x768xi256 */, (grub_uint32_t []) { 0x6156b420, 0x6156b420, 0x6156b420, 0x6156b420, 0x6156b420, }, 5 },
++  { "videotest", 640, 480, 0x1, 256, 15, 2, 10, 5, 5, 5, 0, 5, 0, 0 /* 640x480xrgba5550 */, (grub_uint32_t []) { 0x363285ca, 0x363285ca, 0x363285ca, 0x363285ca, 0x363285ca, }, 5 },
++  { "videotest", 800, 600, 0x1, 256, 15, 2, 10, 5, 5, 5, 0, 5, 0, 0 /* 800x600xrgba5550 */, (grub_uint32_t []) { 0x25bb37f4, 0x25bb37f4, 0x25bb37f4, 0x25bb37f4, 0x25bb37f4, }, 5 },
++  { "videotest", 1024, 768, 0x1, 256, 15, 2, 10, 5, 5, 5, 0, 5, 0, 0 /* 1024x768xrgba5550 */, (grub_uint32_t []) { 0xeeab9e91, 0xeeab9e91, 0xeeab9e91, 0xeeab9e91, 0xeeab9e91, }, 5 },
++  { "videotest", 640, 480, 0x1, 256, 16, 2, 11, 5, 5, 6, 0, 5, 0, 0 /* 640x480xrgba5650 */, (grub_uint32_t []) { 0x26a9a50b, 0x26a9a50b, 0x26a9a50b, 0x26a9a50b, 0x26a9a50b, }, 5 },
++  { "videotest", 800, 600, 0x1, 256, 16, 2, 11, 5, 5, 6, 0, 5, 0, 0 /* 800x600xrgba5650 */, (grub_uint32_t []) { 0x2c0f4fe7, 0x2c0f4fe7, 0x2c0f4fe7, 0x2c0f4fe7, 0x2c0f4fe7, }, 5 },
++  { "videotest", 1024, 768, 0x1, 256, 16, 2, 11, 5, 5, 6, 0, 5, 0, 0 /* 1024x768xrgba5650 */, (grub_uint32_t []) { 0x46c11052, 0x46c11052, 0x46c11052, 0x46c11052, 0x46c11052, }, 5 },
++  { "videotest", 640, 480, 0x1, 256, 24, 3, 16, 8, 8, 8, 0, 8, 0, 0 /* 640x480xrgba8880 */, (grub_uint32_t []) { 0xe56cf615, 0xcd2be572, 0xb5e2d0db, 0x9da5c3bc, 0x4470bb89, }, 5 },
++  { "videotest", 800, 600, 0x1, 256, 24, 3, 16, 8, 8, 8, 0, 8, 0, 0 /* 800x600xrgba8880 */, (grub_uint32_t []) { 0x2a25b871, 0x4bf85361, 0xe99e6e51, 0x88438541, 0xa8be62c0, }, 5 },
++  { "videotest", 1024, 768, 0x1, 256, 24, 3, 16, 8, 8, 8, 0, 8, 0, 0 /* 1024x768xrgba8880 */, (grub_uint32_t []) { 0x81523037, 0xd8c0bfd3, 0x32772fff, 0x6be5a01b, 0xe2f47956, }, 5 },
++  { "videotest", 640, 480, 0x1, 256, 15, 2, 0, 5, 5, 5, 10, 5, 0, 0 /* 640x480xbgra5550 */, (grub_uint32_t []) { 0x1833bb41, 0x1833bb41, 0x1833bb41, 0x1833bb41, 0x1833bb41, }, 5 },
++  { "videotest", 800, 600, 0x1, 256, 15, 2, 0, 5, 5, 5, 10, 5, 0, 0 /* 800x600xbgra5550 */, (grub_uint32_t []) { 0x2c39a0e8, 0x2c39a0e8, 0x2c39a0e8, 0x2c39a0e8, 0x2c39a0e8, }, 5 },
++  { "videotest", 1024, 768, 0x1, 256, 15, 2, 0, 5, 5, 5, 10, 5, 0, 0 /* 1024x768xbgra5550 */, (grub_uint32_t []) { 0xf0d4c23, 0xf0d4c23, 0xf0d4c23, 0xf0d4c23, 0xf0d4c23, }, 5 },
++  { "videotest", 640, 480, 0x1, 256, 16, 2, 0, 5, 5, 6, 11, 5, 0, 0 /* 640x480xbgra5650 */, (grub_uint32_t []) { 0x456d063c, 0x456d063c, 0x456d063c, 0x456d063c, 0x456d063c, }, 5 },
++  { "videotest", 800, 600, 0x1, 256, 16, 2, 0, 5, 5, 6, 11, 5, 0, 0 /* 800x600xbgra5650 */, (grub_uint32_t []) { 0x47e15a2e, 0x47e15a2e, 0x47e15a2e, 0x47e15a2e, 0x47e15a2e, }, 5 },
++  { "videotest", 1024, 768, 0x1, 256, 16, 2, 0, 5, 5, 6, 11, 5, 0, 0 /* 1024x768xbgra5650 */, (grub_uint32_t []) { 0x54d7300d, 0x54d7300d, 0x54d7300d, 0x54d7300d, 0x54d7300d, }, 5 },
++  { "videotest", 640, 480, 0x1, 256, 24, 3, 0, 8, 8, 8, 16, 8, 0, 0 /* 640x480xbgra8880 */, (grub_uint32_t []) { 0x770da211, 0x8ef2528e, 0x811e35de, 0x78e1c541, 0x9ec6fb7e, }, 5 },
++  { "videotest", 800, 600, 0x1, 256, 24, 3, 0, 8, 8, 8, 16, 8, 0, 0 /* 800x600xbgra8880 */, (grub_uint32_t []) { 0xeb181fbc, 0xae648cc1, 0x61e13946, 0x249daa3b, 0xfb0624b9, }, 5 },
++  { "videotest", 1024, 768, 0x1, 256, 24, 3, 0, 8, 8, 8, 16, 8, 0, 0 /* 1024x768xbgra8880 */, (grub_uint32_t []) { 0x2b6f64dc, 0xc25f8431, 0xfce2d3f7, 0x15d2331a, 0x81987c7b, }, 5 },
++  { "videotest", 640, 480, 0x1, 256, 32, 4, 0, 8, 8, 8, 16, 8, 24, 8 /* 640x480xbgra8888 */, (grub_uint32_t []) { 0xa260f7dd, 0x3e2f4980, 0x9f13fd96, 0x35c43cb, 0xd886e34b, }, 5 },
++  { "videotest", 800, 600, 0x1, 256, 32, 4, 0, 8, 8, 8, 16, 8, 24, 8 /* 800x600xbgra8888 */, (grub_uint32_t []) { 0x41a9bff8, 0xa0d3f7c3, 0x86b1597f, 0x67cb1144, 0xca740407, }, 5 },
++  { "videotest", 1024, 768, 0x1, 256, 32, 4, 0, 8, 8, 8, 16, 8, 24, 8 /* 1024x768xbgra8888 */, (grub_uint32_t []) { 0x8f7a3b6d, 0xcb84c6e3, 0x687c071, 0x42793dff, 0x996dbba4, }, 5 },
+diff --git a/include/grub/aout.h b/include/grub/aout.h
+index 10d7dde61ececf0e980c6ad62420764fcefd5e67..c8c1d94eca518042992a6fc5e3777f81a39b431d 100644
+--- a/include/grub/aout.h
++++ b/include/grub/aout.h
+@@ -52,6 +52,7 @@
+ #define GRUB_AOUT_HEADER 1
+ 
+ #include <grub/types.h>
++#include <grub/file.h>
+ 
+ struct grub_aout32_header
+ {
+diff --git a/include/grub/arc/arc.h b/include/grub/arc/arc.h
+index 7615a49a92cac0ac16326c188e438b789b09acec..999de7196753b58781a02c5311c9bc3834408021 100644
+--- a/include/grub/arc/arc.h
++++ b/include/grub/arc/arc.h
+@@ -53,7 +53,7 @@ enum grub_arc_memory_type
+ #ifndef GRUB_CPU_WORDS_BIGENDIAN
+     GRUB_ARC_MEMORY_FREE_CONTIGUOUS,
+ #endif
+-  } grub_arc_memory_type_t;
++  };
+ 
+ struct grub_arc_timeinfo
+ {
+diff --git a/include/grub/arm/coreboot/console.h b/include/grub/arm/coreboot/console.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..13a14b783839a6cae96845973ae3087bcaef670e
+--- /dev/null
++++ b/include/grub/arm/coreboot/console.h
+@@ -0,0 +1,29 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_MACHINE_CONSOLE_HEADER
++#define GRUB_MACHINE_CONSOLE_HEADER	1
++
++void grub_video_coreboot_fb_init (void);
++void grub_video_coreboot_fb_early_init (void);
++void grub_video_coreboot_fb_late_init (void);
++void grub_video_coreboot_fb_fini (void);
++
++extern struct grub_linuxbios_table_framebuffer *grub_video_coreboot_fbtable;
++
++#endif /* ! GRUB_MACHINE_CONSOLE_HEADER */
+diff --git a/include/grub/arm/coreboot/kernel.h b/include/grub/arm/coreboot/kernel.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..2695053427050f306b8ca86ba066df90c519e8e0
+--- /dev/null
++++ b/include/grub/arm/coreboot/kernel.h
+@@ -0,0 +1,44 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2013 Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_KERNEL_MACHINE_HEADER
++#define GRUB_KERNEL_MACHINE_HEADER	1
++
++#ifndef ASM_FILE
++
++#include <grub/symbol.h>
++#include <grub/types.h>
++
++struct grub_fdt_board
++{
++  const char *vendor, *part;
++  const grub_uint8_t *dtb;
++  grub_size_t dtb_size;
++};
++
++extern struct grub_fdt_board grub_fdt_boards[];
++void grub_machine_timer_init (void);
++void grub_pl050_init (void);
++void grub_cros_init (void);
++void grub_rk3288_spi_init (void);
++extern grub_addr_t EXPORT_VAR (start_of_ram);
++#endif /* ! ASM_FILE */
++
++#define GRUB_KERNEL_MACHINE_STACK_SIZE GRUB_KERNEL_ARM_STACK_SIZE
++
++#endif /* ! GRUB_KERNEL_MACHINE_HEADER */
+diff --git a/include/grub/arm/cros_ec.h b/include/grub/arm/cros_ec.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..45a372572a5c3c411c9b2b7f328135f5cbe551c8
+--- /dev/null
++++ b/include/grub/arm/cros_ec.h
+@@ -0,0 +1,21 @@
++#ifndef GRUB_ARM_CROS_EC_H
++#define GRUB_ARM_CROS_EC_H 1
++
++#include <grub/types.h>
++#include <grub/fdtbus.h>
++
++#define GRUB_CROS_EC_KEYSCAN_COLS 13
++#define GRUB_CROS_EC_KEYSCAN_ROWS 8
++
++struct grub_cros_ec_keyscan {
++  grub_uint8_t data[GRUB_CROS_EC_KEYSCAN_COLS];
++};
++
++int
++grub_cros_ec_scan_keyboard (const struct grub_fdtbus_dev *dev,
++			    struct grub_cros_ec_keyscan *scan);
++
++int
++grub_cros_ec_validate (const struct grub_fdtbus_dev *dev);
++
++#endif
+diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h
+index a66caad13db8c5c3b0da10f624d01a81640eab44..712ba17b9ba30cf850b6a9011d08a04d57816227 100644
+--- a/include/grub/arm/linux.h
++++ b/include/grub/arm/linux.h
+@@ -17,14 +17,28 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#ifndef GRUB_LINUX_CPU_HEADER
+-#define GRUB_LINUX_CPU_HEADER 1
+-
+-#define LINUX_ZIMAGE_OFFSET 0x24
+-#define LINUX_ZIMAGE_MAGIC  0x016f2818
++#ifndef GRUB_ARM_LINUX_HEADER
++#define GRUB_ARM_LINUX_HEADER 1
+ 
+ #include "system.h"
+ 
++#define GRUB_LINUX_ARM_MAGIC_SIGNATURE 0x016f2818
++
++struct linux_arm_kernel_header {
++  grub_uint32_t code0;
++  grub_uint32_t reserved1[8];
++  grub_uint32_t magic;
++  grub_uint32_t start; /* _start */
++  grub_uint32_t end;   /* _edata */
++  grub_uint32_t reserved2[4];
++  grub_uint32_t hdr_offset;
++};
++
++#if defined(__arm__)
++# define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM_MAGIC_SIGNATURE
++# define linux_armxx_kernel_header linux_arm_kernel_header
++#endif
++
+ #if defined GRUB_MACHINE_UBOOT
+ # include <grub/uboot/uboot.h>
+ # define LINUX_ADDRESS        (start_of_ram + 0x8000)
+@@ -32,15 +46,17 @@
+ # define LINUX_FDT_ADDRESS    (LINUX_INITRD_ADDRESS - 0x10000)
+ # define grub_arm_firmware_get_boot_data grub_uboot_get_boot_data
+ # define grub_arm_firmware_get_machine_type grub_uboot_get_machine_type
+-#elif defined GRUB_MACHINE_EFI
+-# include <grub/efi/efi.h>
+-# include <grub/machine/loader.h>
+-/* On UEFI platforms - load the images at the lowest available address not
+-   less than *_PHYS_OFFSET from the first available memory location. */
+-# define LINUX_PHYS_OFFSET        (0x00008000)
+-# define LINUX_INITRD_PHYS_OFFSET (LINUX_PHYS_OFFSET + 0x02000000)
+-# define LINUX_FDT_PHYS_OFFSET    (LINUX_INITRD_PHYS_OFFSET - 0x10000)
+-# define grub_arm_firmware_get_boot_data (grub_addr_t)grub_efi_get_firmware_fdt
++#elif defined (GRUB_MACHINE_COREBOOT)
++#include <grub/fdtbus.h>
++#include <grub/arm/coreboot/kernel.h>
++# define LINUX_ADDRESS        (start_of_ram + 0x8000)
++# define LINUX_INITRD_ADDRESS (start_of_ram + 0x02000000)
++# define LINUX_FDT_ADDRESS    (LINUX_INITRD_ADDRESS - 0x10000)
++static inline const void *
++grub_arm_firmware_get_boot_data (void)
++{
++  return grub_fdtbus_get_fdt ();
++}
+ static inline grub_uint32_t
+ grub_arm_firmware_get_machine_type (void)
+ {
+@@ -48,6 +64,4 @@ grub_arm_firmware_get_machine_type (void)
+ }
+ #endif
+ 
+-#define FDT_ADDITIONAL_ENTRIES_SIZE	0x300
+-
+-#endif /* ! GRUB_LINUX_CPU_HEADER */
++#endif /* ! GRUB_ARM_LINUX_HEADER */
+diff --git a/include/grub/arm/startup.h b/include/grub/arm/startup.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..9afb6c57c0bc4c53e96f711bf545d94a8ed07aa5
+--- /dev/null
++++ b/include/grub/arm/startup.h
+@@ -0,0 +1,16 @@
++#ifndef GRUB_STARTUP_CPU_HEADER
++#define GRUB_STARTUP_CPU_HEADER
++
++struct grub_arm_startup_registers
++{
++  /* registers 0-11 */
++  /* for U-boot r[1] is machine type */
++  /* for U-boot r[2] is boot data */
++  grub_uint32_t r[12];
++  grub_uint32_t sp;
++  grub_uint32_t lr;
++};
++
++extern struct grub_arm_startup_registers grub_arm_saved_registers;
++
++#endif
+diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h
+index 1ea23696e7a096e53075af2314da11ecce91f8d7..8655067e03924793293ba86cb1bae2e44efa5fee 100644
+--- a/include/grub/arm64/linux.h
++++ b/include/grub/arm64/linux.h
+@@ -16,17 +16,13 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#ifndef GRUB_LINUX_CPU_HEADER
+-#define GRUB_LINUX_CPU_HEADER 1
++#ifndef GRUB_ARM64_LINUX_HEADER
++#define GRUB_ARM64_LINUX_HEADER 1
+ 
+-#include <grub/efi/efi.h>
+-
+-#define GRUB_ARM64_LINUX_MAGIC 0x644d5241 /* 'ARM\x64' */
+-
+-#define GRUB_EFI_PE_MAGIC	0x5A4D
++#define GRUB_LINUX_ARM64_MAGIC_SIGNATURE 0x644d5241 /* 'ARM\x64' */
+ 
+ /* From linux/Documentation/arm64/booting.txt */
+-struct grub_arm64_linux_kernel_header
++struct linux_arm64_kernel_header
+ {
+   grub_uint32_t code0;		/* Executable code */
+   grub_uint32_t code1;		/* Executable code */
+@@ -40,9 +36,9 @@ struct grub_arm64_linux_kernel_header
+   grub_uint32_t hdr_offset;	/* Offset of PE/COFF header */
+ };
+ 
+-grub_err_t grub_arm64_uefi_check_image (struct grub_arm64_linux_kernel_header
+-                                        *lh);
+-grub_err_t grub_arm64_uefi_boot_image (grub_addr_t addr, grub_size_t size,
+-                                       char *args);
++#if defined(__aarch64__)
++# define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM64_MAGIC_SIGNATURE
++# define linux_armxx_kernel_header linux_arm64_kernel_header
++#endif
+ 
+-#endif /* ! GRUB_LINUX_CPU_HEADER */
++#endif /* ! GRUB_ARM64_LINUX_HEADER */
+diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h
+index b4f8ff0a06117756a770129683796edf0050b867..bcb4d9ba78f1376bdaa82249418f847eb4e543a6 100644
+--- a/include/grub/at_keyboard.h
++++ b/include/grub/at_keyboard.h
+@@ -23,13 +23,11 @@
+ #define KEYBOARD_COMMAND_ISREADY(x)	!((x) & 0x02)
+ #define KEYBOARD_COMMAND_READ		0x20
+ #define KEYBOARD_COMMAND_WRITE		0x60
++#define KEYBOARD_COMMAND_ENABLE		0xf4
+ #define KEYBOARD_COMMAND_REBOOT		0xfe
+ 
+ #define KEYBOARD_AT_TRANSLATE		0x40
+-
+-#define GRUB_AT_ACK                     0xfa
+-#define GRUB_AT_NACK                    0xfe
+-#define GRUB_AT_TRIES                   5
++#define KEYBOARD_AT_DISABLE		0x10
+ 
+ #define KEYBOARD_ISMAKE(x)	!((x) & 0x80)
+ #define KEYBOARD_ISREADY(x)	((x) & 0x01)
+diff --git a/include/grub/autoefi.h b/include/grub/autoefi.h
+index b75591176eb9d785de3f2867e32edc1b9a626280..b7a252e079e2137b4d27639b5c981e9085cb8a82 100644
+--- a/include/grub/autoefi.h
++++ b/include/grub/autoefi.h
+@@ -55,7 +55,7 @@ static inline grub_err_t grub_autoefi_prepare (void)
+ # define SYSTEM_TABLE_PTR GRUB_EFIEMU_SYSTEM_TABLE_PTR
+ # define SIZEOF_OF_UINTN GRUB_EFIEMU_SIZEOF_OF_UINTN
+ # define SYSTEM_TABLE GRUB_EFIEMU_SYSTEM_TABLE
+-# define grub_efi_allocate_pages(x,y) (x)
++# define grub_efi_allocate_fixed(x,y) (x)
+ # define grub_efi_free_pages(x,y) GRUB_EFI_SUCCESS
+ # define grub_autoefi_finish_boot_services grub_efiemu_finish_boot_services
+ # define EFI_PRESENT 1
+diff --git a/include/grub/cache.h b/include/grub/cache.h
+index fc669dfd1892c14bb43c6230e48067a0ff8e7c23..ccfa717e669625e0db96df0692c65f5a4c5ff916 100644
+--- a/include/grub/cache.h
++++ b/include/grub/cache.h
+@@ -34,15 +34,16 @@ void EXPORT_FUNC(grub_arch_sync_caches) (void *address, grub_size_t len);
+ #endif
+ 
+ #ifndef GRUB_MACHINE_EMU
+-#ifdef _mips
+-void EXPORT_FUNC(grub_arch_sync_dma_caches) (volatile void *address,
+-					     grub_size_t len);
+-#else
++#if defined (__aarch64__) || defined (__powerpc__) || defined (__sparc__)
++
++#elif defined (__i386__) || defined (__x86_64__)
+ static inline void
+ grub_arch_sync_dma_caches (volatile void *address __attribute__ ((unused)),
+ 			   grub_size_t len __attribute__ ((unused)))
+ {
+ }
++#else
++void EXPORT_FUNC(grub_arch_sync_dma_caches) (volatile void *address, grub_size_t len);
+ #endif
+ #endif
+ 
+diff --git a/include/grub/i386/coreboot/lbio.h b/include/grub/coreboot/lbio.h
+similarity index 93%
+rename from include/grub/i386/coreboot/lbio.h
+rename to include/grub/coreboot/lbio.h
+index 1c3fa6f1953c3a6b41ea3644c30f000c98524224..5076d36c71ba32e5c55a6242287e5fe159e09b4f 100644
+--- a/include/grub/i386/coreboot/lbio.h
++++ b/include/grub/coreboot/lbio.h
+@@ -20,6 +20,9 @@
+ #ifndef _GRUB_MACHINE_LBIO_HEADER
+ #define _GRUB_MACHINE_LBIO_HEADER      1
+ 
++#include <grub/types.h>
++#include <grub/err.h>
++
+ struct grub_linuxbios_table_header
+ {
+   grub_uint8_t signature[4];
+@@ -102,4 +105,10 @@ EXPORT_FUNC(grub_linuxbios_table_iterate) (int (*hook) (grub_linuxbios_table_ite
+ 					   void *),
+ 					   void *hook_data);
+ 
++grub_linuxbios_table_header_t
++grub_linuxbios_get_tables (void);
++
++int
++grub_linuxbios_check_signature (grub_linuxbios_table_header_t tbl_header);
++
+ #endif
+diff --git a/include/grub/dma.h b/include/grub/dma.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..19992ebc131d4fc93a45f31992ad3c03b9de2821
+--- /dev/null
++++ b/include/grub/dma.h
+@@ -0,0 +1,44 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2008,2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef	GRUB_DMA_H
++#define	GRUB_DMA_H	1
++
++struct grub_pci_dma_chunk;
++
++struct grub_pci_dma_chunk *EXPORT_FUNC(grub_memalign_dma32) (grub_size_t align,
++							     grub_size_t size);
++void EXPORT_FUNC(grub_dma_free) (struct grub_pci_dma_chunk *ch);
++volatile void *EXPORT_FUNC(grub_dma_get_virt) (struct grub_pci_dma_chunk *ch);
++grub_uint32_t EXPORT_FUNC(grub_dma_get_phys) (struct grub_pci_dma_chunk *ch);
++
++static inline void *
++grub_dma_phys2virt (grub_uint32_t phys, struct grub_pci_dma_chunk *chunk)
++{
++  return ((grub_uint8_t *) grub_dma_get_virt (chunk)
++	  + (phys - grub_dma_get_phys (chunk)));
++}
++
++static inline grub_uint32_t
++grub_dma_virt2phys (volatile void *virt, struct grub_pci_dma_chunk *chunk)
++{
++  return (((grub_uint8_t *) virt - (grub_uint8_t *) grub_dma_get_virt (chunk))
++	  + grub_dma_get_phys (chunk));
++}
++
++#endif
+diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
+index e9c601f34103ae1a4ced7e93be8204970bfef193..2c6648d46fc1a377312c81220c38470d9d1cc99a 100644
+--- a/include/grub/efi/efi.h
++++ b/include/grub/efi/efi.h
+@@ -38,16 +38,25 @@ void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle,
+ int EXPORT_FUNC(grub_efi_set_text_mode) (int on);
+ void EXPORT_FUNC(grub_efi_stall) (grub_efi_uintn_t microseconds);
+ void *
+-EXPORT_FUNC(grub_efi_allocate_pages) (grub_efi_physical_address_t address,
++EXPORT_FUNC(grub_efi_allocate_pages_real) (grub_efi_physical_address_t address,
++				           grub_efi_uintn_t pages,
++					   grub_efi_allocate_type_t alloctype,
++					   grub_efi_memory_type_t memtype);
++void *
++EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address,
+ 				      grub_efi_uintn_t pages);
++void *
++EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages);
+ void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address,
+ 				       grub_efi_uintn_t pages);
++grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void);
+ int
+ EXPORT_FUNC(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_uintn_t *descriptor_size,
+ 				      grub_efi_uint32_t *descriptor_version);
++void grub_efi_memory_fini (void);
+ grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle);
+ void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp);
+ char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp);
+@@ -83,6 +92,11 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd,
+ 
+ #if defined(__arm__) || defined(__aarch64__)
+ void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
++grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
++#include <grub/cpu/linux.h>
++grub_err_t grub_armxx_efi_linux_check_image(struct linux_armxx_kernel_header *lh);
++grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, grub_size_t size,
++                                           char *args);
+ #endif
+ 
+ grub_addr_t grub_efi_modules_addr (void);
+diff --git a/include/grub/arm64/fdtload.h b/include/grub/efi/fdtload.h
+similarity index 89%
+rename from include/grub/arm64/fdtload.h
+rename to include/grub/efi/fdtload.h
+index 7b9ddba916d9980fbad51e7b02d99f0737ebc3fa..713c9424d0a9ebe47b1923a247e691566842b2d0 100644
+--- a/include/grub/arm64/fdtload.h
++++ b/include/grub/efi/fdtload.h
+@@ -29,7 +29,4 @@ grub_fdt_unload (void);
+ grub_err_t
+ grub_fdt_install (void);
+ 
+-#define GRUB_EFI_PAGE_SHIFT	12
+-#define GRUB_EFI_BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> GRUB_EFI_PAGE_SHIFT)
+-
+ #endif
+diff --git a/include/grub/efi/memory.h b/include/grub/efi/memory.h
+index 20526b14676de9295d17968f5ddc837a06bc56b6..08fe62277839dde3434e506cde78174f1977e9c9 100644
+--- a/include/grub/efi/memory.h
++++ b/include/grub/efi/memory.h
+@@ -22,6 +22,13 @@
+ #include <grub/err.h>
+ #include <grub/types.h>
+ 
++/* The term "page" in UEFI refers only to a 4 KiB-aligned 4 KiB size region of
++   memory. It is not concerned with underlying translation management concepts,
++   but only used as the granule for memory allocations. */
++#define GRUB_EFI_PAGE_SHIFT             12
++#define GRUB_EFI_PAGE_SIZE              (1 << GRUB_EFI_PAGE_SHIFT)
++#define GRUB_EFI_BYTES_TO_PAGES(bytes)  (((bytes) + 0xfff) >> GRUB_EFI_PAGE_SHIFT)
++
+ #define GRUB_MMAP_REGISTER_BY_FIRMWARE  1
+ 
+ grub_err_t grub_machine_mmap_register (grub_uint64_t start, grub_uint64_t size,
+diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
+index f79c36c026e0a518b3f9edaca36251d6d4943757..7d44732d2c353b74271262a1cf094d4aafd8dd10 100644
+--- a/include/grub/efi/pe32.h
++++ b/include/grub/efi/pe32.h
+@@ -45,6 +45,8 @@
+ 
+ #define GRUB_PE32_MSDOS_STUB_SIZE	0x80
+ 
++#define GRUB_PE32_MAGIC			0x5a4d
++
+ /* According to the spec, the minimal alignment is 512 bytes...
+    But some examples (such as EFI drivers in the Intel
+    Sample Implementation) use 32 bytes (0x20) instead, and it seems
+diff --git a/include/grub/efiemu/runtime.h b/include/grub/efiemu/runtime.h
+index 9b6b729f4ccde7274678b1324c16c9f6854477a2..36d2dedf47e4346b86f17882dc554207201b6401 100644
+--- a/include/grub/efiemu/runtime.h
++++ b/include/grub/efiemu/runtime.h
+@@ -29,7 +29,7 @@ struct grub_efiemu_ptv_rel
+ 
+ struct efi_variable
+ {
+-  grub_efi_guid_t guid;
++  grub_efi_packed_guid_t guid;
+   grub_uint32_t namelen;
+   grub_uint32_t size;
+   grub_efi_uint32_t attributes;
+diff --git a/include/grub/fat.h b/include/grub/fat.h
+index 4a5aab7934652cfde20c6fb291e00c29170b8753..8d7e4a1e54d644e6d70bb249802c699d5092728e 100644
+--- a/include/grub/fat.h
++++ b/include/grub/fat.h
+@@ -28,20 +28,15 @@ struct grub_fat_bpb
+   grub_uint16_t bytes_per_sector;
+   grub_uint8_t sectors_per_cluster;
+   grub_uint16_t num_reserved_sectors;
+-  grub_uint8_t num_fats;
+-  /* 0x10 */
++  grub_uint8_t num_fats;		/* 0x10 */
+   grub_uint16_t num_root_entries;
+   grub_uint16_t num_total_sectors_16;
+-  grub_uint8_t media;
+-  /*0 x15 */
++  grub_uint8_t media;			/* 0x15 */
+   grub_uint16_t sectors_per_fat_16;
+-  grub_uint16_t sectors_per_track;
+-  /*0 x19 */
+-  grub_uint16_t num_heads;
+-  /*0 x1b */
+-  grub_uint32_t num_hidden_sectors;
+-  /* 0x1f */
+-  grub_uint32_t num_total_sectors_32;
++  grub_uint16_t sectors_per_track;	/* 0x18 */
++  grub_uint16_t num_heads;		/* 0x1A */
++  grub_uint32_t num_hidden_sectors;	/* 0x1C */
++  grub_uint32_t num_total_sectors_32;	/* 0x20 */
+   union
+   {
+     struct
+diff --git a/include/grub/fdt.h b/include/grub/fdt.h
+index fdfca75bf487f17e8621fee5d1642f4874a2bf16..158b1bc4b3ad8bac60860e298b816781d6c57090 100644
+--- a/include/grub/fdt.h
++++ b/include/grub/fdt.h
+@@ -20,6 +20,7 @@
+ #define GRUB_FDT_HEADER	1
+ 
+ #include <grub/types.h>
++#include <grub/symbol.h>
+ 
+ #define FDT_MAGIC 0xD00DFEED
+ 
+@@ -49,6 +50,11 @@ struct grub_fdt_empty_tree {
+ 
+ #define GRUB_FDT_EMPTY_TREE_SZ  sizeof (struct grub_fdt_empty_tree)
+ 
++/* Size needed by a property entry: 1 token (FDT_PROPERTY), plus len and nameoff
++   fields, plus the property value, plus padding if needed. */
++#define grub_fdt_prop_entry_size(prop_len)						\
++  (3 * sizeof(grub_uint32_t) + ALIGN_UP(prop_len, sizeof(grub_uint32_t)))
++
+ #define grub_fdt_get_header(fdt, field)	\
+ 	grub_be_to_cpu32(((const grub_fdt_header_t *)(fdt))->field)
+ #define grub_fdt_set_header(fdt, field, value)	\
+@@ -95,16 +101,22 @@ struct grub_fdt_empty_tree {
+ #define grub_fdt_set_size_dt_struct(fdt, value)	\
+ 	grub_fdt_set_header(fdt, size_dt_struct, value)
+ 
+-int grub_fdt_create_empty_tree (void *fdt, unsigned int size);
+-int grub_fdt_check_header (void *fdt, unsigned int size);
+-int grub_fdt_check_header_nosize (void *fdt);
+-int grub_fdt_find_subnode (const void *fdt, unsigned int parentoffset,
+-			   const char *name);
+-int grub_fdt_add_subnode (void *fdt, unsigned int parentoffset,
++int EXPORT_FUNC(grub_fdt_create_empty_tree) (void *fdt, unsigned int size);
++int EXPORT_FUNC(grub_fdt_check_header) (const void *fdt, unsigned int size);
++int EXPORT_FUNC(grub_fdt_check_header_nosize) (const void *fdt);
++int EXPORT_FUNC(grub_fdt_find_subnode) (const void *fdt, unsigned int parentoffset,
++					const char *name);
++int EXPORT_FUNC(grub_fdt_first_node) (const void *fdt, unsigned int parentoffset);
++int EXPORT_FUNC(grub_fdt_next_node) (const void *fdt, unsigned int currentoffset);
++int EXPORT_FUNC(grub_fdt_add_subnode) (void *fdt, unsigned int parentoffset,
+ 			  const char *name);
++const char *
++EXPORT_FUNC(grub_fdt_get_nodename) (const void *fdt, unsigned int nodeoffset);
++const void *EXPORT_FUNC(grub_fdt_get_prop) (const void *fdt, unsigned int nodeoffset, const char *name,
++					    grub_uint32_t *len);
+ 
+-int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name,
+-		      const void *val, grub_uint32_t len);
++int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const char *name,
++				    const void *val, grub_uint32_t len);
+ #define grub_fdt_set_prop32(fdt, nodeoffset, name, val)	\
+ ({ \
+   grub_uint32_t _val = grub_cpu_to_be32(val); \
+diff --git a/include/grub/fdtbus.h b/include/grub/fdtbus.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..f519c40ec35faea9aeedca055164012d9d9b3fb5
+--- /dev/null
++++ b/include/grub/fdtbus.h
+@@ -0,0 +1,89 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2016  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_FDTBUS_HEADER
++#define GRUB_FDTBUS_HEADER	1
++
++#include <grub/fdt.h>
++#include <grub/err.h>
++
++struct grub_fdtbus_dev
++{
++  struct grub_fdtbus_dev *next;
++  struct grub_fdtbus_dev *parent;
++  int node;
++  struct grub_fdtbus_driver *driver;
++};
++
++struct grub_fdtbus_driver
++{
++  struct grub_fdtbus_driver *next;
++  struct grub_fdtbus_driver **prev;
++
++  const char *compatible;
++
++  grub_err_t (*attach) (const struct grub_fdtbus_dev *dev);
++  void (*detach) (const struct grub_fdtbus_dev *dev);
++
++  /* Message bus operations.  */
++  grub_err_t (*send) (const struct grub_fdtbus_dev *dev, const void *data, grub_size_t sz);
++  grub_err_t (*receive) (const struct grub_fdtbus_dev *dev, void *data, grub_size_t sz);
++  grub_err_t (*start) (const struct grub_fdtbus_dev *dev);
++  void (*stop) (const struct grub_fdtbus_dev *dev);
++};
++
++extern char EXPORT_VAR(grub_fdtbus_invalid_mapping)[1];
++
++static inline int
++grub_fdtbus_is_mapping_valid (volatile void *m)
++{
++  return m != grub_fdtbus_invalid_mapping;
++}
++
++volatile void *
++EXPORT_FUNC(grub_fdtbus_map_reg) (const struct grub_fdtbus_dev *dev, int reg, grub_size_t *size);
++
++const void *
++EXPORT_FUNC(grub_fdtbus_get_fdt) (void);
++
++const char *
++EXPORT_FUNC(grub_fdtbus_get_name) (const struct grub_fdtbus_dev *dev);
++
++const void *
++EXPORT_FUNC(grub_fdtbus_get_prop) (const struct grub_fdtbus_dev *dev,
++		      const char *name,
++		      grub_uint32_t *len);
++
++void
++EXPORT_FUNC(grub_fdtbus_register) (struct grub_fdtbus_driver *driver);
++
++void
++EXPORT_FUNC(grub_fdtbus_unregister) (struct grub_fdtbus_driver *driver);
++
++int
++EXPORT_FUNC(grub_fdtbus_is_compatible) (const char *compat_string,
++					const struct grub_fdtbus_dev *dev);
++
++/* Must be called before any register(). */
++/* dtb is assumed to be unfreeable and must remain
++   valid for lifetime of GRUB.
++ */
++void
++grub_fdtbus_init (const void *dtb, grub_size_t size);
++
++#endif
+diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h
+index 1b32f6725a498f16941991771efe6a7a04ed6f5e..7a93f43291cce490cbaecc140ef2e5e0577ae274 100644
+--- a/include/grub/gpt_partition.h
++++ b/include/grub/gpt_partition.h
+@@ -22,14 +22,14 @@
+ #include <grub/types.h>
+ #include <grub/partition.h>
+ 
+-struct grub_gpt_part_type
++struct grub_gpt_part_guid
+ {
+   grub_uint32_t data1;
+   grub_uint16_t data2;
+   grub_uint16_t data3;
+   grub_uint8_t data4[8];
+-} __attribute__ ((aligned(8)));
+-typedef struct grub_gpt_part_type grub_gpt_part_type_t;
++} GRUB_PACKED;
++typedef struct grub_gpt_part_guid grub_gpt_part_guid_t;
+ 
+ #define GRUB_GPT_PARTITION_TYPE_EMPTY \
+   { 0x0, 0x0, 0x0, \
+@@ -70,8 +70,8 @@ struct grub_gpt_header
+ 
+ struct grub_gpt_partentry
+ {
+-  grub_gpt_part_type_t type;
+-  grub_uint8_t guid[16];
++  grub_gpt_part_guid_t type;
++  grub_gpt_part_guid_t guid;
+   grub_uint64_t start;
+   grub_uint64_t end;
+   grub_uint64_t attrib;
+diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h
+index da0ca3b83cdc7355fc5b9815415ad7fc8732d153..60c7c3b5e660276dc11d23f4a53ccc2f1e5536a5 100644
+--- a/include/grub/i386/linux.h
++++ b/include/grub/i386/linux.h
+@@ -16,10 +16,10 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#ifndef GRUB_LINUX_MACHINE_HEADER
+-#define GRUB_LINUX_MACHINE_HEADER	1
++#ifndef GRUB_I386_LINUX_HEADER
++#define GRUB_I386_LINUX_HEADER	1
+ 
+-#define GRUB_LINUX_MAGIC_SIGNATURE	0x53726448      /* "HdrS" */
++#define GRUB_LINUX_I386_MAGIC_SIGNATURE	0x53726448      /* "HdrS" */
+ #define GRUB_LINUX_DEFAULT_SETUP_SECTS	4
+ #define GRUB_LINUX_INITRD_MAX_ADDRESS	0x37FFFFFF
+ #define GRUB_LINUX_MAX_SETUP_SECTS	64
+@@ -43,6 +43,9 @@
+ 
+ #define GRUB_LINUX_CL_MAGIC		0xA33F
+ 
++#define VIDEO_CAPABILITY_SKIP_QUIRKS	(1 << 0)
++#define VIDEO_CAPABILITY_64BIT_BASE	(1 << 1)	/* Frame buffer base is 64-bit. */
++
+ #ifdef __x86_64__
+ 
+ #define GRUB_LINUX_EFI_SIGNATURE	\
+@@ -85,7 +88,7 @@ enum
+   };
+ 
+ /* For the Linux/i386 boot protocol version 2.10.  */
+-struct linux_kernel_header
++struct linux_i386_kernel_header
+ {
+   grub_uint8_t code1[0x0020];
+   grub_uint16_t cl_magic;		/* Magic number 0xA33F */
+@@ -188,8 +191,9 @@ struct linux_kernel_params
+   grub_uint16_t lfb_pages;		/* 32 */
+   grub_uint16_t vesa_attrib;		/* 34 */
+   grub_uint32_t capabilities;		/* 36 */
++  grub_uint32_t ext_lfb_base;		/* 3a */
+ 
+-  grub_uint8_t padding3[0x40 - 0x3a];
++  grub_uint8_t padding3[0x40 - 0x3e];
+ 
+   grub_uint16_t apm_version;		/* 40 */
+   grub_uint16_t apm_code_segment;	/* 42 */
+@@ -312,4 +316,4 @@ struct linux_kernel_params
+ } GRUB_PACKED;
+ #endif /* ! ASM_FILE */
+ 
+-#endif /* ! GRUB_LINUX_MACHINE_HEADER */
++#endif /* ! GRUB_I386_LINUX_HEADER */
+diff --git a/include/grub/i386/multiboot.h b/include/grub/i386/multiboot.h
+index 807a1de27f900c8393476736051e20ee1af6717c..0b596fc2060a63f2fd9e1c67cb002279454aebe5 100644
+--- a/include/grub/i386/multiboot.h
++++ b/include/grub/i386/multiboot.h
+@@ -19,6 +19,13 @@
+ #ifndef GRUB_MULTIBOOT_CPU_HEADER
+ #define GRUB_MULTIBOOT_CPU_HEADER	1
+ 
++#define MULTIBOOT2_INITIAL_STATE  { .eax = MULTIBOOT2_BOOTLOADER_MAGIC,	\
++    .ecx = 0,								\
++    .edx = 0,								\
++    /* Set esp to some random location in low memory to avoid breaking */ \
++    /* non-compliant kernels.  */					\
++    .esp = 0x7ff00							\
++      }
+ #define MULTIBOOT_INITIAL_STATE  { .eax = MULTIBOOT_BOOTLOADER_MAGIC,	\
+     .ecx = 0,								\
+     .edx = 0,								\
+@@ -28,7 +35,7 @@
+       }
+ #define MULTIBOOT_ENTRY_REGISTER eip
+ #define MULTIBOOT_MBI_REGISTER ebx
+-#define MULTIBOOT_ARCHITECTURE_CURRENT MULTIBOOT_ARCHITECTURE_I386
++#define MULTIBOOT2_ARCHITECTURE_CURRENT MULTIBOOT2_ARCHITECTURE_I386
+ 
+ #ifdef GRUB_MACHINE_EFI
+ #ifdef __x86_64__
+@@ -36,6 +43,10 @@
+     .rcx = 0,									\
+     .rdx = 0,									\
+       }
++#define MULTIBOOT2_EFI_INITIAL_STATE  { .rax = MULTIBOOT2_BOOTLOADER_MAGIC,	\
++    .rcx = 0,									\
++    .rdx = 0,									\
++      }
+ #define MULTIBOOT_EFI_ENTRY_REGISTER rip
+ #define MULTIBOOT_EFI_MBI_REGISTER rbx
+ #endif
+diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
+index 8e425130327e193af1c1e34760e7255c9d6e6223..8868f3a756fe57b90188e25aaba2b203edacde13 100644
+--- a/include/grub/ieee1275/ieee1275.h
++++ b/include/grub/ieee1275/ieee1275.h
+@@ -210,7 +210,25 @@ int EXPORT_FUNC(grub_ieee1275_set_property) (grub_ieee1275_phandle_t phandle,
+ int EXPORT_FUNC(grub_ieee1275_set_color) (grub_ieee1275_ihandle_t ihandle,
+ 					  int index, int r, int g, int b);
+ int EXPORT_FUNC(grub_ieee1275_milliseconds) (grub_uint32_t *msecs);
+-
++int EXPORT_FUNC(grub_ieee1275_set_address) (grub_ieee1275_ihandle_t ihandle,
++                                            grub_uint32_t target,
++                                            grub_uint32_t lun);
++int EXPORT_FUNC(grub_ieee1275_no_data_command) (grub_ieee1275_ihandle_t ihandle,
++                                                const void *cmd_addr,
++                                                grub_ssize_t *result);
++int EXPORT_FUNC(grub_ieee1275_decode_unit4) (grub_ieee1275_ihandle_t ihandle,
++                                             void *addr, grub_size_t size,
++                                             grub_uint32_t *phy_lo,
++                                             grub_uint32_t *phy_hi,
++                                             grub_uint32_t *lun_lo,
++                                             grub_uint32_t *lun_hi);
++char *EXPORT_FUNC(grub_ieee1275_encode_uint4) (grub_ieee1275_ihandle_t ihandle,
++                                             grub_uint32_t phy_lo,
++                                             grub_uint32_t phy_hi,
++                                             grub_uint32_t lun_lo,
++                                             grub_uint32_t lun_hi,
++                                             grub_size_t *size);
++int EXPORT_FUNC(grub_ieee1275_get_block_size) (grub_ieee1275_ihandle_t ihandle);
+ 
+ grub_err_t EXPORT_FUNC(grub_claimmap) (grub_addr_t addr, grub_size_t size);
+ 
+@@ -235,6 +253,8 @@ void EXPORT_FUNC(grub_ieee1275_children_peer) (struct grub_ieee1275_devalias *al
+ void EXPORT_FUNC(grub_ieee1275_children_first) (const char *devpath,
+ 						struct grub_ieee1275_devalias *alias);
+ 
++char *EXPORT_FUNC(grub_ieee1275_get_boot_dev) (void);
++
+ #define FOR_IEEE1275_DEVALIASES(alias) for (grub_ieee1275_devalias_init_iterator (&(alias)); grub_ieee1275_devalias_next (&(alias));)
+ 
+ #define FOR_IEEE1275_DEVCHILDREN(devpath, alias) for (grub_ieee1275_children_first ((devpath), &(alias)); \
+diff --git a/include/grub/kernel.h b/include/grub/kernel.h
+index 20ddf2da297d5c883ed5b5542f2cfd99ee9c18da..ecd88ca72c6dea39be9f046463e7c51c874cb351 100644
+--- a/include/grub/kernel.h
++++ b/include/grub/kernel.h
+@@ -28,7 +28,8 @@ enum
+   OBJ_TYPE_MEMDISK,
+   OBJ_TYPE_CONFIG,
+   OBJ_TYPE_PREFIX,
+-  OBJ_TYPE_PUBKEY
++  OBJ_TYPE_PUBKEY,
++  OBJ_TYPE_DTB
+ };
+ 
+ /* The module header.  */
+diff --git a/include/grub/mips/multiboot.h b/include/grub/mips/multiboot.h
+index 4aebf29e73240b575bb90c699fd02e8185ab5171..cdfb41e315af4aa22d549f76fb0131835abd957e 100644
+--- a/include/grub/mips/multiboot.h
++++ b/include/grub/mips/multiboot.h
+@@ -19,11 +19,11 @@
+ #ifndef GRUB_MULTIBOOT_CPU_HEADER
+ #define GRUB_MULTIBOOT_CPU_HEADER	1
+ 
+-#define MULTIBOOT_INITIAL_STATE  { .gpr[4] = MULTIBOOT_BOOTLOADER_MAGIC, \
++#define MULTIBOOT2_INITIAL_STATE  { .gpr[4] = MULTIBOOT2_BOOTLOADER_MAGIC, \
+     .jumpreg = 1 }
+ #define MULTIBOOT_ENTRY_REGISTER gpr[1]
+ #define MULTIBOOT_MBI_REGISTER gpr[5]
+-#define MULTIBOOT_ARCHITECTURE_CURRENT MULTIBOOT_ARCHITECTURE_MIPS32
++#define MULTIBOOT2_ARCHITECTURE_CURRENT MULTIBOOT2_ARCHITECTURE_MIPS32
+ 
+ #define MULTIBOOT_ELF32_MACHINE EM_MIPS
+ #define MULTIBOOT_ELF64_MACHINE EM_MIPS
+diff --git a/include/grub/misc.h b/include/grub/misc.h
+index 2a9f87cc255eda94476733513807ec757c6d9cd9..372f009e84f12a58c3185dda63216bab7325be8f 100644
+--- a/include/grub/misc.h
++++ b/include/grub/misc.h
+@@ -396,7 +396,8 @@ grub_abs (int x)
+ }
+ 
+ /* Reboot the machine.  */
+-#if defined (GRUB_MACHINE_EMU) || defined (GRUB_MACHINE_QEMU_MIPS)
++#if defined (GRUB_MACHINE_EMU) || defined (GRUB_MACHINE_QEMU_MIPS) || \
++    defined (GRUB_MACHINE_EFI)
+ void EXPORT_FUNC(grub_reboot) (void) __attribute__ ((noreturn));
+ #else
+ void grub_reboot (void) __attribute__ ((noreturn));
+diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h
+index c96492bb5fa771831a62d4ab1bac3798328093f0..bd0a9873e6c158f77190c38546007c544cb0d6c9 100644
+--- a/include/grub/multiboot.h
++++ b/include/grub/multiboot.h
+@@ -22,19 +22,11 @@
+ 
+ #include <grub/file.h>
+ 
+-#ifdef GRUB_USE_MULTIBOOT2
+-#include <multiboot2.h>
+-/* Same thing as far as our loader is concerned.  */
+-#define MULTIBOOT_BOOTLOADER_MAGIC	MULTIBOOT2_BOOTLOADER_MAGIC
+-#define MULTIBOOT_HEADER_MAGIC		MULTIBOOT2_HEADER_MAGIC
+-#else
+ #include <multiboot.h>
+-#endif
+ 
+ #include <grub/types.h>
+ #include <grub/err.h>
+ 
+-#ifndef GRUB_USE_MULTIBOOT2
+ typedef enum
+   {
+     GRUB_MULTIBOOT_QUIRKS_NONE = 0,
+@@ -42,7 +34,6 @@ typedef enum
+     GRUB_MULTIBOOT_QUIRK_MODULES_AFTER_KERNEL = 2
+   } grub_multiboot_quirks_t;
+ extern grub_multiboot_quirks_t grub_multiboot_quirks;
+-#endif
+ 
+ extern struct grub_relocator *grub_multiboot_relocator;
+ 
+@@ -60,7 +51,7 @@ void
+ grub_multiboot_add_elfsyms (grub_size_t num, grub_size_t entsize,
+ 			    unsigned shndx, void *data);
+ 
+-grub_uint32_t grub_get_multiboot_mmap_count (void);
++grub_uint32_t grub_multiboot_get_mmap_count (void);
+ grub_err_t grub_multiboot_set_video_mode (void);
+ 
+ /* FIXME: support coreboot as well.  */
+diff --git a/include/grub/multiboot2.h b/include/grub/multiboot2.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..502d34ef18045e898680f2198522139c3066b587
+--- /dev/null
++++ b/include/grub/multiboot2.h
+@@ -0,0 +1,104 @@
++/* multiboot.h - multiboot header file with grub definitions. */
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2003,2007,2008,2010  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_MULTIBOOT2_HEADER
++#define GRUB_MULTIBOOT2_HEADER 1
++
++#include <grub/file.h>
++
++#include <multiboot2.h>
++
++#include <grub/types.h>
++#include <grub/err.h>
++
++extern struct grub_relocator *grub_multiboot2_relocator;
++
++void grub_multiboot2 (int argc, char *argv[]);
++void grub_module2 (int argc, char *argv[]);
++
++void grub_multiboot2_set_accepts_video (int val);
++grub_err_t grub_multiboot2_make_mbi (grub_uint32_t *target);
++void grub_multiboot2_free_mbi (void);
++grub_err_t grub_multiboot2_init_mbi (int argc, char *argv[]);
++grub_err_t grub_multiboot2_add_module (grub_addr_t start, grub_size_t size,
++				      int argc, char *argv[]);
++void grub_multiboot2_set_bootdev (void);
++void
++grub_multiboot2_add_elfsyms (grub_size_t num, grub_size_t entsize,
++			    unsigned shndx, void *data);
++
++grub_uint32_t grub_multiboot2_get_mmap_count (void);
++grub_err_t grub_multiboot2_set_video_mode (void);
++
++/* FIXME: support coreboot as well.  */
++#if defined (GRUB_MACHINE_PCBIOS)
++#define GRUB_MACHINE_HAS_VBE 1
++#else
++#define GRUB_MACHINE_HAS_VBE 0
++#endif
++
++#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_QEMU)
++#define GRUB_MACHINE_HAS_VGA_TEXT 1
++#else
++#define GRUB_MACHINE_HAS_VGA_TEXT 0
++#endif
++
++#if defined (GRUB_MACHINE_EFI) || defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_MULTIBOOT)
++#define GRUB_MACHINE_HAS_ACPI 1
++#else
++#define GRUB_MACHINE_HAS_ACPI 0
++#endif
++
++#define GRUB_MULTIBOOT2_CONSOLE_EGA_TEXT 1
++#define GRUB_MULTIBOOT2_CONSOLE_FRAMEBUFFER 2 
++
++grub_err_t
++grub_multiboot2_set_console (int console_type, int accepted_consoles,
++			    int width, int height, int depth,
++			    int console_required);
++grub_err_t
++grub_multiboot2_load (grub_file_t file, const char *filename);
++
++struct mbi_load_data
++{
++  grub_file_t file;
++  const char *filename;
++  void *buffer;
++  unsigned int mbi_ver;
++  int relocatable;
++  grub_uint32_t min_addr;
++  grub_uint32_t max_addr;
++  grub_size_t align;
++  grub_uint32_t preference;
++  grub_uint32_t link_base_addr;
++  grub_uint32_t load_base_addr;
++  int avoid_efi_boot_services;
++};
++typedef struct mbi_load_data mbi_load_data_t;
++
++/* Load ELF32 or ELF64.  */
++grub_err_t
++grub_multiboot2_load_elf (mbi_load_data_t *mld);
++
++extern grub_size_t grub_multiboot2_pure_size;
++extern grub_size_t grub_multiboot2_alloc_mbi;
++extern grub_uint32_t grub_multiboot2_payload_eip;
++
++
++#endif /* ! GRUB_MULTIBOOT_HEADER */
+diff --git a/include/grub/net.h b/include/grub/net.h
+index 2192fa18628862e8e3a6046d854b12613e914ff9..1096b24322eb1ba36e8c996872fce2a255e6bccc 100644
+--- a/include/grub/net.h
++++ b/include/grub/net.h
+@@ -291,6 +291,7 @@ struct grub_net_network_level_interface
+   grub_net_interface_flags_t flags;
+   struct grub_net_bootp_packet *dhcp_ack;
+   grub_size_t dhcp_acklen;
++  grub_uint16_t vlantag;
+   void *data;
+ };
+ 
+@@ -561,4 +562,6 @@ extern char *grub_net_default_server;
+ #define GRUB_NET_INTERVAL 400
+ #define GRUB_NET_INTERVAL_ADDITION 20
+ 
++#define VLANTAG_IDENTIFIER 0x8100
++
+ #endif /* ! GRUB_NET_HEADER */
+diff --git a/include/grub/net/arp.h b/include/grub/net/arp.h
+index bb1703622e1529479618e7f71b0d5e88adb631d1..8d9d081134f52e2d33c23928baae7f6b4c08470f 100644
+--- a/include/grub/net/arp.h
++++ b/include/grub/net/arp.h
+@@ -22,10 +22,11 @@
+ #include <grub/net.h>
+ 
+ extern grub_err_t grub_net_arp_receive (struct grub_net_buff *nb,
+-					struct grub_net_card *card);
++                                        struct grub_net_card *card,
++                                        grub_uint16_t *vlantag);
+ 
+ grub_err_t
+ grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
+-			   const grub_net_network_level_address_t *proto_addr);
++                           const grub_net_network_level_address_t *proto_addr);
+ 
+ #endif 
+diff --git a/include/grub/net/ip.h b/include/grub/net/ip.h
+index dcceaa56894605a39f87858964da7af11951ff11..ab9d68f98252b9772853a712ff1e8556162002ee 100644
+--- a/include/grub/net/ip.h
++++ b/include/grub/net/ip.h
+@@ -48,7 +48,8 @@ grub_err_t
+ grub_net_recv_ip_packets (struct grub_net_buff *nb,
+ 			  struct grub_net_card *card,
+ 			  const grub_net_link_level_address_t *hwaddress,
+-			  const grub_net_link_level_address_t *src_hwaddress);
++			  const grub_net_link_level_address_t *src_hwaddress,
++                          grub_uint16_t *vlantag);
+ 
+ grub_err_t
+ grub_net_send_ip_packet (struct grub_net_network_level_interface *inf,
+diff --git a/include/grub/offsets.h b/include/grub/offsets.h
+index c88c86d4d2ebddddb23f25c50ad2c29b52e54ccb..330e4c70738abcacc3c1d53fb16ae1ec8896d9e3 100644
+--- a/include/grub/offsets.h
++++ b/include/grub/offsets.h
+@@ -50,7 +50,7 @@
+ /* The offset of GRUB_CORE_ENTRY_ADDR.  */
+ #define GRUB_KERNEL_I386_QEMU_CORE_ENTRY_ADDR	0x8
+ 
+-#define GRUB_KERNEL_I386_QEMU_LINK_ADDR         0x8200
++#define GRUB_KERNEL_I386_QEMU_LINK_ADDR         0x9000
+ 
+ /* The offset of GRUB_TOTAL_MODULE_SIZE.  */
+ #define GRUB_KERNEL_SPARC64_IEEE1275_TOTAL_MODULE_SIZE	0x8
+@@ -91,7 +91,7 @@
+ 
+ #define GRUB_KERNEL_MIPS_ARC_TOTAL_MODULE_SIZE	0x08
+ 
+-#define GRUB_KERNEL_I386_COREBOOT_LINK_ADDR	0x8200
++#define GRUB_KERNEL_I386_COREBOOT_LINK_ADDR	0x9000
+ #define GRUB_KERNEL_I386_COREBOOT_MODULES_ADDR  0x100000
+ 
+ #define GRUB_KERNEL_I386_IEEE1275_LINK_ADDR	0x10000
+@@ -122,6 +122,12 @@
+ #define GRUB_KERNEL_ARM_UBOOT_MOD_ALIGN 	0x8
+ #define GRUB_KERNEL_ARM_UBOOT_TOTAL_MODULE_SIZE	0x4
+ 
++#define GRUB_KERNEL_ARM_COREBOOT_MOD_ALIGN 	0x8
++#define GRUB_KERNEL_ARM_COREBOOT_TOTAL_MODULE_SIZE	0x4
++
++#define GRUB_KERNEL_ARM_STACK_SIZE 0x40000
++#define GRUB_KERNEL_ARM_COREBOOT_MOD_GAP (GRUB_KERNEL_ARM_STACK_SIZE + 1024)
++
+ /* Minimal gap between _end and the start of the modules.  It's a hack
+    for PowerMac to prevent "CLAIM failed" error.  The real fix is to
+    rewrite grub-mkimage to generate valid ELF files.  */
+diff --git a/include/grub/pci.h b/include/grub/pci.h
+index 70d9a05131b240bbe3c7fe12df899c8e3de237ce..262c89b748bbfccc98ffa27912ce7e2a5005f545 100644
+--- a/include/grub/pci.h
++++ b/include/grub/pci.h
+@@ -142,27 +142,7 @@ grub_pci_address_t EXPORT_FUNC(grub_pci_make_address) (grub_pci_device_t dev,
+ void EXPORT_FUNC(grub_pci_iterate) (grub_pci_iteratefunc_t hook,
+ 				    void *hook_data);
+ 
+-struct grub_pci_dma_chunk;
+-
+-struct grub_pci_dma_chunk *EXPORT_FUNC(grub_memalign_dma32) (grub_size_t align,
+-							     grub_size_t size);
+-void EXPORT_FUNC(grub_dma_free) (struct grub_pci_dma_chunk *ch);
+-volatile void *EXPORT_FUNC(grub_dma_get_virt) (struct grub_pci_dma_chunk *ch);
+-grub_uint32_t EXPORT_FUNC(grub_dma_get_phys) (struct grub_pci_dma_chunk *ch);
+-
+-static inline void *
+-grub_dma_phys2virt (grub_uint32_t phys, struct grub_pci_dma_chunk *chunk)
+-{
+-  return ((grub_uint8_t *) grub_dma_get_virt (chunk)
+-	  + (phys - grub_dma_get_phys (chunk)));
+-}
+-
+-static inline grub_uint32_t
+-grub_dma_virt2phys (volatile void *virt, struct grub_pci_dma_chunk *chunk)
+-{
+-  return (((grub_uint8_t *) virt - (grub_uint8_t *) grub_dma_get_virt (chunk))
+-	  + grub_dma_get_phys (chunk));
+-}
++#include <grub/dma.h>
+ 
+ grub_uint8_t
+ EXPORT_FUNC (grub_pci_find_capability) (grub_pci_device_t dev, grub_uint8_t cap);
+diff --git a/include/grub/ps2.h b/include/grub/ps2.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..4f2e527e49767c297646f1ea3d0e09bdc2855892
+--- /dev/null
++++ b/include/grub/ps2.h
+@@ -0,0 +1,43 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2007,2008,2009  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef GRUB_PS2_HEADER
++#define GRUB_PS2_HEADER	1
++
++#include <grub/types.h>
++
++#define GRUB_AT_ACK                     0xfa
++#define GRUB_AT_NACK                    0xfe
++#define GRUB_AT_TRIES                   5
++
++/* Make sure it's zeroed-out and set current_set at init.  */
++struct grub_ps2_state
++{
++  int e0_received;
++  int f0_received;
++  grub_uint8_t led_status;
++  short at_keyboard_status;
++  grub_uint8_t current_set;
++};
++
++/* If there is a key pending, return it; otherwise return GRUB_TERM_NO_KEY.  */
++int
++grub_ps2_process_incoming_byte (struct grub_ps2_state *ps2_state,
++				grub_uint8_t data);
++
++#endif
+diff --git a/include/grub/sparc64/ieee1275/ieee1275.h b/include/grub/sparc64/ieee1275/ieee1275.h
+index 32c77f80f1a136c0127aecb6d5643ebd64cb5e88..4b18468d8d654bb3fe62050e7a4f439e1544889c 100644
+--- a/include/grub/sparc64/ieee1275/ieee1275.h
++++ b/include/grub/sparc64/ieee1275/ieee1275.h
+@@ -42,6 +42,8 @@ extern int EXPORT_FUNC(grub_ieee1275_claim_vaddr) (grub_addr_t vaddr,
+ extern int EXPORT_FUNC(grub_ieee1275_alloc_physmem) (grub_addr_t *paddr,
+ 						     grub_size_t size,
+ 						     grub_uint32_t align);
++extern grub_uint64_t EXPORT_FUNC(grub_ieee1275_num_blocks) (grub_uint32_t ihandle);
++extern grub_uint64_t EXPORT_FUNC(grub_ieee1275_num_blocks64) (grub_uint32_t ihandle);
+ 
+ extern grub_addr_t EXPORT_VAR (grub_ieee1275_original_stack);
+ 
+diff --git a/include/grub/term.h b/include/grub/term.h
+index 5ffb38f69aaa8911a66bdc6f417a72666b19e514..8117e2a24dac3f270d05408f1897fae9f0fa1593 100644
+--- a/include/grub/term.h
++++ b/include/grub/term.h
+@@ -55,7 +55,8 @@
+ #define GRUB_TERM_KEY_INSERT    (GRUB_TERM_EXTENDED | 0x52)
+ #define GRUB_TERM_KEY_CENTER    (GRUB_TERM_EXTENDED | 0x4c)
+ 
+-#define GRUB_TERM_ESC		'\e'
++/* Hex value is used for ESC, since '\e' is nonstandard */
++#define GRUB_TERM_ESC		0x1b
+ #define GRUB_TERM_TAB		'\t'
+ #define GRUB_TERM_BACKSPACE	'\b'
+ 
+diff --git a/include/grub/usb.h b/include/grub/usb.h
+index 11d96481ff6b58cc43f468bcb2020475663fa098..512ae1dd0e64931c852847c9d52efdbd6b2caccb 100644
+--- a/include/grub/usb.h
++++ b/include/grub/usb.h
+@@ -321,5 +321,9 @@ grub_usb_err_t
+ grub_usb_check_transfer (grub_usb_transfer_t trans, grub_size_t *actual);
+ void
+ grub_usb_cancel_transfer (grub_usb_transfer_t trans);
++void
++grub_ehci_init_device (volatile void *regs);
++void
++grub_ehci_pci_scan (void);
+ 
+ #endif /* GRUB_USB_H */
+diff --git a/include/grub/util/install.h b/include/grub/util/install.h
+index 5ca4811cd130f6810f07e6fbce89af1de36827c7..0dba8b67f93d44f875f2d1065ed5bf745f7813a5 100644
+--- a/include/grub/util/install.h
++++ b/include/grub/util/install.h
+@@ -29,6 +29,8 @@
+ #define GRUB_INSTALL_OPTIONS					  \
+   { "modules",      GRUB_INSTALL_OPTIONS_MODULES, N_("MODULES"),	  \
+     0, N_("pre-load specified modules MODULES"), 1 },			  \
++  { "dtb",      GRUB_INSTALL_OPTIONS_DTB, N_("FILE"),	  \
++    0, N_("embed a specific DTB"), 1 },			  \
+   { "install-modules", GRUB_INSTALL_OPTIONS_INSTALL_MODULES,	  \
+     N_("MODULES"), 0,							  \
+     N_("install only MODULES and their dependencies [default=all]"), 1 }, \
+@@ -99,6 +101,7 @@ enum grub_install_plat
+     GRUB_INSTALL_PLATFORM_I386_XEN,
+     GRUB_INSTALL_PLATFORM_X86_64_XEN,
+     GRUB_INSTALL_PLATFORM_ARM64_EFI,
++    GRUB_INSTALL_PLATFORM_ARM_COREBOOT,
+     GRUB_INSTALL_PLATFORM_MAX
+   };
+ 
+@@ -115,7 +118,8 @@ enum grub_install_options {
+   GRUB_INSTALL_OPTIONS_LOCALE_DIRECTORY,
+   GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY,
+   GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE,
+-  GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS
++  GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS,
++  GRUB_INSTALL_OPTIONS_DTB
+ };
+ 
+ extern char *grub_install_source_directory;
+@@ -176,7 +180,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
+ 			     char *config_path,
+ 			     const struct grub_install_image_target_desc *image_target,
+ 			     int note,
+-			     grub_compression_t comp);
++			     grub_compression_t comp, const char *dtb_file);
+ 
+ const struct grub_install_image_target_desc *
+ grub_install_get_image_target (const char *arg);
+@@ -206,7 +210,7 @@ grub_install_create_envblk_file (const char *name);
+ const char *
+ grub_install_get_default_x86_platform (void);
+ 
+-void
++int
+ grub_install_register_efi (grub_device_t efidir_grub_dev,
+ 			   const char *efifile_path,
+ 			   const char *efi_distributor);
+diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
+index 1a18708a89c6e5503dd29b0b76f5098cef3ac893..b3a5ca132bc4d336f8d85158726bcce77fd7cd37 100644
+--- a/include/grub/util/mkimage.h
++++ b/include/grub/util/mkimage.h
+@@ -51,13 +51,13 @@ grub_mkimage_load_image64 (const char *kernel_path,
+ void
+ grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target,
+ 			     int note, char **core_img, size_t *core_size,
+-			     Elf32_Addr target_addr, grub_size_t align,
+-			     size_t kernel_size, size_t bss_size);
++			     Elf32_Addr target_addr,
++			     struct grub_mkimage_layout *layout);
+ void
+ grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target,
+ 			     int note, char **core_img, size_t *core_size,
+-			     Elf64_Addr target_addr, grub_size_t align,
+-			     size_t kernel_size, size_t bss_size);
++			     Elf64_Addr target_addr,
++			     struct grub_mkimage_layout *layout);
+ 
+ struct grub_install_image_target_desc
+ {
+diff --git a/include/multiboot2.h b/include/multiboot2.h
+index 5a3db5a7cae38c26be516dc76a4fa6a9ad4ed354..5693923c014f2fa9e855dcc89c7328a19e0e6408 100644
+--- a/include/multiboot2.h
++++ b/include/multiboot2.h
+@@ -75,8 +75,8 @@
+ #define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64  9
+ #define MULTIBOOT_HEADER_TAG_RELOCATABLE  10
+ 
+-#define MULTIBOOT_ARCHITECTURE_I386  0
+-#define MULTIBOOT_ARCHITECTURE_MIPS32  4
++#define MULTIBOOT2_ARCHITECTURE_I386  0
++#define MULTIBOOT2_ARCHITECTURE_MIPS32  4
+ #define MULTIBOOT_HEADER_TAG_OPTIONAL 1
+ 
+ #define MULTIBOOT_LOAD_PREFERENCE_NONE 0
+diff --git a/grub-core/boot/i386/pc/diskboot.S b/grub-core/boot/i386/pc/diskboot.S
+index 1ee4cf5b2e0fd03ba177e953fafdaf5e0ca457a6..c1addc0df29bc78009238690a9514ea301bf3a29 100644
+--- a/grub-core/boot/i386/pc/diskboot.S
++++ b/grub-core/boot/i386/pc/diskboot.S
+@@ -37,8 +37,8 @@
+ start:
+ _start:
+ 	/*
+-	 * _start is loaded at 0x2000 and is jumped to with
+-	 * CS:IP 0:0x2000 in kernel.
++	 * _start is loaded at 0x8000 and is jumped to with
++	 * CS:IP 0:0x8000 in kernel.
+ 	 */
+ 
+ 	/*
+diff --git a/grub-core/boot/sparc64/ieee1275/boot.S b/grub-core/boot/sparc64/ieee1275/boot.S
+index 586efb4014e8648e560fb43eee8eea8b09da669b..9ea9b4e06627bbd8b7da422ffba3357b4fba0a6a 100644
+--- a/grub-core/boot/sparc64/ieee1275/boot.S
++++ b/grub-core/boot/sparc64/ieee1275/boot.S
+@@ -69,6 +69,10 @@ prom_seek_name:		.asciz "seek"
+ prom_read_name:		.asciz "read"
+ prom_exit_name:		.asciz "exit"
+ grub_name:		.asciz "GRUB "
++#ifdef CDBOOT
++prom_close_name:	.asciz "close"
++#endif
++
+ #define GRUB_NAME_LEN	5
+ 
+ 	.align	4
+@@ -213,6 +217,12 @@ bootpath_known:
+ 	call	prom_call_3_1_o1
+ #ifdef CDBOOT
+ 	 LDUW_ABS(kernel_size, 0x00, %o3)
++
++	GET_ABS(prom_close_name, %o0)
++	mov	1, %g1
++	mov	0, %o5
++	call	prom_call
++	 mov	BOOTDEV_REG, %o1
+ #else
+ 	 mov	512, %o3
+ #endif
+diff --git a/grub-core/kern/arm/cache_armv7.S b/grub-core/kern/arm/cache_armv7.S
+index 1ef2754af8a7612c35c26011fab442dbba074dfd..5ae76a3d819c002676f54db3311f517791e0c4e8 100644
+--- a/grub-core/kern/arm/cache_armv7.S
++++ b/grub-core/kern/arm/cache_armv7.S
+@@ -33,6 +33,18 @@
+ # define ISB	isb
+ #define ARMV7 1
+ 
++FUNCTION(grub_arm_clean_dcache_range_poc_armv7)
++	DSB
++	@ Clean data cache for range to point-of-coherence
++1:	cmp	r0, r1
++	bge	2f
++	mcr	p15, 0, r0, c7, c14, 1	@ DCCMVAC
++	add	r0, r0, r2		@ Next line
++	b	1b
++2:	DSB
++	bx	lr
++
++
+ 	@ r0  - CLIDR
+ 	@ r1  - LoC
+ 	@ r2  - current level
+diff --git a/include/grub/arm/efi/loader.h b/grub-core/kern/arm/coreboot/coreboot.S
+similarity index 62%
+rename from include/grub/arm/efi/loader.h
+rename to grub-core/kern/arm/coreboot/coreboot.S
+index 4bab18e83ee833d6932fea917d839fe7dcc212d1..a1104526c154bd5a9dfd9e3680d8bb787c1088ef 100644
+--- a/include/grub/arm/efi/loader.h
++++ b/grub-core/kern/arm/coreboot/coreboot.S
+@@ -1,6 +1,6 @@
+ /*
+  *  GRUB  --  GRand Unified Bootloader
+- *  Copyright (C) 2013  Free Software Foundation, Inc.
++ *  Copyright (C) 2016  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
+@@ -16,11 +16,29 @@
+  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+  */
+ 
+-#ifndef GRUB_LOADER_MACHINE_HEADER
+-#define GRUB_LOADER_MACHINE_HEADER	1
++#include <grub/symbol.h>
+ 
+-grub_err_t EXPORT_FUNC (grub_efi_prepare_platform) (void);
+-void * EXPORT_FUNC (grub_efi_allocate_loader_memory) (grub_uint32_t min_offset,
+-						      grub_uint32_t size);
++	.file	"coreboot.S"
++	.text
++	.syntax	unified
++#if !defined (__thumb2__)
++	.arch	armv7a
++	.arm
++#else
++	.arch	armv7
++	.thumb
++#endif
++
++FUNCTION(grub_arm_pfr1)
++	mrc p15, 0, r0, c0, c1, 1
++	bx	lr
++
++FUNCTION(grub_armv7_get_timer_value)
++	isb
++	mrrc p15, 1, r0, r1, c14
++	bx	lr
++
++FUNCTION(grub_armv7_get_timer_frequency)
++	mrc p15, 0, r0, c14, c0, 0
++	bx	lr
+ 
+-#endif /* ! GRUB_LOADER_MACHINE_HEADER */
+diff --git a/grub-core/kern/arm/uboot/startup.S b/grub-core/kern/arm/startup.S
+similarity index 77%
+rename from grub-core/kern/arm/uboot/startup.S
+rename to grub-core/kern/arm/startup.S
+index 5efaae16e838b48dd4d9a5debfc2937a558c65ba..3946fe8e183023f80e3a90ae4ee7b942f02f204d 100644
+--- a/grub-core/kern/arm/uboot/startup.S
++++ b/grub-core/kern/arm/startup.S
+@@ -24,6 +24,7 @@
+  * GRUB is called from U-Boot as a Linux Kernel type image, which
+  * means among other things that it always enters in ARM state.
+  *
++ * coreboot starts in ARM mode as well.
+  *
+  * Overview of GRUB image layout:
+  *
+@@ -86,7 +87,7 @@ FUNCTION(codestart)
+ 	@ Stack pointer used as start address for signature probing
+ 	mov	r12, sp
+ 	adr	sp, entry_state
+-	push	{r1-r12,lr}	@ store U-Boot context (sp in r12)
++	push	{r0-r12,lr}	@ store U-Boot context (sp in r12)
+ 
+ 	adr     r1, _start
+ 	ldr	r0, bss_start_ptr		@ src
+@@ -127,6 +128,8 @@ reloc_done:
+ 
+ 	str     r1, EXT_C(grub_modbase)
+ 
++	/* Coreboot already places modules at right place.  */
++#ifndef GRUB_MACHINE_COREBOOT
+ 	add	r1, r1, r2
+ 	add	r0, r0, r2
+ 	sub     r1, r1, #4
+@@ -136,6 +139,7 @@ reloc_done:
+ 	str	r3, [r1], #-4			@ *dst-- = r3 
+ 	subs	r2, #4				@ remaining -= 4
+ 	bne	1b				@ while remaining != 0
++#endif
+ 
+ 	@ Since we _are_ the C run-time, we need to manually zero the BSS
+ 	@ region before continuing
+@@ -153,69 +157,21 @@ reloc_done:
+ 	
+ 	b	EXT_C(grub_main)
+ 
+-	/*
+-	 * uboot_syscall():
+-	 *   This function is effectively a veneer, so it cannot
+-	 *   modify the stack or corrupt any registers other than
+-	 *   r12 (ip). Furthermore it needs to restore r8 for
+-	 *   U-Boot (Global Data Pointer) and preserve it for Grub.
+-	 */
+-FUNCTION(grub_uboot_syscall)
+-	str     r8, transition_space
+-	str     lr, transition_space + 4
+-	str     r9, transition_space + 8
+-
+-	ldr	r8, gd_backup
+-	ldr	r9, gd_backup + 4
+-
+-	bl	do_syscall
+-
+-	ldr     r8, transition_space
+-	ldr     lr, transition_space + 4
+-	ldr     r9, transition_space + 8
+-
+-	bx	lr
+-do_syscall:
+-
+-	ldr	ip, grub_uboot_syscall_ptr
+-	bx	ip
+-	
+-FUNCTION(grub_uboot_return)
+-	adr	sp, entry_state_end
+-	pop	{r4-r12, lr}
+-	mov	sp, r12
+-	bx	lr
+-
+-	
+ 	.align	3
+-@ U-boot context stack space
+-entry_state_end:
+-VARIABLE(grub_uboot_machine_type)
++@ U-boot/coreboot context stack space
++VARIABLE(grub_arm_saved_registers)
++	.long	0	@ r0
+ 	.long	0	@ r1
+-VARIABLE(grub_uboot_boot_data)
+ 	.long	0	@ r2
+ 	.long	0	@ r3
+ 	.long	0	@ r4
+ 	.long	0	@ r5
+ 	.long	0	@ r6
+ 	.long	0	@ r7
+-gd_backup:	
+-	.long	0	@ r8 - U-Boot global data pointer up to 2013-09-21
+-	.long	0	@ r9 - U-Boot global data pointer 2013-09-21 onwards
+-	.long	0	@ r10
+-	.long	0	@ r11
+-VARIABLE(grub_uboot_search_hint)@ U-Boot stack pointer - 
+-	.long	0	@ also API signature address hint.
+-	.long	0	@ lr
+-entry_state:		@ backup for U-Boot context
+-
+-@ GRUB context stack space
+-transition_space:	
+ 	.long	0	@ r8
+-	.long	0	@ lr
+ 	.long	0	@ r9
+-
+-VARIABLE(grub_uboot_syscall_ptr)
+-	.long	0	@
+-
+-	END
++	.long	0	@ r10
++	.long	0	@ r11
++	.long	0	@ sp
++	.long	0	@ lr
++entry_state:
+diff --git a/grub-core/kern/arm/uboot/uboot.S b/grub-core/kern/arm/uboot/uboot.S
+new file mode 100644
+index 0000000000000000000000000000000000000000..d128775f19ea1f862b46bc82b05b453be577d741
+--- /dev/null
++++ b/grub-core/kern/arm/uboot/uboot.S
+@@ -0,0 +1,73 @@
++/*
++ *  GRUB  --  GRand Unified Bootloader
++ *  Copyright (C) 2013  Free Software Foundation, Inc.
++ *
++ *  GRUB is free software: you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation, either version 3 of the License, or
++ *  (at your option) any later version.
++ *
++ *  GRUB is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <grub/offsets.h>
++#include <grub/symbol.h>
++#include <grub/machine/kernel.h>
++
++	/*
++	 * uboot_syscall():
++	 *   This function is effectively a veneer, so it cannot
++	 *   modify the stack or corrupt any registers other than
++	 *   r12 (ip). Furthermore it needs to restore r8 for
++	 *   U-Boot (Global Data Pointer) and preserve it for Grub.
++	 */
++FUNCTION(grub_uboot_syscall)
++	str     r8, transition_space
++	str     lr, transition_space + 4
++	str     r9, transition_space + 8
++
++	ldr	ip, saved_registers_ptr
++	ldr	r8, [ip, #4 * 8]
++	ldr	r9, [ip, #4 * 9]
++
++	bl	do_syscall
++
++	ldr     r8, transition_space
++	ldr     lr, transition_space + 4
++	ldr     r9, transition_space + 8
++
++	bx	lr
++do_syscall:
++
++	ldr	ip, grub_uboot_syscall_ptr
++	bx	ip
++	
++FUNCTION(grub_uboot_return)
++	ldr	ip, saved_registers_ptr
++	ldr	sp, [ip, #4 * 4]
++	pop	{r4-r12, lr}
++	mov	sp, r12
++	bx	lr
++
++	
++	.align	3
++
++@ GRUB context stack space
++transition_space:	
++	.long	0	@ r8
++	.long	0	@ lr
++	.long	0	@ r9
++
++saved_registers_ptr:
++	.long EXT_C(grub_arm_saved_registers)
++
++VARIABLE(grub_uboot_syscall_ptr)
++	.long	0	@
++
++	END
+diff --git a/conf/Makefile.common b/conf/Makefile.common
+index 11296b550a7cd40ded498613620f556d78c67d84..311da61c6c59fed3de8cba06c2c581b217d8273f 100644
+--- a/conf/Makefile.common
++++ b/conf/Makefile.common
+@@ -86,9 +86,11 @@ CPPFLAGS_TERMINAL_LIST += '-Dgrub_term_register_output(...)=OUTPUT_TERMINAL_LIST
+ CPPFLAGS_COMMAND_LIST = '-Dgrub_register_command(...)=COMMAND_LIST_MARKER(__VA_ARGS__)'
+ CPPFLAGS_COMMAND_LIST += '-Dgrub_register_extcmd(...)=EXTCOMMAND_LIST_MARKER(__VA_ARGS__)'
+ CPPFLAGS_COMMAND_LIST += '-Dgrub_register_command_p1(...)=P1COMMAND_LIST_MARKER(__VA_ARGS__)'
++CPPFLAGS_FDT_LIST := '-Dgrub_fdtbus_register(...)=FDT_DRIVER_LIST_MARKER(__VA_ARGS__)'
+ CPPFLAGS_MARKER = $(CPPFLAGS_FS_LIST) $(CPPFLAGS_VIDEO_LIST) \
+ 	$(CPPFLAGS_PARTTOOL_LIST) $(CPPFLAGS_PARTMAP_LIST) \
+-	$(CPPFLAGS_TERMINAL_LIST) $(CPPFLAGS_COMMAND_LIST)
++	$(CPPFLAGS_TERMINAL_LIST) $(CPPFLAGS_COMMAND_LIST) \
++	$(CPPFLAGS_FDT_LIST)
+ 
+ # Define these variables to calm down automake
+ 
+diff --git a/docs/grub.texi b/docs/grub.texi
+index e935af33ea5e24d832e588d1345e3721b826d5a0..2adfa97bee8f8b2dcd53ead368dfd6f115b8cb82 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -360,8 +360,9 @@ blocklist notation. The currently supported filesystem types are @dfn{Amiga
+ Fast FileSystem (AFFS)}, @dfn{AtheOS fs}, @dfn{BeFS},
+ @dfn{BtrFS} (including raid0, raid1, raid10, gzip and lzo),
+ @dfn{cpio} (little- and big-endian bin, odc and newc variants),
+-@dfn{Linux ext2/ext3/ext4}, @dfn{DOS FAT12/FAT16/FAT32}, @dfn{exFAT}, @dfn{HFS},
+-@dfn{HFS+}, @dfn{ISO9660} (including Joliet, Rock-ridge and multi-chunk files),
++@dfn{Linux ext2/ext3/ext4}, @dfn{DOS FAT12/FAT16/FAT32},
++@dfn{exFAT}, @dfn{F2FS}, @dfn{HFS}, @dfn{HFS+},
++@dfn{ISO9660} (including Joliet, Rock-ridge and multi-chunk files),
+ @dfn{JFS}, @dfn{Minix fs} (versions 1, 2 and 3), @dfn{nilfs2},
+ @dfn{NTFS} (including compression), @dfn{ReiserFS}, @dfn{ROMFS},
+ @dfn{Amiga Smart FileSystem (SFS)}, @dfn{Squash4}, @dfn{tar}, @dfn{UDF},
+@@ -1213,10 +1214,11 @@ GRUB is configured using @file{grub.cfg}, usually located under
+ need to write the whole thing by hand.
+ 
+ @menu
+-* Simple configuration::        Recommended for most users
+-* Shell-like scripting::        For power users and developers
+-* Multi-boot manual config::    For non-standard multi-OS scenarios
+-* Embedded configuration::      Embedding a configuration file into GRUB
++* Simple configuration::            Recommended for most users
++* Root Identifcation Heuristics::   Summary on how the root file system is identified.
++* Shell-like scripting::            For power users and developers
++* Multi-boot manual config::        For non-standard multi-OS scenarios
++* Embedded configuration::          Embedding a configuration file into GRUB
+ @end menu
+ 
+ 
+@@ -1398,6 +1400,25 @@ for all respectively normal entries.
+ The values of these options replace the values of @samp{GRUB_CMDLINE_LINUX}
+ and @samp{GRUB_CMDLINE_LINUX_DEFAULT} for Linux and Xen menu entries.
+ 
++@item GRUB_EARLY_INITRD_LINUX_CUSTOM
++@itemx GRUB_EARLY_INITRD_LINUX_STOCK
++List of space-separated early initrd images to be loaded from @samp{/boot}.
++This is for loading things like CPU microcode, firmware, ACPI tables, crypto
++keys, and so on. These early images will be loaded in the order declared,
++and all will be loaded before the actual functional initrd image.
++
++@samp{GRUB_EARLY_INITRD_LINUX_STOCK} is for your distribution to declare
++images that are provided by the distribution. It should not be modified
++without understanding the consequences. They will be loaded first.
++
++@samp{GRUB_EARLY_INITRD_LINUX_CUSTOM} is for your custom created images.
++
++The default stock images are as follows, though they may be overridden by
++your distribution:
++@example
++intel-uc.img intel-ucode.img amd-uc.img amd-ucode.img early_ucode.cpio microcode.cpio
++@end example
++
+ @item GRUB_DISABLE_LINUX_UUID
+ Normally, @command{grub-mkconfig} will generate menu entries that use
+ universally-unique identifiers (UUIDs) to identify the root filesystem to
+@@ -1405,6 +1426,17 @@ the Linux kernel, using a @samp{root=UUID=...} kernel parameter.  This is
+ usually more reliable, but in some cases it may not be appropriate.  To
+ disable the use of UUIDs, set this option to @samp{true}.
+ 
++@item GRUB_DISABLE_LINUX_PARTUUID
++If @command{grub-mkconfig} cannot identify the root filesystem via its
++universally-unique indentifier (UUID), @command{grub-mkconfig} can use the UUID
++of the partition containing the filesystem to identify the root filesystem to
++the Linux kernel via a @samp{root=PARTUUID=...} kernel parameter.  This is not
++as reliable as using the filesystem UUID, but is more reliable than using the
++Linux device names. When @samp{GRUB_DISABLE_LINUX_PARTUUID} is set to
++@samp{false}, the Linux kernel version must be 2.6.37 (3.10 for systems using
++the MSDOS partition scheme) or newer.  This option defaults to @samp{true}.  To
++enable the use of partition UUIDs, set this option to @samp{false}.
++
+ @item GRUB_DISABLE_RECOVERY
+ If this option is set to @samp{true}, disable the generation of recovery
+ mode menu entries.
+@@ -1536,6 +1568,53 @@ edit the scripts in @file{/etc/grub.d} directly.
+ menu entries; simply type the menu entries you want to add at the end of
+ that file, making sure to leave at least the first two lines intact.
+ 
++@node Root Identifcation Heuristics
++@section Root Identifcation Heuristics
++If the target operating system uses the Linux kernel, @command{grub-mkconfig}
++attempts to identify the root file system via a heuristic algoirthm.  This
++algorithm selects the identification method of the root file system by
++considering three factors.  The first is if an initrd for the target operating
++system is also present.  The second is @samp{GRUB_DISABLE_LINUX_UUID} and if set
++to @samp{true}, prevents @command{grub-mkconfig} from identifying the root file
++system by its UUID.  The third is @samp{GRUB_DISABLE_LINUX_PARTUUID} and if set
++to @samp{true}, prevents @command{grub-mkconfig} from identifying the root file
++system via the UUID of its enclosing partition.  If the variables are assigned
++any other value, that value is considered equivalent to @samp{false}.  The
++variables are also considered to be set to @samp{false} if they are not set.
++
++When booting, the Linux kernel will delegate the task of mounting the root
++filesystem to the initrd.  Most initrd images determine the root file system by
++checking the Linux kernel's command-line for the @samp{root} key and use its
++value as the identification method of the root file system.  To improve the
++reliability of booting, most initrd images also allow the root file system to be
++identified by its UUID.  Because of this behavior, the @command{grub-mkconfig}
++command will set @samp{root} to @samp{root=UUID=...} to provide the initrd with
++the filesystem UUID of the root file system.
++
++If no initrd is detected or @samp{GRUB_DISABLE_LINUX_UUID} is set to @samp{true}
++then @command{grub-command} will identify the root filesystem by setting the
++kernel command-line variable @samp{root} to @samp{root=PARTUUID=...} unless
++@samp{GRUB_DISABLE_LINUX_PARTUUID} is also set to @samp{true}.  If
++@samp{GRUB_DISABLE_LINUX_PARTUUID} is also set to @samp{true},
++@command{grub-command} will identify by its Linux device name.
++
++The following table summarizes the behavior of the @command{grub-mkconfig}
++command.
++
++@multitable {detected} {GRUB_DISABLE_LINUX_PARTUUID} {GRUB_DISABLE_LINUX_UUID} {Linux Root}
++@headitem Initrd detected @tab GRUB_DISABLE_LINUX_PARTUUID Set To @tab GRUB_DISABLE_LINUX_UUID Set To @tab Linux Root ID Method
++@item false         @tab false                       @tab false                   @tab part UUID
++@item false         @tab false                       @tab true                    @tab part UUID
++@item false         @tab true                        @tab false                   @tab dev name
++@item false         @tab true                        @tab true                    @tab dev name
++@item true          @tab false                       @tab false                   @tab fs UUID
++@item true          @tab false                       @tab true                    @tab part UUID
++@item true          @tab true                        @tab false                   @tab fs UUID
++@item true          @tab true                        @tab true                    @tab dev name
++@end multitable
++
++Remember, @samp{GRUB_DISABLE_LINUX_PARTUUID} and @samp{GRUB_DISABLE_LINUX_UUID}
++are also considered to be set to @samp{false} when they are unset.
+ 
+ @node Shell-like scripting
+ @section Writing full configuration files directly
+@@ -3873,11 +3952,9 @@ you forget a command, you can run the command @command{help}
+ @comment * vbeinfo::                     List available video modes
+ * verify_detached::             Verify detached digital signature
+ * videoinfo::                   List available video modes
+-@comment * xen_*::              Xen boot commands
+-* xen_hypervisor::              Load xen hypervisor binary
+-* xen_linux::                   Load dom0 kernel for xen hypervisor
+-* xen_initrd::                  Load dom0 initrd for dom0 kernel
+-* xen_xsm::                     Load xen security module for xen hypervisor
++@comment * xen_*::              Xen boot commands for AArch64
++* xen_hypervisor::              Load xen hypervisor binary (only on AArch64)
++* xen_module::                  Load xen modules for xen hypervisor (only on AArch64)
+ @end menu
+ 
+ 
+@@ -4645,7 +4722,7 @@ range 0-0xFF (prefix with @samp{0x} to enter it in hexadecimal).
+ When enabled, this hides the selected partition by setting the @dfn{hidden}
+ bit in its partition type code; when disabled, unhides the selected
+ partition by clearing this bit.  This is useful only when booting DOS or
+-Wwindows and multiple primary FAT partitions exist in one disk.  See also
++Windows and multiple primary FAT partitions exist in one disk.  See also
+ @ref{DOS/Windows}.
+ @end table
+ @end deffn
+@@ -5153,32 +5230,22 @@ List available video modes. If resolution is given, show only matching modes.
+ Load a Xen hypervisor binary from @var{file}. The rest of the line is passed
+ verbatim as the @dfn{kernel command-line}. Any other binaries must be
+ reloaded after using this command.
++This command is only available on AArch64 systems.
+ @end deffn
+ 
+-@node xen_linux
+-@subsection xen_linux
++@node xen_module
++@subsection xen_module
+ 
+-@deffn Command xen_linux file [arguments]
+-Load a dom0 kernel image for xen hypervisor at the booting process of xen.
++@deffn Command xen_module [--nounzip] file [arguments]
++Load a module for xen hypervisor at the booting process of xen.
+ The rest of the line is passed verbatim as the module command line.
++Modules should be loaded in the following order:
++ - dom0 kernel image
++ - dom0 ramdisk if present
++ - XSM policy if present
++This command is only available on AArch64 systems.
+ @end deffn
+ 
+-@node xen_initrd
+-@subsection xen_initrd
+-
+-@deffn Command xen_initrd file
+-Load a initrd image for dom0 kernel at the booting process of xen.
+-@end deffn
+-
+-@node xen_xsm
+-@subsection xen_xsm
+-
+-@deffn Command xen_xsm file
+-Load a xen security module for xen hypervisor at the booting process of xen.
+-See @uref{http://wiki.xen.org/wiki/XSM} for more detail.
+-@end deffn
+-
+-
+ @node Networking commands
+ @section The list of networking commands
+ 
+@@ -5368,7 +5435,7 @@ NTFS, JFS, UDF, HFS+, exFAT, long filenames in FAT, Joliet part of
+ ISO9660 are treated as UTF-16 as per specification. AFS and BFS are read
+ as UTF-8, again according to specification. BtrFS, cpio, tar, squash4, minix,
+ minix2, minix3, ROMFS, ReiserFS, XFS, ext2, ext3, ext4, FAT (short names),
+-RockRidge part of ISO9660, nilfs2, UFS1, UFS2 and ZFS are assumed
++F2FS, RockRidge part of ISO9660, nilfs2, UFS1, UFS2 and ZFS are assumed
+ to be UTF-8. This might be false on systems configured with legacy charset
+ but as long as the charset used is superset of ASCII you should be able to
+ access ASCII-named files. And it's recommended to configure your system to use
+diff --git a/gentpl.py b/gentpl.py
+index f08bcc404f6a8bd8c3b13a6d5bb041ee32422776..da67965a41a40cde7c987b719fea39cd02ba10e5 100644
+--- a/gentpl.py
++++ b/gentpl.py
+@@ -31,7 +31,8 @@ GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
+                    "i386_xen", "x86_64_xen",
+                    "mips_loongson", "sparc64_ieee1275",
+                    "powerpc_ieee1275", "mips_arc", "ia64_efi",
+-                   "mips_qemu_mips", "arm_uboot", "arm_efi", "arm64_efi" ]
++                   "mips_qemu_mips", "arm_uboot", "arm_efi", "arm64_efi",
++                   "arm_coreboot"]
+ 
+ GROUPS = {}
+ 
+@@ -44,7 +45,7 @@ GROUPS["x86"]      = GROUPS["i386"] + GROUPS["x86_64"]
+ GROUPS["mips"]     = [ "mips_loongson", "mips_qemu_mips", "mips_arc" ]
+ GROUPS["sparc64"]  = [ "sparc64_ieee1275" ]
+ GROUPS["powerpc"]  = [ "powerpc_ieee1275" ]
+-GROUPS["arm"]      = [ "arm_uboot", "arm_efi" ]
++GROUPS["arm"]      = [ "arm_uboot", "arm_efi", "arm_coreboot" ]
+ GROUPS["arm64"]    = [ "arm64_efi" ]
+ 
+ # Groups based on firmware
+@@ -52,6 +53,7 @@ GROUPS["efi"]  = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi"
+ GROUPS["ieee1275"]   = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
+ GROUPS["uboot"] = [ "arm_uboot" ]
+ GROUPS["xen"]  = [ "i386_xen", "x86_64_xen" ]
++GROUPS["coreboot"]  = [ "i386_coreboot", "arm_coreboot" ]
+ 
+ # emu is a special case so many core functionality isn't needed on this platform
+ GROUPS["noemu"]   = GRUB_PLATFORMS[:]; GROUPS["noemu"].remove("emu")
+@@ -61,10 +63,10 @@ GROUPS["cmos"] = GROUPS["x86"][:] + ["mips_loongson", "mips_qemu_mips",
+                                      "sparc64_ieee1275", "powerpc_ieee1275"]
+ GROUPS["cmos"].remove("i386_efi"); GROUPS["cmos"].remove("x86_64_efi");
+ GROUPS["pci"]      = GROUPS["x86"] + ["mips_loongson"]
+-GROUPS["usb"]      = GROUPS["pci"]
++GROUPS["usb"]      = GROUPS["pci"] + ["arm_coreboot"]
+ 
+ # If gfxterm is main output console integrate it into kernel
+-GROUPS["videoinkernel"] = ["mips_loongson", "i386_coreboot" ]
++GROUPS["videoinkernel"] = ["mips_loongson", "i386_coreboot", "arm_coreboot" ]
+ GROUPS["videomodules"]   = GRUB_PLATFORMS[:];
+ for i in GROUPS["videoinkernel"]: GROUPS["videomodules"].remove(i)
+ 
+diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
+index 04e9395fd949460672c1113c3d49c90a5d4471ec..f4ff62b769ae99f1d9b2fadf51378966c93d835c 100644
+--- a/grub-core/Makefile.am
++++ b/grub-core/Makefile.am
+@@ -112,7 +112,7 @@ endif
+ 
+ if COND_i386_coreboot
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/tsc.h
+-KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i386/coreboot/lbio.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/coreboot/lbio.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video_fb.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/gfxterm.h
+@@ -239,8 +239,21 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h
+ endif
+ 
++if COND_arm_coreboot
++KERNEL_HEADER_FILES += $(top_builddir)/include/grub/keyboard_layouts.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video_fb.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/gfxterm.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/font.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/bufio.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdt.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/dma.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/coreboot/kernel.h
++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdtbus.h
++endif
++
+ if COND_arm_efi
+-KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/efi/loader.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
+ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h
+@@ -278,7 +291,7 @@ BUILT_SOURCES += symlist.h
+ 
+ symlist.c: symlist.h gensymlist.sh
+ 	$(TARGET_CPP) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS_KERNEL) $(CPPFLAGS) -DGRUB_SYMBOL_GENERATOR=1 symlist.h > symlist.p || (rm -f symlist.p; exit 1)
+-	cat symlist.p | /bin/sh $(srcdir)/gensymlist.sh $(top_builddir)/config.h $(KERNEL_HEADER_FILES) >$@ || (rm -f $@; exit 1)
++	cat symlist.p | $(SHELL) $(srcdir)/gensymlist.sh $(top_builddir)/config.h $(KERNEL_HEADER_FILES) >$@ || (rm -f $@; exit 1)
+ 	rm -f symlist.p
+ CLEANFILES += symlist.c
+ BUILT_SOURCES += symlist.c
+@@ -358,6 +371,16 @@ terminal.lst: $(MARKER_FILES)
+ platform_DATA += terminal.lst
+ CLEANFILES += terminal.lst
+ 
++fdt.lst: $(MARKER_FILES)
++	(for pp in $^; do \
++	  b=`basename $$pp .marker`; \
++	  sed -n \
++	    -e "/FDT_DRIVER_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/i\1: $$b/;p;}" \
++	    -e "/FDT_DRIVER_LIST_MARKER *( *\"/{s/.*( *\"\([^\"]*\)\".*/o\1: $$b/;p;}" $$pp; \
++	done) | sort -u > $@
++platform_DATA += fdt.lst
++CLEANFILES += fdt.lst
++
+ parttool.lst: $(MARKER_FILES)
+ 	(for pp in $^; do \
+ 	  b=`basename $$pp .marker`; \
+diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in
+index 03cc3b7f69ed3cfb69b744f8114895fd0e14fde7..1250589b3f5f88b52d7ea6de361427339fe7e578 100644
+--- a/grub-core/genmod.sh.in
++++ b/grub-core/genmod.sh.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ # Copyright (C) 2010 Free Software Foundation, Inc.
+@@ -58,6 +58,10 @@ if test x@TARGET_APPLE_LINKER@ != x1; then
+ 		-K grub_mod_init -K grub_mod_fini \
+ 		-K _grub_mod_init -K _grub_mod_fini \
+ 		-R .note.gnu.gold-version -R .note.GNU-stack \
++		-R .gnu.build.attributes \
++		-R .rel.gnu.build.attributes \
++		-R .rela.gnu.build.attributes \
++		-R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \
+ 		-R .note -R .comment -R .ARM.exidx $tmpfile || exit 1
+ 	fi
+ 	if ! test -z "${TARGET_OBJ2ELF}"; then
+diff --git a/grub-core/genmoddep.awk b/grub-core/genmoddep.awk
+index bd98d84cdd7427eef2f3651f455377d469955250..04c2863e5abfa4d950df2c41d579dea03a361927 100644
+--- a/grub-core/genmoddep.awk
++++ b/grub-core/genmoddep.awk
+@@ -18,6 +18,10 @@ BEGIN {
+ 
+ {
+   if ($1 == "defined") {
++    if ($3 !~ /^\.refptr\./ && $3 in symtab) {
++      printf "%s in %s is duplicated in %s\n", $3, $2, symtab[$3] >"/dev/stderr";
++      error++;
++    }
+     symtab[$3] = $2;
+     modtab[$2] = "" modtab[$2]
+   } else if ($1 == "undefined") {
+diff --git a/grub-core/gensyminfo.sh.in b/grub-core/gensyminfo.sh.in
+index 2e8716b425cb04d9379ef5e2c629283d0f346c90..9bc7675327a6d9229492548671dd004054282434 100644
+--- a/grub-core/gensyminfo.sh.in
++++ b/grub-core/gensyminfo.sh.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ # Copyright (C) 2010 Free Software Foundation, Inc.
+diff --git a/grub-core/modinfo.sh.in b/grub-core/modinfo.sh.in
+index faf0ad30edbe878270a185add45aa70e245d8b3a..f6cd657ce0f8307547fc5d011efa35622c318e63 100644
+--- a/grub-core/modinfo.sh.in
++++ b/grub-core/modinfo.sh.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ # User-controllable options
+ grub_modinfo_target_cpu=@target_cpu@
+diff --git a/grub-core/script/yylex.l b/grub-core/script/yylex.l
+index 95b2191705ac826833e0951fa323242a9f8859d1..7b44c37b76ffa87f24b6f04260b9519f0c8654c0 100644
+--- a/grub-core/script/yylex.l
++++ b/grub-core/script/yylex.l
+@@ -91,7 +91,7 @@ typedef size_t yy_size_t;
+ #define stdin  0
+ #define stdout 0
+ 
+-#define fprintf(...) 0
++#define fprintf(...) (void)0
+ #define exit(...) grub_fatal("fatal error in lexer")
+ #endif
+ 
+diff --git a/po/Makefile.in.in b/po/Makefile.in.in
+index 3619458e85f2bed3f92a76a9d919c26a30116dee..e68e9da843d927bfb6bbd519f4b3923c733abd7c 100644
+--- a/po/Makefile.in.in
++++ b/po/Makefile.in.in
+@@ -15,7 +15,7 @@ PACKAGE = @PACKAGE@
+ VERSION = @VERSION@
+ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+ 
+-SHELL = /bin/sh
++SHELL = @SHELL@
+ @SET_MAKE@
+ 
+ srcdir = @srcdir@
+diff --git a/po/exclude.pot b/po/exclude.pot
+index 0a9b215eaf1971bf2a2af8a36e9605043de38e36..816089c30cbd36939b2a72724b3d591a0ac8a290 100644
+GIT binary patch
+delta 49
+zcmaEUhNJl`#|G_WNh^i)qS7SY<ou#k{j_5JG^4a)y<{sxBh%><eHg`>?UJ|KB{OOs
+F1^~&~5lR36
+
+delta 27
+jcmZoZ%klgS#|G`>=`Ng%LX#(mur$XeZ;wr8R67g+m_Q0B
+
+diff --git a/tests/ahci_test.in b/tests/ahci_test.in
+index 1d01d1f59a0aac8911ff7ca3e62565f2dee5954d..7df56046201e4c2e4a55bdcdd403853cde902268 100644
+--- a/tests/ahci_test.in
++++ b/tests/ahci_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/btrfs_test.in b/tests/btrfs_test.in
+index c55d9477f78e01b6556bc0da9695f038523936f4..2b37ddd3324cc77f1edeb03feb369c22d03204a2 100644
+--- a/tests/btrfs_test.in
++++ b/tests/btrfs_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/cdboot_test.in b/tests/cdboot_test.in
+index 1cc901977c229dcf839bf58bede2b34f04252d57..75acdfedb7fe4a634d4122e44b3cd01778ed6f35 100644
+--- a/tests/cdboot_test.in
++++ b/tests/cdboot_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/core_compress_test.in b/tests/core_compress_test.in
+index 1003587ccca65616b0c7e3c1b90353ef7f459299..9d216ebcff60bfce04e3be4dbd1f8834800a6948 100644
+--- a/tests/core_compress_test.in
++++ b/tests/core_compress_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/cpio_test.in b/tests/cpio_test.in
+index 0b09db549f07868a524376f0eb25fd6a2cac9e40..5742cf17b9d8f587d00590d481f0a00aaf6cada8 100644
+--- a/tests/cpio_test.in
++++ b/tests/cpio_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/ehci_test.in b/tests/ehci_test.in
+index 7dd8d3e8fbd4a76b8efb88d69ecd8989546dc543..b197f8cdc922628ed35863dfa384eeef4cc4cc09 100644
+--- a/tests/ehci_test.in
++++ b/tests/ehci_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/example_scripted_test.in b/tests/example_scripted_test.in
+index 09633e89341e079a05fda7461d867e1541df4287..783b7f13853f39f9ec63b8da1da6e8a1b3a887a5 100644
+--- a/tests/example_scripted_test.in
++++ b/tests/example_scripted_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ set -e
+ 
+ true
+diff --git a/tests/exfat_test.in b/tests/exfat_test.in
+index fc1a0fe5ec0306434434f0b49b20c44a1736dca1..cd3cd4cb2f70bb99df7edbfa8b5697f4316548ac 100644
+--- a/tests/exfat_test.in
++++ b/tests/exfat_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/ext234_test.in b/tests/ext234_test.in
+index c986960a8bec696deb37a55cba00915219d77215..4f1eb527eb2ed41095266dba6d5013ead77d9be3 100644
+--- a/tests/ext234_test.in
++++ b/tests/ext234_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+@@ -30,3 +30,4 @@ fi
+ "@builddir@/grub-fs-tester" ext3
+ "@builddir@/grub-fs-tester" ext4
+ "@builddir@/grub-fs-tester" ext4_metabg
++"@builddir@/grub-fs-tester" ext4_encrypt
+diff --git a/tests/f2fs_test.in b/tests/f2fs_test.in
+new file mode 100644
+index 0000000000000000000000000000000000000000..1ea77c826d32bd01e33d13ea7ad6639eb1cb77b0
+--- /dev/null
++++ b/tests/f2fs_test.in
+@@ -0,0 +1,19 @@
++#!/bin/sh
++
++set -e
++
++if [ "x$EUID" = "x" ] ; then
++ EUID=`id -u`
++fi
++
++if [ "$EUID" != 0 ] ; then
++ exit 77
++fi
++
++if ! which mkfs.f2fs >/dev/null 2>&1; then
++ echo "mkfs.f2fs not installed; cannot test f2fs."
++ exit 77
++fi
++
++
++"@builddir@/grub-fs-tester" f2fs
+diff --git a/tests/fat_test.in b/tests/fat_test.in
+index 1d132b51703c43e269d5500ca1740fa1e6b9a42c..b6b4748ca694b59337441a2f3111863e01799884 100644
+--- a/tests/fat_test.in
++++ b/tests/fat_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/fddboot_test.in b/tests/fddboot_test.in
+index a59645b7f873872490ac2474a30420c2df7a5caf..2d7dfc8891f6d7fdf42f88dea1213428e23b6f2e 100644
+--- a/tests/fddboot_test.in
++++ b/tests/fddboot_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/file_filter_test.in b/tests/file_filter_test.in
+index 8909e4021fb1d507cd5bf3b63319824fdc005dd5..bfb6382274e48d409d6cf6f918fc252f993f717f 100644
+--- a/tests/file_filter_test.in
++++ b/tests/file_filter_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2014  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/gettext_strings_test.in b/tests/gettext_strings_test.in
+index 5c305e75b7e9583f6be8a23d389051cf1fe2c243..813999ebe6ea5ee35796669e58baa57d0a2ace95 100644
+--- a/tests/gettext_strings_test.in
++++ b/tests/gettext_strings_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ cd '@srcdir@'
+ 
+diff --git a/tests/grub_cmd_date.in b/tests/grub_cmd_date.in
+index a459353e8a51c22fb966a842af532cff904de2a3..f7c9ca00432fa3307a2fb53ac88ca11115d7f73f 100644
+--- a/tests/grub_cmd_date.in
++++ b/tests/grub_cmd_date.in
+@@ -1,4 +1,4 @@
+-#! /bin/bash
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ . "@builddir@/grub-core/modinfo.sh"
+@@ -9,7 +9,7 @@ if [ "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" = sparc64-ieee1275 ];
+ fi
+ 
+ pdt="$(date -u +%s)"
+-dt=`echo date | @builddir@/grub-shell`
++dt=`echo date | @builddir@/grub-shell | sed 's, [A-Z][a-z]*$,,'`
+ dtg="$(date -u -d "$dt" +%s)"
+ ndt="$(date -u +%s)"
+ 
+diff --git a/tests/grub_cmd_regexp.in b/tests/grub_cmd_regexp.in
+index e7e6257011525ee42ca6945485208155fe717d24..6520bd6d79acc0c8f5bfddc443912d74e826a0c8 100644
+--- a/tests/grub_cmd_regexp.in
++++ b/tests/grub_cmd_regexp.in
+@@ -1,4 +1,4 @@
+-#! /bin/bash
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ # Run GRUB script in a Qemu instance
+diff --git a/tests/grub_cmd_set_date.in b/tests/grub_cmd_set_date.in
+index c594ae3fc14ebf7a6be86b90f4d048747383a69f..aac120a6c52731649678549d34372af14fef52d9 100644
+--- a/tests/grub_cmd_set_date.in
++++ b/tests/grub_cmd_set_date.in
+@@ -1,4 +1,4 @@
+-#! /bin/bash
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ . "@builddir@/grub-core/modinfo.sh"
+diff --git a/tests/grub_cmd_sleep.in b/tests/grub_cmd_sleep.in
+index eb362aa2439d713bf4246e2c56932bbc6200d710..8797f6632845f5a76ac22b813c223897ceddd672 100644
+--- a/tests/grub_cmd_sleep.in
++++ b/tests/grub_cmd_sleep.in
+@@ -1,4 +1,4 @@
+-#! /bin/bash
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ . "@builddir@/grub-core/modinfo.sh"
+@@ -11,8 +11,8 @@ fi
+ # Compare RTC with interval timer.
+ # Not 100% proper but should check that timer is running ok
+ dt=`echo 'date; sleep 10; date' | @builddir@/grub-shell`
+-dt1="$(date -u -d "$(echo "$dt" | head -n 1)" +%s)"
+-dt2="$(date -u -d "$(echo "$dt" | tail -n 1)" +%s)"
++dt1="$(date -u -d "$(echo "$dt" | head -n 1 | sed 's, [A-Z][a-z]*$,,')" +%s)"
++dt2="$(date -u -d "$(echo "$dt" | tail -n 1 | sed 's, [A-Z][a-z]*$,,')" +%s)"
+ 
+ # Ignore QEMU bug
+ if [ "${grub_modinfo_target_cpu}" = arm ] && [ $((dt2 - dt1)) -ge 15 ] && [ $((dt2 - dt1)) -le 17 ]; then
+diff --git a/tests/grub_cmd_test.in b/tests/grub_cmd_test.in
+index 6269891c9eeddb70f42da372e5636089e666818d..3399eb2929408570e9dad99db8dbc7215b41aea4 100644
+--- a/tests/grub_cmd_test.in
++++ b/tests/grub_cmd_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/bash
++#! @BUILD_SHEBANG@
+ 
+ # create a randome file
+ empty="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1
+diff --git a/tests/grub_cmd_tr.in b/tests/grub_cmd_tr.in
+index 3fb15e35c8ac3ac218abf580f8ff5cdcaa2925ca..bed469c03ddc9a762112896d75af399678af711e 100644
+--- a/tests/grub_cmd_tr.in
++++ b/tests/grub_cmd_tr.in
+@@ -1,4 +1,4 @@
+-#! /bin/bash -e
++#! @BUILD_SHEBANG@ -e
+ 
+ # Run GRUB script in a Qemu instance
+ # Copyright (C) 2010  Free Software Foundation, Inc.
+diff --git a/tests/grub_func_test.in b/tests/grub_func_test.in
+index c8cc263763377fd23d6c7f1eca49c1edafe530a7..c67f9e422534a402614eb280fe67d165fd0bb906 100644
+--- a/tests/grub_func_test.in
++++ b/tests/grub_func_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/bash
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ . "@builddir@/grub-core/modinfo.sh"
+diff --git a/tests/grub_script_blanklines.in b/tests/grub_script_blanklines.in
+index 89ed763d3f4e0bb2a3ac3a61de9e0ec49b2eaccf..bd8735491be3b947c72fffbf5767d7ab6bcf91ae 100644
+--- a/tests/grub_script_blanklines.in
++++ b/tests/grub_script_blanklines.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ @builddir@/grub-script-check <<EOF
+diff --git a/tests/grub_script_blockarg.in b/tests/grub_script_blockarg.in
+index 2765b61acbb8c1081f620960e0350c5489dc2875..6ea9b8c3d87cb2e9fc5693da93cb9885cfdd20e2 100644
+--- a/tests/grub_script_blockarg.in
++++ b/tests/grub_script_blockarg.in
+@@ -1,4 +1,4 @@
+-#! /bin/bash
++#! @BUILD_SHEBANG@
+ 
+ # Run GRUB script in a Qemu instance
+ # Copyright (C) 2010  Free Software Foundation, Inc.
+diff --git a/tests/grub_script_dollar.in b/tests/grub_script_dollar.in
+index 2e076427afbc86e05260b58e9f22f7e3fe48ce4e..392fe2e7ab0f773ef3ba04366386d799cda3f83c 100644
+--- a/tests/grub_script_dollar.in
++++ b/tests/grub_script_dollar.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ @builddir@/grub-script-check << EOF
+diff --git a/tests/grub_script_expansion.in b/tests/grub_script_expansion.in
+index e46401c4c9f1b6bea3c7bed452882d373e51bd61..9d0dcdd29100904bfba93ccd429340d4a5afbcf3 100644
+--- a/tests/grub_script_expansion.in
++++ b/tests/grub_script_expansion.in
+@@ -1,4 +1,4 @@
+-#! /bin/bash
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ # Run GRUB script in a Qemu instance
+diff --git a/tests/grub_script_final_semicolon.in b/tests/grub_script_final_semicolon.in
+index 3ac26540bbd7cf4614dc199534417b139c2bb7f0..f17a9bf95e6db3d710d683fdbdc749fdab7e3a0a 100644
+--- a/tests/grub_script_final_semicolon.in
++++ b/tests/grub_script_final_semicolon.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ @builddir@/grub-script-check <<EOF
+diff --git a/tests/grub_script_no_commands.in b/tests/grub_script_no_commands.in
+index c31d267e5fdf090fda15878cbe0b794b2f4e8b9f..996bb181043dcbddd95ab98c8cbcc57b0fe91f4d 100644
+--- a/tests/grub_script_no_commands.in
++++ b/tests/grub_script_no_commands.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ # grub-script-check refuses to pass a file with no commands; this usually
+diff --git a/tests/gzcompress_test.in b/tests/gzcompress_test.in
+index 11b6bb208302e03e0c5198f678bc7cc119862898..42c8fe7c4e8fc83022f656c0be7963aab3166a75 100644
+--- a/tests/gzcompress_test.in
++++ b/tests/gzcompress_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/hddboot_test.in b/tests/hddboot_test.in
+index c229716a642942d1eba6cc9d00867c0292c8e7a4..6d70847a5dec394fec13e6b21a9dd0d890cf2a4d 100644
+--- a/tests/hddboot_test.in
++++ b/tests/hddboot_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/help_test.in b/tests/help_test.in
+index e780924ef7b02245b6009956bd2baab3623aa5a8..b08cf201382e043e6b2fc07fd6f7a410aa051dca 100644
+--- a/tests/help_test.in
++++ b/tests/help_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/bash
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ . "@builddir@/grub-core/modinfo.sh"
+diff --git a/tests/hfs_test.in b/tests/hfs_test.in
+index e3e88f190677d24699def63ba666df3b2748b045..d7ec56beffa7909c28636a4af5142a2c8ee334de 100644
+--- a/tests/hfs_test.in
++++ b/tests/hfs_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/hfsplus_test.in b/tests/hfsplus_test.in
+index f947c4a447fe1a310761a3606257c793b9e2358a..85f1c37dce6a0c5a217d75b051b1ab426d06a2be 100644
+--- a/tests/hfsplus_test.in
++++ b/tests/hfsplus_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/iso9660_test.in b/tests/iso9660_test.in
+index fdcc9e124208dd3b8d5a997c8522ffb52bc3ced1..571b938d7a08b14ca21dd6497bd0092f3d6d40cb 100644
+--- a/tests/iso9660_test.in
++++ b/tests/iso9660_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/jfs_test.in b/tests/jfs_test.in
+index c2e5eceddcd2cb433dcdc120fe44dc9d8bd2b45e..6cf7576b35ed8ce4b86036ed67df02b698fbc062 100644
+--- a/tests/jfs_test.in
++++ b/tests/jfs_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/lzocompress_test.in b/tests/lzocompress_test.in
+index 41984c25419b78c727b3b8957bde3ac611cbd76e..4e5f7e078d5116f0794b035cabe1002420fb1d2c 100644
+--- a/tests/lzocompress_test.in
++++ b/tests/lzocompress_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/minixfs_test.in b/tests/minixfs_test.in
+index 1784b1261f7592a78820dbd9f1900f89df133f9b..3b16a4de09314b95eb45ee21fe9441789b429e51 100644
+--- a/tests/minixfs_test.in
++++ b/tests/minixfs_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/netboot_test.in b/tests/netboot_test.in
+index c757023d989e89a9400dbbc79e674edd5bea9fd6..9f71e3d88542ae9b87e9218c1c1197aeef29989a 100644
+--- a/tests/netboot_test.in
++++ b/tests/netboot_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/nilfs2_test.in b/tests/nilfs2_test.in
+index 780b60ec1ac980ea1e40af3a319c83a86a6415e6..ad44d5b33c8af3ab9f62b7c8ca866c025a51d24a 100644
+--- a/tests/nilfs2_test.in
++++ b/tests/nilfs2_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/ntfs_test.in b/tests/ntfs_test.in
+index e25c6384a9cd6e086961116c83db4a31353d6e7c..9eb7b01f66e923009939abf7b839276a15fa67a3 100644
+--- a/tests/ntfs_test.in
++++ b/tests/ntfs_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/ohci_test.in b/tests/ohci_test.in
+index 7fede6f262c1fdac41609dc660017e279a06f3a1..8693f8c472879fcbd43f52d4e61973d19b52ddc1 100644
+--- a/tests/ohci_test.in
++++ b/tests/ohci_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/partmap_test.in b/tests/partmap_test.in
+index f8dc456fb8c6c25d034c53821066ad618664afa0..6ef518b0adc1e001bfc64c853ffb5c490d02330d 100644
+--- a/tests/partmap_test.in
++++ b/tests/partmap_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ # Copyright (C) 2010  Free Software Foundation, Inc.
+diff --git a/tests/pata_test.in b/tests/pata_test.in
+index c1d0f63ea21b5cdc6d818a1aabbd691a2e7a2fa5..4b18fdef3d3594ccb105dd0d265e8517890d9853 100644
+--- a/tests/pata_test.in
++++ b/tests/pata_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/pseries_test.in b/tests/pseries_test.in
+index 226494593d1514112f33eee695c3c418421198c1..655eb4f3a63a210ffd1271ac16da47bcbad70434 100644
+--- a/tests/pseries_test.in
++++ b/tests/pseries_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/reiserfs_test.in b/tests/reiserfs_test.in
+index 678efe7b36662dfb1325b969e7451ccb5024c3dc..b5fed7635673467d5c46409625463e50498b9807 100644
+--- a/tests/reiserfs_test.in
++++ b/tests/reiserfs_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/romfs_test.in b/tests/romfs_test.in
+index 83e09315acf62eb00c54faa95e785b114b08017a..98bb50c324b6e8cd1163c772a78271b64768ae57 100644
+--- a/tests/romfs_test.in
++++ b/tests/romfs_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/squashfs_test.in b/tests/squashfs_test.in
+index ec34e0108c3bfb663e1a8959fb4cd3bb736bff76..2f044f95d99b2ee7a6ddf1d2b2e54be3944f235f 100644
+--- a/tests/squashfs_test.in
++++ b/tests/squashfs_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/syslinux_test.in b/tests/syslinux_test.in
+index fc4edd8ef6b91f7d0759c85c7a657402248fd120..4ea86390e0a320ed9afdf77ecc42e4d328e17e28 100644
+--- a/tests/syslinux_test.in
++++ b/tests/syslinux_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/tar_test.in b/tests/tar_test.in
+index 46ba3bce295b256631eaa8ab12c581f2bdafb7f6..6e2f2de8b7ff78ca84401213dadd011a0b65f281 100644
+--- a/tests/tar_test.in
++++ b/tests/tar_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/test_sha512sum.in b/tests/test_sha512sum.in
+index d5ef7f9ea62d1c9749c6a134580dace95fa7624a..027092a8b17f398776e605251fcd8d48b7b4965e 100644
+--- a/tests/test_sha512sum.in
++++ b/tests/test_sha512sum.in
+@@ -1,4 +1,4 @@
+-#! /bin/bash
++#! @BUILD_SHEBANG@
+ 
+ # create a randome file
+ file="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1
+diff --git a/tests/udf_test.in b/tests/udf_test.in
+index fe244e2bdfc8b7d17ec25ac80d12724dcdbb1cba..fb92f0173cc74151d7fdc722522d654efa2233b5 100644
+--- a/tests/udf_test.in
++++ b/tests/udf_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/uhci_test.in b/tests/uhci_test.in
+index 89e2c18051ac00f414edd0e80bdcfd911c8f9842..4af72fd8fea5ab2b3e2059d2a89f0b0dfaa74c9a 100644
+--- a/tests/uhci_test.in
++++ b/tests/uhci_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/util/grub-fs-tester.in b/tests/util/grub-fs-tester.in
+index 2337771a1b9ce287c3e5e24e49c7c27baee7edb8..ef65fbc93414daf310b842f0d9a360ca10a0e5a3 100644
+--- a/tests/util/grub-fs-tester.in
++++ b/tests/util/grub-fs-tester.in
+@@ -1,4 +1,4 @@
+-#!/bin/bash
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+@@ -13,8 +13,29 @@ run_it () {
+     LC_ALL=C "$GRUBFSTEST" "$@"
+ }
+ 
++range() {
++    range_counter="$1"
++    while test "$range_counter" -le "$2"; do
++	echo "$range_counter"
++	range_counter="$((range_counter + $3))"
++    done
++}
++
++powrange() {
++    range_counter="$1"
++    while test "$range_counter" -le "$2"; do
++	echo "$range_counter"
++	range_counter="$((range_counter * 2))"
++    done
++}
++
+ run_grubfstest () {
+-    run_it -c $NEED_IMAGES_N "${NEED_IMAGES[@]}"  "$@"
++    need_images=
++    for i in $(range 0 $((NEED_IMAGES_N-1)) 1); do
++	need_images="$need_images $FSIMAGEP${i}.img";
++    done
++
++    run_it -c $NEED_IMAGES_N $need_images  "$@"
+ }
+ 
+ # OS LIMITATION: GNU/Linux has no AFS support, so we use a premade image and a reference tar file. I.a. no multiblocksize test
+@@ -51,7 +72,7 @@ case x"$fs" in
+ 	# OS limitation: zfs-fuse always uses ashift=9 with loop devices
+ 	MAXLOGSECSIZE=9;;
+ esac
+-for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE + 1)); do
++for LOGSECSIZE in $(range "$MINLOGSECSIZE" "$MAXLOGSECSIZE" 1); do
+     SECSIZE="$((1 << LOGSECSIZE))"
+     MINBLKSIZE=512
+     MAXBLKSIZE=512
+@@ -135,6 +156,12 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		# Could go further but what's the point?
+ 	    MAXBLKSIZE=$((65536*1024))
+ 	    ;;
++       xext4_encrypt)
++           # OS LIMITATION: Linux currently only allows the 'encrypt' feature
++           # in combination with block_size = PAGE_SIZE (4096 bytes on x86).
++           MINBLKSIZE=$(getconf PAGE_SIZE)
++           MAXBLKSIZE=$MINBLKSIZE
++           ;;
+ 	xext*)
+ 	    MINBLKSIZE=1024
+ 	    if [ $MINBLKSIZE -lt $SECSIZE ]; then
+@@ -145,7 +172,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	xsquash*)
+ 	    MINBLKSIZE=4096
+ 	    MAXBLKSIZE=1048576;;
+-	xxfs)
++	xxfs|xf2fs)
+ 	    MINBLKSIZE=$SECSIZE
+ 		# OS Limitation: GNU/Linux doesn't accept > 4096
+ 	    MAXBLKSIZE=4096;;
+@@ -169,7 +196,12 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    MINBLKSIZE=1024
+ 	    MAXBLKSIZE=4096;;
+     esac
+-    for ((BLKSIZE=MINBLKSIZE;BLKSIZE<=MAXBLKSIZE;BLKSIZE=BLKSTEP?BLKSIZE+BLKSTEP:2*BLKSIZE)); do
++    if test "$BLKSTEP" -eq 0; then
++	blksizes="$(powrange "$MINBLKSIZE" "$MAXBLKSIZE")"
++    else
++	blksizes="$(range "$MINBLKSIZE" "$MAXBLKSIZE" "$BLKSTEP")"
++    fi
++    for BLKSIZE in $blksizes; do
+ 	MAXDEVICES=1
+ 	MINDEVICES=1
+ 	export fs
+@@ -199,13 +231,11 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		MAXDEVICES=7;;
+ 	esac
+ 
+-	for ((NDEVICES=MINDEVICES; NDEVICES <= MAXDEVICES; NDEVICES++)); do
++	for NDEVICES in $(range "$MINDEVICES" "$MAXDEVICES" 1); do
+ 	    export NDEVICES
+-	    unset FSIMAGES
+-	    for ((i=0; i < NDEVICES; i++)); do
+-		FSIMAGES[i]="${tempdir}/${fs}_${SECSIZE}_${BLKSIZE}_${NDEVICES}_$i.img"
+-	    done
+-	    export FSIMAGES
++	    unset FSIMAGEP
++	    FSIMAGEP="${tempdir}/${fs}_${SECSIZE}_${BLKSIZE}_${NDEVICES}_"
++	    export FSIMAGEP
+ 	    unset NEED_IMAGES;
+ 
+ 	    case x$fs in
+@@ -226,11 +256,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		*)
+ 		    NEED_IMAGES_N=$NDEVICES;;
+ 	    esac
+-	    for ((i=0;i < NEED_IMAGES_N; i++)); do
+-		NEED_IMAGES[i]="${FSIMAGES[i]}";
+-	    done
+ 	    export NEED_IMAGES_N
+-	    export NEED_IMAGES
+ 
+ 	    MNTPOINTRO="${tempdir}/${fs}_ro"
+ 	    MNTPOINTRW="${tempdir}/${fs}_rw"
+@@ -238,20 +264,25 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    MOUNTFS="$fs"
+ 	    MASTER="${tempdir}/master"
+ 	    FSLABEL="grub_;/testé莭莽茝😁киритi urewfceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoifoirefoireoifoijfoirereoireoivoioirevoinvoinreoinvnoieoinreoinveoinveoinreoinvoineoinoinoineoinernoiveoinvreoiioewdioewoirvnoireoivfoirewfewoifoijewoijfoijewfoijfewoijoijoijoijoijoijoijfewceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoifoirefoireoifoijfoirereoireoivoioirevoinvoinreoinvnoieoinreoinveoinveoinreoinvoineoinoinoineoinernoiveoinvreoiioewdioewoirvnoireoivfoirewfewoifoijewoijfoijewfoijfewoijoijoijoijoijoijoijfewrewfceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoifoirefoireoifoijfoirereoireoivoioirevoinvoinreoinvnoieoinreoinveoinveoinreoinvoineoinoinoineoinernoiveoinvreoiioewdioewoirvnoireoivfoirewfewoifoijewoijfoijewfoijfewoijoijoijoijoijoijoijfewceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoifoirefoireoifoijfoirereoireoivoioirevoinvoinreoinvnoieoinreoinveoinveoinreoinvoineoinoinoineoinernoiveoinvreoiioewdioewoirvnoireoivfoirewfewoifoijewoijfoijewfoijfewoijoijoijoijoijoijoijfew"
+-	    CFILESN=1
+-	    if test -f /usr/share/dict/american-english; then
+-		CFILESSRC[0]="/usr/share/dict/american-english"
+-	    else
+-		CFILESSRC[0]="/usr/share/dict/linux.words"
++	    CFILESRC=
++	    for cand in /usr/share/dict/american-english /usr/share/dict/linux.words /data/data/com.termux/files/usr/share/hunspell/en_US.dic; do
++		if test -f "$cand" ; then
++		    CFILESRC="$cand"
++		    break
++		fi
++	    done
++	    if test "$CFILESRC" = "" ; then
++		echo "Couldn't find compressible file" >&2
++		exit 1
+ 	    fi
+ 	    case x"$fs" in
+ 		    # FS LIMITATION: 8.3 names
+ 		xmsdos*)
+-		    CFILES[0]="american.eng";;
++		    CFILE="american.eng";;
+ 		xiso9660)
+-		    CFILES[0]="american_english";;
++		    CFILE="american_english";;
+ 		*)
+-		    CFILES[0]="american-english";;
++		    CFILE="american-english";;
+ 	    esac
+         # OS LIMITATION: Limited by NAME_MAX (usually 255) in GNU/Linux
+ 	    LONGNAME="qwertzuiopasdfghjklyxcvbnm1234567890qwertzuiopasdfghjklyxcvbnm1234567890oiewqfiewioqoiqoiurqruewqoiuwoieoiiuewqroreqiufieiuwrnureweriuvceoiroiewqoiricdsalkcndsakfirefoiwqeoircorejwoijfreoijojoiewjfwnfcoirenfoirefnreoifenoiwfnoi"
+@@ -268,6 +299,10 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		x"btrfs"*)
+ 		    FSLABEL="grub_;/testé莭莽😁киритi urewfceniuewruevrewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoi";;
+ 
++	    # FS LIMITATION: f2fs label is at most 512 UTF-16 chars
++		x"f2fs")
++		    FSLABEL="grub_;/testé䏌䐓䏕киритiurewfceniuewruewnuuireurevueurnievrewfnerfcnevirivinrewvnirewnivrewiuvcrewvnuewvrrrewniuerwreiuviurewiuviurewnuvewnvrenurnunuvrevuurerejiremvreijnvvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoirvcreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoircreivire nverivnreivrevnureiorfnfrvoeoiroireoireoifrefoieroifoireoifoiq";;
++
+ 	    # FS LIMITATION: exfat is at most 15 UTF-16 chars
+ 		x"exfat")
+ 		    FSLABEL="géт ;/莭莽😁кир";;
+@@ -388,8 +423,8 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		    ;;
+ 		x"vfat16" | xmsdos16)
+ 		    BIGBLOCKCNT=$((25000 * BLKSIZE))
+-		    if [ $BIGBLOCKCNT -gt $((16#ffffffff)) ]; then
+-			BIGBLOCKCNT=$((16#ffffffff))
++		    if [ $BIGBLOCKCNT -gt 4294967295 ]; then
++			BIGBLOCKCNT=4294967295
+ 		    fi
+ 		    ;;
+ 		x"minix")
+@@ -410,7 +445,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		    BIGBLOCKCNT=$((4000 * 1048576));;
+ 		    # FS LIMITATION: These FS have uint32 as file size field
+ 		x"vfat"* | xmsdos* | x"cpio_crc" | x"cpio_newc" | x"cpio_bin" | x"cpio_hpbin" | xsfs*)
+-		    BIGBLOCKCNT=$((16#ffffffff));;
++		    BIGBLOCKCNT=4294967295;;
+ 		    # FS LIMITATION: These FS have int32 as file size field
+ 		    # FIXME: not so sure about AFFS
+ 		    # OS LIMITATION: minix2/minix3 could be formatted in a way to permit more.
+@@ -477,7 +512,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    # FIXME: Not sure about BtrFS, NTFS, JFS, AFS, UDF and SFS. Check it.
+ 	# FS LIMITATION: as far as I know those FS don't store their last modification date.
+ 		x"jfs_caseins" | x"jfs" | x"xfs" | x"xfs_crc" | x"btrfs"* | x"reiserfs_old" | x"reiserfs" \
+-		    | x"bfs" | x"afs" \
++		    | x"bfs" | x"afs" | x"f2fs" \
+ 		    | x"tarfs" | x"cpio_"* | x"minix" | x"minix2" \
+ 		    | x"minix3" | x"ntfs"* | x"udf" | x"sfs"*)
+ 		    NOFSTIME=y;;
+@@ -543,18 +578,18 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 
+ 	    PDIR=""
+ 		# OS LIMITATION: Limited by PATH_MAX (usually 1024)
+-	    for ((i=0;i<PDIRCOMPNUM;i++)); do
++	    for i in $(range 0 $((PDIRCOMPNUM-1)) 1); do
+ 		PDIR="$PDIR/$i";
+-		if [ $((i%3)) == 0 ]; then
++		if test $((i%3)) = 0; then
+ 		    PDIR="$PDIR/"
+ 		fi
+ 	    done
+ 
+ 	    PDIR2=""
+ 		# OS LIMITATION: Limited by PATH_MAX (usually 1024)
+-	    for ((i=0;i<PDIR2COMPNUM;i++)); do
++	    for i in $(range 0 $((PDIR2COMPNUM-1)) 1); do
+ 		PDIR2="${PDIR2}/$i";
+-		if [ $((i%3)) == 0 ]; then
++		if test $((i%3)) = 0; then
+ 		    PDIR2="${PDIR2}/"
+ 		fi
+ 	    done
+@@ -563,7 +598,9 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 
+ 	    unset LODEVICES
+ 	    GENERATED=n
+-
++	    LODEVICES=
++	    MOUNTDEVICE=
++	    
+ 	    case x"$fs" in
+ 		x"tarfs" | x"cpio_"*| x"ziso9660" | x"romfs" | x"squash4_"*\
+                     | x"iso9660" | xjoliet | xrockridge | xrockridge_joliet \
+@@ -577,62 +614,64 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		*)
+ 		    mkdir -p "$MNTPOINTRW"
+ 		    mkdir -p "$MNTPOINTRO"
+-		    for ((i=0; i < NDEVICES; i++)); do
+-			dd if=/dev/zero of="${FSIMAGES[i]}" count=1 bs=1 seek=$((DISKSIZE-1)) &> /dev/null
+-			LODEVICES[i]=`losetup -f`
+-			losetup "${LODEVICES[i]}" "${FSIMAGES[i]}"
++		    for i in $(range 0 $((NDEVICES-1)) 1); do
++			dd if=/dev/zero of="$FSIMAGEP${i}.img" count=1 bs=1 seek=$((DISKSIZE-1)) &> /dev/null
++			LODEVICE=$(losetup --find --show "$FSIMAGEP${i}.img")
++			LODEVICES="$LODEVICES $LODEVICE"
++			if test "$i" = 0; then
++			    MOUNTDEVICE="$LODEVICE"
++			fi
+ 		    done ;;
+ 	    esac
+ 
+-	    MOUNTDEVICE="${LODEVICES[0]}"
+ 	    case x"$fs" in
+ 		x"afs")
+ 		    ;;
+ 		x"btrfs")
+-		    "mkfs.btrfs" -s $SECSIZE -L "$FSLABEL" "${LODEVICES[0]}" ;;
++		    "mkfs.btrfs" -s $SECSIZE -L "$FSLABEL" "${MOUNTDEVICE}" ;;
+ 		x"btrfs_zlib" | x"btrfs_lzo")
+-		    "mkfs.btrfs" -s $SECSIZE -L "$FSLABEL" "${LODEVICES[0]}"
++		    "mkfs.btrfs" -s $SECSIZE -L "$FSLABEL" "${MOUNTDEVICE}"
+ 		    MOUNTOPTS="compress=${fs/btrfs_/},"
+ 		    MOUNTFS="btrfs"
+ 		    ;;
+ 		x"btrfs_raid0")
+-		    "mkfs.btrfs" -s $SECSIZE -d raid0 -m raid0 -L "$FSLABEL" "${LODEVICES[@]}"
++		    "mkfs.btrfs" -s $SECSIZE -d raid0 -m raid0 -L "$FSLABEL" $LODEVICES
+ 		    MOUNTFS="btrfs"
+ 		    ;;
+ 		x"btrfs_raid1")
+-		    "mkfs.btrfs" -s $SECSIZE -d raid1 -m raid1 -L "$FSLABEL" "${LODEVICES[@]}"
++		    "mkfs.btrfs" -s $SECSIZE -d raid1 -m raid1 -L "$FSLABEL" $LODEVICES
+ 		    MOUNTFS="btrfs"
+ 		    ;;
+ 		x"btrfs_raid10")
+-		    "mkfs.btrfs" -s $SECSIZE -d raid10 -m raid10 -L "$FSLABEL" "${LODEVICES[@]}"
++		    "mkfs.btrfs" -s $SECSIZE -d raid10 -m raid10 -L "$FSLABEL" $LODEVICES
+ 		    MOUNTFS="btrfs"
+ 		    ;;
+ 		x"btrfs_single")
+-		    "mkfs.btrfs" -s $SECSIZE -d single -L "$FSLABEL" "${LODEVICES[@]}"
++		    "mkfs.btrfs" -s $SECSIZE -d single -L "$FSLABEL" $LODEVICES
+ 		    MOUNTFS="btrfs"
+ 		    ;;
+ 		x"exfat")
+-		    "mkfs.$fs" -s $((BLKSIZE/512)) -n "$FSLABEL" "${LODEVICES[0]}"
++		    "mkfs.$fs" -s $((BLKSIZE/512)) -n "$FSLABEL" "${MOUNTDEVICE}"
+ 		    MOUNTOPTS="iocharset=utf8,"
+ 		    MOUNTFS="exfat-fuse";;
+ 		x"minix")
+-		    "mkfs.minix" "${LODEVICES[0]}"
++		    "mkfs.minix" "${MOUNTDEVICE}"
+ 		    ;;
+ 	# mkfs.hfs and mkfs.hfsplus don't fill UUID.
+ 		x"hfsplus")
+-		    "mkfs.hfsplus" -b $BLKSIZE -v "$FSLABEL" "${LODEVICES[0]}"
+-		    dd if=/dev/urandom of="${LODEVICES[0]}" bs=1 seek=$((16#468)) conv=notrunc count=8 ;;
++		    "mkfs.hfsplus" -b $BLKSIZE -v "$FSLABEL" "${MOUNTDEVICE}"
++		    dd if=/dev/urandom of="${MOUNTDEVICE}" bs=1 seek=$((16#468)) conv=notrunc count=8 ;;
+ 		x"hfsplus_wrap")
+-		    "mkfs.hfsplus" -w -b $BLKSIZE -v "$FSLABEL" "${LODEVICES[0]}"
+-		    dd if=/dev/urandom of="${LODEVICES[0]}" bs=1 seek=$((16#468)) conv=notrunc count=8
++		    "mkfs.hfsplus" -w -b $BLKSIZE -v "$FSLABEL" "${MOUNTDEVICE}"
++		    dd if=/dev/urandom of="${MOUNTDEVICE}" bs=1 seek=$((16#468)) conv=notrunc count=8
+ 		    MOUNTFS="hfsplus";;
+ 		x"hfsplus_casesens")
+-		    "mkfs.hfsplus" -s -b $BLKSIZE -v "$FSLABEL" "${LODEVICES[0]}"
+-		    dd if=/dev/urandom of="${LODEVICES[0]}" bs=1 seek=$((16#468)) conv=notrunc count=8
++		    "mkfs.hfsplus" -s -b $BLKSIZE -v "$FSLABEL" "${MOUNTDEVICE}"
++		    dd if=/dev/urandom of="${MOUNTDEVICE}" bs=1 seek=$((16#468)) conv=notrunc count=8
+ 		    MOUNTFS="hfsplus";;
+ 		x"hfs")
+-		    "mkfs.hfs" -b $BLKSIZE -v "`echo $FSLABEL |recode utf8..macroman`" -h "${LODEVICES[0]}"
+-		    dd if=/dev/urandom of="${LODEVICES[0]}" bs=1 seek=$((16#474)) conv=notrunc count=8
++		    "mkfs.hfs" -b $BLKSIZE -v "`echo $FSLABEL |recode utf8..macroman`" -h "${MOUNTDEVICE}"
++		    dd if=/dev/urandom of="${MOUNTDEVICE}" bs=1 seek=$((16#474)) conv=notrunc count=8
+ 		    MOUNTOPTS="iocharset=utf8,codepage=macroman,"
+ 		    ;;
+ 		x"vfat"*|xmsdos*)
+@@ -643,98 +682,98 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		    else
+ 			A=
+ 		    fi
+-		    "mkfs.vfat" -a $A -S $SECSIZE -s $((BLKSIZE/SECSIZE)) -F "${BITS:0:2}" -n "$FSLABEL" "${FSIMAGES[0]}"
++		    "mkfs.vfat" -a $A -S $SECSIZE -s $((BLKSIZE/SECSIZE)) -F "${BITS:0:2}" -n "$FSLABEL" "${MOUNTDEVICE}"
+ 		    MOUNTOPTS="iocharset=utf8,codepage=437,"
+ 		    MOUNTFS="$(echo "$fs"|sed 's,[0-9]*a\?$,,')";;
+ 		x"minix2")
+-		    "mkfs.minix" -v "${LODEVICES[0]}"
++		    "mkfs.minix" -v "${MOUNTDEVICE}"
+ 		    MOUNTFS="minix";;
+ 		x"minix3")
+-		    "mkfs.minix" -B $BLKSIZE -3 "${LODEVICES[0]}"
++		    "mkfs.minix" -B $BLKSIZE -3 "${MOUNTDEVICE}"
+ 		    MOUNTFS="minix";;
+ 		x"ntfs"*)
+-		    "mkfs.ntfs" -s "$SECSIZE" -c "$BLKSIZE" -L "$FSLABEL" -Q -q "${LODEVICES[0]}"
++		    "mkfs.ntfs" -s "$SECSIZE" -c "$BLKSIZE" -L "$FSLABEL" -Q -q "${MOUNTDEVICE}"
+ 		    MOUNTOPTS="iocharset=utf8,compression,"
+ 		    MOUNTFS="ntfs-3g";;
+ 		x"udf")
+-		    "mkudffs" --utf8 -b $BLKSIZE --lvid="$FSLABEL" "${LODEVICES[0]}"
++		    "mkudffs" --utf8 -b $BLKSIZE --lvid="$FSLABEL" "${MOUNTDEVICE}"
+ 		    MOUNTOPTS="iocharset=utf8,bs=$BLKSIZE,";;
+ 		x"ufs2")
+-		    "mkfs.ufs" -b $BLKSIZE -L "$FSLABEL" -O 2 "${LODEVICES[0]}"
++		    "mkfs.ufs" -b $BLKSIZE -L "$FSLABEL" -O 2 "${MOUNTDEVICE}"
+ 		    MOUNTOPTS="ufstype=ufs2,"
+ 		    MOUNTFS="ufs";;
+ 		x"ufs1")
+-		    "mkfs.ufs" -b $BLKSIZE -L "$FSLABEL" -O 1 "${LODEVICES[0]}"
++		    "mkfs.ufs" -b $BLKSIZE -L "$FSLABEL" -O 1 "${MOUNTDEVICE}"
+ 		    MOUNTOPTS="ufstype=44bsd,"
+ 		    MOUNTFS="ufs";;
+ 		x"ufs1_sun")
+-		    "mkfs.ufs" -b $BLKSIZE -L "$FSLABEL" -O 1 "${LODEVICES[0]}"
++		    "mkfs.ufs" -b $BLKSIZE -L "$FSLABEL" -O 1 "${MOUNTDEVICE}"
+ 		    MOUNTOPTS="ufstype=sun,"
+ 		    MOUNTFS="ufs";;
+ 		x"zfs")
+-		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" "${LODEVICES[0]}"
++		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" "${MOUNTDEVICE}"
+ 		    sleep 1
+ 		    "zfs" create "$FSLABEL"/"grub fs"
+ 		    sleep 1;;
+ 		x"zfs_caseins")
+-		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" "${LODEVICES[0]}"
++		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" "${MOUNTDEVICE}"
+ 		    sleep 1
+ 		    "zfs" create -o casesensitivity=insensitive "$FSLABEL"/"grub fs"
+ 		    sleep 1;;
+ 		x"zfs_lzjb" | xzfs_gzip | xzfs_zle)
+-		    "zpool" create -O compression=${fs/zfs_/} -R "$MNTPOINTRW" "$FSLABEL" "${LODEVICES[0]}"
++		    "zpool" create -O compression=${fs/zfs_/} -R "$MNTPOINTRW" "$FSLABEL" "${MOUNTDEVICE}"
+ 		    sleep 1
+ 		    "zfs" create -o compression=${fs/zfs_/} "$FSLABEL"/"grub fs"
+ 		    sleep 1;;
+ 		x"zfs_raidz")
+-		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" raidz1 "${LODEVICES[@]}"
++		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" raidz1 $LODEVICES
+ 		    sleep 1
+ 		    "zfs" create "$FSLABEL"/"grub fs"
+ 		    sleep 1;;
+ 		x"zfs_raidz2")
+-		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" raidz2 "${LODEVICES[@]}"
++		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" raidz2 $LODEVICES
+ 		    sleep 1
+ 		    "zfs" create "$FSLABEL"/"grub fs"
+ 		    sleep 1;;
+ 		x"zfs_raidz3")
+-		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" raidz3 "${LODEVICES[@]}"
++		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" raidz3 $LODEVICES
+ 		    sleep 1
+ 		    "zfs" create "$FSLABEL"/"grub fs"
+ 		    sleep 1;;
+ 		x"zfs_mirror")
+-		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" mirror "${LODEVICES[@]}"
++		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" mirror $LODEVICES
+ 		    sleep 1
+ 		    "zfs" create "$FSLABEL"/"grub fs"
+ 		    sleep 1;;
+ 		x"zfs_stripe")
+-		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" "${LODEVICES[@]}"
++		    "zpool" create -R "$MNTPOINTRW" "$FSLABEL" $LODEVICES
+ 		    sleep 1
+ 		    "zfs" create "$FSLABEL"/"grub fs"
+ 		    sleep 1;;
+ 		x"tarfs" | x"cpio_"* | x"iso9660" | xjoliet | xrockridge | xrockridge_joliet | x"iso9660_1999" | xjoliet_1999 | xrockridge_1999 | xrockridge_joliet_1999 | x"ziso9660" | x"romfs" | x"squash4_"*)
+ 		    INSTDEVICE=/dev/null;;
+ 		x"reiserfs")
+-		    "mkfs.reiserfs" --format=3.6 -b $BLKSIZE -l "$FSLABEL" -q "${LODEVICES[0]}" ;;
++		    "mkfs.reiserfs" --format=3.6 -b $BLKSIZE -l "$FSLABEL" -q "${MOUNTDEVICE}" ;;
+ 		x"reiserfs_old")
+-		    "mkfs.reiserfs" --format=3.5 -b $BLKSIZE -l "$FSLABEL" -q "${LODEVICES[0]}"
++		    "mkfs.reiserfs" --format=3.5 -b $BLKSIZE -l "$FSLABEL" -q "${MOUNTDEVICE}"
+ 		    MOUNTFS=reiserfs;;
+ 		x"jfs")
+-		    "mkfs.jfs" -L "$FSLABEL" -q "${LODEVICES[0]}"
++		    "mkfs.jfs" -L "$FSLABEL" -q "${MOUNTDEVICE}"
+ 		    MOUNTOPTS="iocharset=utf8,";;
+ 		x"jfs_caseins")
+-		    "mkfs.jfs" -O -L "$FSLABEL" -q "${LODEVICES[0]}"
++		    "mkfs.jfs" -O -L "$FSLABEL" -q "${MOUNTDEVICE}"
+ 		    MOUNTFS=jfs
+ 		    MOUNTOPTS="iocharset=utf8,";;
+ 		x"mdraid"*)
+-		    mdadm -C --chunk=$((BLKSIZE/1024)) --force -e "${fs:6:1}.${fs:7:1}" "/dev/md/${fs}_${NDEVICES}" --level="${fs:13}" --raid-devices="$NDEVICES" "${LODEVICES[@]}"
++		    mdadm -C --chunk=$((BLKSIZE/1024)) --force -e "${fs:6:1}.${fs:7:1}" "/dev/md/${fs}_${NDEVICES}" --level="${fs:13}" --raid-devices="$NDEVICES" $LODEVICES
+ 		    MOUNTDEVICE="/dev/md/${fs}_${NDEVICES}"
+ 		    MOUNTFS=ext2
+ 		    "mkfs.ext2" -L "$FSLABEL" -q "${MOUNTDEVICE}" ;;
+ 		x"lvm"*)
+-		    for ((i=0;i<NDEVICES;i++)); do
+-			pvcreate "${LODEVICES[i]}"
++		    for lodev in $LODEVICES; do
++			pvcreate "$lodev"
+ 		    done
+-		    vgcreate -s $((BLKSIZE/1024))K grub_test "${LODEVICES[@]}"
++		    vgcreate -s $((BLKSIZE/1024))K grub_test $LODEVICES
+ 		    if [ x$fs = xlvm ] ; then
+ 			lvcreate -l "$((NDEVICES*7*LVMBLKMUL))" -n testvol grub_test
+ 		    elif [ x$fs = xlvm_stripe ] ; then
+@@ -756,23 +795,29 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		    MOUNTDEVICE="/dev/mapper/grub_test-testvol"
+ 		    MOUNTFS=ext2
+ 		    "mkfs.ext2" -L "$FSLABEL" -q "${MOUNTDEVICE}"  ;;
++		xf2fs)
++		    "mkfs.f2fs" -l "$FSLABEL" -q "${LODEVICES[0]}" ;;
+ 		xnilfs2)
+-		    "mkfs.nilfs2" -L "$FSLABEL" -b $BLKSIZE  -q "${LODEVICES[0]}" ;;
++		    "mkfs.nilfs2" -L "$FSLABEL" -b $BLKSIZE  -q "${MOUNTDEVICE}" ;;
+ 		xext2_old)
+-		    MKE2FS_DEVICE_SECTSIZE=$SECSIZE "mkfs.ext2" -r 0 -b $BLKSIZE -L "$FSLABEL" -q "${LODEVICES[0]}"
++		    MKE2FS_DEVICE_SECTSIZE=$SECSIZE "mkfs.ext2" -r 0 -b $BLKSIZE -L "$FSLABEL" -q "${MOUNTDEVICE}"
+ 		    MOUNTFS=ext2
+ 		    ;;
+ 		xext4_metabg)
+-		    MKE2FS_DEVICE_SECTSIZE=$SECSIZE "mkfs.ext4" -O meta_bg,^resize_inode -b $BLKSIZE -L "$FSLABEL" -q "${LODEVICES[0]}"
++		    MKE2FS_DEVICE_SECTSIZE=$SECSIZE "mkfs.ext4" -O meta_bg,^resize_inode -b $BLKSIZE -L "$FSLABEL" -q "${MOUNTDEVICE}"
+ 		    MOUNTFS=ext4
+ 		    ;;
++               xext4_encrypt)
++                   MKE2FS_DEVICE_SECTSIZE=$SECSIZE "mkfs.ext4" -O encrypt -b $BLKSIZE -L "$FSLABEL" -q "${MOUNTDEVICE}"
++                   MOUNTFS=ext4
++                   ;;
+ 		xext*)
+-		    MKE2FS_DEVICE_SECTSIZE=$SECSIZE "mkfs.$fs" -b $BLKSIZE -L "$FSLABEL" -q "${LODEVICES[0]}" ;;
++		    MKE2FS_DEVICE_SECTSIZE=$SECSIZE "mkfs.$fs" -b $BLKSIZE -L "$FSLABEL" -q "${MOUNTDEVICE}" ;;
+ 		xxfs)
+-		    "mkfs.xfs" -m crc=0 -b size=$BLKSIZE -s size=$SECSIZE -L "$FSLABEL" -q "${LODEVICES[0]}" ;;
++		    "mkfs.xfs" -m crc=0 -b size=$BLKSIZE -s size=$SECSIZE -L "$FSLABEL" -q "${MOUNTDEVICE}" ;;
+ 		xxfs_crc)
+ 		    MOUNTFS="xfs"
+-		    "mkfs.xfs" -m crc=1 -b size=$BLKSIZE -s size=$SECSIZE -L "$FSLABEL" -q "${LODEVICES[0]}" ;;
++		    "mkfs.xfs" -m crc=1 -b size=$BLKSIZE -s size=$SECSIZE -L "$FSLABEL" -q "${MOUNTDEVICE}" ;;
+ 		*)
+ 		    echo "Add appropriate mkfs command here"
+ 		    exit 1
+@@ -873,11 +918,13 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		*)
+ 		    if ! mount -t "$MOUNTFS" "${MOUNTDEVICE}" "$MNTPOINTRW" -o ${MOUNTOPTS}${SELINUXOPTS}rw  ; then
+ 			echo "MOUNT FAILED."
+-			for ((i=0; i < NDEVICES; i++)); do
+-			    while ! losetup -d "${LODEVICES[i]}"; do
++			for lodev in $LODEVICES; do
++			    while ! losetup -d "$lodev"; do
+ 				sleep 1
+ 			    done
+-			    rm "${FSIMAGES[i]}"
++			done
++			for i in $(range 0 $((NDEVICES-1)) 1); do
++			    rm "$FSIMAGEP${i}.img"
+ 			done
+ 			exit 1;
+ 		    fi
+@@ -915,7 +962,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    esac
+ 	    # Make sure file is not exact multiple of block size. This helps to force
+ 	    # tail packing in case of squash4.
+-	    : $((BLOCKCNT--))
++	    BLOCKCNT="$((BLOCKCNT-1))"
+ 	    case x"$fs" in
+ 		x"ntfscomp")
+ 		    setfattr -h -v 0x00000800 -n system.ntfs_attrib_be "$MNTPOINTRW/$OSDIR";;
+@@ -939,11 +986,11 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    if (test x$fs = xvfat12a || test x$fs = xmsdos12a) && test x$BLKSIZE = x131072; then
+ 		    # With this config there isn't enough space for full copy.
+ 		    # Copy as much as we can
+-		cp "${CFILESSRC[0]}" "$MNTPOINTRW/$OSDIR/${CFILES[0]}" &> /dev/null;
++		cp "${CFILESRC}" "$MNTPOINTRW/$OSDIR/${CFILE}" &> /dev/null;
+ 	    else
+-		for ((i=0;i<$CFILESN;i++)); do
+-		    cp "${CFILESSRC[i]}" "$MNTPOINTRW/$OSDIR/${CFILES[i]}";
+-		done
++
++		cp "${CFILESRC}" "$MNTPOINTRW/$OSDIR/${CFILE}";
++
+ 	    fi
+ 
+ 	    if [ x$NOSYMLINK != xy ]; then
+@@ -968,48 +1015,48 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		    sleep 2
+ 		    ;;
+ 		x"tarfs")
+-		    (cd "$MASTER"; tar cf "${FSIMAGES[0]}" .) ;;
++		    (cd "$MASTER"; tar cf "${FSIMAGEP}0.img" .) ;;
+ 		x"cpio_"*)
+-		    (cd "$MASTER"; find . | cpio -o -H "${fs/cpio_/}" > "${FSIMAGES[0]}" ) ;;
++		    (cd "$MASTER"; find . | cpio -o -H "$(echo ${fs} | sed 's@^cpio_@@')" > "${FSIMAGEP}0.img" ) ;;
+ 		x"ziso9660")
+ 		    FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+-		    xorriso -compliance rec_mtime -set_filter_r --zisofs -- -zisofs default -as mkisofs -iso-level 3 -graft-points -R -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}"  -- -set_filter_r --zisofs -- -zisofs default -add /="$MASTER" ;;
++		    xorriso -compliance rec_mtime -set_filter_r --zisofs -- -zisofs default -as mkisofs -iso-level 3 -graft-points -R -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGEP}0.img"  -- -set_filter_r --zisofs -- -zisofs default -add /="$MASTER" ;;
+ 		x"iso9660")
+ 		    FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+-		    xorriso --rockridge off -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
++		    xorriso --rockridge off -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGEP}0.img" /="$MASTER"  ;;
+ 		x"joliet")
+ 		    FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+-		    xorriso --rockridge off  -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
++		    xorriso --rockridge off  -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGEP}0.img" /="$MASTER"  ;;
+ 		x"rockridge")
+ 		    FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+-		    xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
++		    xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGEP}0.img" /="$MASTER"  ;;
+ 		x"rockridge_joliet")
+ 		    FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+-		    xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
++		    xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 3 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGEP}0.img" /="$MASTER"  ;;
+ 		x"iso9660_1999")
+ 		    FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+-		    xorriso --rockridge off -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
++		    xorriso --rockridge off -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGEP}0.img" /="$MASTER"  ;;
+ 		x"joliet_1999")
+ 		    FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+-		    xorriso --rockridge off  -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
++		    xorriso --rockridge off  -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGEP}0.img" /="$MASTER"  ;;
+ 		x"rockridge_1999")
+ 		    FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+-		    xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
++		    xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGEP}0.img" /="$MASTER"  ;;
+ 		x"rockridge_joliet_1999")
+ 		    FSUUID=$(date -u +%Y-%m-%d-%H-%M-%S-00);
+-		    xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGES[0]}" /="$MASTER"  ;;
++		    xorriso --rockridge on -compliance rec_mtime -as mkisofs -iso-level 4 -graft-points -J -joliet-long -V "$FSLABEL" --modification-date=$(echo ${FSUUID} | sed 's/-//g;') -o "${FSIMAGEP}0.img" /="$MASTER"  ;;
+ 		x"romfs")
+-		    genromfs -V "$FSLABEL" -f "${FSIMAGES[0]}" -d "$MASTER" ;;
++		    genromfs -V "$FSLABEL" -f "${FSIMAGEP}0.img" -d "$MASTER" ;;
+ 		xsquash4_*)
+-		    echo mksquashfs "$MASTER" "${FSIMAGES[0]}" -always-use-fragments -comp "${fs/squash4_/}" -b $BLKSIZE
+-		    mksquashfs "$MASTER" "${FSIMAGES[0]}" -always-use-fragments -comp "${fs/squash4_/}" -b $BLKSIZE ;;
++		    echo mksquashfs "$MASTER" "${FSIMAGEP}0.img" -always-use-fragments -comp "${fs/squash4_/}" -b $BLKSIZE
++		    mksquashfs "$MASTER" "${FSIMAGEP}0.img" -always-use-fragments -comp "${fs/squash4_/}" -b $BLKSIZE ;;
+ 		x"bfs")
+ 		    sleep 1
+ 		    fusermount -u "$MNTPOINTRW"
+ 		    ;;
+ 		xlvm*)
+ 		    sleep 1
+-		    for ((try=0;try < 20; try++)); do
++		    for try in $(range 0 20 1); do
+ 			if umount "$MNTPOINTRW" ; then
+ 			    break;
+ 			fi
+@@ -1021,7 +1068,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		    ;;
+ 		xmdraid*)
+ 		    sleep 1
+-		    for ((try=0;try < 20; try++)); do
++		    for try in $(range 0 20 1); do
+ 			if umount "$MNTPOINTRW" ; then
+ 			    break;
+ 			fi
+@@ -1033,7 +1080,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		    ;;
+ 		*)
+ 		    sleep 1
+-		    for ((try=0;try < 20; try++)); do
++		    for try in $(range 0 20 1); do
+ 			if umount "$MNTPOINTRW" ; then
+ 			    break;
+ 			fi
+@@ -1066,7 +1113,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		    sleep 1
+ 		    mount -t "$MOUNTFS" "${MOUNTDEVICE}" "$MNTPOINTRO" -o ${MOUNTOPTS}${SELINUXOPTS}ro ;;
+ 		xmdraid*)
+-		    mdadm --assemble /dev/md/"${fs}_$NDEVICES" "${LODEVICES[@]}"
++		    mdadm --assemble /dev/md/"${fs}_$NDEVICES" $LODEVICES
+ 		    sleep 1
+ 		    mount -t "$MOUNTFS" "${MOUNTDEVICE}" "$MNTPOINTRO" -o ${MOUNTOPTS}${SELINUXOPTS}ro ;;
+ 		*)
+@@ -1085,7 +1132,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    else
+ 		echo LIST FAIL
+ 		echo "$LSROUT"
+-		TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
++		TZ=UTC ls -l "$MNTPOINTRO"
+ 		exit 1
+ 	    fi
+ 
+@@ -1094,7 +1141,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    else
+ 		echo NLIST FAIL
+ 		echo "$LSROUT"
+-		TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -lA "$MNTPOINTRO"
++		TZ=UTC ls -lA "$MNTPOINTRO"
+ 		exit 1
+ 	    fi
+ 
+@@ -1103,7 +1150,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    else
+ 		echo ILIST FAIL
+ 		echo "$LSROUT"
+-		TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
++		TZ=UTC ls -l "$MNTPOINTRO"
+ 		exit 1
+ 	    fi
+ 
+@@ -1112,7 +1159,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    else
+ 		echo LONG LIST FAIL
+ 		echo "$LSROUT"
+-		TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
++		TZ=UTC ls -l "$MNTPOINTRO"
+ 		exit 1
+ 	    fi
+ 
+@@ -1123,7 +1170,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		else
+ 		    echo TIME FAIL
+ 		    echo "$LSROUT"
+-		    TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
++		    TZ=UTC ls -l "$MNTPOINTRO"
+ 		    exit 1
+ 		fi
+ 
+@@ -1133,7 +1180,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		else
+ 		    echo LONG TIME FAIL
+ 		    echo "$LSROUT"
+-		    TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
++		    TZ=UTC ls -l "$MNTPOINTRO"
+ 		    exit 1
+ 		fi
+ 	    fi
+@@ -1149,7 +1196,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    else
+ 		echo DOT IN ROOTDIR FAIL
+ 		echo "$LSROUT"
+-		TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
++		TZ=UTC ls -l "$MNTPOINTRO"
+ 		exit 1
+ 	    fi
+ 
+@@ -1163,7 +1210,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		    else
+ 			echo DOTDOT IN ROOTDIR FAIL
+ 			echo "$LSROUT"
+-			TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO"
++			TZ=UTC ls -l "$MNTPOINTRO"
+ 			exit 1
+ 		    fi
+ 		    ;;
+@@ -1180,7 +1227,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    else
+ 		echo SLIST FAIL
+ 		echo "$LSROUT"
+-		TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO/sdir"
++		TZ=UTC ls -l "$MNTPOINTRO/sdir"
+ 		exit 1
+ 	    fi
+ 
+@@ -1195,7 +1242,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    else
+ 		echo PLIST FAIL
+ 		echo "$LSROUT"
+-		TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO/$PDIR"
++		TZ=UTC ls -l "$MNTPOINTRO/$PDIR"
+ 		exit 1
+ 	    fi
+ 
+@@ -1210,7 +1257,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    else
+ 		echo DOT IN SUBDIR FAIL
+ 		echo "$LSROUT"
+-		TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO/$OSDIR/sdir"
++		TZ=UTC ls -l "$MNTPOINTRO/$OSDIR/sdir"
+ 		exit 1
+ 	    fi
+ 
+@@ -1225,7 +1272,7 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    else
+ 		echo DOTDOT IN SUBDIR FAIL
+ 		echo "$LSROUT"
+-		TZ=UTC ls --time-style=+%Y%m%d%H%M%S.%N -l "$MNTPOINTRO/$OSDIR/ssdir"
++		TZ=UTC ls -l "$MNTPOINTRO/$OSDIR/ssdir"
+ 		exit 1
+ 	    fi
+ 
+@@ -1245,8 +1292,8 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 	    case x"$fs" in
+ 		x"iso9660" | x"ziso9660" | xrockridge | xjoliet | xrockridge_joliet | x"iso9660_1999" | xrockridge_1999 | xjoliet_1999 | xrockridge_joliet_1999) ;;
+ 		x"zfs"*)
+-		    for ((i=0;i<NDEVICES;i++)); do
+-			FSUUID=$(printf "%016x\n" $(blkid -o export "${LODEVICES[i]}" |grep -F UUID=|sed s,UUID=,,g))
++		    for lodev in $LODEVICES; do
++			FSUUID=$(printf "%016x\n" $(blkid -o export "$lodev" |grep -F UUID=|sed s,UUID=,,g))
+ 			if [ "$FSUUID" != 0000000000000000 ]; then
+ 			    break;
+ 			fi
+@@ -1264,8 +1311,8 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 			echo UUID FAIL
+ 			echo "$LSOUT"
+ 			echo "$GRUBUUID"
+-			for ((i=0;i<NDEVICES;i++)); do
+-			    blkid "${LODEVICES[i]}"
++			for lodev in $LODEVICES; do
++			    blkid "$lodev"
+ 			done
+ 			exit 1
+ 		    fi
+@@ -1290,37 +1337,37 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 			echo UUID FAIL
+ 			echo "$FSUUID"
+ 			echo "$LSOUT"
+-			blkid "${LODEVICES[0]}"
++			blkid "${MOUNTDEVICE}"
+ 			exit 1
+ 		    fi
+ 		    ;;
+ 	    esac
+ 
+-	    case x$fs in
+-		xiso9660 | xziso9660 | xrockridge | xjoliet | xrockridge_joliet | xiso9660_1999 | xrockridge_1999 | xjoliet_1999 | xrockridge_joliet_1999)
+-		    FSTIME="$(date -d "$(echo ${FSUUID} | awk -F - '{ print $1"-"$2"-"$3" "$4":"$5":"$6 ;}')" '+%Y-%m-%d %H:%M:%S')";;
+-		xlvm*|xmdraid*)
+-		    # With some abstractions like mdraid flushing to disk
+-		    # may be delayed for a long time.
+-		    FSTIME="$UMOUNT_TIME";;
+-		*)
+-		    FSTIME="$(TZ=UTC ls --time-style="+%Y-%m-%d_%H:%M:%S" -l -d "${FSIMAGES[0]}"|awk '{print $6; }'|sed 's,_, ,g')";;
+-	    esac
+-	    # With some abstractions like mdraid computing of UMOUNT_TIME
+-	    # is not precise. Account for small difference here.
+-	    FSTIMEM1="$(date -d "$FSTIME UTC -1 second" -u "+%Y-%m-%d %H:%M:%S")"
+-	    FSTIMEM2="$(date -d "$FSTIME UTC -2 second" -u "+%Y-%m-%d %H:%M:%S")"
+-	    FSTIMEM3="$(date -d "$FSTIME UTC -3 second" -u "+%Y-%m-%d %H:%M:%S")"
++	    if [ x$NOFSTIME != xy ]; then
++		case x$fs in
++		    xiso9660 | xziso9660 | xrockridge | xjoliet | xrockridge_joliet | xiso9660_1999 | xrockridge_1999 | xjoliet_1999 | xrockridge_joliet_1999)
++			FSTIME="$(date -d "$(echo ${FSUUID} | awk -F - '{ print $1"-"$2"-"$3" "$4":"$5":"$6 ;}')" '+%Y-%m-%d %H:%M:%S')";;
++		    xlvm*|xmdraid*)
++			# With some abstractions like mdraid flushing to disk
++			# may be delayed for a long time.
++			FSTIME="$UMOUNT_TIME";;
++		    *)
++			FSTIME="$(TZ=UTC ls --time-style="+%Y-%m-%d_%H:%M:%S" -l -d "${FSIMAGEP}0.img"|awk '{print $6; }'|sed 's,_, ,g')";;
++		esac
++		# With some abstractions like mdraid computing of UMOUNT_TIME
++		# is not precise. Account for small difference here.
++		FSTIMEM1="$(date -d "$FSTIME UTC -1 second" -u "+%Y-%m-%d %H:%M:%S")"
++		FSTIMEM2="$(date -d "$FSTIME UTC -2 second" -u "+%Y-%m-%d %H:%M:%S")"
++		FSTIMEM3="$(date -d "$FSTIME UTC -3 second" -u "+%Y-%m-%d %H:%M:%S")"
+ 
+-	    if [ x$NOFSTIME = xy ]; then
+-		:
+-	    elif echo "$LSOUT" | grep -F 'Last modification time '"$FSTIME" > /dev/null || echo "$LSOUT" | grep -F 'Last modification time '"$FSTIMEM1" > /dev/null || echo "$LSOUT" | grep -F 'Last modification time '"$FSTIMEM2" || echo "$LSOUT" | grep -F 'Last modification time '"$FSTIMEM3" > /dev/null; then
+-		:
+-	    else
+-		echo FSTIME FAIL
+-		echo "$FSTIME"
+-		echo "$LSOUT"
+-		exit 1
++		if echo "$LSOUT" | grep -F 'Last modification time '"$FSTIME" > /dev/null || echo "$LSOUT" | grep -F 'Last modification time '"$FSTIMEM1" > /dev/null || echo "$LSOUT" | grep -F 'Last modification time '"$FSTIMEM2" || echo "$LSOUT" | grep -F 'Last modification time '"$FSTIMEM3" > /dev/null; then
++		    :
++		else
++		    echo FSTIME FAIL
++		    echo "$FSTIME"
++		    echo "$LSOUT"
++		    exit 1
++		fi
+ 	    fi
+ 
+ 	    if [ x$NOHARDLINK != xy ]; then
+@@ -1410,11 +1457,9 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		exit 1
+ 	    fi
+ 	    ok=true
+-	    for ((i=0;i<$CFILESN;i++)); do
+-		if ! run_grubfstest cmp "$GRUBDIR/${CFILES[i]}" "$MNTPOINTRO/$OSDIR/${CFILES[i]}"  ; then
+-		    ok=false;
+-		fi
+-	    done
++	    if ! run_grubfstest cmp "$GRUBDIR/${CFILE}" "$MNTPOINTRO/$OSDIR/${CFILE}"  ; then
++		ok=false;
++	    fi
+ 	    if  test x$ok = xtrue; then
+ 		:
+ 	    else
+@@ -1503,15 +1548,17 @@ for ((LOGSECSIZE=MINLOGSECSIZE;LOGSECSIZE<=MAXLOGSECSIZE;LOGSECSIZE=LOGSECSIZE +
+ 		    sleep 1
+ 		    ;;
+ 	    esac
+-	    for ((i=0; i < NDEVICES; i++)); do
+-		case x"$fs" in
+-		    x"tarfs" | x"cpio_"* | x"iso9660" | xrockridge | xjoliet | xrockridge_joliet | x"ziso9660" | x"romfs" | x"squash4_"* | x"iso9660_1999" | xrockridge_1999 | xjoliet_1999 | xrockridge_joliet_1999) ;;
+-		    *)
+-			while ! losetup -d "${LODEVICES[i]}"; do
++	    case x"$fs" in
++		x"tarfs" | x"cpio_"* | x"iso9660" | xrockridge | xjoliet | xrockridge_joliet | x"ziso9660" | x"romfs" | x"squash4_"* | x"iso9660_1999" | xrockridge_1999 | xjoliet_1999 | xrockridge_joliet_1999) ;;
++		*)
++		    for lodev in $LODEVICES; do
++			while ! losetup -d "$lodev"; do
+ 			    sleep 1
+-			done;;
+-		esac
+-		rm "${FSIMAGES[i]}"
++			done
++		    done;;
++	    esac
++	    for i in $(range 0 $((NDEVICES-1)) 1); do
++		rm "$FSIMAGEP${i}.img"
+ 	    done
+ 	    if [ x"$fs" = x"zfs" ]; then
+ 		rmdir "$MNTPOINTRW"/"grub fs"  || true
+diff --git a/tests/util/grub-shell-tester.in b/tests/util/grub-shell-tester.in
+index 5adce0a47fe3208e14bbbf4820685d67b43ef9bb..8a87109b15240de9d61f2ac02becfcb5300582f1 100644
+--- a/tests/util/grub-shell-tester.in
++++ b/tests/util/grub-shell-tester.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ # Compares GRUB script output with BASH output.
+diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in
+index 814f36c6bd2438b7f9c59f5f4a9777e95b9e38db..d690d6734efb82109f7635c4688b6fc7417a5751 100644
+--- a/tests/util/grub-shell.in
++++ b/tests/util/grub-shell.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ set -e
+ 
+ # Run GRUB script in a Qemu instance
+diff --git a/tests/xfs_test.in b/tests/xfs_test.in
+index 3807e2e5c77e244f8b2f0d43ec28b86b3f2f9e9b..03a3513595dc719cd72b4d9b7198f22b338cb588 100644
+--- a/tests/xfs_test.in
++++ b/tests/xfs_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/tests/xzcompress_test.in b/tests/xzcompress_test.in
+index b2bd999ec071c24205533e50cf51f46ec59a2218..03bfb5e951dd8dfb7ccb15fb6a31dd4aea639df9 100644
+--- a/tests/xzcompress_test.in
++++ b/tests/xzcompress_test.in
+@@ -1,4 +1,4 @@
+-#! /bin/sh
++#! @BUILD_SHEBANG@
+ # Copyright (C) 2013  Free Software Foundation, Inc.
+ #
+ # GRUB is free software: you can redistribute it and/or modify
+diff --git a/tests/zfs_test.in b/tests/zfs_test.in
+index 047120e47a0e042f0540d6762666edf4cb0b37fb..eee62c10d704ec42b090eba5ac16b4966ff760ad 100644
+--- a/tests/zfs_test.in
++++ b/tests/zfs_test.in
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!@BUILD_SHEBANG@
+ 
+ set -e
+ 
+diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in
+index f8496d28bdf7f4bcbc2413888330834c1e252a64..33332360eecf954fc2952df944fe171006fc4143 100644
+--- a/util/grub-mkconfig.in
++++ b/util/grub-mkconfig.in
+@@ -134,6 +134,7 @@ fi
+ # Device containing our userland.  Typically used for root= parameter.
+ GRUB_DEVICE="`${grub_probe} --target=device /`"
+ GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true
++GRUB_DEVICE_PARTUUID="`${grub_probe} --device ${GRUB_DEVICE} --target=partuuid 2> /dev/null`" || true
+ 
+ # Device containing our /boot partition.  Usually the same as GRUB_DEVICE.
+ GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`"
+@@ -147,6 +148,12 @@ if [ x"$GRUB_FS" = xunknown ]; then
+     GRUB_FS="$(stat -f --printf=%T / || echo unknown)"
+ fi
+ 
++# Provide a default set of stock linux early initrd images.
++# Define here so the list can be modified in the sourced config file.
++if [ "x${GRUB_EARLY_INITRD_LINUX_STOCK}" = "x" ]; then
++	GRUB_EARLY_INITRD_LINUX_STOCK="intel-uc.img intel-ucode.img amd-uc.img amd-ucode.img early_ucode.cpio microcode.cpio"
++fi
++
+ if test -f ${sysconfdir}/default/grub ; then
+   . ${sysconfdir}/default/grub
+ fi
+@@ -182,6 +189,7 @@ if [ "x${GRUB_ACTUAL_DEFAULT}" = "xsaved" ] ; then GRUB_ACTUAL_DEFAULT="`"${grub
+ # override them.
+ export GRUB_DEVICE \
+   GRUB_DEVICE_UUID \
++  GRUB_DEVICE_PARTUUID \
+   GRUB_DEVICE_BOOT \
+   GRUB_DEVICE_BOOT_UUID \
+   GRUB_FS \
+@@ -211,10 +219,13 @@ export GRUB_DEFAULT \
+   GRUB_CMDLINE_NETBSD \
+   GRUB_CMDLINE_NETBSD_DEFAULT \
+   GRUB_CMDLINE_GNUMACH \
++  GRUB_EARLY_INITRD_LINUX_CUSTOM \
++  GRUB_EARLY_INITRD_LINUX_STOCK \
+   GRUB_TERMINAL_INPUT \
+   GRUB_TERMINAL_OUTPUT \
+   GRUB_SERIAL_COMMAND \
+   GRUB_DISABLE_LINUX_UUID \
++  GRUB_DISABLE_LINUX_PARTUUID \
+   GRUB_DISABLE_RECOVERY \
+   GRUB_VIDEO_BACKEND \
+   GRUB_GFXMODE \
+diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in
+index 60b31caddeb42b5db338897dc18acdc156dd2c22..0f801cab3e4d05efface62c7fcb9b787c69995c3 100644
+--- a/util/grub-mkconfig_lib.in
++++ b/util/grub-mkconfig_lib.in
+@@ -188,6 +188,7 @@ grub_file_is_not_garbage ()
+       *.dpkg-*) return 1 ;; # debian dpkg
+       *.rpmsave|*.rpmnew) return 1 ;;
+       README*|*/README*)  return 1 ;; # documentation
++      *.sig) return 1 ;; # signatures
+     esac
+   else
+     return 1
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index de9044c7f28611d56358f581ac52ca2d2b7fc982..61ebd7dc714e87aedb167345729f574426d69b77 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -43,12 +43,22 @@ case ${GRUB_DEVICE} in
+   ;;
+ esac
+ 
++# Default to disabling partition uuid support to maintian compatibility with
++# older kernels.
++GRUB_DISABLE_LINUX_PARTUUID=${GRUB_DISABLE_LINUX_PARTUUID-true}
++
+ # btrfs may reside on multiple devices. We cannot pass them as value of root= parameter
+ # and mounting btrfs requires user space scanning, so force UUID in this case.
+-if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
+-    || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \
++if ( [ "x${GRUB_DEVICE_UUID}" = "x" ] && [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] ) \
++    || ( [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
++	&& [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ] ) \
++    || ( ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \
++	&& ! test -e "/dev/disk/by-partuuid/${GRUB_DEVICE_PARTUUID}" ) \
+     || ( test -e "${GRUB_DEVICE}" && uses_abstraction "${GRUB_DEVICE}" lvm ); then
+   LINUX_ROOT_DEVICE=${GRUB_DEVICE}
++elif [ "x${GRUB_DEVICE_UUID}" = "x" ] \
++    || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ]; then
++  LINUX_ROOT_DEVICE=PARTUUID=${GRUB_DEVICE_PARTUUID}
+ else
+   LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
+ fi
+@@ -136,9 +146,13 @@ EOF
+   if test -n "${initrd}" ; then
+     # TRANSLATORS: ramdisk isn't identifier. Should be translated.
+     message="$(gettext_printf "Loading initial ramdisk ...")"
++    initrd_path=
++    for i in ${initrd}; do
++      initrd_path="${initrd_path} ${rel_dirname}/${i}"
++    done
+     sed "s/^/$submenu_indentation/" << EOF
+ 	echo	'$(echo "$message" | grub_quote)'
+-	initrd	${rel_dirname}/${initrd}
++	initrd	$(echo $initrd_path)
+ EOF
+   fi
+   sed "s/^/$submenu_indentation/" << EOF
+@@ -188,7 +202,15 @@ while [ "x$list" != "x" ] ; do
+   alt_version=`echo $version | sed -e "s,\.old$,,g"`
+   linux_root_device_thisversion="${LINUX_ROOT_DEVICE}"
+ 
+-  initrd=
++  initrd_early=
++  for i in ${GRUB_EARLY_INITRD_LINUX_STOCK} \
++	   ${GRUB_EARLY_INITRD_LINUX_CUSTOM}; do
++    if test -e "${dirname}/${i}" ; then
++      initrd_early="${initrd_early} ${i}"
++    fi
++  done
++
++  initrd_real=
+   for i in "initrd.img-${version}" "initrd-${version}.img" "initrd-${version}.gz" \
+ 	   "initrd-${version}" "initramfs-${version}.img" \
+ 	   "initrd.img-${alt_version}" "initrd-${alt_version}.img" \
+@@ -198,11 +220,22 @@ while [ "x$list" != "x" ] ; do
+ 	   "initramfs-genkernel-${GENKERNEL_ARCH}-${version}" \
+ 	   "initramfs-genkernel-${GENKERNEL_ARCH}-${alt_version}"; do
+     if test -e "${dirname}/${i}" ; then
+-      initrd="$i"
++      initrd_real="${i}"
+       break
+     fi
+   done
+ 
++  initrd=
++  if test -n "${initrd_early}" || test -n "${initrd_real}"; then
++    initrd="${initrd_early} ${initrd_real}"
++
++    initrd_display=
++    for i in ${initrd}; do
++      initrd_display="${initrd_display} ${dirname}/${i}"
++    done
++    gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2
++  fi
++
+   config=
+   for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do
+     if test -e "${i}" ; then
+@@ -216,12 +249,16 @@ while [ "x$list" != "x" ] ; do
+       initramfs=`grep CONFIG_INITRAMFS_SOURCE= "${config}" | cut -f2 -d= | tr -d \"`
+   fi
+ 
+-  if test -n "${initrd}" ; then
+-    gettext_printf "Found initrd image: %s\n" "${dirname}/${initrd}" >&2
+-  elif test -z "${initramfs}" ; then
++  if test -z "${initramfs}" && test -z "${initrd_real}" ; then
+     # "UUID=" and "ZFS=" magic is parsed by initrd or initramfs.  Since there's
+     # no initrd or builtin initramfs, it can't work here.
+-    linux_root_device_thisversion=${GRUB_DEVICE}
++    if [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] \
++	|| [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ]; then
++
++	linux_root_device_thisversion=${GRUB_DEVICE}
++    else
++	linux_root_device_thisversion=PARTUUID=${GRUB_DEVICE_PARTUUID}
++    fi
+   fi
+ 
+   if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xy ]; then
+diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in
+index c48af948d6ecdf672aa341f713912ba15de8f27d..e8143b079dc8bcdf21ec8a763b19a356c863a5e3 100644
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -43,12 +43,22 @@ case ${GRUB_DEVICE} in
+   ;;
+ esac
+ 
++# Default to disabling partition uuid support to maintian compatibility with
++# older kernels.
++GRUB_DISABLE_LINUX_PARTUUID=${GRUB_DISABLE_LINUX_PARTUUID-true}
++
+ # btrfs may reside on multiple devices. We cannot pass them as value of root= parameter
+ # and mounting btrfs requires user space scanning, so force UUID in this case.
+-if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
+-    || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \
++if ( [ "x${GRUB_DEVICE_UUID}" = "x" ] && [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] ) \
++    || ( [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
++	&& [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ] ) \
++    || ( ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \
++	&& ! test -e "/dev/disk/by-partuuid/${GRUB_DEVICE_PARTUUID}" ) \
+     || ( test -e "${GRUB_DEVICE}" && uses_abstraction "${GRUB_DEVICE}" lvm ); then
+   LINUX_ROOT_DEVICE=${GRUB_DEVICE}
++elif [ "x${GRUB_DEVICE_UUID}" = "x" ] \
++    || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ]; then
++  LINUX_ROOT_DEVICE=PARTUUID=${GRUB_DEVICE_PARTUUID}
+ else
+   LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
+ fi
+@@ -122,16 +132,16 @@ linux_entry ()
+         else
+             xen_rm_opts="no-real-mode edd=off"
+         fi
+-	multiboot	${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts}
++	${xen_loader}	${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts}
+ 	echo	'$(echo "$lmessage" | grub_quote)'
+-	module	${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args}
++	${module_loader}	${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args}
+ EOF
+   if test -n "${initrd}" ; then
+     # TRANSLATORS: ramdisk isn't identifier. Should be translated.
+     message="$(gettext_printf "Loading initial ramdisk ...")"
+     sed "s/^/$submenu_indentation/" << EOF
+ 	echo	'$(echo "$message" | grub_quote)'
+-	module	--nounzip   ${rel_dirname}/${initrd}
++	${module_loader}	--nounzip   ${rel_dirname}/${initrd}
+ EOF
+   fi
+   sed "s/^/$submenu_indentation/" << EOF
+@@ -206,6 +216,18 @@ while [ "x${xen_list}" != "x" ] ; do
+     if [ "x$is_top_level" != xtrue ]; then
+ 	echo "	submenu '$(gettext_printf "Xen hypervisor, version %s" "${xen_version}" | grub_quote)' \$menuentry_id_option 'xen-hypervisor-$xen_version-$boot_device_id' {"
+     fi
++    if ($grub_file --is-arm64-efi $current_xen); then
++	xen_loader="xen_hypervisor"
++	module_loader="xen_module"
++    else
++	if ($grub_file --is-x86-multiboot2 $current_xen); then
++	    xen_loader="multiboot2"
++	    module_loader="module2"
++	else
++	    xen_loader="multiboot"
++	    module_loader="module"
++        fi
++    fi
+     while [ "x$list" != "x" ] ; do
+ 	linux=`version_find_latest $list`
+ 	gettext_printf "Found linux image: %s\n" "$linux" >&2
+@@ -234,7 +256,13 @@ while [ "x${xen_list}" != "x" ] ; do
+ 	    gettext_printf "Found initrd image: %s\n" "${dirname}/${initrd}" >&2
+ 	else
+     # "UUID=" magic is parsed by initrds.  Since there's no initrd, it can't work here.
+-	    linux_root_device_thisversion=${GRUB_DEVICE}
++	    if [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] \
++		|| [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ]; then
++
++		linux_root_device_thisversion=${GRUB_DEVICE}
++	    else
++		linux_root_device_thisversion=PARTUUID=${GRUB_DEVICE_PARTUUID}
++	    fi
+ 	fi
+ 
+ 	if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xy ]; then
diff --git a/SOURCES/secureboot.cer b/SOURCES/secureboot.cer
new file mode 100644
index 0000000..4ff8b79
Binary files /dev/null and b/SOURCES/secureboot.cer differ
diff --git a/SOURCES/securebootca.cer b/SOURCES/securebootca.cer
new file mode 100644
index 0000000..b235400
Binary files /dev/null and b/SOURCES/securebootca.cer differ
diff --git a/SOURCES/strtoull_test.c b/SOURCES/strtoull_test.c
new file mode 100644
index 0000000..7da615f
--- /dev/null
+++ b/SOURCES/strtoull_test.c
@@ -0,0 +1,63 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2016 Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/test.h>
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static void
+strtoull_testcase (const char *input, int base, unsigned long long expected,
+		   int num_digits, grub_err_t error)
+{
+  char *output;
+  unsigned long long value;
+  grub_errno = 0;
+  value = grub_strtoull(input, &output, base);
+  grub_test_assert (grub_errno == error,
+		    "unexpected error. Expected %d, got %d. Input \"%s\"",
+		    error, grub_errno, input);
+  if (grub_errno)
+    {
+      grub_errno = 0;
+      return;
+    }
+  grub_test_assert (input + num_digits == output,
+		    "unexpected number of digits. Expected %d, got %d, input \"%s\"",
+		    num_digits, (int) (output - input), input);
+  grub_test_assert (value == expected,
+		    "unexpected return value. Expected %llu, got %llu, input \"\%s\"",
+		    expected, value, input);
+}
+
+static void
+strtoull_test (void)
+{
+  strtoull_testcase ("9", 0, 9, 1, GRUB_ERR_NONE);
+  strtoull_testcase ("0xaa", 0, 0xaa, 4, GRUB_ERR_NONE);
+  strtoull_testcase ("0xff", 0, 0xff, 4, GRUB_ERR_NONE);
+  strtoull_testcase ("0", 10, 0, 1, GRUB_ERR_NONE);
+  strtoull_testcase ("8", 8, 0, 0, GRUB_ERR_BAD_NUMBER);
+  strtoull_testcase ("38", 8, 3, 1, GRUB_ERR_NONE);
+  strtoull_testcase ("7", 8, 7, 1, GRUB_ERR_NONE);
+  strtoull_testcase ("1]", 16, 1, 1, GRUB_ERR_NONE);
+  strtoull_testcase ("18446744073709551616", 10, 0, 0, GRUB_ERR_OUT_OF_RANGE);
+}
+
+
+GRUB_FUNCTIONAL_TEST (strtoull_test, strtoull_test);
diff --git a/SPECS/grub2.spec b/SPECS/grub2.spec
new file mode 100644
index 0000000..471f12e
--- /dev/null
+++ b/SPECS/grub2.spec
@@ -0,0 +1,1255 @@
+%undefine _hardened_build
+
+%global tarversion 2.02
+%undefine _missing_build_ids_terminate_build
+%global _configure_gnuconfig_hack 0
+
+Name:		grub2
+Epoch:		1
+Version:	2.02
+Release:	66%{?dist}
+Summary:	Bootloader with support for Linux, Multiboot and more
+Group:		System Environment/Base
+License:	GPLv3+
+URL:		http://www.gnu.org/software/grub/
+Obsoletes:	grub < 1:0.98
+Source0:	ftp://alpha.gnu.org/gnu/grub/grub-%{tarversion}.tar.xz
+#Source0:	ftp://ftp.gnu.org/gnu/grub/grub-%%{tarversion}.tar.xz
+Source1:	grub.macros
+Source2:	grub.patches
+Source3:	release-to-master.patch
+Source4:	http://unifoundry.com/unifont-5.1.20080820.pcf.gz
+Source5:	theme.tar.bz2
+Source6:	gitignore
+Source8:	strtoull_test.c
+Source9:	20-grub.install
+Source12:	99-grub-mkconfig.install
+Source13:	securebootca.cer
+Source14:	secureboot.cer
+
+%include %{SOURCE1}
+
+# generate with do-rebase
+%include %{SOURCE2}
+
+BuildRequires:	gcc efi-srpm-macros
+BuildRequires:	flex bison binutils python3-devel
+BuildRequires:	ncurses-devel xz-devel bzip2-devel
+BuildRequires:	freetype-devel libusb-devel
+BuildRequires:	rpm-devel
+BuildRequires:	rpm-devel rpm-libs
+BuildRequires:	autoconf automake autogen device-mapper-devel
+BuildRequires:	freetype-devel gettext-devel git
+BuildRequires:	texinfo
+BuildRequires:	dejavu-sans-fonts
+BuildRequires:	help2man
+# For %%_userunitdir macro
+BuildRequires:	systemd
+%ifarch %{efi_arch}
+BuildRequires:	pesign >= 0.99-8
+%endif
+%if %{?_with_ccache: 1}%{?!_with_ccache: 0}
+BuildRequires:	ccache
+%endif
+
+ExcludeArch:	s390 s390x %{arm}
+Obsoletes:	%{name} <= %{evr}
+
+%if 0%{with_legacy_arch}
+Requires:	%{name}-%{legacy_package_arch} = %{evr}
+%else
+Requires:	%{name}-%{package_arch} = %{evr}
+%endif
+
+%global desc \
+The GRand Unified Bootloader (GRUB) is a highly configurable and \
+customizable bootloader with modular architecture.  It supports a rich \
+variety of kernel formats, file systems, computer architectures and \
+hardware devices.\
+%{nil}
+
+%description
+%{desc}
+
+%package common
+Summary:	grub2 common layout
+Group:		System Environment/Base
+BuildArch:	noarch
+Conflicts:	grubby < 8.40-13
+
+%description common
+This package provides some directories which are required by various grub2
+subpackages.
+
+%package tools
+Summary:	Support tools for GRUB.
+Group:		System Environment/Base
+Obsoletes:	%{name}-tools < %{evr}
+Requires:	%{name}-common = %{epoch}:%{version}-%{release}
+Requires:	gettext os-prober which file
+Requires(pre):	dracut
+Requires(post):	dracut
+
+%description tools
+%{desc}
+This subpackage provides tools for support of all platforms.
+
+%ifarch x86_64
+%package tools-efi
+Summary:	Support tools for GRUB.
+Group:		System Environment/Base
+Requires:	gettext os-prober which file
+Requires:	%{name}-common = %{epoch}:%{version}-%{release}
+Obsoletes:	%{name}-tools < %{evr}
+
+%description tools-efi
+%{desc}
+This subpackage provides tools for support of EFI platforms.
+%endif
+
+%package tools-minimal
+Summary:	Support tools for GRUB.
+Group:		System Environment/Base
+Requires:	gettext
+Requires:	%{name}-common = %{epoch}:%{version}-%{release}
+Obsoletes:	%{name}-tools < %{evr}
+
+%description tools-minimal
+%{desc}
+This subpackage provides tools for support of all platforms.
+
+%package tools-extra
+Summary:	Support tools for GRUB.
+Group:		System Environment/Base
+Requires:	gettext os-prober which file
+Requires:	%{name}-tools-minimal = %{epoch}:%{version}-%{release}
+Requires:	%{name}-common = %{epoch}:%{version}-%{release}
+Obsoletes:	%{name}-tools < %{evr}
+
+%description tools-extra
+%{desc}
+This subpackage provides tools for support of all platforms.
+
+%if 0%{with_efi_arch}
+%{expand:%define_efi_variant %%{package_arch} -o}
+%endif
+%if 0%{with_alt_efi_arch}
+%{expand:%define_efi_variant %%{alt_package_arch}}
+%endif
+%if 0%{with_legacy_arch}
+%{expand:%define_legacy_variant %%{legacy_package_arch}}
+%endif
+
+%prep
+%do_common_setup
+%if 0%{with_efi_arch}
+mkdir grub-%{grubefiarch}-%{tarversion}
+grep -A100000 '# stuff "make" creates' .gitignore > grub-%{grubefiarch}-%{tarversion}/.gitignore
+cp %{SOURCE4} grub-%{grubefiarch}-%{tarversion}/unifont.pcf.gz
+git add grub-%{grubefiarch}-%{tarversion}
+%endif
+%if 0%{with_alt_efi_arch}
+mkdir grub-%{grubaltefiarch}-%{tarversion}
+grep -A100000 '# stuff "make" creates' .gitignore > grub-%{grubaltefiarch}-%{tarversion}/.gitignore
+cp %{SOURCE4} grub-%{grubaltefiarch}-%{tarversion}/unifont.pcf.gz
+git add grub-%{grubaltefiarch}-%{tarversion}
+%endif
+%if 0%{with_legacy_arch}
+mkdir grub-%{grublegacyarch}-%{tarversion}
+grep -A100000 '# stuff "make" creates' .gitignore > grub-%{grublegacyarch}-%{tarversion}/.gitignore
+cp %{SOURCE4} grub-%{grublegacyarch}-%{tarversion}/unifont.pcf.gz
+git add grub-%{grublegacyarch}-%{tarversion}
+%endif
+git commit -m "After making subdirs"
+
+%build
+%if 0%{with_efi_arch}
+%{expand:%do_primary_efi_build %%{grubefiarch} %%{grubefiname} %%{grubeficdname} %%{_target_platform} %%{efi_target_cflags} %%{efi_host_cflags} %{SOURCE13} %{SOURCE14} redhatsecureboot301}
+%endif
+%if 0%{with_alt_efi_arch}
+%{expand:%do_alt_efi_build %%{grubaltefiarch} %%{grubaltefiname} %%{grubalteficdname} %%{_alt_target_platform} %%{alt_efi_target_cflags} %%{alt_efi_host_cflags} %{SOURCE13} %{SOURCE14} redhatsecureboot301}
+%endif
+%if 0%{with_legacy_arch}
+%{expand:%do_legacy_build %%{grublegacyarch}}
+%endif
+makeinfo --info --no-split -I docs -o docs/grub-dev.info \
+	docs/grub-dev.texi
+makeinfo --info --no-split -I docs -o docs/grub.info \
+	docs/grub.texi
+makeinfo --html --no-split -I docs -o docs/grub-dev.html \
+	docs/grub-dev.texi
+makeinfo --html --no-split -I docs -o docs/grub.html \
+	docs/grub.texi
+
+%install
+set -e
+rm -fr $RPM_BUILD_ROOT
+
+%do_common_install
+%if 0%{with_efi_arch}
+%{expand:%do_efi_install %%{grubefiarch} %%{grubefiname} %%{grubeficdname}}
+%endif
+%if 0%{with_alt_efi_arch}
+%{expand:%do_alt_efi_install %%{grubaltefiarch} %%{grubaltefiname} %%{grubalteficdname}}
+%endif
+%if 0%{with_legacy_arch}
+%{expand:%do_legacy_install %%{grublegacyarch} %%{alt_grub_target_name} 0%{with_efi_arch}}
+%endif
+
+rm -f $RPM_BUILD_ROOT%{_infodir}/dir
+ln -s %{name}-set-password ${RPM_BUILD_ROOT}/%{_sbindir}/%{name}-setpassword
+echo '.so man8/%{name}-set-password.8' > ${RPM_BUILD_ROOT}/%{_datadir}/man/man8/%{name}-setpassword.8
+%ifnarch x86_64
+rm -vf ${RPM_BUILD_ROOT}/%{_bindir}/%{name}-render-label
+rm -vf ${RPM_BUILD_ROOT}/%{_sbindir}/%{name}-bios-setup
+rm -vf ${RPM_BUILD_ROOT}/%{_sbindir}/%{name}-macbless
+%endif
+
+%find_lang grub
+
+# Make selinux happy with exec stack binaries.
+mkdir ${RPM_BUILD_ROOT}%{_sysconfdir}/prelink.conf.d/
+cat << EOF > ${RPM_BUILD_ROOT}%{_sysconfdir}/prelink.conf.d/grub2.conf
+# these have execstack, and break under selinux
+-b /usr/bin/grub2-script-check
+-b /usr/bin/grub2-mkrelpath
+-b /usr/bin/grub2-fstest
+-b /usr/sbin/grub2-bios-setup
+-b /usr/sbin/grub2-probe
+-b /usr/sbin/grub2-sparc64-setup
+EOF
+
+# Install kernel-install scripts
+install -d -m 0755 %{buildroot}%{_prefix}/lib/kernel/install.d/
+install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ %{SOURCE9}
+install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ %{SOURCE12}
+install -d -m 0755 %{buildroot}%{_sysconfdir}/kernel/install.d/
+install -m 0644 /dev/null %{buildroot}%{_sysconfdir}/kernel/install.d/20-grubby.install
+install -m 0644 /dev/null %{buildroot}%{_sysconfdir}/kernel/install.d/90-loaderentry.install
+# Install systemd user service to set the boot_success flag
+install -D -m 0755 -t %{buildroot}%{_userunitdir} \
+	docs/grub-boot-success.{timer,service}
+install -d -m 0755 %{buildroot}%{_userunitdir}/timers.target.wants
+ln -s ../grub-boot-success.timer \
+	%{buildroot}%{_userunitdir}/timers.target.wants
+# Install systemd system-update unit to set boot_indeterminate for offline-upd
+install -D -m 0755 -t %{buildroot}%{_unitdir} docs/grub-boot-indeterminate.service
+install -d -m 0755 %{buildroot}%{_unitdir}/system-update.target.wants
+ln -s ../grub-boot-indeterminate.service \
+	%{buildroot}%{_unitdir}/system-update.target.wants
+
+# Don't run debuginfo on all the grub modules and whatnot; it just
+# rejects them, complains, and slows down extraction.
+%global finddebugroot "%{_builddir}/%{?buildsubdir}/debug"
+
+%global dip RPM_BUILD_ROOT=%{finddebugroot} %{__debug_install_post}
+%define __debug_install_post (						\
+	mkdir -p %{finddebugroot}/usr					\
+	mv ${RPM_BUILD_ROOT}/usr/bin %{finddebugroot}/usr/bin		\
+	mv ${RPM_BUILD_ROOT}/usr/sbin %{finddebugroot}/usr/sbin		\
+	%{dip}								\
+	install -m 0755 -d %{buildroot}/usr/lib/ %{buildroot}/usr/src/	\
+	cp -al %{finddebugroot}/usr/lib/debug/				\\\
+		%{buildroot}/usr/lib/debug/				\
+	cp -al %{finddebugroot}/usr/src/debug/				\\\
+		%{buildroot}/usr/src/debug/ )				\
+	mv %{finddebugroot}/usr/bin %{buildroot}/usr/bin		\
+	mv %{finddebugroot}/usr/sbin %{buildroot}/usr/sbin		\
+	%{nil}
+
+%undefine buildsubdir
+
+%pre tools
+if [ -f /boot/grub2/user.cfg ]; then
+    if grep -q '^GRUB_PASSWORD=' /boot/grub2/user.cfg ; then
+	sed -i 's/^GRUB_PASSWORD=/GRUB2_PASSWORD=/' /boot/grub2/user.cfg
+    fi
+elif [ -f %{efi_esp_dir}/user.cfg ]; then
+    if grep -q '^GRUB_PASSWORD=' %{efi_esp_dir}/user.cfg ; then
+	sed -i 's/^GRUB_PASSWORD=/GRUB2_PASSWORD=/' \
+	    %{efi_esp_dir}/user.cfg
+    fi
+elif [ -f /etc/grub.d/01_users ] && \
+	grep -q '^password_pbkdf2 root' /etc/grub.d/01_users ; then
+    if [ -f %{efi_esp_dir}/grub.cfg ]; then
+	# on EFI we don't get permissions on the file, but
+	# the directory is protected.
+	grep '^password_pbkdf2 root' /etc/grub.d/01_users | \
+		sed 's/^password_pbkdf2 root \(.*\)$/GRUB2_PASSWORD=\1/' \
+	    > %{efi_esp_dir}/user.cfg
+    fi
+    if [ -f /boot/grub2/grub.cfg ]; then
+	install -m 0600 /dev/null /boot/grub2/user.cfg
+	chmod 0600 /boot/grub2/user.cfg
+	grep '^password_pbkdf2 root' /etc/grub.d/01_users | \
+		sed 's/^password_pbkdf2 root \(.*\)$/GRUB2_PASSWORD=\1/' \
+	    > /boot/grub2/user.cfg
+    fi
+fi
+
+%post tools
+if [ "$1" = 1 ]; then
+	/sbin/install-info --info-dir=%{_infodir} %{_infodir}/%{name}.info.gz || :
+	/sbin/install-info --info-dir=%{_infodir} %{_infodir}/%{name}-dev.info.gz || :
+fi
+
+if [ "$1" = 2 ]; then
+	/sbin/grub2-switch-to-blscfg --backup-suffix=.rpmsave &>/dev/null || :
+fi
+
+%triggerun -- grub2 < 1:1.99-4
+# grub2 < 1.99-4 removed a number of essential files in postun. To fix upgrades
+# from the affected grub2 packages, we first back up the files in triggerun and
+# later restore them in triggerpostun.
+# https://bugzilla.redhat.com/show_bug.cgi?id=735259
+
+# Back up the files before uninstalling old grub2
+mkdir -p /boot/grub2.tmp &&
+mv -f /boot/grub2/*.mod \
+      /boot/grub2/*.img \
+      /boot/grub2/*.lst \
+      /boot/grub2/device.map \
+      /boot/grub2.tmp/ || :
+
+%triggerpostun -- grub2 < 1:1.99-4
+# ... and restore the files.
+test ! -f /boot/grub2/device.map &&
+test -d /boot/grub2.tmp &&
+mv -f /boot/grub2.tmp/*.mod \
+      /boot/grub2.tmp/*.img \
+      /boot/grub2.tmp/*.lst \
+      /boot/grub2.tmp/device.map \
+      /boot/grub2/ &&
+rm -r /boot/grub2.tmp/ || :
+
+%preun tools
+if [ "$1" = 0 ]; then
+	/sbin/install-info --delete --info-dir=%{_infodir} %{_infodir}/%{name}.info.gz || :
+	/sbin/install-info --delete --info-dir=%{_infodir} %{_infodir}/%{name}-dev.info.gz || :
+fi
+
+%files common -f grub.lang
+%dir %{_libdir}/grub/
+%dir %{_datarootdir}/grub/
+%dir %{_datarootdir}/grub/themes/
+%exclude %{_datarootdir}/grub/themes/*
+%attr(0700,root,root) %dir %{_sysconfdir}/grub.d
+%{_prefix}/lib/kernel/install.d/20-grub.install
+%{_sysconfdir}/kernel/install.d/20-grubby.install
+%{_sysconfdir}/kernel/install.d/90-loaderentry.install
+%{_prefix}/lib/kernel/install.d/99-grub-mkconfig.install
+%dir %{_datarootdir}/grub
+%exclude %{_datarootdir}/grub/*
+%dir /boot/%{name}
+%dir /boot/%{name}/themes/
+%dir /boot/%{name}/themes/system
+%exclude /boot/%{name}/themes/system/*
+%attr(0700,root,root) %dir /boot/grub2
+%exclude /boot/grub2/*
+%dir %attr(0700,root,root) %{efi_esp_dir}
+%exclude %{efi_esp_dir}/*
+%license COPYING
+%ghost %config(noreplace) /boot/grub2/grubenv
+%doc INSTALL
+%doc NEWS
+%doc README
+%doc THANKS
+%doc TODO
+%doc docs/grub.html
+%doc docs/grub-dev.html
+%doc docs/font_char_metrics.png
+
+%files tools-minimal
+%{_sysconfdir}/prelink.conf.d/grub2.conf
+%{_sbindir}/%{name}-get-kernel-settings
+%attr(4755, root, root) %{_sbindir}/%{name}-set-bootflag
+%{_sbindir}/%{name}-set-default
+%{_sbindir}/%{name}-set*password
+%{_bindir}/%{name}-editenv
+%{_bindir}/%{name}-mkpasswd-pbkdf2
+
+%{_datadir}/man/man3/%{name}-get-kernel-settings*
+%{_datadir}/man/man8/%{name}-set-default*
+%{_datadir}/man/man8/%{name}-set*password*
+%{_datadir}/man/man1/%{name}-editenv*
+%{_datadir}/man/man1/%{name}-mkpasswd-*
+
+%ifarch x86_64
+%files tools-efi
+%{_sbindir}/%{name}-macbless
+%{_bindir}/%{name}-render-label
+%{_datadir}/man/man8/%{name}-macbless*
+%{_datadir}/man/man1/%{name}-render-label*
+%endif
+
+%files tools
+%attr(0644,root,root) %ghost %config(noreplace) %{_sysconfdir}/default/grub
+%config %{_sysconfdir}/grub.d/??_*
+%ifarch ppc64 ppc64le
+%exclude %{_sysconfdir}/grub.d/10_linux
+%else
+%exclude %{_sysconfdir}/grub.d/10_linux_bls
+%endif
+%{_sysconfdir}/grub.d/README
+%{_userunitdir}/grub-boot-success.timer
+%{_userunitdir}/grub-boot-success.service
+%{_userunitdir}/timers.target.wants
+%{_unitdir}/grub-boot-indeterminate.service
+%{_unitdir}/system-update.target.wants
+%{_infodir}/%{name}*
+%{_datarootdir}/grub/*
+%{_sbindir}/%{name}-install
+%exclude %{_datarootdir}/grub/themes
+%exclude %{_datarootdir}/grub/*.h
+%{_datarootdir}/bash-completion/completions/grub
+%{_sbindir}/%{name}-mkconfig
+%{_sbindir}/%{name}-switch-to-blscfg
+%{_sbindir}/%{name}-probe
+%{_sbindir}/%{name}-rpm-sort
+%{_sbindir}/%{name}-reboot
+%{_bindir}/%{name}-file
+%{_bindir}/%{name}-menulst2cfg
+%{_bindir}/%{name}-mkimage
+%{_bindir}/%{name}-mkrelpath
+%{_bindir}/%{name}-script-check
+%{_datadir}/man/man?/*
+
+# exclude man pages from tools-extra
+%exclude %{_datadir}/man/man8/%{name}-sparc64-setup*
+%exclude %{_datadir}/man/man8/%{name}-install*
+%exclude %{_datadir}/man/man1/%{name}-fstest*
+%exclude %{_datadir}/man/man1/%{name}-glue-efi*
+%exclude %{_datadir}/man/man1/%{name}-kbdcomp*
+%exclude %{_datadir}/man/man1/%{name}-mkfont*
+%exclude %{_datadir}/man/man1/%{name}-mklayout*
+%exclude %{_datadir}/man/man1/%{name}-mknetdir*
+%exclude %{_datadir}/man/man1/%{name}-mkrescue*
+%exclude %{_datadir}/man/man1/%{name}-mkstandalone*
+%exclude %{_datadir}/man/man1/%{name}-syslinux2cfg*
+
+# exclude man pages from tools-minimal
+%exclude %{_datadir}/man/man3/%{name}-get-kernel-settings*
+%exclude %{_datadir}/man/man8/%{name}-set-default*
+%exclude %{_datadir}/man/man8/%{name}-set*password*
+%exclude %{_datadir}/man/man1/%{name}-editenv*
+%exclude %{_datadir}/man/man1/%{name}-mkpasswd-*
+%exclude %{_datadir}/man/man8/%{name}-macbless*
+%exclude %{_datadir}/man/man1/%{name}-render-label*
+
+%if %{with_legacy_arch}
+%{_sbindir}/%{name}-install
+%ifarch x86_64
+%{_sbindir}/%{name}-bios-setup
+%else
+%exclude %{_sbindir}/%{name}-bios-setup
+%exclude %{_datadir}/man/man8/%{name}-bios-setup*
+%endif
+%ifarch %{sparc}
+%{_sbindir}/%{name}-sparc64-setup
+%else
+%exclude %{_sbindir}/%{name}-sparc64-setup
+%exclude %{_datadir}/man/man8/%{name}-sparc64-setup*
+%endif
+%ifarch %{sparc} ppc ppc64 ppc64le
+%{_sbindir}/%{name}-ofpathname
+%else
+%exclude %{_sbindir}/%{name}-ofpathname
+%exclude %{_datadir}/man/man8/%{name}-ofpathname*
+%endif
+%endif
+
+%files tools-extra
+%{_sbindir}/%{name}-sparc64-setup
+%{_sbindir}/%{name}-ofpathname
+%{_bindir}/%{name}-fstest
+%{_bindir}/%{name}-glue-efi
+%{_bindir}/%{name}-kbdcomp
+%{_bindir}/%{name}-mkfont
+%{_bindir}/%{name}-mklayout
+%{_bindir}/%{name}-mknetdir
+%ifnarch %{sparc}
+%{_bindir}/%{name}-mkrescue
+%endif
+%{_bindir}/%{name}-mkstandalone
+%{_bindir}/%{name}-syslinux2cfg
+%{_sysconfdir}/sysconfig/grub
+%{_datadir}/man/man8/%{name}-sparc64-setup*
+%{_datadir}/man/man8/%{name}-install*
+%{_datadir}/man/man1/%{name}-fstest*
+%{_datadir}/man/man1/%{name}-glue-efi*
+%{_datadir}/man/man1/%{name}-kbdcomp*
+%{_datadir}/man/man1/%{name}-mkfont*
+%{_datadir}/man/man1/%{name}-mklayout*
+%{_datadir}/man/man1/%{name}-mknetdir*
+%{_datadir}/man/man1/%{name}-mkrescue*
+%{_datadir}/man/man1/%{name}-mkstandalone*
+%{_datadir}/man/man8/%{name}-ofpathname*
+%{_datadir}/man/man1/%{name}-syslinux2cfg*
+%exclude %{_datarootdir}/grub/themes/starfield
+
+%if 0%{with_efi_arch}
+%{expand:%define_efi_variant_files %%{package_arch} %%{grubefiname} %%{grubeficdname} %%{grubefiarch} %%{target_cpu_name} %%{grub_target_name}}
+%endif
+%if 0%{with_alt_efi_arch}
+%{expand:%define_efi_variant_files %%{alt_package_arch} %%{grubaltefiname} %%{grubalteficdname} %%{grubaltefiarch} %%{alt_target_cpu_name} %%{alt_grub_target_name}}
+%endif
+%if 0%{with_legacy_arch}
+%{expand:%define_legacy_variant_files %%{legacy_package_arch} %%{grublegacyarch}}
+%endif
+
+%changelog
+* Wed Dec 19 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-66
+- Fix grub.cfg-XXX look up when booting over TFTP
+  Resolves: rhbz#1658500
+
+* Mon Dec 17 2018 Peter Jones <pjones@redhat.com> - 2.02-65
+- Don't build the grub2-efi-ia32-* packages on i686; it causes multilib
+  errors and we don't ship the result anyway.
+  Related: rhbz#1637875
+
+* Tue Dec 11 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-64
+- Make grub2-mkconfig to honour GRUB_CMDLINE_LINUX in /etc/default/grub
+  Resolves: rhbz#1637875
+- docs: Stop using polkit / pkexec for grub-boot-success.timer / service
+  Resolves: rhbz#1655687
+
+* Tue Dec 04 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-63
+- BLS files should only be copied by grub-switch-to-blscfg if BLS isn't set
+  Related: rhbz#1638117
+- Fix get_entry_number() wrongly dereferencing the tail pointer
+  Resolves: rhbz#1654936
+
+* Fri Nov 30 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-62
+- Drop "Be more aggro about actually using the *configured* network device."
+  Resolves: rhbz#1654388
+- Fix menu entry selection based on title
+  Resolves: rhbz#1654936
+
+* Tue Nov 27 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-61
+- Drop buggy downstream patch "efinet: retransmit if our device is busy"
+  Resolves: rhbz#1649048
+- Make the menu entry users option argument to be optional
+  Related: rhbz#1652434
+- 10_linux_bls: add missing menu entries options
+  Resolves: rhbz#1652434
+
+* Wed Nov 21 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-60
+- Remove quotes when reading ID value from /etc/os-release
+  Related: rhbz#1650706
+- blscfg: expand grub_users before passing to grub_normal_add_menu_entry()
+  Resolves: rhbz#1650706
+
+* Thu Nov 08 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-59
+- Remove installkernel-bls script
+  Related: rhbz#1647721
+
+* Wed Oct 24 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-58
+- Don't unconditionally set default entry when installing debug kernels
+  Resolves: rhbz#1636346
+
+* Fri Oct 19 2018 Peter Jones <pjones@redhat.com> - 2.02-57
+- Fix menu entry selection based on ID and title
+  Resolves: rhbz#1640979
+
+* Fri Oct 19 2018 Javier Martinez Canillas <javierm@redhat.com>
+- don't set saved_entry on grub2-mkconfig
+  Resolves: rhbz#1636466
+
+* Tue Oct 16 2018 Peter Jones <pjones@redhat.com> - 2.02-56
+- Rebuild for signing
+  Resolves: rhbz#1625565
+- blscfg: Make 10_linux_bls sort the same way as well
+  Related: rhbz#1638103
+
+* Mon Oct 15 2018 Peter Jones <pjones@redhat.com> - 2.02-55
+- blscfg: sort everything with rpm *package* comparison
+  Related: rhbz#1638103
+
+* Thu Oct 11 2018 Peter Jones <pjones@redhat.com> - 2.02-54
+- kernel-install: Remove existing initramfs if it's older than the kernel
+  Resolves: rhbz#1638405
+- Update the saved entry correctly after a kernel install
+  Resolves: rhbz#1638117
+
+* Fri Oct 05 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-53
+- Only set kernelopts in grubenv if it wasn't set before
+  Resolves: rhbz#1636466
+
+* Thu Oct 04 2018 Peter Jones <pjones@redhat.com> - 2.02-52
+- Remove 01_fallback_counting entirely until we can sort its issues out.
+  Resolves: rhbz#1615954
+
+* Thu Oct 04 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-51
+- add 10_linux_bls grub.d snippet to generate menu entries from BLS files
+  Resolves: rhbz#1636013
+- Fix syntax issues in 01_fallback_counting.in
+  Resolves: rhbz#1615954
+
+* Mon Oct 01 2018 pjones <pjones@redhat.com> - 1:2.02-50
+- Disable TPM (again) on BIOS; it really does not work reliably.
+  Resolves: rhbz#1579835
+- Make blscfg module loadable on other grub2 builds
+  Resolves: rhbz#1633646
+- Include blscfg module on ppc builds
+  Related: rhbz#1633646
+- Fix rpmdiff complaints about execstack
+  Related: rhbz#1633646
+
+* Mon Sep 24 2018 Peter Jones <pjones@redhat.com> - 2.02-49
+- Add an installkernel script for BLS configurations
+  Related: rhbz#1619344
+
+* Fri Sep 14 2018 Peter Jones <pjones@redhat.com> - 2.02-48
+- Go back to forcing all allocations on x86_64 to be 32-bit, as many UEFI
+  implementations seem to have drivers with DMA issues for addresses
+  above 4GB.
+  Resolves: rhbz#1628346
+
+* Wed Sep 12 2018 Peter Jones <pjones@redhat.com> - 2.02-47
+- BLS fixes from the F29 tree
+  - Use /boot/loader/entries as BLS dir also on EFI systems
+  - Make 20-grub.install to exit if there is no machine ID set
+  - More fixes for BLS
+  Resolves: rhbz#1620954
+
+* Mon Aug 27 2018 Peter Jones <pjones@redhat.com> - 2.02-46
+- Better memory allocation for kernel/initramfs on aarch64
+  Resolves: rhbz#1620954
+
+* Tue Aug 14 2018 Peter Jones <pjones@redhat.com> - 2.02-45
+- Fix a typo in /etc/grub.d/01_fallback_counting
+  Resolves: rhbz#1615954
+
+* Thu Aug 09 2018 Peter Jones <pjones@redhat.com> - 2.02-44
+- Rebased to newer upstream for fedora-29
+
+* Thu Aug 09 2018 pjones <pjones@redhat.com> - 1:2.02-43
+- Rebased to newer upstream for fedora-29
+
+* Tue Jul 17 2018 Peter Jones <pjones@redhat.com> - 2.02-42
+- Fix some minor BLS issues
+- Rework the FDT module linking to make aarch64 build and boot right
+  Resolves: rhbz#1601835
+
+* Mon Jul 16 2018 pjones <pjones@redhat.com> - 2.02-41
+- Pull in newer sb patches that do a better job with config file writing
+
+* Mon Jul 16 2018 Hans de Goede <hdegoede@redhat.com>
+- Make the user session automatically set the boot_success grubenv flag
+- Make offline-updates increment the boot_indeterminate grubenv variable
+
+* Fri Jul 13 2018 Peter Jones <pjones@redhat.com> - 2.02-40
+- Revert broken moduledir fix in this tree as well.
+
+* Tue Jul 10 2018 pjones <pjones@redhat.com> - 2.02-39
+- Fix our linuxefi/linux command reunion.
+
+* Tue Jul 10 2018 pjones <pjones@redhat.com> - 2.02-38
+- Rebased to newer upstream for RHEL-8
+
+* Wed May 16 2018 Peter Jones <pjones@redhat.com> - 2.02-37
+- Fixups to work with gcc 8
+- Experimental https boot support on UEFI
+- XFS fixes for sparse inode support
+  Resolves: rhbz#1575797
+
+* Thu May 10 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-36
+- Use version field to sort BLS entries if id field isn't defined
+- Add version field to BLS fragments generated by 20-grub.install
+
+* Tue Apr 24 2018 Peter Jones <pjones@redhat.com> - 2.02-35
+- A couple of fixes needed by Fedora Atomic - javierm
+
+* Mon Apr 23 2018 Peter Jones <pjones@redhat.com> - 2.02-34
+- Put the os-prober dep back in - we need to change test plans and criteria
+  before it can go.
+  Resolves: rhbz#1569411
+
+* Wed Apr 11 2018 Peter Jones <pjones@redhat.com> - 2.02-33
+- Work around some issues with older automake found in CentOS.
+- Make multiple initramfs images work in BLS.
+
+* Wed Apr 11 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-32
+- Make 20-grub.install to generate debug BLS when MAKEDEBUG is set.
+
+* Fri Apr 06 2018 Peter Jones <pjones@redhat.com> - 2.02-31
+- Pull in some TPM fixes I missed.
+
+* Fri Apr 06 2018 Peter Jones <pjones@redhat.com> - 2.02-30
+- Enable TPM measurements
+- Set the default boot entry to the first entry when we're using BLS.
+
+* Tue Apr 03 2018 Peter Jones <pjones@redhat.com> - 2.02-29
+- Add grub2-switch-to-blscfg
+- Fix for BLS paths on BIOS / non-UEFI (javierm)
+
+* Fri Mar 09 2018 Javier Martinez Canillas <javierm@redhat.com> - 2.02-28
+- Install kernel-install scripts.
+
+* Tue Mar 06 2018 Peter Jones <pjones@redhat.com> - 2.02-27
+- Build the blscfg module in on EFI builds.
+
+* Wed Feb 28 2018 Peter Jones <pjones@redhat.com> - 2.02-26
+- Try to fix things for new compiler madness.
+  I really don't know why gcc decided __attribute__((packed)) on a "typedef
+  struct" should imply __attribute__((align (1))) and that it should have a
+  warning that it does so.  The obvious behavior would be to keep the alignment
+  of the first element unless it's used in another object or type that /also/
+  hask the packed attribute.  Why should it change the default alignment at
+  all?
+- Merge in the BLS patches Javier and I wrote.
+- Attempt to fix pmtimer initialization failures to not be super duper slow.
+
+* Fri Feb 09 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org>
+- Escape macros in %%changelog
+
+* Tue Jan 23 2018 Peter Jones <pjones@redhat.com> - 2.02-24
+- Fix a merge error from 2.02-21 that affected kernel loading on Aarch64.
+  Related: rhbz#1519311
+  Related: rhbz#1506704
+  Related: rhbz#1502312
+
+* Fri Jan 19 2018 Peter Jones <pjones@redhat.com> - 2.02-23
+- Only nerf annobin, not -fstack-crash-protection.
+- Fix a conflict on /boot/efi directory permissions between -cdboot and the
+  normal bootloader.
+
+* Thu Jan 18 2018 Peter Jones <pjones@redhat.com> - 2.02-22
+- Nerf some gcc 7.2.1-6 'features' that cause grub to crash on start.
+
+* Thu Jan 18 2018 Peter Jones <pjones@redhat.com> - 2.02-21
+- Fix grub2-efi-modules provides/obsoletes generation
+  Resolves: rhbz#1506704
+- *Also* build grub-efi-ia32{,-*,!-modules} packages for i686 builds
+  Resolves: rhbz#1502312
+- Make everything under /boot/efi be mode 0700, since that's what FAT will
+  show anyway.
+
+* Wed Jan 17 2018 Peter Jones <pjones@redhat.com> - 2.02-20
+- Update to newer upstream for F28
+- Pull in patches for Apollo Lake hardware
+  Resolves: rhbz#1519311
+
+* Tue Oct 24 2017 Peter Jones <pjones@redhat.com> - 2.02-19
+- Handle xen module loading (somewhat) better
+  Resolves: rhbz#1486002
+
+* Wed Sep 20 2017 Peter Jones <pjones@redhat.com> - 2.02-18
+- Make grub2-efi-aa64 provide grub2
+  Resolves: rhbz#1491045
+
+* Mon Sep 11 2017 Dennis Gilmore <dennis@ausil.us> - 2.02-17
+- bump for Obsoletes again
+
+* Wed Sep 06 2017 Peter Jones <pjones@redhat.com> - 2.02-16
+- Fix Obsoletes on grub2-pc
+
+* Wed Aug 30 2017 Petr Šabata <contyk@redhat.com> - 2.02-15
+- Limit the pattern matching in do_alt_efi_install to files to
+  unbreak module builds
+
+* Fri Aug 25 2017 Peter Jones <pjones@redhat.com> - 2.02-14
+- Revert the /usr/lib/.build-id/ change:
+  https://fedoraproject.org/wiki/Changes/ParallelInstallableDebuginfo
+  says (without any particularly convincing reasoning):
+    The main build-id file should not be in the debuginfo file, but in the
+    main package (this was always a problem since the package and debuginfo
+    package installed might not match). If we want to make usr/lib/debug/ a
+    network resource then we will need to move the symlink to another
+    location (maybe /usr/lib/.build-id).
+  So do it that way.  Of course it doesn't matter, because exclude gets
+  ignored due to implementation details.
+
+* Fri Aug 25 2017 Peter Jones <pjones@redhat.com> - 2.02-13
+- Add some unconditional Provides:
+  grub2-efi on grub2-efi-${arch}
+  grub2-efi-cdboot on grub2-efi-${arch}-cdboot
+  grub2 on all grub2-${arch} pacakges
+- Something is somehow adding /usr/lib/.build-id/... to all the -tools
+  subpackages, so exclude all that.
+
+* Thu Aug 24 2017 Peter Jones <pjones@redhat.com> - 2.02-12
+- Fix arm kernel command line allocation
+  Resolves: rhbz#1484609
+- Get rid of the temporary extra efi packages hack.
+
+* Wed Aug 23 2017 Peter Jones <pjones@redhat.com> - 2.02-11
+- Put grub2-mkimage in -tools, not -tools-extra.
+- Fix i686 building
+- Fix ppc HFS+ usage due to /boot/efi's presence.
+
+* Fri Aug 18 2017 Peter Jones <pjones@redhat.com> - 2.02-10
+- Add the .img files into grub2-pc-modules (and all legacy variants)
+
+* Wed Aug 16 2017 Peter Jones <pjones@redhat.com> - 2.02-9
+- Re-work for ia32-efi.
+
+* Wed Aug 16 2017 pjones <pjones@redhat.com> - 2.02-8
+- Rebased to newer upstream for fedora-27
+
+* Tue Aug 15 2017 Peter Jones <pjones@redhat.com> - 2.02-7
+- Rebuild again with new fixed rpm. (bug #1480407)
+
+* Fri Aug 11 2017 Kevin Fenzi <kevin@scrye.com> - 2.02-6
+- Rebuild again with new fixed rpm. (bug #1480407)
+
+* Thu Aug 10 2017 Kevin Fenzi <kevin@scrye.com> - 2.02-5
+- Rebuild for rpm soname bump again.
+
+* Thu Aug 10 2017 Igor Gnatenko <ignatenko@redhat.com> - 2.02-4
+- Rebuilt for RPM soname bump
+
+* Thu Aug 03 2017 Peter Jones <pjones@redhat.com> - 2.02-3
+- Rebuild so it gets SB signed correctly.
+  Related: rhbz#1335533
+- Enable lsefi
+
+* Mon Jul 24 2017 Michael Cronenworth <mike@cchtml.com> - 2.02-2
+- Fix symlink to work on both EFI and BIOS machines
+  Resolves: rhbz#1335533
+
+* Mon Jul 10 2017 Peter Jones <pjones@redhat.com> - 2.02-1
+- Rebased to newer upstream for fedora-27
+
+* Wed Feb 01 2017 Stephen Gallagher <sgallagh@redhat.com> - 2.02-0.39
+- Add missing %%license macro
+- Fix deps that should have moved to -tools but didn't.
+
+* Thu Dec 08 2016 Peter Jones <pjones@redhat.com> - 2.02-0.38
+- Fix regexp in power compile flags, and synchronize release number with
+  other branches.
+
+* Fri Dec 02 2016 pjones <pjones@redhat.com> - 1:2.02-0.37
+- Rebased to newer upstream for fedora-26
+
+* Thu Dec 01 2016 Peter Jones <pjones@redhat.com> - 2.02-0.36
+- Update version to .36 because I already built an f25 one named 0.35
+
+* Thu Dec 01 2016 pjones <pjones@redhat.com> - 1:2.02-0.35
+- Rebased to newer upstream for fedora-26
+
+* Thu Dec 01 2016 Peter Jones <pjones@redhat.com> - 2.02-0.34
+- Fix power6 makefile bits for newer autoconf defaults.
+- efi/chainloader: fix wrong sanity check in relocate_coff() (Laszlo Ersek)
+  Resolves: rhbz#1347291
+
+* Thu Aug 25 2016 Peter Jones <pjones@redhat.com> - 2.02-0.34
+- Update to be newer than f24's branch.
+- Add grub2-get-kernel-settings
+  Related: rhbz#1226325
+
+* Thu Apr 07 2016 pjones <pjones@redhat.com> - 1:2.02-0.30
+- Revert 27e66193, which was replaced by upstream's 49426e9fd
+  Resolves: rhbz#1251600
+
+* Thu Apr 07 2016 Peter Jones <pjones@redhat.com> - 2.02-0.29
+- Fix ppc64 build failure and rebase to newer f24 code.
+
+* Tue Apr 05 2016 pjones <pjones@redhat.com> - 1:2.02-0.27
+- Pull TPM updates from mjg59.
+  Resolves: rhbz#1318067
+
+* Tue Mar 08 2016 pjones <pjones@redhat.com> - 1:2.02-0.27
+- Fix aarch64 build problem.
+
+* Fri Mar 04 2016 Peter Jones <pjones@redhat.com> - 2.02-0.26
+- Rebased to newer upstream (grub-2.02-beta3) for fedora-24
+
+* Thu Dec 10 2015 Peter Jones <pjones@redhat.com> - 2.02-0.25
+- Fix security issue when reading username and password
+  Related: CVE-2015-8370
+- Do a better job of handling GRUB2_PASSWORD
+  Related: rhbz#1284370
+
+* Fri Nov 20 2015 Peter Jones <pjones@redhat.com> - 2.02-0.24
+- Rebuild without multiboot* modules in the EFI image.
+  Related: rhbz#1264103
+
+* Sat Sep 05 2015 Kalev Lember <klember@redhat.com> - 2.02-0.23
+- Rebuilt for librpm soname bump
+
+* Wed Aug 05 2015 Peter Jones <pjones@redhat.com> - 2.02-0.21
+- Back out one of the debuginfo generation patches; it doesn't work right on
+  aarch64 yet.
+  Resolves: rhbz#1250197
+
+* Mon Aug 03 2015 Peter Jones <pjones@redhat.com> - 2.02-0.20
+- The previous fix was completely not right, so fix it a different way.
+  Resolves: rhbz#1249668
+
+* Fri Jul 31 2015 Peter Jones <pjones@redhat.com> - 2.02-0.19
+- Fix grub2-mkconfig's sort to put kernels in the right order.
+  Related: rhbz#1124074
+
+* Thu Jul 30 2015 Peter Jones <pjones@redhat.com> - 2.02-0.18
+- Fix a build failure on aarch64
+
+* Wed Jul 22 2015 Peter Jones <pjones@redhat.com> - 2.02-0.17
+- Don't build hardened (fixes FTBFS) (pbrobinson)
+- Reconcile with the current upstream
+- Fixes for gcc 5
+
+* Tue Apr 28 2015 Peter Jones <pjones@redhat.com> - 2.02-0.16
+- Make grub2-mkconfig produce the kernel titles we actually want.
+  Resolves: rhbz#1215839
+
+* Sat Feb 21 2015 Till Maas <opensource@till.name>
+- Rebuilt for Fedora 23 Change
+  https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code
+
+* Mon Jan 05 2015 Peter Jones <pjones@redhat.com> - 2.02-0.15
+- Bump release to rebuild with Ralf Corsépius's fixes.
+
+* Sun Jan 04 2015 Ralf Corsépius <corsepiu@fedoraproject.org> - 2.02-0.14
+- Move grub2.info/grub2-dev.info install-info scriptlets into *-tools package.
+- Use sub-shell in %%__debug_install_post (RHBZ#1168732).
+- Cleanup grub2-starfield-theme packaging.
+
+* Thu Dec 04 2014 Peter Jones <pjones@redhat.com> - 2.02-0.13
+- Update minilzo to 2.08 for CVE-2014-4607
+  Resolves: rhbz#1131793
+
+* Thu Nov 13 2014 Peter Jones <pjones@redhat.com> - 2.02-0.12
+- Make backtrace and usb conditional on !arm
+- Make sure gcdaa64.efi is packaged.
+  Resolves: rhbz#1163481
+
+* Fri Nov 07 2014 Peter Jones <pjones@redhat.com> - 2.02-0.11
+- fix a copy-paste error in patch 0154.
+  Resolves: rhbz#964828
+
+* Mon Oct 27 2014 Peter Jones <pjones@redhat.com> - 2.02-0.10
+- Try to emit linux16/initrd16 and linuxefi/initrdefi when appropriate
+  in 30_os-prober.
+  Resolves: rhbz#1108296
+- If $fw_path doesn't work to find the config file, try $prefix as well
+  Resolves: rhbz#1148652
+
+* Mon Sep 29 2014 Peter Jones <pjones@redhat.com> - 2.02-0.9
+- Clean up the build a bit to make it faster
+- Make grubenv work right on UEFI machines
+  Related: rhbz#1119943
+- Sort debug and rescue kernels later than normal ones
+  Related: rhbz#1065360
+- Allow "fallback" to include entries by title as well as number.
+  Related: rhbz#1026084
+- Fix a segfault on aarch64.
+- Load arm with SB enabled if available.
+- Add some serial port options to GRUB_MODULES.
+
+* Tue Aug 19 2014 Peter Jones <pjones@redhat.com> - 2.02-0.8
+- Add ppc64le support.
+  Resolves: rhbz#1125540
+
+* Thu Jul 24 2014 Peter Jones <pjones@redhat.com> - 2.02-0.7
+- Enabled syslinuxcfg module.
+
+* Wed Jul 02 2014 Peter Jones <pjones@redhat.com> - 2.02-0.6
+- Re-merge RHEL 7 changes and ARM works in progress.
+
+* Mon Jun 30 2014 Peter Jones <pjones@redhat.com> - 2.02-0.5
+- Avoid munging raw spaces when we're escaping command line arguments.
+  Resolves: rhbz#923374
+
+* Tue Jun 24 2014 Peter Jones <pjones@redhat.com> - 2.02-0.4
+- Update to latest upstream.
+
+* Thu Mar 13 2014 Peter Jones <pjones@redhat.com> - 2.02-0.3
+- Merge in RHEL 7 changes and ARM works in progress.
+
+* Mon Jan 06 2014 Peter Jones <pjones@redhat.com> - 2.02-0.2
+- Update to grub-2.02~beta2
+
+* Sat Aug 10 2013 Peter Jones <pjones@redhat.com> - 2.00-25
+- Last build failed because of a hardware error on the builder.
+
+* Mon Aug 05 2013 Peter Jones <pjones@redhat.com> - 2.00-24
+- Fix compiler flags to deal with -fstack-protector-strong
+
+* Sat Aug 03 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1:2.00-24
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
+
+* Tue Jul 02 2013 Dennis Gilmore <dennis@ausil.us> - 2.00-23
+- add epoch to obsoletes
+
+* Fri Jun 21 2013 Peter Jones <pjones@redhat.com> - 2.00-22
+- Fix linewrapping in edit menu.
+  Resolves: rhbz #976643
+
+* Thu Jun 20 2013 Peter Jones <pjones@redhat.com> - 2.00-21
+- Fix obsoletes to pull in -starfield-theme subpackage when it should.
+
+* Fri Jun 14 2013 Peter Jones <pjones@redhat.com> - 2.00-20
+- Put the theme entirely ento the subpackage where it belongs (#974667)
+
+* Wed Jun 12 2013 Peter Jones <pjones@redhat.com> - 2.00-19
+- Rebase to upstream snapshot.
+- Fix PPC build error (#967862)
+- Fix crash on net_bootp command (#960624)
+- Reset colors on ppc when appropriate (#908519)
+- Left align "Loading..." messages (#908492)
+- Fix probing of SAS disks on PPC (#953954)
+- Add support for UEFI OSes returned by os-prober
+- Disable "video" mode on PPC for now (#973205)
+- Make grub fit better into the boot sequence, visually (#966719)
+
+* Fri May 10 2013 Matthias Clasen <mclasen@redhat.com> - 2.00-18
+- Move the starfield theme to a subpackage (#962004)
+- Don't allow SSE or MMX on UEFI builds (#949761)
+
+* Wed Apr 24 2013 Peter Jones <pjones@redhat.com> - 2.00-17.pj0
+- Rebase to upstream snapshot.
+
+* Thu Apr 04 2013 Peter Jones <pjones@redhat.com> - 2.00-17
+- Fix booting from drives with 4k sectors on UEFI.
+- Move bash completion to new location (#922997)
+- Include lvm support for /boot (#906203)
+
+* Thu Feb 14 2013 Peter Jones <pjones@redhat.com> - 2.00-16
+- Allow the user to disable submenu generation
+- (partially) support BLS-style configuration stanzas.
+
+* Tue Feb 12 2013 Peter Jones <pjones@redhat.com> - 2.00-15.pj0
+- Add various config file related changes.
+
+* Thu Dec 20 2012 Dennis Gilmore <dennis@ausil.us> - 2.00-15
+- bump nvr
+
+* Mon Dec 17 2012 Karsten Hopp <karsten@redhat.com> 2.00-14
+- add bootpath device to the device list (pfsmorigo, #886685)
+
+* Tue Nov 27 2012 Peter Jones <pjones@redhat.com> - 2.00-13
+- Add vlan tag support (pfsmorigo, #871563)
+- Follow symlinks during PReP installation in grub2-install (pfsmorigo, #874234)
+- Improve search paths for config files on network boot (pfsmorigo, #873406)
+
+* Tue Oct 23 2012 Peter Jones <pjones@redhat.com> - 2.00-12
+- Don't load modules when grub transitions to "normal" mode on UEFI.
+
+* Mon Oct 22 2012 Peter Jones <pjones@redhat.com> - 2.00-11
+- Rebuild with newer pesign so we'll get signed with the final signing keys.
+
+* Thu Oct 18 2012 Peter Jones <pjones@redhat.com> - 2.00-10
+- Various PPC fixes.
+- Fix crash fetching from http (gustavold, #860834)
+- Issue separate dns queries for ipv4 and ipv6 (gustavold, #860829)
+- Support IBM CAS reboot (pfsmorigo, #859223)
+- Include all modules in the core image on ppc (pfsmorigo, #866559)
+
+* Mon Oct 01 2012 Peter Jones <pjones@redhat.com> - 1:2.00-9
+- Work around bug with using "\x20" in linux command line.
+  Related: rhbz#855849
+
+* Thu Sep 20 2012 Peter Jones <pjones@redhat.com> - 2.00-8
+- Don't error on insmod on UEFI/SB, but also don't do any insmodding.
+- Increase device path size for ieee1275
+  Resolves: rhbz#857936
+- Make network booting work on ieee1275 machines.
+  Resolves: rhbz#857936
+
+* Wed Sep 05 2012 Matthew Garrett <mjg@redhat.com> - 2.00-7
+- Add Apple partition map support for EFI
+
+* Thu Aug 23 2012 David Cantrell <dcantrell@redhat.com> - 2.00-6
+- Only require pesign on EFI architectures (#851215)
+
+* Tue Aug 14 2012 Peter Jones <pjones@redhat.com> - 2.00-5
+- Work around AHCI firmware bug in efidisk driver.
+- Move to newer pesign macros
+- Don't allow insmod if we're in secure-boot mode.
+
+* Wed Aug 08 2012 Peter Jones <pjones@redhat.com>
+- Split module lists for UEFI boot vs UEFI cd images.
+- Add raid modules for UEFI image (related: #750794)
+- Include a prelink whitelist for binaries that need execstack (#839813)
+- Include fix efi memory map fix from upstream (#839363)
+
+* Wed Aug 08 2012 Peter Jones <pjones@redhat.com> - 2.00-4
+- Correct grub-mkimage invocation to use efidir RPM macro (jwb)
+- Sign with test keys on UEFI systems.
+- PPC - Handle device paths with commas correctly.
+  Related: rhbz#828740
+
+* Wed Jul 25 2012 Peter Jones <pjones@redhat.com> - 2.00-3
+- Add some more code to support Secure Boot, and temporarily disable
+  some other bits that don't work well enough yet.
+  Resolves: rhbz#836695
+
+* Wed Jul 11 2012 Matthew Garrett <mjg@redhat.com> - 2.00-2
+- Set a prefix for the image - needed for installer work
+- Provide the font in the EFI directory for the same reason
+
+* Thu Jun 28 2012 Peter Jones <pjones@redhat.com> - 2.00-1
+- Rebase to grub-2.00 release.
+
+* Mon Jun 18 2012 Peter Jones <pjones@redhat.com> - 2.0-0.37.beta6
+- Fix double-free in grub-probe.
+
+* Wed Jun 06 2012 Peter Jones <pjones@redhat.com> - 2.0-0.36.beta6
+- Build with patch19 applied.
+
+* Wed Jun 06 2012 Peter Jones <pjones@redhat.com> - 2.0-0.35.beta6
+- More ppc fixes.
+
+* Wed Jun 06 2012 Peter Jones <pjones@redhat.com> - 2.0-0.34.beta6
+- Add IBM PPC fixes.
+
+* Mon Jun 04 2012 Peter Jones <pjones@redhat.com> - 2.0-0.33.beta6
+- Update to beta6.
+- Various fixes from mads.
+
+* Fri May 25 2012 Peter Jones <pjones@redhat.com> - 2.0-0.32.beta5
+- Revert builddep change for crt1.o; it breaks ppc build.
+
+* Fri May 25 2012 Peter Jones <pjones@redhat.com> - 2.0-0.31.beta5
+- Add fwsetup command (pjones)
+- More ppc fixes (IBM)
+
+* Tue May 22 2012 Peter Jones <pjones@redhat.com> - 2.0-0.30.beta5
+- Fix the /other/ grub2-tools require to include epoch.
+
+* Mon May 21 2012 Peter Jones <pjones@redhat.com> - 2.0-0.29.beta5
+- Get rid of efi_uga and efi_gop, favoring all_video instead.
+
+* Mon May 21 2012 Peter Jones <pjones@redhat.com> - 2.0-0.28.beta5
+- Name grub.efi something that's arch-appropriate (kiilerix, pjones)
+- use EFI/$SOMETHING_DISTRO_BASED/ not always EFI/redhat/grub2-efi/ .
+- move common stuff to -tools (kiilerix)
+- spec file cleanups (kiilerix)
+
+* Mon May 14 2012 Peter Jones <pjones@redhat.com> - 2.0-0.27.beta5
+- Fix module trampolining on ppc (benh)
+
+* Thu May 10 2012 Peter Jones <pjones@redhat.com> - 2.0-0.27.beta5
+- Fix license of theme (mizmo)
+  Resolves: rhbz#820713
+- Fix some PPC bootloader detection IBM problem
+  Resolves: rhbz#820722
+
+* Thu May 10 2012 Peter Jones <pjones@redhat.com> - 2.0-0.26.beta5
+- Update to beta5.
+- Update how efi building works (kiilerix)
+- Fix theme support to bring in fonts correctly (kiilerix, pjones)
+
+* Wed May 09 2012 Peter Jones <pjones@redhat.com> - 2.0-0.25.beta4
+- Include theme support (mizmo)
+- Include locale support (kiilerix)
+- Include html docs (kiilerix)
+
+* Thu Apr 26 2012 Peter Jones <pjones@redhat.com> - 2.0-0.24
+- Various fixes from Mads Kiilerich
+
+* Thu Apr 19 2012 Peter Jones <pjones@redhat.com> - 2.0-0.23
+- Update to 2.00~beta4
+- Make fonts work so we can do graphics reasonably
+
+* Thu Mar 29 2012 David Aquilina <dwa@redhat.com> - 2.0-0.22
+- Fix ieee1275 platform define for ppc
+
+* Thu Mar 29 2012 Peter Jones <pjones@redhat.com> - 2.0-0.21
+- Remove ppc excludearch lines (dwa)
+- Update ppc terminfo patch (hamzy)
+
+* Wed Mar 28 2012 Peter Jones <pjones@redhat.com> - 2.0-0.20
+- Fix ppc64 vs ppc exclude according to what dwa tells me they need
+- Fix version number to better match policy.
+
+* Tue Mar 27 2012 Dan Horák <dan[at]danny.cz> - 1.99-19.2
+- Add support for serial terminal consoles on PPC by Mark Hamzy
+
+* Sun Mar 25 2012 Dan Horák <dan[at]danny.cz> - 1.99-19.1
+- Use Fix-tests-of-zeroed-partition patch by Mark Hamzy
+
+* Thu Mar 15 2012 Peter Jones <pjones@redhat.com> - 1.99-19
+- Use --with-grubdir= on configure to make it behave like -17 did.
+
+* Wed Mar 14 2012 Peter Jones <pjones@redhat.com> - 1.99-18
+- Rebase from 1.99 to 2.00~beta2
+
+* Wed Mar 07 2012 Peter Jones <pjones@redhat.com> - 1.99-17
+- Update for newer autotools and gcc 4.7.0
+  Related: rhbz#782144
+- Add /etc/sysconfig/grub link to /etc/default/grub
+  Resolves: rhbz#800152
+- ExcludeArch s390*, which is not supported by this package.
+  Resolves: rhbz#758333
+
+* Fri Feb 17 2012 Orion Poplawski <orion@cora.nwra.com> - 1:1.99-16
+- Build with -Os (bug 782144)
+
+* Fri Jan 13 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1:1.99-15
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Wed Dec 14 2011 Matthew Garrett <mjg@redhat.com> - 1.99-14
+- fix up various grub2-efi issues
+
+* Thu Dec 08 2011 Adam Williamson <awilliam@redhat.com> - 1.99-13
+- fix hardwired call to grub-probe in 30_os-prober (rhbz#737203)
+
+* Mon Nov 07 2011 Peter Jones <pjones@redhat.com> - 1.99-12
+- Lots of .spec fixes from Mads Kiilerich:
+  Remove comment about update-grub - it isn't run in any scriptlets
+  patch info pages so they can be installed and removed correctly when renamed
+  fix references to grub/grub2 renames in info pages (#743964)
+  update README.Fedora (#734090)
+  fix comments for the hack for upgrading from grub2 < 1.99-4
+  fix sed syntax error preventing use of $RPM_OPT_FLAGS (#704820)
+  make /etc/grub2*.cfg %%config(noreplace)
+  make grub.cfg %%ghost - an empty file is of no use anyway
+  create /etc/default/grub more like anaconda would create it (#678453)
+  don't create rescue entries by default - grubby will not maintain them anyway
+  set GRUB_SAVEDEFAULT=true so saved defaults works (rbhz#732058)
+  grub2-efi should have its own bash completion
+  don't set gfxpayload in efi mode - backport upstream r3402
+- Handle dmraid better. Resolves: rhbz#742226
+
+* Wed Oct 26 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1:1.99-11
+- Rebuilt for glibc bug#747377
+
+* Wed Oct 19 2011 Adam Williamson <awilliam@redhat.com> - 1.99-10
+- /etc/default/grub is explicitly intended for user customization, so
+  mark it as config(noreplace)
+
+* Tue Oct 11 2011 Peter Jones <pjones@redhat.com> - 1.99-9
+- grub has an epoch, so we need that expressed in the obsolete as well.
+  Today isn't my day.
+
+* Tue Oct 11 2011 Peter Jones <pjones@redhat.com> - 1.99-8
+- Fix my bad obsoletes syntax.
+
+* Thu Oct 06 2011 Peter Jones <pjones@redhat.com> - 1.99-7
+- Obsolete grub
+  Resolves: rhbz#743381
+
+* Wed Sep 14 2011 Peter Jones <pjones@redhat.com> - 1.99-6
+- Use mv not cp to try to avoid moving disk blocks around for -5 fix
+  Related: rhbz#735259
+- handle initramfs on xen better (patch from Marko Ristola)
+  Resolves: rhbz#728775
+
+* Sat Sep 03 2011 Kalev Lember <kalevlember@gmail.com> - 1.99-5
+- Fix upgrades from grub2 < 1.99-4 (#735259)
+
+* Fri Sep 02 2011 Peter Jones <pjones@redhat.com> - 1.99-4
+- Don't do sysadminny things in %%preun or %%post ever. (#735259)
+- Actually include the changelog in this build (sorry about -3)
+
+* Thu Sep 01 2011 Peter Jones <pjones@redhat.com> - 1.99-2
+- Require os-prober (#678456) (patch from Elad Alfassa)
+- Require which (#734959) (patch from Elad Alfassa)
+
+* Thu Sep 01 2011 Peter Jones <pjones@redhat.com> - 1.99-1
+- Update to grub-1.99 final.
+- Fix crt1.o require on x86-64 (fix from Mads Kiilerich)
+- Various CFLAGS fixes (from Mads Kiilerich)
+  - -fexceptions and -m64
+- Temporarily ignore translations (from Mads Kiilerich)
+
+* Thu Jul 21 2011 Peter Jones <pjones@redhat.com> - 1.99-0.3
+- Use /sbin not /usr/sbin .
+
+* Thu Jun 23 2011 Peter Lemenkov <lemenkov@gmail.com> - 1:1.99-0.2
+- Fixes for ppc and ppc64
+
+* Wed Feb 09 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1:1.98-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild