Blame SOURCES/0001-Add-support-for-Linux-EFI-stub-loading.patch

d9d99f
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
d9d99f
From: Matthew Garrett <mjg@redhat.com>
d9d99f
Date: Tue, 10 Jul 2012 11:58:52 -0400
d9d99f
Subject: [PATCH] Add support for Linux EFI stub loading.
d9d99f
d9d99f
Also:
d9d99f
d9d99f
commit 71c843745f22f81e16d259e2e19c99bf3c1855c1
d9d99f
Author: Colin Watson <cjwatson@ubuntu.com>
d9d99f
Date:   Tue Oct 23 10:40:49 2012 -0400
d9d99f
d9d99f
Don't allow insmod when secure boot is enabled.
d9d99f
d9d99f
Hi,
d9d99f
d9d99f
Fedora's patch to forbid insmod in UEFI Secure Boot environments is fine
d9d99f
as far as it goes.  However, the insmod command is not the only way that
d9d99f
modules can be loaded.  In particular, the 'normal' command, which
d9d99f
implements the usual GRUB menu and the fully-featured command prompt,
d9d99f
will implicitly load commands not currently loaded into memory.  This
d9d99f
permits trivial Secure Boot violations by writing commands implementing
d9d99f
whatever you want to do and pointing $prefix at the malicious code.
d9d99f
d9d99f
I'm currently test-building this patch (replacing your current
d9d99f
grub-2.00-no-insmod-on-sb.patch), but this should be more correct.  It
d9d99f
moves the check into grub_dl_load_file.
d9d99f
---
d9d99f
 grub-core/Makefile.core.def       |  16 +-
d9d99f
 grub-core/kern/dl.c               |  21 +++
d9d99f
 grub-core/kern/efi/efi.c          |  28 ++++
d9d99f
 grub-core/kern/efi/mm.c           |  32 ++++
d9d99f
 grub-core/loader/arm64/linux.c    | 118 +++++++-------
d9d99f
 grub-core/loader/arm64/xen_boot.c |   1 -
d9d99f
 grub-core/loader/efi/linux.c      |  70 ++++++++
d9d99f
 grub-core/loader/i386/efi/linux.c | 335 ++++++++++++++++++++++++++++++++++++++
d9d99f
 grub-core/loader/i386/pc/linux.c  |  10 +-
d9d99f
 include/grub/arm/linux.h          |   9 +
d9d99f
 include/grub/arm64/linux.h        |  10 ++
d9d99f
 include/grub/efi/efi.h            |   7 +-
d9d99f
 include/grub/efi/linux.h          |  31 ++++
d9d99f
 include/grub/i386/linux.h         |   1 +
d9d99f
 14 files changed, 620 insertions(+), 69 deletions(-)
d9d99f
 create mode 100644 grub-core/loader/efi/linux.c
d9d99f
 create mode 100644 grub-core/loader/i386/efi/linux.c
d9d99f
 create mode 100644 include/grub/efi/linux.h
d9d99f
d9d99f
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
b71686
index 9590e87d9..0b4b0c212 100644
d9d99f
--- a/grub-core/Makefile.core.def
d9d99f
+++ b/grub-core/Makefile.core.def
d9d99f
@@ -1626,13 +1626,6 @@ module = {
d9d99f
   enable = i386_pc;
d9d99f
 };
d9d99f
 
d9d99f
-
d9d99f
-module = {
d9d99f
-  name = linux16;
d9d99f
-  common = loader/i386/pc/linux.c;
d9d99f
-  enable = x86;
d9d99f
-};
d9d99f
-
d9d99f
 module = {
d9d99f
   name = ntldr;
d9d99f
   i386_pc = loader/i386/pc/ntldr.c;
d9d99f
@@ -1685,7 +1678,9 @@ module = {
d9d99f
 
d9d99f
 module = {
d9d99f
   name = linux;
d9d99f
-  x86 = loader/i386/linux.c;
d9d99f
+  i386_pc = loader/i386/pc/linux.c;
d9d99f
+  x86_64_efi = loader/i386/efi/linux.c;
d9d99f
+  i386_efi = loader/i386/efi/linux.c;
d9d99f
   xen = loader/i386/xen.c;
d9d99f
   i386_pc = lib/i386/pc/vesa_modes_table.c;
d9d99f
   mips = loader/mips/linux.c;
d9d99f
@@ -1696,9 +1691,14 @@ module = {
d9d99f
   arm_efi = loader/arm64/linux.c;
d9d99f
   arm_uboot = loader/arm/linux.c;
d9d99f
   arm64 = loader/arm64/linux.c;
d9d99f
+  emu = loader/emu/linux.c;
d9d99f
+  fdt = lib/fdt.c;
d9d99f
+
d9d99f
   common = loader/linux.c;
d9d99f
   common = lib/cmdline.c;
d9d99f
   enable = noemu;
d9d99f
+
d9d99f
+  efi = loader/efi/linux.c;
d9d99f
 };
d9d99f
 
d9d99f
 module = {
d9d99f
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
b71686
index e394cd96f..04e804d16 100644
d9d99f
--- a/grub-core/kern/dl.c
d9d99f
+++ b/grub-core/kern/dl.c
d9d99f
@@ -38,6 +38,14 @@
d9d99f
 #define GRUB_MODULES_MACHINE_READONLY
d9d99f
 #endif
d9d99f
 
d9d99f
+#ifdef GRUB_MACHINE_EMU
d9d99f
+#include <sys/mman.h>
d9d99f
+#endif
d9d99f
+
d9d99f
+#ifdef GRUB_MACHINE_EFI
d9d99f
+#include <grub/efi/efi.h>
d9d99f
+#endif
d9d99f
+
d9d99f
 
d9d99f
 
d9d99f
 #pragma GCC diagnostic ignored "-Wcast-align"
d9d99f
@@ -686,6 +694,19 @@ grub_dl_load_file (const char *filename)
d9d99f
   void *core = 0;
d9d99f
   grub_dl_t mod = 0;
d9d99f
 
d9d99f
+#ifdef GRUB_MACHINE_EFI
d9d99f
+  if (grub_efi_secure_boot ())
d9d99f
+    {
d9d99f
+#if 0
d9d99f
+      /* This is an error, but grub2-mkconfig still generates a pile of
d9d99f
+       * insmod commands, so emitting it would be mostly just obnoxious. */
d9d99f
+      grub_error (GRUB_ERR_ACCESS_DENIED,
d9d99f
+		  "Secure Boot forbids loading module from %s", filename);
d9d99f
+#endif
d9d99f
+      return 0;
d9d99f
+    }
d9d99f
+#endif
d9d99f
+
d9d99f
   grub_boot_time ("Loading module %s", filename);
d9d99f
 
d9d99f
   file = grub_file_open (filename);
d9d99f
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
b71686
index 708581fcb..c8a9d8307 100644
d9d99f
--- a/grub-core/kern/efi/efi.c
d9d99f
+++ b/grub-core/kern/efi/efi.c
d9d99f
@@ -273,6 +273,34 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid,
d9d99f
   return NULL;
d9d99f
 }
d9d99f
 
d9d99f
+grub_efi_boolean_t
d9d99f
+grub_efi_secure_boot (void)
d9d99f
+{
d9d99f
+  grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID;
d9d99f
+  grub_size_t datasize;
d9d99f
+  char *secure_boot = NULL;
d9d99f
+  char *setup_mode = NULL;
d9d99f
+  grub_efi_boolean_t ret = 0;
d9d99f
+
d9d99f
+  secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize);
d9d99f
+
d9d99f
+  if (datasize != 1 || !secure_boot)
d9d99f
+    goto out;
d9d99f
+
d9d99f
+  setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize);
d9d99f
+
d9d99f
+  if (datasize != 1 || !setup_mode)
d9d99f
+    goto out;
d9d99f
+
d9d99f
+  if (*secure_boot && !*setup_mode)
d9d99f
+    ret = 1;
d9d99f
+
d9d99f
+ out:
d9d99f
+  grub_free (secure_boot);
d9d99f
+  grub_free (setup_mode);
d9d99f
+  return ret;
d9d99f
+}
d9d99f
+
d9d99f
 #pragma GCC diagnostic ignored "-Wcast-align"
d9d99f
 
d9d99f
 /* Search the mods section from the PE32/PE32+ image. This code uses
d9d99f
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
b71686
index 42ad7c570..5cdf6c943 100644
d9d99f
--- a/grub-core/kern/efi/mm.c
d9d99f
+++ b/grub-core/kern/efi/mm.c
d9d99f
@@ -113,6 +113,38 @@ grub_efi_drop_alloc (grub_efi_physical_address_t address,
d9d99f
     }
d9d99f
 }
d9d99f
 
d9d99f
+/* Allocate pages below a specified address */
d9d99f
+void *
d9d99f
+grub_efi_allocate_pages_max (grub_efi_physical_address_t max,
d9d99f
+			     grub_efi_uintn_t pages)
d9d99f
+{
d9d99f
+  grub_efi_status_t status;
d9d99f
+  grub_efi_boot_services_t *b;
d9d99f
+  grub_efi_physical_address_t address = max;
d9d99f
+
d9d99f
+  if (max > 0xffffffff)
d9d99f
+    return 0;
d9d99f
+
d9d99f
+  b = grub_efi_system_table->boot_services;
d9d99f
+  status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
d9d99f
+
d9d99f
+  if (status != GRUB_EFI_SUCCESS)
d9d99f
+    return 0;
d9d99f
+
d9d99f
+  if (address == 0)
d9d99f
+    {
d9d99f
+      /* Uggh, the address 0 was allocated... This is too annoying,
d9d99f
+	 so reallocate another one.  */
d9d99f
+      address = max;
d9d99f
+      status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address);
d9d99f
+      grub_efi_free_pages (0, pages);
d9d99f
+      if (status != GRUB_EFI_SUCCESS)
d9d99f
+	return 0;
d9d99f
+    }
d9d99f
+
d9d99f
+  return (void *) ((grub_addr_t) address);
d9d99f
+}
d9d99f
+
d9d99f
 /* Allocate pages. Return the pointer to the first of allocated pages.  */
d9d99f
 void *
d9d99f
 grub_efi_allocate_pages_real (grub_efi_physical_address_t address,
d9d99f
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
b71686
index 1f86229f8..6c00af98d 100644
d9d99f
--- a/grub-core/loader/arm64/linux.c
d9d99f
+++ b/grub-core/loader/arm64/linux.c
d9d99f
@@ -29,6 +29,7 @@
d9d99f
 #include <grub/efi/efi.h>
d9d99f
 #include <grub/efi/fdtload.h>
d9d99f
 #include <grub/efi/memory.h>
d9d99f
+#include <grub/efi/linux.h>
d9d99f
 #include <grub/efi/pe32.h>
d9d99f
 #include <grub/i18n.h>
d9d99f
 #include <grub/lib/cmdline.h>
d9d99f
@@ -40,6 +41,7 @@ static int loaded;
d9d99f
 
d9d99f
 static void *kernel_addr;
d9d99f
 static grub_uint64_t kernel_size;
d9d99f
+static grub_uint32_t handover_offset;
d9d99f
 
d9d99f
 static char *linux_args;
d9d99f
 static grub_uint32_t cmdline_size;
d9d99f
@@ -66,7 +68,8 @@ grub_armxx_efi_linux_check_image (struct linux_armxx_kernel_header * lh)
d9d99f
 static grub_err_t
d9d99f
 finalize_params_linux (void)
d9d99f
 {
d9d99f
-  int node, retval;
d9d99f
+  grub_efi_loaded_image_t *loaded_image = NULL;
d9d99f
+  int node, retval, len;
d9d99f
 
d9d99f
   void *fdt;
d9d99f
 
d9d99f
@@ -101,79 +104,70 @@ finalize_params_linux (void)
d9d99f
   if (grub_fdt_install() != GRUB_ERR_NONE)
d9d99f
     goto failure;
d9d99f
 
d9d99f
-  return GRUB_ERR_NONE;
d9d99f
-
d9d99f
-failure:
d9d99f
-  grub_fdt_unload();
d9d99f
-  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
d9d99f
-}
d9d99f
-
d9d99f
-grub_err_t
d9d99f
-grub_armxx_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args)
d9d99f
-{
d9d99f
-  grub_efi_memory_mapped_device_path_t *mempath;
d9d99f
-  grub_efi_handle_t image_handle;
d9d99f
-  grub_efi_boot_services_t *b;
d9d99f
-  grub_efi_status_t status;
d9d99f
-  grub_efi_loaded_image_t *loaded_image;
d9d99f
-  int len;
d9d99f
-
d9d99f
-  mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t));
d9d99f
-  if (!mempath)
d9d99f
-    return grub_errno;
d9d99f
-
d9d99f
-  mempath[0].header.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE;
d9d99f
-  mempath[0].header.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE;
d9d99f
-  mempath[0].header.length = grub_cpu_to_le16_compile_time (sizeof (*mempath));
d9d99f
-  mempath[0].memory_type = GRUB_EFI_LOADER_DATA;
d9d99f
-  mempath[0].start_address = addr;
d9d99f
-  mempath[0].end_address = addr + size;
d9d99f
-
d9d99f
-  mempath[1].header.type = GRUB_EFI_END_DEVICE_PATH_TYPE;
d9d99f
-  mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
d9d99f
-  mempath[1].header.length = sizeof (grub_efi_device_path_t);
d9d99f
-
d9d99f
-  b = grub_efi_system_table->boot_services;
d9d99f
-  status = b->load_image (0, grub_efi_image_handle,
d9d99f
-			  (grub_efi_device_path_t *) mempath,
d9d99f
-			  (void *) addr, size, &image_handle);
d9d99f
-  if (status != GRUB_EFI_SUCCESS)
d9d99f
-    return grub_error (GRUB_ERR_BAD_OS, "cannot load image");
d9d99f
-
d9d99f
-  grub_dprintf ("linux", "linux command line: '%s'\n", args);
d9d99f
+  grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
d9d99f
+		fdt);
d9d99f
 
d9d99f
   /* Convert command line to UCS-2 */
d9d99f
-  loaded_image = grub_efi_get_loaded_image (image_handle);
d9d99f
+  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
d9d99f
+  if (!loaded_image)
d9d99f
+    goto failure;
d9d99f
+
d9d99f
   loaded_image->load_options_size = len =
d9d99f
-    (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t);
d9d99f
+    (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t);
d9d99f
   loaded_image->load_options =
d9d99f
     grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
d9d99f
   if (!loaded_image->load_options)
d9d99f
-    return grub_errno;
d9d99f
+    return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters");
d9d99f
 
d9d99f
   loaded_image->load_options_size =
d9d99f
     2 * grub_utf8_to_utf16 (loaded_image->load_options, len,
d9d99f
-			    (grub_uint8_t *) args, len, NULL);
d9d99f
+			    (grub_uint8_t *) linux_args, len, NULL);
d9d99f
 
d9d99f
-  grub_dprintf ("linux", "starting image %p\n", image_handle);
d9d99f
-  status = b->start_image (image_handle, 0, NULL);
d9d99f
+  return GRUB_ERR_NONE;
d9d99f
 
d9d99f
-  /* When successful, not reached */
d9d99f
-  b->unload_image (image_handle);
d9d99f
-  grub_efi_free_pages ((grub_addr_t) loaded_image->load_options,
d9d99f
-		       GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
d9d99f
+failure:
d9d99f
+  grub_fdt_unload();
d9d99f
+  return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT");
d9d99f
+}
d9d99f
 
d9d99f
-  return grub_errno;
d9d99f
+static void
d9d99f
+free_params (void)
d9d99f
+{
d9d99f
+  grub_efi_loaded_image_t *loaded_image = NULL;
d9d99f
+
d9d99f
+  loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
d9d99f
+  if (loaded_image)
d9d99f
+    {
d9d99f
+      if (loaded_image->load_options)
d9d99f
+	grub_efi_free_pages ((grub_efi_physical_address_t)(grub_efi_uintn_t)loaded_image->load_options,
d9d99f
+			     GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size));
d9d99f
+      loaded_image->load_options = NULL;
d9d99f
+      loaded_image->load_options_size = 0;
d9d99f
+    }
d9d99f
+}
d9d99f
+
d9d99f
+grub_err_t
d9d99f
+grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args)
d9d99f
+{
d9d99f
+  grub_err_t retval;
d9d99f
+
d9d99f
+  retval = finalize_params_linux ();
d9d99f
+  if (retval != GRUB_ERR_NONE)
d9d99f
+    return grub_errno;
d9d99f
+
d9d99f
+  grub_dprintf ("linux", "linux command line: '%s'\n", args);
d9d99f
+
d9d99f
+  retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr);
d9d99f
+
d9d99f
+  /* Never reached... */
d9d99f
+  free_params();
d9d99f
+  return retval;
d9d99f
 }
d9d99f
 
d9d99f
 static grub_err_t
d9d99f
 grub_linux_boot (void)
d9d99f
 {
d9d99f
-  if (finalize_params_linux () != GRUB_ERR_NONE)
d9d99f
-    return grub_errno;
d9d99f
-
d9d99f
-  return (grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr,
d9d99f
-                                          kernel_size, linux_args));
d9d99f
+  return grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args);
d9d99f
 }
d9d99f
 
d9d99f
 static grub_err_t
d9d99f
@@ -287,6 +281,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
d9d99f
 {
d9d99f
   grub_file_t file = 0;
d9d99f
   struct linux_armxx_kernel_header lh;
d9d99f
+  struct grub_armxx_linux_pe_header *pe;
d9d99f
 
d9d99f
   grub_dl_ref (my_mod);
d9d99f
 
d9d99f
@@ -331,6 +326,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
d9d99f
 
d9d99f
   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
d9d99f
 
d9d99f
+  if (!grub_linuxefi_secure_validate (kernel_addr, kernel_size))
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
d9d99f
+  handover_offset = pe->opt.entry_addr;
d9d99f
+
d9d99f
   cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
d9d99f
   linux_args = grub_malloc (cmdline_size);
d9d99f
   if (!linux_args)
d9d99f
diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
b71686
index 1003a0b99..f35b16caa 100644
d9d99f
--- a/grub-core/loader/arm64/xen_boot.c
d9d99f
+++ b/grub-core/loader/arm64/xen_boot.c
d9d99f
@@ -266,7 +266,6 @@ xen_boot (void)
d9d99f
     return err;
d9d99f
 
d9d99f
   return grub_armxx_efi_linux_boot_image (xen_hypervisor->start,
d9d99f
-					  xen_hypervisor->size,
d9d99f
 					  xen_hypervisor->cmdline);
d9d99f
 }
d9d99f
 
d9d99f
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
d9d99f
new file mode 100644
b71686
index 000000000..c24202a5d
d9d99f
--- /dev/null
d9d99f
+++ b/grub-core/loader/efi/linux.c
d9d99f
@@ -0,0 +1,70 @@
d9d99f
+/*
d9d99f
+ *  GRUB  --  GRand Unified Bootloader
d9d99f
+ *  Copyright (C) 2014 Free Software Foundation, Inc.
d9d99f
+ *
d9d99f
+ *  GRUB is free software: you can redistribute it and/or modify
d9d99f
+ *  it under the terms of the GNU General Public License as published by
d9d99f
+ *  the Free Software Foundation, either version 3 of the License, or
d9d99f
+ *  (at your option) any later version.
d9d99f
+ *
d9d99f
+ *  GRUB is distributed in the hope that it will be useful,
d9d99f
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
d9d99f
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d9d99f
+ *  GNU General Public License for more details.
d9d99f
+ *
d9d99f
+ *  You should have received a copy of the GNU General Public License
d9d99f
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
d9d99f
+ */
d9d99f
+
d9d99f
+#include <grub/err.h>
d9d99f
+#include <grub/mm.h>
d9d99f
+#include <grub/types.h>
d9d99f
+#include <grub/cpu/linux.h>
d9d99f
+#include <grub/efi/efi.h>
d9d99f
+#include <grub/efi/pe32.h>
d9d99f
+#include <grub/efi/linux.h>
d9d99f
+
d9d99f
+#define SHIM_LOCK_GUID \
d9d99f
+ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
d9d99f
+
d9d99f
+struct grub_efi_shim_lock
d9d99f
+{
d9d99f
+  grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size);
d9d99f
+};
d9d99f
+typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
d9d99f
+
d9d99f
+grub_efi_boolean_t
d9d99f
+grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
d9d99f
+{
d9d99f
+  grub_efi_guid_t guid = SHIM_LOCK_GUID;
d9d99f
+  grub_efi_shim_lock_t *shim_lock;
d9d99f
+
d9d99f
+  shim_lock = grub_efi_locate_protocol(&guid, NULL);
d9d99f
+
d9d99f
+  if (!shim_lock)
d9d99f
+    return 1;
d9d99f
+
d9d99f
+  if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
d9d99f
+    return 1;
d9d99f
+
d9d99f
+  return 0;
d9d99f
+}
d9d99f
+
d9d99f
+#pragma GCC diagnostic push
d9d99f
+#pragma GCC diagnostic ignored "-Wcast-align"
d9d99f
+
d9d99f
+typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
d9d99f
+
d9d99f
+grub_err_t
d9d99f
+grub_efi_linux_boot (void *kernel_addr, grub_off_t offset,
d9d99f
+		     void *kernel_params)
d9d99f
+{
d9d99f
+  handover_func hf;
d9d99f
+
d9d99f
+  hf = (handover_func)((char *)kernel_addr + offset);
d9d99f
+  hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
d9d99f
+
d9d99f
+  return GRUB_ERR_BUG;
d9d99f
+}
d9d99f
+
d9d99f
+#pragma GCC diagnostic pop
d9d99f
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
d9d99f
new file mode 100644
b71686
index 000000000..3db82e782
d9d99f
--- /dev/null
d9d99f
+++ b/grub-core/loader/i386/efi/linux.c
d9d99f
@@ -0,0 +1,335 @@
d9d99f
+/*
d9d99f
+ *  GRUB  --  GRand Unified Bootloader
d9d99f
+ *  Copyright (C) 2012  Free Software Foundation, Inc.
d9d99f
+ *
d9d99f
+ *  GRUB is free software: you can redistribute it and/or modify
d9d99f
+ *  it under the terms of the GNU General Public License as published by
d9d99f
+ *  the Free Software Foundation, either version 3 of the License, or
d9d99f
+ *  (at your option) any later version.
d9d99f
+ *
d9d99f
+ *  GRUB is distributed in the hope that it will be useful,
d9d99f
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
d9d99f
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d9d99f
+ *  GNU General Public License for more details.
d9d99f
+ *
d9d99f
+ *  You should have received a copy of the GNU General Public License
d9d99f
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
d9d99f
+ */
d9d99f
+
d9d99f
+#include <grub/loader.h>
d9d99f
+#include <grub/file.h>
d9d99f
+#include <grub/err.h>
d9d99f
+#include <grub/types.h>
d9d99f
+#include <grub/mm.h>
d9d99f
+#include <grub/cpu/linux.h>
d9d99f
+#include <grub/command.h>
d9d99f
+#include <grub/i18n.h>
d9d99f
+#include <grub/lib/cmdline.h>
d9d99f
+#include <grub/efi/efi.h>
d9d99f
+#include <grub/efi/linux.h>
d9d99f
+
d9d99f
+GRUB_MOD_LICENSE ("GPLv3+");
d9d99f
+
d9d99f
+static grub_dl_t my_mod;
d9d99f
+static int loaded;
d9d99f
+static void *kernel_mem;
d9d99f
+static grub_uint64_t kernel_size;
d9d99f
+static grub_uint8_t *initrd_mem;
d9d99f
+static grub_uint32_t handover_offset;
d9d99f
+struct linux_kernel_params *params;
d9d99f
+static char *linux_cmdline;
d9d99f
+
d9d99f
+#define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> 12)
d9d99f
+
d9d99f
+static grub_err_t
d9d99f
+grub_linuxefi_boot (void)
d9d99f
+{
d9d99f
+  int offset = 0;
d9d99f
+
d9d99f
+#ifdef __x86_64__
d9d99f
+  offset = 512;
d9d99f
+#endif
d9d99f
+  asm volatile ("cli");
d9d99f
+
d9d99f
+  return grub_efi_linux_boot ((char *)kernel_mem, handover_offset + offset,
d9d99f
+			      params);
d9d99f
+}
d9d99f
+
d9d99f
+static grub_err_t
d9d99f
+grub_linuxefi_unload (void)
d9d99f
+{
d9d99f
+  grub_dl_unref (my_mod);
d9d99f
+  loaded = 0;
d9d99f
+  if (initrd_mem)
d9d99f
+    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem,
d9d99f
+			 BYTES_TO_PAGES(params->ramdisk_size));
d9d99f
+  if (linux_cmdline)
d9d99f
+    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)
d9d99f
+			 linux_cmdline,
d9d99f
+			 BYTES_TO_PAGES(params->cmdline_size + 1));
d9d99f
+  if (kernel_mem)
d9d99f
+    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem,
d9d99f
+			 BYTES_TO_PAGES(kernel_size));
d9d99f
+  if (params)
d9d99f
+    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params,
d9d99f
+			 BYTES_TO_PAGES(16384));
d9d99f
+  return GRUB_ERR_NONE;
d9d99f
+}
d9d99f
+
d9d99f
+static grub_err_t
d9d99f
+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
d9d99f
+                 int argc, char *argv[])
d9d99f
+{
d9d99f
+  grub_file_t *files = 0;
d9d99f
+  int i, nfiles = 0;
d9d99f
+  grub_size_t size = 0;
d9d99f
+  grub_uint8_t *ptr;
d9d99f
+
d9d99f
+  if (argc == 0)
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  if (!loaded)
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  files = grub_zalloc (argc * sizeof (files[0]));
d9d99f
+  if (!files)
d9d99f
+    goto fail;
d9d99f
+
d9d99f
+  for (i = 0; i < argc; i++)
d9d99f
+    {
d9d99f
+      grub_file_filter_disable_compression ();
d9d99f
+      files[i] = grub_file_open (argv[i]);
d9d99f
+      if (! files[i])
d9d99f
+        goto fail;
d9d99f
+      nfiles++;
d9d99f
+      size += ALIGN_UP (grub_file_size (files[i]), 4);
d9d99f
+    }
d9d99f
+
d9d99f
+  initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size));
d9d99f
+  if (!initrd_mem)
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd"));
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  params->ramdisk_size = size;
d9d99f
+  params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem;
d9d99f
+
d9d99f
+  ptr = initrd_mem;
d9d99f
+
d9d99f
+  for (i = 0; i < nfiles; i++)
d9d99f
+    {
d9d99f
+      grub_ssize_t cursize = grub_file_size (files[i]);
d9d99f
+      if (grub_file_read (files[i], ptr, cursize) != cursize)
d9d99f
+        {
d9d99f
+          if (!grub_errno)
d9d99f
+            grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
d9d99f
+                        argv[i]);
d9d99f
+          goto fail;
d9d99f
+        }
d9d99f
+      ptr += cursize;
d9d99f
+      grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
d9d99f
+      ptr += ALIGN_UP_OVERHEAD (cursize, 4);
d9d99f
+    }
d9d99f
+
d9d99f
+  params->ramdisk_size = size;
d9d99f
+
d9d99f
+ fail:
d9d99f
+  for (i = 0; i < nfiles; i++)
d9d99f
+    grub_file_close (files[i]);
d9d99f
+  grub_free (files);
d9d99f
+
d9d99f
+  if (initrd_mem && grub_errno)
d9d99f
+    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem,
d9d99f
+			 BYTES_TO_PAGES(size));
d9d99f
+
d9d99f
+  return grub_errno;
d9d99f
+}
d9d99f
+
d9d99f
+static grub_err_t
d9d99f
+grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
d9d99f
+		int argc, char *argv[])
d9d99f
+{
d9d99f
+  grub_file_t file = 0;
d9d99f
+  struct linux_kernel_header lh;
d9d99f
+  grub_ssize_t len, start, filelen;
d9d99f
+  void *kernel = NULL;
d9d99f
+
d9d99f
+  grub_dl_ref (my_mod);
d9d99f
+
d9d99f
+  if (argc == 0)
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  file = grub_file_open (argv[0]);
d9d99f
+  if (! file)
d9d99f
+    goto fail;
d9d99f
+
d9d99f
+  filelen = grub_file_size (file);
d9d99f
+
d9d99f
+  kernel = grub_malloc(filelen);
d9d99f
+
d9d99f
+  if (!kernel)
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer"));
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  if (grub_file_read (file, kernel, filelen) != filelen)
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]);
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  if (! grub_linuxefi_secure_validate (kernel, filelen))
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"),
d9d99f
+		  argv[0]);
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384));
d9d99f
+
d9d99f
+  if (! params)
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters");
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  grub_memset (params, 0, 16384);
d9d99f
+
d9d99f
+  grub_memcpy (&lh, kernel, sizeof (lh));
d9d99f
+
d9d99f
+  if (lh.boot_flag != grub_cpu_to_le16 (0xaa55))
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number"));
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors"));
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  if (lh.version < grub_cpu_to_le16 (0x020b))
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_BAD_OS, N_("kernel too old"));
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  if (!lh.handover_offset)
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover"));
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  grub_dprintf ("linux", "setting up cmdline\n");
d9d99f
+  linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff,
d9d99f
+					 BYTES_TO_PAGES(lh.cmdline_size + 1));
d9d99f
+
d9d99f
+  if (!linux_cmdline)
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline"));
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
d9d99f
+  grub_create_loader_cmdline (argc, argv,
d9d99f
+                              linux_cmdline + sizeof (LINUX_IMAGE) - 1,
d9d99f
+			      lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1));
d9d99f
+
d9d99f
+  lh.cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline;
d9d99f
+
d9d99f
+  handover_offset = lh.handover_offset;
d9d99f
+
d9d99f
+  start = (lh.setup_sects + 1) * 512;
d9d99f
+  len = grub_file_size(file) - start;
d9d99f
+
d9d99f
+  kernel_mem = grub_efi_allocate_pages_max(lh.pref_address,
d9d99f
+					   BYTES_TO_PAGES(lh.init_size));
d9d99f
+
d9d99f
+  if (!kernel_mem)
d9d99f
+    kernel_mem = grub_efi_allocate_pages_max(0x3fffffff,
d9d99f
+					     BYTES_TO_PAGES(lh.init_size));
d9d99f
+
d9d99f
+  if (!kernel_mem)
d9d99f
+    {
d9d99f
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel"));
d9d99f
+      goto fail;
d9d99f
+    }
d9d99f
+
d9d99f
+  grub_memcpy (kernel_mem, (char *)kernel + start, len);
d9d99f
+  grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0);
d9d99f
+  loaded=1;
d9d99f
+
d9d99f
+  lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem;
d9d99f
+  grub_memcpy (params, &lh, 2 * 512);
d9d99f
+
d9d99f
+  params->type_of_loader = 0x21;
d9d99f
+
d9d99f
+ fail:
d9d99f
+
d9d99f
+  if (file)
d9d99f
+    grub_file_close (file);
d9d99f
+
d9d99f
+  if (kernel)
d9d99f
+    grub_free (kernel);
d9d99f
+
d9d99f
+  if (grub_errno != GRUB_ERR_NONE)
d9d99f
+    {
d9d99f
+      grub_dl_unref (my_mod);
d9d99f
+      loaded = 0;
d9d99f
+    }
d9d99f
+
d9d99f
+  if (linux_cmdline && !loaded)
d9d99f
+    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)
d9d99f
+			 linux_cmdline,
d9d99f
+			 BYTES_TO_PAGES(lh.cmdline_size + 1));
d9d99f
+
d9d99f
+  if (kernel_mem && !loaded)
d9d99f
+    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem,
d9d99f
+			 BYTES_TO_PAGES(kernel_size));
d9d99f
+
d9d99f
+  if (params && !loaded)
d9d99f
+    grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params,
d9d99f
+			 BYTES_TO_PAGES(16384));
d9d99f
+
d9d99f
+  return grub_errno;
d9d99f
+}
d9d99f
+
d9d99f
+static grub_command_t cmd_linux, cmd_initrd;
d9d99f
+static grub_command_t cmd_linuxefi, cmd_initrdefi;
d9d99f
+
d9d99f
+GRUB_MOD_INIT(linux)
d9d99f
+{
d9d99f
+  cmd_linux =
d9d99f
+    grub_register_command ("linux", grub_cmd_linux,
d9d99f
+                           0, N_("Load Linux."));
d9d99f
+  cmd_linuxefi =
d9d99f
+    grub_register_command ("linuxefi", grub_cmd_linux,
d9d99f
+                           0, N_("Load Linux."));
d9d99f
+  cmd_initrd =
d9d99f
+    grub_register_command ("initrd", grub_cmd_initrd,
d9d99f
+                           0, N_("Load initrd."));
d9d99f
+  cmd_initrdefi =
d9d99f
+    grub_register_command ("initrdefi", grub_cmd_initrd,
d9d99f
+                           0, N_("Load initrd."));
d9d99f
+  my_mod = mod;
d9d99f
+}
d9d99f
+
d9d99f
+GRUB_MOD_FINI(linux)
d9d99f
+{
d9d99f
+  grub_unregister_command (cmd_linux);
d9d99f
+  grub_unregister_command (cmd_linuxefi);
d9d99f
+  grub_unregister_command (cmd_initrd);
d9d99f
+  grub_unregister_command (cmd_initrdefi);
d9d99f
+}
d9d99f
diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
b71686
index b69cb7a3a..a3c87cf2f 100644
d9d99f
--- a/grub-core/loader/i386/pc/linux.c
d9d99f
+++ b/grub-core/loader/i386/pc/linux.c
d9d99f
@@ -468,14 +468,20 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
d9d99f
   return grub_errno;
d9d99f
 }
d9d99f
 
d9d99f
-static grub_command_t cmd_linux, cmd_initrd;
d9d99f
+static grub_command_t cmd_linux, cmd_linux16, cmd_initrd, cmd_initrd16;
d9d99f
 
d9d99f
 GRUB_MOD_INIT(linux16)
d9d99f
 {
d9d99f
   cmd_linux =
d9d99f
+    grub_register_command ("linux", grub_cmd_linux,
d9d99f
+			   0, N_("Load Linux."));
d9d99f
+  cmd_linux16 =
d9d99f
     grub_register_command ("linux16", grub_cmd_linux,
d9d99f
 			   0, N_("Load Linux."));
d9d99f
   cmd_initrd =
d9d99f
+    grub_register_command ("initrd", grub_cmd_initrd,
d9d99f
+			   0, N_("Load initrd."));
d9d99f
+  cmd_initrd16 =
d9d99f
     grub_register_command ("initrd16", grub_cmd_initrd,
d9d99f
 			   0, N_("Load initrd."));
d9d99f
   my_mod = mod;
d9d99f
@@ -484,5 +490,7 @@ GRUB_MOD_INIT(linux16)
d9d99f
 GRUB_MOD_FINI(linux16)
d9d99f
 {
d9d99f
   grub_unregister_command (cmd_linux);
d9d99f
+  grub_unregister_command (cmd_linux16);
d9d99f
   grub_unregister_command (cmd_initrd);
d9d99f
+  grub_unregister_command (cmd_initrd16);
d9d99f
 }
d9d99f
diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h
b71686
index 712ba17b9..5900fc8a4 100644
d9d99f
--- a/include/grub/arm/linux.h
d9d99f
+++ b/include/grub/arm/linux.h
d9d99f
@@ -20,6 +20,7 @@
d9d99f
 #ifndef GRUB_ARM_LINUX_HEADER
d9d99f
 #define GRUB_ARM_LINUX_HEADER 1
d9d99f
 
d9d99f
+#include <grub/efi/pe32.h>
d9d99f
 #include "system.h"
d9d99f
 
d9d99f
 #define GRUB_LINUX_ARM_MAGIC_SIGNATURE 0x016f2818
d9d99f
@@ -34,9 +35,17 @@ struct linux_arm_kernel_header {
d9d99f
   grub_uint32_t hdr_offset;
d9d99f
 };
d9d99f
 
d9d99f
+struct grub_arm_linux_pe_header
d9d99f
+{
d9d99f
+  grub_uint32_t magic;
d9d99f
+  struct grub_pe32_coff_header coff;
d9d99f
+  struct grub_pe32_optional_header opt;
d9d99f
+};
d9d99f
+
d9d99f
 #if defined(__arm__)
d9d99f
 # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM_MAGIC_SIGNATURE
d9d99f
 # define linux_armxx_kernel_header linux_arm_kernel_header
d9d99f
+# define grub_armxx_linux_pe_header grub_arm_linux_pe_header
d9d99f
 #endif
d9d99f
 
d9d99f
 #if defined GRUB_MACHINE_UBOOT
d9d99f
diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h
b71686
index 8655067e0..7b533b571 100644
d9d99f
--- a/include/grub/arm64/linux.h
d9d99f
+++ b/include/grub/arm64/linux.h
d9d99f
@@ -19,6 +19,8 @@
d9d99f
 #ifndef GRUB_ARM64_LINUX_HEADER
d9d99f
 #define GRUB_ARM64_LINUX_HEADER 1
d9d99f
 
d9d99f
+#include <grub/efi/pe32.h>
d9d99f
+
d9d99f
 #define GRUB_LINUX_ARM64_MAGIC_SIGNATURE 0x644d5241 /* 'ARM\x64' */
d9d99f
 
d9d99f
 /* From linux/Documentation/arm64/booting.txt */
d9d99f
@@ -36,9 +38,17 @@ struct linux_arm64_kernel_header
d9d99f
   grub_uint32_t hdr_offset;	/* Offset of PE/COFF header */
d9d99f
 };
d9d99f
 
d9d99f
+struct grub_arm64_linux_pe_header
d9d99f
+{
d9d99f
+  grub_uint32_t magic;
d9d99f
+  struct grub_pe32_coff_header coff;
d9d99f
+  struct grub_pe64_optional_header opt;
d9d99f
+};
d9d99f
+
d9d99f
 #if defined(__aarch64__)
d9d99f
 # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM64_MAGIC_SIGNATURE
d9d99f
 # define linux_armxx_kernel_header linux_arm64_kernel_header
d9d99f
+# define grub_armxx_linux_pe_header grub_arm64_linux_pe_header
d9d99f
 #endif
d9d99f
 
d9d99f
 #endif /* ! GRUB_ARM64_LINUX_HEADER */
d9d99f
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
b71686
index 2c6648d46..1061aee97 100644
d9d99f
--- a/include/grub/efi/efi.h
d9d99f
+++ b/include/grub/efi/efi.h
d9d99f
@@ -47,6 +47,9 @@ EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address,
d9d99f
 				      grub_efi_uintn_t pages);
d9d99f
 void *
d9d99f
 EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages);
d9d99f
+void *
d9d99f
+EXPORT_FUNC(grub_efi_allocate_pages_max) (grub_efi_physical_address_t max,
d9d99f
+					  grub_efi_uintn_t pages);
d9d99f
 void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address,
d9d99f
 				       grub_efi_uintn_t pages);
d9d99f
 grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void);
d9d99f
@@ -82,6 +85,7 @@ EXPORT_FUNC (grub_efi_set_variable) (const char *var,
d9d99f
 				     const grub_efi_guid_t *guid,
d9d99f
 				     void *data,
d9d99f
 				     grub_size_t datasize);
d9d99f
+grub_efi_boolean_t EXPORT_FUNC (grub_efi_secure_boot) (void);
d9d99f
 int
d9d99f
 EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1,
d9d99f
 					     const grub_efi_device_path_t *dp2);
d9d99f
@@ -95,8 +99,7 @@ void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void);
d9d99f
 grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *);
d9d99f
 #include <grub/cpu/linux.h>
d9d99f
 grub_err_t grub_armxx_efi_linux_check_image(struct linux_armxx_kernel_header *lh);
d9d99f
-grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, grub_size_t size,
d9d99f
-                                           char *args);
d9d99f
+grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, char *args);
d9d99f
 #endif
d9d99f
 
d9d99f
 grub_addr_t grub_efi_modules_addr (void);
d9d99f
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
d9d99f
new file mode 100644
b71686
index 000000000..d9ede3677
d9d99f
--- /dev/null
d9d99f
+++ b/include/grub/efi/linux.h
d9d99f
@@ -0,0 +1,31 @@
d9d99f
+/*
d9d99f
+ *  GRUB  --  GRand Unified Bootloader
d9d99f
+ *  Copyright (C) 2014  Free Software Foundation, Inc.
d9d99f
+ *
d9d99f
+ *  GRUB is free software: you can redistribute it and/or modify
d9d99f
+ *  it under the terms of the GNU General Public License as published by
d9d99f
+ *  the Free Software Foundation, either version 3 of the License, or
d9d99f
+ *  (at your option) any later version.
d9d99f
+ *
d9d99f
+ *  GRUB is distributed in the hope that it will be useful,
d9d99f
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
d9d99f
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d9d99f
+ *  GNU General Public License for more details.
d9d99f
+ *
d9d99f
+ *  You should have received a copy of the GNU General Public License
d9d99f
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
d9d99f
+ */
d9d99f
+#ifndef GRUB_EFI_LINUX_HEADER
d9d99f
+#define GRUB_EFI_LINUX_HEADER	1
d9d99f
+
d9d99f
+#include <grub/efi/api.h>
d9d99f
+#include <grub/err.h>
d9d99f
+#include <grub/symbol.h>
d9d99f
+
d9d99f
+grub_efi_boolean_t
d9d99f
+EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size);
d9d99f
+grub_err_t
d9d99f
+EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset,
d9d99f
+				  void *kernel_param);
d9d99f
+
d9d99f
+#endif /* ! GRUB_EFI_LINUX_HEADER */
d9d99f
diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h
b71686
index 60c7c3b5e..bb19dbd5a 100644
d9d99f
--- a/include/grub/i386/linux.h
d9d99f
+++ b/include/grub/i386/linux.h
d9d99f
@@ -142,6 +142,7 @@ struct linux_i386_kernel_header
d9d99f
   grub_uint64_t setup_data;
d9d99f
   grub_uint64_t pref_address;
d9d99f
   grub_uint32_t init_size;
d9d99f
+  grub_uint32_t handover_offset;
d9d99f
 } GRUB_PACKED;
d9d99f
 
d9d99f
 /* Boot parameters for Linux based on 2.6.12. This is used by the setup