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