From 3b75fa5071e4b1a40510669119791928859b46e7 Mon Sep 17 00:00:00 2001
From: Matt Fleming <matt.fleming@intel.com>
Date: Fri, 27 Mar 2015 08:11:19 -0700
Subject: [PATCH 3/7] efi: chainloader: implement an UEFI Exit service for shim
 in grub

Upstream-Status: Inappropriate [embedded specific]

When exiting, grub will call the UEFI boot-time service Exit. The
effect of this is that UEFI will jump to the entry point of the
UEFI started image. If we execute an image using shim within grub,
shim takes care of loading/parsing/relocating/executing the image.
Under this scenario, we also need to take care of the Exit call. Thus,
we need to reimplement the function to make sure we perform a jump
to the instruction after which shim executed the image.

Once we have taken care of the exit of the shim-executed image
the system Exit call is restored.

Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
---
 grub-core/kern/x86_64/efi/callwrap.S | 23 +++++++++++++++++++++++
 include/grub/efi/api.h               |  4 ++++
 2 files changed, 27 insertions(+)

diff --git a/grub-core/kern/x86_64/efi/callwrap.S b/grub-core/kern/x86_64/efi/callwrap.S
index 2df95dd..f0f1dd8 100644
--- a/grub-core/kern/x86_64/efi/callwrap.S
+++ b/grub-core/kern/x86_64/efi/callwrap.S
@@ -48,6 +48,26 @@ FUNCTION(efi_wrap_1)
 	addq $48, %rsp
 	ret
 
+FUNCTION(efi_call_foo)
+	pushq %rbp
+	pushq %r12
+	pushq %r13
+	pushq %r14
+	pushq %r15
+	movq %rsp, saved_sp(%rip)
+	subq $48, %rsp
+	mov  %rsi, %rcx
+	call *%rdi
+
+FUNCTION(efi_shim_exit)
+	movq saved_sp(%rip), %rsp
+	popq %r15
+	popq %r14
+	popq %r13
+	popq %r12
+	popq %rbp
+	ret
+
 FUNCTION(efi_wrap_2)
 	subq $48, %rsp
 	mov  %rsi, %rcx
@@ -127,3 +147,6 @@ FUNCTION(efi_wrap_10)
 	call *%rdi
 	addq $96, %rsp
 	ret
+
+	.data
+saved_sp:	.quad   0
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 26127de..374d88b 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -1437,6 +1437,10 @@ typedef struct grub_efi_block_io grub_efi_block_io_t;
 
 grub_uint64_t EXPORT_FUNC(efi_wrap_0) (void *func);
 grub_uint64_t EXPORT_FUNC(efi_wrap_1) (void *func, grub_uint64_t arg1);
+grub_efi_status_t EXPORT_FUNC(efi_shim_exit) (grub_efi_handle_t handle, grub_efi_status_t exit_status,
+					      grub_efi_uintn_t exit_data_size, grub_efi_char16_t *exit_data) __attribute__((noreturn));
+grub_uint64_t EXPORT_FUNC(efi_call_foo) (void *func, grub_uint64_t arg1,
+					 grub_uint64_t arg2);
 grub_uint64_t EXPORT_FUNC(efi_wrap_2) (void *func, grub_uint64_t arg1,
                                        grub_uint64_t arg2);
 grub_uint64_t EXPORT_FUNC(efi_wrap_3) (void *func, grub_uint64_t arg1,
-- 
1.9.1

