6b2dd0f
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
ad4aff0
From: Raymund Will <rw@suse.com>
e153146
Date: Mon, 8 Jul 2019 11:55:18 +0200
31cddd6
Subject: [PATCH] Add secureboot support on efi chainloader
b9efc54
b9efc54
Expand the chainloader to be able to verify the image by means of shim
b9efc54
lock protocol. The PE/COFF image is loaded and relocated by the
b9efc54
chainloader instead of calling LoadImage and StartImage UEFI boot
b9efc54
Service as they require positive verification result from keys enrolled
b9efc54
in KEK or DB. The shim will use MOK in addition to firmware enrolled
b9efc54
keys to verify the image.
b9efc54
b9efc54
The chainloader module could be used to load other UEFI bootloaders,
b9efc54
such as xen.efi, and could be signed by any of MOK, KEK or DB.
b9efc54
b9efc54
Based on https://build.opensuse.org/package/view_file/openSUSE:Factory/grub2/grub2-secureboot-chainloader.patch
b9efc54
b9efc54
Signed-off-by: Peter Jones <pjones@redhat.com>
ad4aff0
ad4aff0
Also:
ad4aff0
ad4aff0
commit cd7a8984d4fda905877b5bfe466339100156b3bc
ad4aff0
Author: Raymund Will <rw@suse.com>
ad4aff0
Date:   Fri Apr 10 01:45:02 2015 -0400
ad4aff0
ad4aff0
Use device part of chainloader target, if present.
ad4aff0
ad4aff0
Otherwise chainloading is restricted to '$root', which might not even
ad4aff0
be readable by EFI!
ad4aff0
ad4aff0
v1. use grub_file_get_device_name() to get device name
ad4aff0
ad4aff0
Signed-off-by: Michael Chang <mchang@suse.com>
ad4aff0
Signed-off-by: Peter Jones <pjones@redhat.com>
ad4aff0
ad4aff0
Also:
ad4aff0
ad4aff0
commit 0872a2310a0eeac4ecfe9e1b49dd2d72ab373039
ad4aff0
Author: Peter Jones <pjones@redhat.com>
ad4aff0
Date:   Fri Jun 10 14:06:15 2016 -0400
ad4aff0
ad4aff0
Rework even more of efi chainload so non-sb cases work right.
ad4aff0
ad4aff0
This ensures that if shim protocol is not loaded, or is loaded but shim
ad4aff0
is disabled, we will fall back to a correct load method for the efi
ad4aff0
chain loader.
ad4aff0
ad4aff0
Here's what I tested with this version:
ad4aff0
ad4aff0
results                             expected    actual
ad4aff0
------------------------------------------------------------
ad4aff0
sb + enabled + shim + fedora        success     success
ad4aff0
sb + enabled + shim + win           success     success
ad4aff0
sb + enabled + grub + fedora        fail        fail
ad4aff0
sb + enabled + grub + win           fail        fail
ad4aff0
ad4aff0
sb + mokdisabled + shim + fedora    success     success
ad4aff0
sb + mokdisabled + shim + win       success     success
ad4aff0
sb + mokdisabled + grub + fedora    fail        fail
ad4aff0
sb + mokdisabled + grub + win       fail        fail
ad4aff0
ad4aff0
sb disabled + shim + fedora         success     success*
ad4aff0
sb disabled + shim + win            success     success*
ad4aff0
sb disabled + grub + fedora         success     success
ad4aff0
sb disabled + grub + win            success     success
ad4aff0
ad4aff0
nosb + shim + fedora                success     success*
ad4aff0
nosb + shim + win                   success     success*
ad4aff0
nosb + grub + fedora                success     success
ad4aff0
nosb + grub + win                   success     success
ad4aff0
ad4aff0
* for some reason shim protocol is being installed in these cases, and I
ad4aff0
  can't see why, but I think it may be this firmware build returning an
ad4aff0
  erroneous value.  But this effectively falls back to the mokdisabled
ad4aff0
  behavior, which works correctly, and the presence of the "grub" (i.e.
ad4aff0
  no shim) tests effectively tests the desired behavior here.
ad4aff0
ad4aff0
Resolves: rhbz#1344512
ad4aff0
ad4aff0
Signed-off-by: Peter Jones <pjones@redhat.com>
ad4aff0
ad4aff0
Also:
ad4aff0
ad4aff0
commit ff7b1cb7f69487870211aeb69ff4f54470fbcb58
ad4aff0
Author: Laszlo Ersek <lersek@redhat.com>
ad4aff0
Date:   Mon Nov 21 15:34:00 2016 +0100
ad4aff0
ad4aff0
efi/chainloader: fix wrong sanity check in relocate_coff()
ad4aff0
ad4aff0
In relocate_coff(), the relocation entries are parsed from the original
ad4aff0
image (not the section-wise copied image). The original image is
ad4aff0
pointed-to by the "orig" pointer. The current check
ad4aff0
ad4aff0
  (void *)reloc_end < data
ad4aff0
ad4aff0
compares the addresses of independent memory allocations. "data" is a typo
ad4aff0
here, it should be "orig".
ad4aff0
ad4aff0
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1347291
ad4aff0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
ad4aff0
Tested-by: Bogdan Costescu <bcostescu@gmail.com>
ad4aff0
Tested-by: Juan Orti <j.orti.alcaine@gmail.com>
ad4aff0
ad4aff0
Also:
ad4aff0
ad4aff0
commit ab4ba9997ad4832449e54d930fa2aac6a160d0e9
ad4aff0
Author: Laszlo Ersek <lersek@redhat.com>
ad4aff0
Date:   Wed Nov 23 06:27:09 2016 +0100
ad4aff0
ad4aff0
efi/chainloader: truncate overlong relocation section
ad4aff0
ad4aff0
The UEFI Windows 7 boot loader ("EFI/Microsoft/Boot/bootmgfw.efi", SHA1
ad4aff0
31b410e029bba87d2068c65a80b88882f9f8ea25) has inconsistent headers.
ad4aff0
ad4aff0
Compare:
ad4aff0
ad4aff0
> The Data Directory
ad4aff0
> ...
ad4aff0
> Entry 5 00000000000d9000 00000574 Base Relocation Directory [.reloc]
ad4aff0
ad4aff0
Versus:
ad4aff0
ad4aff0
> Sections:
ad4aff0
> Idx Name      Size      VMA               LMA               File off ...
ad4aff0
> ...
ad4aff0
>  10 .reloc    00000e22  00000000100d9000  00000000100d9000  000a1800 ...
ad4aff0
ad4aff0
That is, the size reported by the RelocDir entry (0x574) is smaller than
ad4aff0
the virtual size of the .reloc section (0xe22).
ad4aff0
ad4aff0
Quoting the grub2 debug log for the same:
ad4aff0
ad4aff0
> chainloader.c:595: reloc_dir: 0xd9000 reloc_size: 0x00000574
ad4aff0
> chainloader.c:603: reloc_base: 0x7d208000 reloc_base_end: 0x7d208573
ad4aff0
> ...
ad4aff0
> chainloader.c:620: Section 10 ".reloc" at 0x7d208000..0x7d208e21
ad4aff0
> chainloader.c:661:  section is not reloc section?
ad4aff0
> chainloader.c:663:  rds: 0x00001000, vs: 00000e22
ad4aff0
> chainloader.c:664:  base: 0x7d208000 end: 0x7d208e21
ad4aff0
> chainloader.c:666:  reloc_base: 0x7d208000 reloc_base_end: 0x7d208573
ad4aff0
> chainloader.c:671:  Section characteristics are 42000040
ad4aff0
> chainloader.c:673:  Section virtual size: 00000e22
ad4aff0
> chainloader.c:675:  Section raw_data size: 00001000
ad4aff0
> chainloader.c:678:  Discarding section
ad4aff0
ad4aff0
After hexdumping "bootmgfw.efi" and manually walking its relocation blocks
ad4aff0
(yes, really), I determined that the (smaller) RelocDir value is correct.
ad4aff0
The remaining area that extends up to the .reloc section size (== 0xe22 -
ad4aff0
0x574 == 0x8ae bytes) exists as zero padding in the file.
ad4aff0
ad4aff0
This zero padding shouldn't be passed to relocate_coff() for parsing. In
ad4aff0
order to cope with it, split the handling of .reloc sections into the
ad4aff0
following branches:
ad4aff0
ad4aff0
- original case (equal size): original behavior (--> relocation
ad4aff0
  attempted),
ad4aff0
ad4aff0
- overlong .reloc section (longer than reported by RelocDir): truncate the
ad4aff0
  section to the RelocDir size for the purposes of relocate_coff(), and
ad4aff0
  attempt relocation,
ad4aff0
ad4aff0
- .reloc section is too short, or other checks fail: original behavior
ad4aff0
  (--> relocation not attempted).
ad4aff0
ad4aff0
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1347291
ad4aff0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
e602a06
e602a06
Also:
e602a06
e602a06
commit cc06f149fbd2d8c1da1e83173d21629ba97e0d92
e602a06
Author: Raymund Will <rw@suse.com>
e602a06
e602a06
chainloader: Define machine types for RISC-V
e602a06
e602a06
The commit "Add secureboot support on efi chainloader" didn't add machine
e602a06
types for RISC-V, so this patch adds them.
e602a06
e602a06
Note, that grub-core/loader/riscv/linux.c is skipped because Linux is not
e602a06
supported yet. This patch might need a new revision once that's the case.
e602a06
e602a06
Signed-off-by: David Abdurachmanov <david.abdurachmanov@sifive.com>
b9efc54
---
ad4aff0
 grub-core/kern/efi/efi.c           |  14 +-
ad4aff0
 grub-core/loader/arm64/linux.c     |   4 +-
e602a06
 grub-core/loader/efi/chainloader.c | 820 +++++++++++++++++++++++++++++++++----
ad4aff0
 grub-core/loader/efi/linux.c       |  25 +-
ad4aff0
 grub-core/loader/i386/efi/linux.c  |  17 +-
ad4aff0
 include/grub/efi/linux.h           |   2 +-
ad4aff0
 include/grub/efi/pe32.h            |  52 ++-
e602a06
 7 files changed, 844 insertions(+), 90 deletions(-)
b9efc54
ad4aff0
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
e622855
index 35b8f67060..4a2259aa1c 100644
ad4aff0
--- a/grub-core/kern/efi/efi.c
ad4aff0
+++ b/grub-core/kern/efi/efi.c
46968b6
@@ -296,14 +296,20 @@ grub_efi_secure_boot (void)
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
+      grub_dprintf ("secureboot", "No SecureBoot variable\n");
ad4aff0
+      goto out;
ad4aff0
+    }
ad4aff0
+  grub_dprintf ("secureboot", "SecureBoot: %d\n", *secure_boot);
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
+      grub_dprintf ("secureboot", "No SetupMode variable\n");
ad4aff0
+      goto out;
ad4aff0
+    }
ad4aff0
+  grub_dprintf ("secureboot", "SetupMode: %d\n", *setup_mode);
ad4aff0
 
ad4aff0
   if (*secure_boot && !*setup_mode)
ad4aff0
     ret = 1;
ad4aff0
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
e622855
index a312c66868..04994d5c67 100644
ad4aff0
--- a/grub-core/loader/arm64/linux.c
ad4aff0
+++ b/grub-core/loader/arm64/linux.c
e153146
@@ -284,6 +284,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
e153146
   struct linux_arch_kernel_header lh;
dbfd2e6
   struct grub_armxx_linux_pe_header *pe;
e153146
   grub_err_t err;
ad4aff0
+  int rc;
ad4aff0
 
ad4aff0
   grub_dl_ref (my_mod);
ad4aff0
 
e153146
@@ -328,7 +329,8 @@ 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
+  rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
ad4aff0
+  if (rc < 0)
ad4aff0
     {
ad4aff0
       grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
ad4aff0
       goto fail;
b9efc54
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
e622855
index 2bd80f4db3..e6a8d4ad0e 100644
b9efc54
--- a/grub-core/loader/efi/chainloader.c
b9efc54
+++ b/grub-core/loader/efi/chainloader.c
b9efc54
@@ -32,6 +32,8 @@
b9efc54
 #include <grub/efi/api.h>
b9efc54
 #include <grub/efi/efi.h>
b9efc54
 #include <grub/efi/disk.h>
b9efc54
+#include <grub/efi/pe32.h>
b9efc54
+#include <grub/efi/linux.h>
b9efc54
 #include <grub/command.h>
b9efc54
 #include <grub/i18n.h>
b9efc54
 #include <grub/net.h>
b9efc54
@@ -46,9 +48,14 @@ static grub_dl_t my_mod;
b9efc54
 
b9efc54
 static grub_efi_physical_address_t address;
b9efc54
 static grub_efi_uintn_t pages;
b9efc54
+static grub_ssize_t fsize;
b9efc54
 static grub_efi_device_path_t *file_path;
b9efc54
 static grub_efi_handle_t image_handle;
b9efc54
 static grub_efi_char16_t *cmdline;
b9efc54
+static grub_ssize_t cmdline_len;
b9efc54
+static grub_efi_handle_t dev_handle;
b9efc54
+
b9efc54
+static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table);
b9efc54
 
b9efc54
 static grub_err_t
b9efc54
 grub_chainloader_unload (void)
b9efc54
@@ -63,6 +70,7 @@ grub_chainloader_unload (void)
b9efc54
   grub_free (cmdline);
b9efc54
   cmdline = 0;
b9efc54
   file_path = 0;
b9efc54
+  dev_handle = 0;
b9efc54
 
b9efc54
   grub_dl_unref (my_mod);
b9efc54
   return GRUB_ERR_NONE;
e602a06
@@ -213,20 +221,694 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
b9efc54
   return file_path;
b9efc54
 }
b9efc54
 
b9efc54
+#define SHIM_LOCK_GUID \
b9efc54
+  { 0x605dab50, 0xe046, 0x4300, { 0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23 } }
b9efc54
+
b9efc54
+typedef union
b9efc54
+{
b9efc54
+  struct grub_pe32_header_32 pe32;
b9efc54
+  struct grub_pe32_header_64 pe32plus;
b9efc54
+} grub_pe_header_t;
b9efc54
+
b9efc54
+struct pe_coff_loader_image_context
b9efc54
+{
b9efc54
+  grub_efi_uint64_t image_address;
b9efc54
+  grub_efi_uint64_t image_size;
b9efc54
+  grub_efi_uint64_t entry_point;
b9efc54
+  grub_efi_uintn_t size_of_headers;
b9efc54
+  grub_efi_uint16_t image_type;
b9efc54
+  grub_efi_uint16_t number_of_sections;
b9efc54
+  grub_efi_uint32_t section_alignment;
b9efc54
+  struct grub_pe32_section_table *first_section;
b9efc54
+  struct grub_pe32_data_directory *reloc_dir;
b9efc54
+  struct grub_pe32_data_directory *sec_dir;
b9efc54
+  grub_efi_uint64_t number_of_rva_and_sizes;
b9efc54
+  grub_pe_header_t *pe_hdr;
b9efc54
+};
b9efc54
+
b9efc54
+typedef struct pe_coff_loader_image_context pe_coff_loader_image_context_t;
b9efc54
+
b9efc54
+struct grub_efi_shim_lock
b9efc54
+{
b9efc54
+  grub_efi_status_t (*verify)(void *buffer,
b9efc54
+                              grub_efi_uint32_t size);
b9efc54
+  grub_efi_status_t (*hash)(void *data,
b9efc54
+                            grub_efi_int32_t datasize,
b9efc54
+                            pe_coff_loader_image_context_t *context,
b9efc54
+                            grub_efi_uint8_t *sha256hash,
b9efc54
+                            grub_efi_uint8_t *sha1hash);
b9efc54
+  grub_efi_status_t (*context)(void *data,
b9efc54
+                               grub_efi_uint32_t size,
b9efc54
+                               pe_coff_loader_image_context_t *context);
b9efc54
+};
b9efc54
+
b9efc54
+typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
b9efc54
+
b9efc54
+static grub_efi_boolean_t
b9efc54
+read_header (void *data, grub_efi_uint32_t size,
b9efc54
+	     pe_coff_loader_image_context_t *context)
b9efc54
+{
b9efc54
+  grub_efi_guid_t guid = SHIM_LOCK_GUID;
b9efc54
+  grub_efi_shim_lock_t *shim_lock;
b9efc54
+  grub_efi_status_t status;
b9efc54
+
b9efc54
+  shim_lock = grub_efi_locate_protocol (&guid, NULL);
b9efc54
+  if (!shim_lock)
b9efc54
+    {
ad4aff0
+      grub_dprintf ("chain", "no shim lock protocol");
b9efc54
+      return 0;
b9efc54
+    }
b9efc54
+
b9efc54
+  status = shim_lock->context (data, size, context);
b9efc54
+
b9efc54
+  if (status == GRUB_EFI_SUCCESS)
b9efc54
+    {
b9efc54
+      grub_dprintf ("chain", "context success\n");
b9efc54
+      return 1;
b9efc54
+    }
b9efc54
+
b9efc54
+  switch (status)
b9efc54
+    {
b9efc54
+      case GRUB_EFI_UNSUPPORTED:
b9efc54
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "context error unsupported");
b9efc54
+      break;
b9efc54
+      case GRUB_EFI_INVALID_PARAMETER:
b9efc54
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "context error invalid parameter");
b9efc54
+      break;
b9efc54
+      default:
b9efc54
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "context error code");
b9efc54
+      break;
b9efc54
+    }
b9efc54
+
ad4aff0
+  return -1;
b9efc54
+}
b9efc54
+
b9efc54
+static void*
b9efc54
+image_address (void *image, grub_efi_uint64_t sz, grub_efi_uint64_t adr)
b9efc54
+{
b9efc54
+  if (adr > sz)
b9efc54
+    return NULL;
b9efc54
+
b9efc54
+  return ((grub_uint8_t*)image + adr);
b9efc54
+}
b9efc54
+
b9efc54
+static int
b9efc54
+image_is_64_bit (grub_pe_header_t *pe_hdr)
b9efc54
+{
b9efc54
+  /* .Magic is the same offset in all cases */
b9efc54
+  if (pe_hdr->pe32plus.optional_header.magic == GRUB_PE32_PE64_MAGIC)
b9efc54
+    return 1;
b9efc54
+  return 0;
b9efc54
+}
b9efc54
+
ad4aff0
+static const grub_uint16_t machine_type __attribute__((__unused__)) =
b9efc54
+#if defined(__x86_64__)
b9efc54
+  GRUB_PE32_MACHINE_X86_64;
b9efc54
+#elif defined(__aarch64__)
b9efc54
+  GRUB_PE32_MACHINE_ARM64;
b9efc54
+#elif defined(__arm__)
b9efc54
+  GRUB_PE32_MACHINE_ARMTHUMB_MIXED;
b9efc54
+#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
b9efc54
+  GRUB_PE32_MACHINE_I386;
b9efc54
+#elif defined(__ia64__)
b9efc54
+  GRUB_PE32_MACHINE_IA64;
e602a06
+#elif defined(__riscv) && (__riscv_xlen == 32)
e602a06
+  GRUB_PE32_MACHINE_RISCV32;
e602a06
+#elif defined(__riscv) && (__riscv_xlen == 64)
e602a06
+  GRUB_PE32_MACHINE_RISCV64;
b9efc54
+#else
b9efc54
+#error this architecture is not supported by grub2
b9efc54
+#endif
b9efc54
+
b9efc54
+static grub_efi_status_t
b9efc54
+relocate_coff (pe_coff_loader_image_context_t *context,
b9efc54
+	       struct grub_pe32_section_table *section,
b9efc54
+	       void *orig, void *data)
b9efc54
+{
b9efc54
+  struct grub_pe32_data_directory *reloc_base, *reloc_base_end;
b9efc54
+  grub_efi_uint64_t adjust;
b9efc54
+  struct grub_pe32_fixup_block *reloc, *reloc_end;
b9efc54
+  char *fixup, *fixup_base, *fixup_data = NULL;
b9efc54
+  grub_efi_uint16_t *fixup_16;
b9efc54
+  grub_efi_uint32_t *fixup_32;
b9efc54
+  grub_efi_uint64_t *fixup_64;
b9efc54
+  grub_efi_uint64_t size = context->image_size;
b9efc54
+  void *image_end = (char *)orig + size;
b9efc54
+  int n = 0;
b9efc54
+
b9efc54
+  if (image_is_64_bit (context->pe_hdr))
b9efc54
+    context->pe_hdr->pe32plus.optional_header.image_base =
b9efc54
+      (grub_uint64_t)(unsigned long)data;
b9efc54
+  else
b9efc54
+    context->pe_hdr->pe32.optional_header.image_base =
b9efc54
+      (grub_uint32_t)(unsigned long)data;
b9efc54
+
b9efc54
+  /* Alright, so here's how this works:
b9efc54
+   *
b9efc54
+   * context->reloc_dir gives us two things:
b9efc54
+   * - the VA the table of base relocation blocks are (maybe) to be
b9efc54
+   *   mapped at (reloc_dir->rva)
b9efc54
+   * - the virtual size (reloc_dir->size)
b9efc54
+   *
b9efc54
+   * The .reloc section (section here) gives us some other things:
b9efc54
+   * - the name! kind of. (section->name)
b9efc54
+   * - the virtual size (section->virtual_size), which should be the same
b9efc54
+   *   as RelocDir->Size
b9efc54
+   * - the virtual address (section->virtual_address)
b9efc54
+   * - the file section size (section->raw_data_size), which is
b9efc54
+   *   a multiple of optional_header->file_alignment.  Only useful for image
b9efc54
+   *   validation, not really useful for iteration bounds.
b9efc54
+   * - the file address (section->raw_data_offset)
b9efc54
+   * - a bunch of stuff we don't use that's 0 in our binaries usually
b9efc54
+   * - Flags (section->characteristics)
b9efc54
+   *
b9efc54
+   * and then the thing that's actually at the file address is an array
b9efc54
+   * of struct grub_pe32_fixup_block structs with some values packed behind
b9efc54
+   * them.  The block_size field of this structure includes the
b9efc54
+   * structure itself, and adding it to that structure's address will
b9efc54
+   * yield the next entry in the array.
b9efc54
+   */
b9efc54
+
b9efc54
+  reloc_base = image_address (orig, size, section->raw_data_offset);
b9efc54
+  reloc_base_end = image_address (orig, size, section->raw_data_offset
ad4aff0
+				  + section->virtual_size);
b9efc54
+
ad4aff0
+  grub_dprintf ("chain", "relocate_coff(): reloc_base %p reloc_base_end %p\n",
ad4aff0
+		reloc_base, reloc_base_end);
b9efc54
+
b9efc54
+  if (!reloc_base && !reloc_base_end)
b9efc54
+    return GRUB_EFI_SUCCESS;
b9efc54
+
b9efc54
+  if (!reloc_base || !reloc_base_end)
b9efc54
+    {
b9efc54
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc table overflows binary");
b9efc54
+      return GRUB_EFI_UNSUPPORTED;
b9efc54
+    }
b9efc54
+
ad4aff0
+  adjust = (grub_uint64_t)(grub_efi_uintn_t)data - context->image_address;
b9efc54
+  if (adjust == 0)
b9efc54
+    return GRUB_EFI_SUCCESS;
b9efc54
+
b9efc54
+  while (reloc_base < reloc_base_end)
b9efc54
+    {
b9efc54
+      grub_uint16_t *entry;
b9efc54
+      reloc = (struct grub_pe32_fixup_block *)((char*)reloc_base);
b9efc54
+
b9efc54
+      if ((reloc_base->size == 0) ||
b9efc54
+	  (reloc_base->size > context->reloc_dir->size))
b9efc54
+	{
b9efc54
+	  grub_error (GRUB_ERR_BAD_ARGUMENT,
b9efc54
+		      "Reloc %d block size %d is invalid\n", n,
b9efc54
+		      reloc_base->size);
b9efc54
+	  return GRUB_EFI_UNSUPPORTED;
b9efc54
+	}
b9efc54
+
b9efc54
+      entry = &reloc->entries[0];
b9efc54
+      reloc_end = (struct grub_pe32_fixup_block *)
b9efc54
+	((char *)reloc_base + reloc_base->size);
b9efc54
+
ad4aff0
+      if ((void *)reloc_end < orig || (void *)reloc_end > image_end)
b9efc54
+        {
b9efc54
+          grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc entry %d overflows binary",
b9efc54
+		      n);
b9efc54
+          return GRUB_EFI_UNSUPPORTED;
b9efc54
+        }
b9efc54
+
b9efc54
+      fixup_base = image_address(data, size, reloc_base->rva);
b9efc54
+
b9efc54
+      if (!fixup_base)
b9efc54
+        {
b9efc54
+          grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc %d Invalid fixupbase", n);
b9efc54
+          return GRUB_EFI_UNSUPPORTED;
b9efc54
+        }
b9efc54
+
b9efc54
+      while ((void *)entry < (void *)reloc_end)
b9efc54
+        {
b9efc54
+          fixup = fixup_base + (*entry & 0xFFF);
b9efc54
+          switch ((*entry) >> 12)
b9efc54
+            {
b9efc54
+              case GRUB_PE32_REL_BASED_ABSOLUTE:
b9efc54
+                break;
b9efc54
+              case GRUB_PE32_REL_BASED_HIGH:
b9efc54
+                fixup_16 = (grub_uint16_t *)fixup;
b9efc54
+                *fixup_16 = (grub_uint16_t)
b9efc54
+		  (*fixup_16 + ((grub_uint16_t)((grub_uint32_t)adjust >> 16)));
b9efc54
+                if (fixup_data != NULL)
b9efc54
+                  {
b9efc54
+                    *(grub_uint16_t *) fixup_data = *fixup_16;
b9efc54
+                    fixup_data = fixup_data + sizeof (grub_uint16_t);
b9efc54
+                  }
b9efc54
+                break;
b9efc54
+              case GRUB_PE32_REL_BASED_LOW:
b9efc54
+                fixup_16 = (grub_uint16_t *)fixup;
b9efc54
+                *fixup_16 = (grub_uint16_t) (*fixup_16 + (grub_uint16_t)adjust);
b9efc54
+                if (fixup_data != NULL)
b9efc54
+                  {
b9efc54
+                    *(grub_uint16_t *) fixup_data = *fixup_16;
b9efc54
+                    fixup_data = fixup_data + sizeof (grub_uint16_t);
b9efc54
+                  }
b9efc54
+                break;
b9efc54
+              case GRUB_PE32_REL_BASED_HIGHLOW:
b9efc54
+                fixup_32 = (grub_uint32_t *)fixup;
b9efc54
+                *fixup_32 = *fixup_32 + (grub_uint32_t)adjust;
b9efc54
+                if (fixup_data != NULL)
b9efc54
+                  {
b9efc54
+                    fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint32_t));
b9efc54
+                    *(grub_uint32_t *) fixup_data = *fixup_32;
b9efc54
+                    fixup_data += sizeof (grub_uint32_t);
b9efc54
+                  }
b9efc54
+                break;
b9efc54
+              case GRUB_PE32_REL_BASED_DIR64:
b9efc54
+                fixup_64 = (grub_uint64_t *)fixup;
b9efc54
+                *fixup_64 = *fixup_64 + (grub_uint64_t)adjust;
b9efc54
+                if (fixup_data != NULL)
b9efc54
+                  {
b9efc54
+                    fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint64_t));
b9efc54
+                    *(grub_uint64_t *) fixup_data = *fixup_64;
b9efc54
+                    fixup_data += sizeof (grub_uint64_t);
b9efc54
+                  }
b9efc54
+                break;
b9efc54
+              default:
b9efc54
+                grub_error (GRUB_ERR_BAD_ARGUMENT,
b9efc54
+			    "Reloc %d unknown relocation type %d",
b9efc54
+			    n, (*entry) >> 12);
b9efc54
+                return GRUB_EFI_UNSUPPORTED;
b9efc54
+            }
b9efc54
+          entry += 1;
b9efc54
+        }
b9efc54
+      reloc_base = (struct grub_pe32_data_directory *)reloc_end;
b9efc54
+      n++;
b9efc54
+    }
b9efc54
+
b9efc54
+  return GRUB_EFI_SUCCESS;
b9efc54
+}
b9efc54
+
b9efc54
+static grub_efi_device_path_t *
b9efc54
+grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
b9efc54
+{
b9efc54
+  while (1)
b9efc54
+    {
b9efc54
+      grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
b9efc54
+      grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
b9efc54
+
b9efc54
+      if (type == GRUB_EFI_END_DEVICE_PATH_TYPE)
b9efc54
+        break;
b9efc54
+      else if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
b9efc54
+            && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE)
b9efc54
+      return dp;
b9efc54
+
b9efc54
+      dp = GRUB_EFI_NEXT_DEVICE_PATH (dp);
b9efc54
+    }
b9efc54
+
b9efc54
+    return NULL;
b9efc54
+}
b9efc54
+
b9efc54
+static grub_efi_boolean_t
b9efc54
+handle_image (void *data, grub_efi_uint32_t datasize)
b9efc54
+{
6f1e3d5
+  grub_efi_boot_services_t *b;
b9efc54
+  grub_efi_loaded_image_t *li, li_bak;
b9efc54
+  grub_efi_status_t efi_status;
6f1e3d5
+  char *buffer = NULL;
b9efc54
+  char *buffer_aligned = NULL;
ad4aff0
+  grub_efi_uint32_t i;
b9efc54
+  struct grub_pe32_section_table *section;
b9efc54
+  char *base, *end;
b9efc54
+  pe_coff_loader_image_context_t context;
b9efc54
+  grub_uint32_t section_alignment;
b9efc54
+  grub_uint32_t buffer_size;
ad4aff0
+  int found_entry_point = 0;
ad4aff0
+  int rc;
b9efc54
+
6f1e3d5
+  b = grub_efi_system_table->boot_services;
6f1e3d5
+
ad4aff0
+  rc = read_header (data, datasize, &context);
ad4aff0
+  if (rc < 0)
b9efc54
+    {
ad4aff0
+      grub_dprintf ("chain", "Failed to read header\n");
ad4aff0
+      goto error_exit;
ad4aff0
+    }
ad4aff0
+  else if (rc == 0)
ad4aff0
+    {
ad4aff0
+      grub_dprintf ("chain", "Secure Boot is not enabled\n");
ad4aff0
+      return 0;
b9efc54
+    }
b9efc54
+  else
b9efc54
+    {
ad4aff0
+      grub_dprintf ("chain", "Header read without error\n");
b9efc54
+    }
b9efc54
+
ad4aff0
+  /*
ad4aff0
+   * The spec says, uselessly, of SectionAlignment:
ad4aff0
+   * =====
ad4aff0
+   * The alignment (in bytes) of sections when they are loaded into
ad4aff0
+   * memory. It must be greater than or equal to FileAlignment. The
ad4aff0
+   * default is the page size for the architecture.
ad4aff0
+   * =====
ad4aff0
+   * Which doesn't tell you whose responsibility it is to enforce the
ad4aff0
+   * "default", or when.  It implies that the value in the field must
ad4aff0
+   * be > FileAlignment (also poorly defined), but it appears visual
ad4aff0
+   * studio will happily write 512 for FileAlignment (its default) and
ad4aff0
+   * 0 for SectionAlignment, intending to imply PAGE_SIZE.
ad4aff0
+   *
ad4aff0
+   * We only support one page size, so if it's zero, nerf it to 4096.
ad4aff0
+   */
b9efc54
+  section_alignment = context.section_alignment;
ad4aff0
+  if (section_alignment == 0)
ad4aff0
+    section_alignment = 4096;
ad4aff0
+
b9efc54
+  buffer_size = context.image_size + section_alignment;
ad4aff0
+  grub_dprintf ("chain", "image size is %08"PRIxGRUB_UINT64_T", datasize is %08x\n",
ad4aff0
+	       context.image_size, datasize);
b9efc54
+
6f1e3d5
+  efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA,
6f1e3d5
+			   buffer_size, &buffer);
6f1e3d5
+
b9efc54
+  if (efi_status != GRUB_EFI_SUCCESS)
b9efc54
+    {
b9efc54
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
b9efc54
+      goto error_exit;
b9efc54
+    }
b9efc54
+
b9efc54
+  buffer_aligned = (char *)ALIGN_UP ((grub_addr_t)buffer, section_alignment);
b9efc54
+  if (!buffer_aligned)
b9efc54
+    {
b9efc54
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
b9efc54
+      goto error_exit;
b9efc54
+    }
b9efc54
+
b9efc54
+  grub_memcpy (buffer_aligned, data, context.size_of_headers);
b9efc54
+
ad4aff0
+  entry_point = image_address (buffer_aligned, context.image_size,
ad4aff0
+			       context.entry_point);
ad4aff0
+
ad4aff0
+  grub_dprintf ("chain", "entry_point: %p\n", entry_point);
ad4aff0
+  if (!entry_point)
ad4aff0
+    {
ad4aff0
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid entry point");
ad4aff0
+      goto error_exit;
ad4aff0
+    }
ad4aff0
+
b9efc54
+  char *reloc_base, *reloc_base_end;
ad4aff0
+  grub_dprintf ("chain", "reloc_dir: %p reloc_size: 0x%08x\n",
ad4aff0
+		(void *)(unsigned long)context.reloc_dir->rva,
ad4aff0
+		context.reloc_dir->size);
ad4aff0
+  reloc_base = image_address (buffer_aligned, context.image_size,
b9efc54
+			      context.reloc_dir->rva);
b9efc54
+  /* RelocBaseEnd here is the address of the last byte of the table */
ad4aff0
+  reloc_base_end = image_address (buffer_aligned, context.image_size,
b9efc54
+				  context.reloc_dir->rva
b9efc54
+				  + context.reloc_dir->size - 1);
ad4aff0
+  grub_dprintf ("chain", "reloc_base: %p reloc_base_end: %p\n",
ad4aff0
+		reloc_base, reloc_base_end);
ad4aff0
+
ad4aff0
+  struct grub_pe32_section_table *reloc_section = NULL, fake_reloc_section;
b9efc54
+
b9efc54
+  section = context.first_section;
b9efc54
+  for (i = 0; i < context.number_of_sections; i++, section++)
b9efc54
+    {
ad4aff0
+      char name[9];
b9efc54
+
b9efc54
+      base = image_address (buffer_aligned, context.image_size,
b9efc54
+			    section->virtual_address);
b9efc54
+      end = image_address (buffer_aligned, context.image_size,
ad4aff0
+			   section->virtual_address + section->virtual_size -1);
b9efc54
+
ad4aff0
+      grub_strncpy(name, section->name, 9);
ad4aff0
+      name[8] = '\0';
ad4aff0
+      grub_dprintf ("chain", "Section %d \"%s\" at %p..%p\n", i,
ad4aff0
+		   name, base, end);
ad4aff0
+
ad4aff0
+      if (end < base)
ad4aff0
+	{
ad4aff0
+	  grub_dprintf ("chain", " base is %p but end is %p... bad.\n",
ad4aff0
+		       base, end);
ad4aff0
+	  grub_error (GRUB_ERR_BAD_ARGUMENT,
ad4aff0
+		      "Image has invalid negative size");
ad4aff0
+	  goto error_exit;
ad4aff0
+	}
ad4aff0
+
ad4aff0
+      if (section->virtual_address <= context.entry_point &&
ad4aff0
+	  (section->virtual_address + section->raw_data_size - 1)
ad4aff0
+	  > context.entry_point)
ad4aff0
+	{
ad4aff0
+	  found_entry_point++;
ad4aff0
+	  grub_dprintf ("chain", " section contains entry point\n");
ad4aff0
+	}
b9efc54
+
b9efc54
+      /* We do want to process .reloc, but it's often marked
b9efc54
+       * discardable, so we don't want to memcpy it. */
b9efc54
+      if (grub_memcmp (section->name, ".reloc\0\0", 8) == 0)
b9efc54
+	{
b9efc54
+	  if (reloc_section)
b9efc54
+	    {
b9efc54
+	      grub_error (GRUB_ERR_BAD_ARGUMENT,
b9efc54
+			  "Image has multiple relocation sections");
b9efc54
+	      goto error_exit;
b9efc54
+	    }
b9efc54
+
b9efc54
+	  /* If it has nonzero sizes, and our bounds check
b9efc54
+	   * made sense, and the VA and size match RelocDir's
b9efc54
+	   * versions, then we believe in this section table. */
b9efc54
+	  if (section->raw_data_size && section->virtual_size &&
ad4aff0
+	      base && end && reloc_base == base)
ad4aff0
+	    {
ad4aff0
+	      if (reloc_base_end == end)
ad4aff0
+		{
ad4aff0
+		  grub_dprintf ("chain", " section is relocation section\n");
ad4aff0
+		  reloc_section = section;
ad4aff0
+		}
ad4aff0
+	      else if (reloc_base_end && reloc_base_end < end)
ad4aff0
+	        {
ad4aff0
+		  /* Bogus virtual size in the reloc section -- RelocDir
ad4aff0
+		   * reported a smaller Base Relocation Directory. Decrease
ad4aff0
+		   * the section's virtual size so that it equal RelocDir's
ad4aff0
+		   * idea, but only for the purposes of relocate_coff(). */
ad4aff0
+		  grub_dprintf ("chain",
ad4aff0
+				" section is (overlong) relocation section\n");
ad4aff0
+		  grub_memcpy (&fake_reloc_section, section, sizeof *section);
ad4aff0
+		  fake_reloc_section.virtual_size -= (end - reloc_base_end);
ad4aff0
+		  reloc_section = &fake_reloc_section;
ad4aff0
+		}
ad4aff0
+	    }
ad4aff0
+
ad4aff0
+	  if (!reloc_section)
b9efc54
+	    {
ad4aff0
+	      grub_dprintf ("chain", " section is not reloc section?\n");
ad4aff0
+	      grub_dprintf ("chain", " rds: 0x%08x, vs: %08x\n",
ad4aff0
+			    section->raw_data_size, section->virtual_size);
ad4aff0
+	      grub_dprintf ("chain", " base: %p end: %p\n", base, end);
ad4aff0
+	      grub_dprintf ("chain", " reloc_base: %p reloc_base_end: %p\n",
ad4aff0
+			    reloc_base, reloc_base_end);
b9efc54
+	    }
b9efc54
+	}
b9efc54
+
ad4aff0
+      grub_dprintf ("chain", " Section characteristics are %08x\n",
ad4aff0
+		   section->characteristics);
ad4aff0
+      grub_dprintf ("chain", " Section virtual size: %08x\n",
ad4aff0
+		   section->virtual_size);
ad4aff0
+      grub_dprintf ("chain", " Section raw_data size: %08x\n",
ad4aff0
+		   section->raw_data_size);
ad4aff0
+      if (section->characteristics & GRUB_PE32_SCN_MEM_DISCARDABLE)
ad4aff0
+	{
ad4aff0
+	  grub_dprintf ("chain", " Discarding section\n");
ad4aff0
+	  continue;
ad4aff0
+	}
b9efc54
+
b9efc54
+      if (!base || !end)
b9efc54
+        {
ad4aff0
+	  grub_dprintf ("chain", " section is invalid\n");
b9efc54
+          grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid section size");
b9efc54
+          goto error_exit;
b9efc54
+        }
b9efc54
+
ad4aff0
+      if (section->characteristics & GRUB_PE32_SCN_CNT_UNINITIALIZED_DATA)
ad4aff0
+	{
ad4aff0
+	  if (section->raw_data_size != 0)
ad4aff0
+	    grub_dprintf ("chain", " UNINITIALIZED_DATA section has data?\n");
ad4aff0
+	}
ad4aff0
+      else if (section->virtual_address < context.size_of_headers ||
ad4aff0
+	       section->raw_data_offset < context.size_of_headers)
b9efc54
+	{
b9efc54
+	  grub_error (GRUB_ERR_BAD_ARGUMENT,
b9efc54
+		      "Section %d is inside image headers", i);
b9efc54
+	  goto error_exit;
b9efc54
+	}
b9efc54
+
b9efc54
+      if (section->raw_data_size > 0)
ad4aff0
+	{
ad4aff0
+	  grub_dprintf ("chain", " copying 0x%08x bytes to %p\n",
ad4aff0
+			section->raw_data_size, base);
ad4aff0
+	  grub_memcpy (base,
ad4aff0
+		       (grub_efi_uint8_t*)data + section->raw_data_offset,
ad4aff0
+		       section->raw_data_size);
ad4aff0
+	}
b9efc54
+
ad4aff0
+      if (section->raw_data_size < section->virtual_size)
ad4aff0
+	{
ad4aff0
+	  grub_dprintf ("chain", " padding with 0x%08x bytes at %p\n",
ad4aff0
+			section->virtual_size - section->raw_data_size,
ad4aff0
+			base + section->raw_data_size);
ad4aff0
+	  grub_memset (base + section->raw_data_size, 0,
ad4aff0
+		       section->virtual_size - section->raw_data_size);
ad4aff0
+	}
b9efc54
+
ad4aff0
+      grub_dprintf ("chain", " finished section %s\n", name);
b9efc54
+    }
b9efc54
+
b9efc54
+  /* 5 == EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC */
b9efc54
+  if (context.number_of_rva_and_sizes <= 5)
b9efc54
+    {
b9efc54
+      grub_dprintf ("chain", "image has no relocation entry\n");
b9efc54
+      goto error_exit;
b9efc54
+    }
b9efc54
+
b9efc54
+  if (context.reloc_dir->size && reloc_section)
b9efc54
+    {
b9efc54
+      /* run the relocation fixups */
b9efc54
+      efi_status = relocate_coff (&context, reloc_section, data,
b9efc54
+				  buffer_aligned);
b9efc54
+
b9efc54
+      if (efi_status != GRUB_EFI_SUCCESS)
b9efc54
+	{
b9efc54
+	  grub_error (GRUB_ERR_BAD_ARGUMENT, "relocation failed");
b9efc54
+	  goto error_exit;
b9efc54
+	}
b9efc54
+    }
b9efc54
+
ad4aff0
+  if (!found_entry_point)
b9efc54
+    {
ad4aff0
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "entry point is not within sections");
ad4aff0
+      goto error_exit;
ad4aff0
+    }
ad4aff0
+  if (found_entry_point > 1)
ad4aff0
+    {
ad4aff0
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "%d sections contain entry point",
ad4aff0
+		  found_entry_point);
b9efc54
+      goto error_exit;
b9efc54
+    }
b9efc54
+
b9efc54
+  li = grub_efi_get_loaded_image (grub_efi_image_handle);
b9efc54
+  if (!li)
b9efc54
+    {
b9efc54
+      grub_error (GRUB_ERR_BAD_ARGUMENT, "no loaded image available");
b9efc54
+      goto error_exit;
b9efc54
+    }
b9efc54
+
b9efc54
+  grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t));
b9efc54
+  li->image_base = buffer_aligned;
b9efc54
+  li->image_size = context.image_size;
b9efc54
+  li->load_options = cmdline;
b9efc54
+  li->load_options_size = cmdline_len;
b9efc54
+  li->file_path = grub_efi_get_media_file_path (file_path);
b9efc54
+  li->device_handle = dev_handle;
ad4aff0
+  if (!li->file_path)
b9efc54
+    {
b9efc54
+      grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found");
b9efc54
+      goto error_exit;
b9efc54
+    }
b9efc54
+
ad4aff0
+  grub_dprintf ("chain", "booting via entry point\n");
b9efc54
+  efi_status = efi_call_2 (entry_point, grub_efi_image_handle,
b9efc54
+			   grub_efi_system_table);
b9efc54
+
ad4aff0
+  grub_dprintf ("chain", "entry_point returned %ld\n", efi_status);
b9efc54
+  grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t));
6f1e3d5
+  efi_status = efi_call_1 (b->free_pool, buffer);
b9efc54
+
b9efc54
+  return 1;
b9efc54
+
b9efc54
+error_exit:
ad4aff0
+  grub_dprintf ("chain", "error_exit: grub_errno: %d\n", grub_errno);
b9efc54
+  if (buffer)
6f1e3d5
+      efi_call_1 (b->free_pool, buffer);
b9efc54
+
b9efc54
+  return 0;
b9efc54
+}
b9efc54
+
b9efc54
+static grub_err_t
b9efc54
+grub_secureboot_chainloader_unload (void)
b9efc54
+{
6f1e3d5
+  grub_efi_boot_services_t *b;
6f1e3d5
+
6f1e3d5
+  b = grub_efi_system_table->boot_services;
6f1e3d5
+  efi_call_2 (b->free_pages, address, pages);
b9efc54
+  grub_free (file_path);
b9efc54
+  grub_free (cmdline);
b9efc54
+  cmdline = 0;
b9efc54
+  file_path = 0;
b9efc54
+  dev_handle = 0;
b9efc54
+
b9efc54
+  grub_dl_unref (my_mod);
b9efc54
+  return GRUB_ERR_NONE;
b9efc54
+}
b9efc54
+
b9efc54
+static grub_err_t
ad4aff0
+grub_load_and_start_image(void *boot_image)
ad4aff0
+{
ad4aff0
+  grub_efi_boot_services_t *b;
ad4aff0
+  grub_efi_status_t status;
ad4aff0
+  grub_efi_loaded_image_t *loaded_image;
ad4aff0
+
ad4aff0
+  b = grub_efi_system_table->boot_services;
ad4aff0
+
ad4aff0
+  status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
ad4aff0
+		       boot_image, fsize, &image_handle);
ad4aff0
+  if (status != GRUB_EFI_SUCCESS)
ad4aff0
+    {
ad4aff0
+      if (status == GRUB_EFI_OUT_OF_RESOURCES)
ad4aff0
+	grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
ad4aff0
+      else
ad4aff0
+	grub_error (GRUB_ERR_BAD_OS, "cannot load image");
ad4aff0
+      return -1;
ad4aff0
+    }
ad4aff0
+
ad4aff0
+  /* LoadImage does not set a device handler when the image is
ad4aff0
+     loaded from memory, so it is necessary to set it explicitly here.
ad4aff0
+     This is a mess.  */
ad4aff0
+  loaded_image = grub_efi_get_loaded_image (image_handle);
ad4aff0
+  if (! loaded_image)
ad4aff0
+    {
ad4aff0
+      grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
ad4aff0
+      return -1;
ad4aff0
+    }
ad4aff0
+  loaded_image->device_handle = dev_handle;
ad4aff0
+
ad4aff0
+  if (cmdline)
ad4aff0
+    {
ad4aff0
+      loaded_image->load_options = cmdline;
ad4aff0
+      loaded_image->load_options_size = cmdline_len;
ad4aff0
+    }
ad4aff0
+
ad4aff0
+  return 0;
ad4aff0
+}
ad4aff0
+
ad4aff0
+static grub_err_t
b9efc54
+grub_secureboot_chainloader_boot (void)
b9efc54
+{
ad4aff0
+  int rc;
ad4aff0
+  rc = handle_image ((void *)(unsigned long)address, fsize);
ad4aff0
+  if (rc == 0)
ad4aff0
+    {
ad4aff0
+      grub_load_and_start_image((void *)(unsigned long)address);
ad4aff0
+    }
ad4aff0
+
b9efc54
+  grub_loader_unset ();
b9efc54
+  return grub_errno;
b9efc54
+}
b9efc54
+
b9efc54
 static grub_err_t
b9efc54
 grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
b9efc54
 		      int argc, char *argv[])
b9efc54
 {
b9efc54
   grub_file_t file = 0;
b9efc54
-  grub_ssize_t size;
b9efc54
   grub_efi_status_t status;
b9efc54
   grub_efi_boot_services_t *b;
b9efc54
   grub_device_t dev = 0;
ad4aff0
   grub_efi_device_path_t *dp = 0;
ad4aff0
-  grub_efi_loaded_image_t *loaded_image;
b9efc54
   char *filename;
b9efc54
   void *boot_image = 0;
b9efc54
-  grub_efi_handle_t dev_handle = 0;
ad4aff0
+  int rc;
b9efc54
 
b9efc54
   if (argc == 0)
b9efc54
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
e602a06
@@ -238,15 +920,45 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
b9efc54
   address = 0;
b9efc54
   image_handle = 0;
b9efc54
   file_path = 0;
b9efc54
+  dev_handle = 0;
b9efc54
 
b9efc54
   b = grub_efi_system_table->boot_services;
b9efc54
 
b9efc54
+  if (argc > 1)
b9efc54
+    {
b9efc54
+      int i;
b9efc54
+      grub_efi_char16_t *p16;
b9efc54
+
b9efc54
+      for (i = 1, cmdline_len = 0; i < argc; i++)
b9efc54
+        cmdline_len += grub_strlen (argv[i]) + 1;
b9efc54
+
b9efc54
+      cmdline_len *= sizeof (grub_efi_char16_t);
b9efc54
+      cmdline = p16 = grub_malloc (cmdline_len);
b9efc54
+      if (! cmdline)
b9efc54
+        goto fail;
b9efc54
+
b9efc54
+      for (i = 1; i < argc; i++)
b9efc54
+        {
b9efc54
+          char *p8;
b9efc54
+
b9efc54
+          p8 = argv[i];
b9efc54
+          while (*p8)
b9efc54
+            *(p16++) = *(p8++);
b9efc54
+
b9efc54
+          *(p16++) = ' ';
b9efc54
+        }
b9efc54
+      *(--p16) = 0;
b9efc54
+    }
b9efc54
+
e153146
   file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE);
b9efc54
   if (! file)
b9efc54
     goto fail;
b9efc54
 
ad4aff0
-  /* Get the root device's device path.  */
ad4aff0
-  dev = grub_device_open (0);
ad4aff0
+  /* Get the device path from filename. */
ad4aff0
+  char *devname = grub_file_get_device_name (filename);
ad4aff0
+  dev = grub_device_open (devname);
ad4aff0
+  if (devname)
ad4aff0
+    grub_free (devname);
ad4aff0
   if (! dev)
ad4aff0
     goto fail;
ad4aff0
 
e602a06
@@ -283,17 +995,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
ad4aff0
   if (! file_path)
ad4aff0
     goto fail;
ad4aff0
 
ad4aff0
-  grub_printf ("file path: ");
ad4aff0
-  grub_efi_print_device_path (file_path);
ad4aff0
-
b9efc54
-  size = grub_file_size (file);
b9efc54
-  if (!size)
b9efc54
+  fsize = grub_file_size (file);
b9efc54
+  if (!fsize)
b9efc54
     {
b9efc54
       grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
b9efc54
 		  filename);
b9efc54
       goto fail;
b9efc54
     }
b9efc54
-  pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12);
b9efc54
+  pages = (((grub_efi_uintn_t) fsize + ((1 << 12) - 1)) >> 12);
b9efc54
 
6f1e3d5
   status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES,
6f1e3d5
 			      GRUB_EFI_LOADER_CODE,
e602a06
@@ -307,7 +1016,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
b9efc54
     }
b9efc54
 
b9efc54
   boot_image = (void *) ((grub_addr_t) address);
b9efc54
-  if (grub_file_read (file, boot_image, size) != size)
b9efc54
+  if (grub_file_read (file, boot_image, fsize) != fsize)
b9efc54
     {
b9efc54
       if (grub_errno == GRUB_ERR_NONE)
b9efc54
 	grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
e602a06
@@ -317,7 +1026,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
b9efc54
     }
b9efc54
 
b9efc54
 #if defined (__i386__) || defined (__x86_64__)
b9efc54
-  if (size >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
b9efc54
+  if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header))
b9efc54
     {
b9efc54
       struct grub_macho_fat_header *head = boot_image;
b9efc54
       if (head->magic
e602a06
@@ -326,6 +1035,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
b9efc54
 	  grub_uint32_t i;
b9efc54
 	  struct grub_macho_fat_arch *archs
b9efc54
 	    = (struct grub_macho_fat_arch *) (head + 1);
b9efc54
+
46968b6
+	  if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
b9efc54
+	    {
b9efc54
+	      grub_error (GRUB_ERR_BAD_OS,
b9efc54
+			  "MACHO binaries are forbidden with Secure Boot");
b9efc54
+	      goto fail;
b9efc54
+	    }
b9efc54
+
b9efc54
 	  for (i = 0; i < grub_cpu_to_le32 (head->nfat_arch); i++)
b9efc54
 	    {
b9efc54
 	      if (GRUB_MACHO_CPUTYPE_IS_HOST_CURRENT (archs[i].cputype))
e602a06
@@ -340,79 +1057,39 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
b9efc54
 	      > ~grub_cpu_to_le32 (archs[i].size)
b9efc54
 	      || grub_cpu_to_le32 (archs[i].offset)
b9efc54
 	      + grub_cpu_to_le32 (archs[i].size)
b9efc54
-	      > (grub_size_t) size)
b9efc54
+	      > (grub_size_t) fsize)
b9efc54
 	    {
b9efc54
 	      grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
b9efc54
 			  filename);
b9efc54
 	      goto fail;
b9efc54
 	    }
b9efc54
 	  boot_image = (char *) boot_image + grub_cpu_to_le32 (archs[i].offset);
b9efc54
-	  size = grub_cpu_to_le32 (archs[i].size);
b9efc54
+	  fsize = grub_cpu_to_le32 (archs[i].size);
b9efc54
 	}
b9efc54
     }
b9efc54
 #endif
b9efc54
 
ad4aff0
-  status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path,
ad4aff0
-		       boot_image, size,
ad4aff0
-		       &image_handle);
ad4aff0
-  if (status != GRUB_EFI_SUCCESS)
ad4aff0
+  rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize);
ad4aff0
+  grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc);
ad4aff0
+  if (rc > 0)
ad4aff0
     {
ad4aff0
-      if (status == GRUB_EFI_OUT_OF_RESOURCES)
ad4aff0
-	grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources");
ad4aff0
-      else
ad4aff0
-	grub_error (GRUB_ERR_BAD_OS, "cannot load image");
ad4aff0
-
ad4aff0
-      goto fail;
b9efc54
+      grub_file_close (file);
ad4aff0
+      grub_device_close (dev);
b9efc54
+      grub_loader_set (grub_secureboot_chainloader_boot,
b9efc54
+		       grub_secureboot_chainloader_unload, 0);
b9efc54
+      return 0;
b9efc54
     }
ad4aff0
-
ad4aff0
-  /* LoadImage does not set a device handler when the image is
ad4aff0
-     loaded from memory, so it is necessary to set it explicitly here.
ad4aff0
-     This is a mess.  */
ad4aff0
-  loaded_image = grub_efi_get_loaded_image (image_handle);
ad4aff0
-  if (! loaded_image)
ad4aff0
+  else if (rc == 0)
b9efc54
     {
ad4aff0
-      grub_error (GRUB_ERR_BAD_OS, "no loaded image available");
ad4aff0
-      goto fail;
ad4aff0
-    }
ad4aff0
-  loaded_image->device_handle = dev_handle;
ad4aff0
-
ad4aff0
-  if (argc > 1)
ad4aff0
-    {
b9efc54
-      int i, len;
b9efc54
-      grub_efi_char16_t *p16;
b9efc54
-
b9efc54
-      for (i = 1, len = 0; i < argc; i++)
b9efc54
-        len += grub_strlen (argv[i]) + 1;
b9efc54
-
b9efc54
-      len *= sizeof (grub_efi_char16_t);
b9efc54
-      cmdline = p16 = grub_malloc (len);
b9efc54
-      if (! cmdline)
b9efc54
-        goto fail;
ad4aff0
+      grub_load_and_start_image(boot_image);
ad4aff0
+      grub_file_close (file);
ad4aff0
+      grub_device_close (dev);
ad4aff0
+      grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
ad4aff0
 
b9efc54
-      for (i = 1; i < argc; i++)
b9efc54
-        {
b9efc54
-          char *p8;
b9efc54
-
b9efc54
-          p8 = argv[i];
b9efc54
-          while (*p8)
b9efc54
-            *(p16++) = *(p8++);
b9efc54
-
b9efc54
-          *(p16++) = ' ';
b9efc54
-        }
b9efc54
-      *(--p16) = 0;
b9efc54
-
ad4aff0
-      loaded_image->load_options = cmdline;
b9efc54
-      loaded_image->load_options_size = len;
ad4aff0
+      return 0;
b9efc54
     }
b9efc54
 
ad4aff0
-  grub_file_close (file);
ad4aff0
-  grub_device_close (dev);
ad4aff0
-
ad4aff0
-  grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0);
ad4aff0
-  return 0;
ad4aff0
-
ad4aff0
- fail:
ad4aff0
-
ad4aff0
+fail:
ad4aff0
   if (dev)
ad4aff0
     grub_device_close (dev);
ad4aff0
 
e602a06
@@ -424,6 +1101,9 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
b9efc54
   if (address)
6f1e3d5
     efi_call_2 (b->free_pages, address, pages);
b9efc54
 
b9efc54
+  if (cmdline)
b9efc54
+    grub_free (cmdline);
b9efc54
+
b9efc54
   grub_dl_unref (my_mod);
b9efc54
 
b9efc54
   return grub_errno;
ad4aff0
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
e622855
index c24202a5dd..c8ecce6dfd 100644
ad4aff0
--- a/grub-core/loader/efi/linux.c
ad4aff0
+++ b/grub-core/loader/efi/linux.c
ad4aff0
@@ -33,21 +33,34 @@ struct grub_efi_shim_lock
ad4aff0
 };
ad4aff0
 typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
ad4aff0
 
ad4aff0
-grub_efi_boolean_t
ad4aff0
+int
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
+  grub_efi_status_t status;
ad4aff0
 
ad4aff0
   shim_lock = grub_efi_locate_protocol(&guid, NULL);
ad4aff0
-
ad4aff0
+  grub_dprintf ("secureboot", "shim_lock: %p\n", shim_lock);
ad4aff0
   if (!shim_lock)
ad4aff0
-    return 1;
ad4aff0
+    {
ad4aff0
+      grub_dprintf ("secureboot", "shim not available\n");
ad4aff0
+      return 0;
ad4aff0
+    }
ad4aff0
 
ad4aff0
-  if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS)
ad4aff0
-    return 1;
ad4aff0
+  grub_dprintf ("secureboot", "Asking shim to verify kernel signature\n");
ad4aff0
+  status = shim_lock->verify (data, size);
70dc033
+  grub_dprintf ("secureboot", "shim_lock->verify(): %ld\n", (long int)status);
ad4aff0
+  if (status == GRUB_EFI_SUCCESS)
ad4aff0
+    {
ad4aff0
+      grub_dprintf ("secureboot", "Kernel signature verification passed\n");
ad4aff0
+      return 1;
ad4aff0
+    }
ad4aff0
 
ad4aff0
-  return 0;
ad4aff0
+  grub_dprintf ("secureboot", "Kernel signature verification failed (0x%lx)\n",
ad4aff0
+		(unsigned long) status);
ad4aff0
+
ad4aff0
+  return -1;
ad4aff0
 }
ad4aff0
 
dbfd2e6
 #pragma GCC diagnostic push
ad4aff0
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
e622855
index bb2616a809..6b24cbb948 100644
ad4aff0
--- a/grub-core/loader/i386/efi/linux.c
ad4aff0
+++ b/grub-core/loader/i386/efi/linux.c
e153146
@@ -117,6 +117,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
ad4aff0
       goto fail;
ad4aff0
     }
ad4aff0
 
ad4aff0
+  grub_dprintf ("linux", "initrd_mem = %lx\n", (unsigned long) initrd_mem);
ad4aff0
+
ad4aff0
   params->ramdisk_size = size;
ad4aff0
   params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem;
ad4aff0
 
e153146
@@ -159,6 +161,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
e153146
   struct linux_i386_kernel_header lh;
ad4aff0
   grub_ssize_t len, start, filelen;
ad4aff0
   void *kernel = NULL;
ad4aff0
+  int rc;
ad4aff0
 
ad4aff0
   grub_dl_ref (my_mod);
ad4aff0
 
e153146
@@ -184,11 +187,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
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
+      grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"),
ad4aff0
+		  argv[0]);
ad4aff0
       goto fail;
ad4aff0
     }
ad4aff0
 
ad4aff0
-  if (! grub_linuxefi_secure_validate (kernel, filelen))
ad4aff0
+  rc = grub_linuxefi_secure_validate (kernel, filelen);
ad4aff0
+  if (rc < 0)
ad4aff0
     {
ad4aff0
       grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"),
ad4aff0
 		  argv[0]);
e153146
@@ -203,6 +208,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
ad4aff0
       goto fail;
ad4aff0
     }
ad4aff0
 
ad4aff0
+  grub_dprintf ("linux", "params = %lx\n", (unsigned long) params);
ad4aff0
+
ad4aff0
   grub_memset (params, 0, 16384);
ad4aff0
 
ad4aff0
   grub_memcpy (&lh, kernel, sizeof (lh));
e153146
@@ -241,6 +248,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
ad4aff0
       goto fail;
ad4aff0
     }
ad4aff0
 
ad4aff0
+  grub_dprintf ("linux", "linux_cmdline = %lx\n",
ad4aff0
+		(unsigned long)linux_cmdline);
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
@@ -275,9 +285,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
ad4aff0
   grub_memcpy (params, &lh, 2 * 512);
ad4aff0
 
ad4aff0
   params->type_of_loader = 0x21;
ad4aff0
+  grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n",
ad4aff0
+	       kernel_mem, handover_offset);
ad4aff0
 
ad4aff0
  fail:
ad4aff0
-
ad4aff0
   if (file)
ad4aff0
     grub_file_close (file);
ad4aff0
 
ad4aff0
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
e622855
index d9ede36773..0033d9305a 100644
ad4aff0
--- a/include/grub/efi/linux.h
ad4aff0
+++ b/include/grub/efi/linux.h
ad4aff0
@@ -22,7 +22,7 @@
ad4aff0
 #include <grub/err.h>
ad4aff0
 #include <grub/symbol.h>
ad4aff0
 
ad4aff0
-grub_efi_boolean_t
ad4aff0
+int
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,
b9efc54
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
e622855
index 0ed8781f03..a43adf2746 100644
b9efc54
--- a/include/grub/efi/pe32.h
b9efc54
+++ b/include/grub/efi/pe32.h
e153146
@@ -223,7 +223,11 @@ struct grub_pe64_optional_header
b9efc54
 struct grub_pe32_section_table
b9efc54
 {
b9efc54
   char name[8];
b9efc54
-  grub_uint32_t virtual_size;
b9efc54
+  union
b9efc54
+    {
b9efc54
+      grub_uint32_t physical_address;
b9efc54
+      grub_uint32_t virtual_size;
b9efc54
+    };
b9efc54
   grub_uint32_t virtual_address;
b9efc54
   grub_uint32_t raw_data_size;
b9efc54
   grub_uint32_t raw_data_offset;
e153146
@@ -234,12 +238,18 @@ struct grub_pe32_section_table
ad4aff0
   grub_uint32_t characteristics;
ad4aff0
 };
ad4aff0
 
ad4aff0
+#define GRUB_PE32_SCN_TYPE_NO_PAD		0x00000008
ad4aff0
 #define GRUB_PE32_SCN_CNT_CODE			0x00000020
ad4aff0
 #define GRUB_PE32_SCN_CNT_INITIALIZED_DATA	0x00000040
ad4aff0
-#define GRUB_PE32_SCN_MEM_DISCARDABLE		0x02000000
ad4aff0
-#define GRUB_PE32_SCN_MEM_EXECUTE		0x20000000
ad4aff0
-#define GRUB_PE32_SCN_MEM_READ			0x40000000
ad4aff0
-#define GRUB_PE32_SCN_MEM_WRITE			0x80000000
ad4aff0
+#define GRUB_PE32_SCN_CNT_UNINITIALIZED_DATA	0x00000080
ad4aff0
+#define GRUB_PE32_SCN_LNK_OTHER			0x00000100
ad4aff0
+#define GRUB_PE32_SCN_LNK_INFO			0x00000200
ad4aff0
+#define GRUB_PE32_SCN_LNK_REMOVE		0x00000800
ad4aff0
+#define GRUB_PE32_SCN_LNK_COMDAT		0x00001000
ad4aff0
+#define GRUB_PE32_SCN_GPREL			0x00008000
ad4aff0
+#define GRUB_PE32_SCN_MEM_16BIT			0x00020000
ad4aff0
+#define GRUB_PE32_SCN_MEM_LOCKED		0x00040000
ad4aff0
+#define GRUB_PE32_SCN_MEM_PRELOAD		0x00080000
ad4aff0
 
ad4aff0
 #define GRUB_PE32_SCN_ALIGN_1BYTES		0x00100000
ad4aff0
 #define GRUB_PE32_SCN_ALIGN_2BYTES		0x00200000
e153146
@@ -248,10 +258,28 @@ struct grub_pe32_section_table
ad4aff0
 #define GRUB_PE32_SCN_ALIGN_16BYTES		0x00500000
ad4aff0
 #define GRUB_PE32_SCN_ALIGN_32BYTES		0x00600000
ad4aff0
 #define GRUB_PE32_SCN_ALIGN_64BYTES		0x00700000
ad4aff0
+#define GRUB_PE32_SCN_ALIGN_128BYTES		0x00800000
ad4aff0
+#define GRUB_PE32_SCN_ALIGN_256BYTES		0x00900000
ad4aff0
+#define GRUB_PE32_SCN_ALIGN_512BYTES		0x00A00000
ad4aff0
+#define GRUB_PE32_SCN_ALIGN_1024BYTES		0x00B00000
ad4aff0
+#define GRUB_PE32_SCN_ALIGN_2048BYTES		0x00C00000
ad4aff0
+#define GRUB_PE32_SCN_ALIGN_4096BYTES		0x00D00000
ad4aff0
+#define GRUB_PE32_SCN_ALIGN_8192BYTES		0x00E00000
ad4aff0
 
ad4aff0
 #define GRUB_PE32_SCN_ALIGN_SHIFT		20
ad4aff0
 #define GRUB_PE32_SCN_ALIGN_MASK		7
ad4aff0
 
ad4aff0
+#define GRUB_PE32_SCN_LNK_NRELOC_OVFL		0x01000000
ad4aff0
+#define GRUB_PE32_SCN_MEM_DISCARDABLE		0x02000000
ad4aff0
+#define GRUB_PE32_SCN_MEM_NOT_CACHED		0x04000000
ad4aff0
+#define GRUB_PE32_SCN_MEM_NOT_PAGED		0x08000000
ad4aff0
+#define GRUB_PE32_SCN_MEM_SHARED		0x10000000
ad4aff0
+#define GRUB_PE32_SCN_MEM_EXECUTE		0x20000000
ad4aff0
+#define GRUB_PE32_SCN_MEM_READ			0x40000000
ad4aff0
+#define GRUB_PE32_SCN_MEM_WRITE			0x80000000
ad4aff0
+
ad4aff0
+
ad4aff0
+
ad4aff0
 #define GRUB_PE32_SIGNATURE_SIZE 4
ad4aff0
 
ad4aff0
 struct grub_pe32_header
e153146
@@ -274,6 +302,20 @@ struct grub_pe32_header
b9efc54
 #endif
b9efc54
 };
b9efc54
 
b9efc54
+struct grub_pe32_header_32
b9efc54
+{
b9efc54
+  char signature[GRUB_PE32_SIGNATURE_SIZE];
b9efc54
+  struct grub_pe32_coff_header coff_header;
b9efc54
+  struct grub_pe32_optional_header optional_header;
b9efc54
+};
b9efc54
+
b9efc54
+struct grub_pe32_header_64
b9efc54
+{
b9efc54
+  char signature[GRUB_PE32_SIGNATURE_SIZE];
b9efc54
+  struct grub_pe32_coff_header coff_header;
b9efc54
+  struct grub_pe64_optional_header optional_header;
b9efc54
+};
b9efc54
+
b9efc54
 struct grub_pe32_fixup_block
b9efc54
 {
b9efc54
   grub_uint32_t page_rva;