From f25778620360ccff55f3d9c1bccba14249978502 Mon Sep 17 00:00:00 2001
From: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Date: Fri, 27 Mar 2015 08:29:13 -0700
Subject: [PATCH 6/7] efi: chainloader: boot the image using shim

Upstream-Status: Inappropriate [embedded specific]

If the image was loaded using shim, boot the image. Given that
shim loaded the image, the UEFI firmware will not know where to
jump after the execution completes. Thus, replace the UEFI boot
service Exit with our own implementation to make sure we jump
to the instruction after the call to the entry point.

Replace the system Exit service when done.

Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
 grub-core/loader/efi/chainloader.c | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 01d2ebe..1c9795c 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -605,9 +605,34 @@ grub_chainloader_boot (void)
   grub_efi_status_t status;
   grub_efi_uintn_t exit_data_size;
   grub_efi_char16_t *exit_data = NULL;
+  grub_efi_loaded_image_t *loaded_image = NULL;
+  grub_efi_status_t
+  (*saved_exit) (grub_efi_handle_t image_handle,
+		 grub_efi_status_t exit_status,
+	         grub_efi_uintn_t exit_data_size,
+                 grub_efi_char16_t *exit_data) __attribute__((noreturn));
 
   b = grub_efi_system_table->boot_services;
-  status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
+
+  if (!shim_used)
+    status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data);
+  else
+    {
+      saved_exit = grub_efi_system_table->boot_services->exit;
+      grub_efi_system_table->boot_services->exit = efi_shim_exit;
+      status = efi_call_foo(shim_entry_point,
+	                    (grub_efi_uint64_t)grub_efi_image_handle,
+	                    (grub_efi_uint64_t)grub_efi_system_table);
+      grub_efi_system_table->boot_services->exit = saved_exit;
+
+      loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle);
+      if (!loaded_image)
+        /* TODO: this is serious, what to do? */
+	grub_error (GRUB_ERR_BAD_OS, "GRUB loaded image not found");
+      else
+	/* restore loaded image */
+	grub_memcpy(loaded_image, &shim_li_bak, sizeof(shim_li_bak));
+    }
   if (status != GRUB_EFI_SUCCESS)
     {
       if (exit_data)
-- 
1.9.1

