[gnu-efi/f16] Correctly pad the stack when doing uefi calls Related: rhbz#677468 Add ability to write UEFI callbac

Peter Jones pjones at fedoraproject.org
Thu Aug 11 15:02:18 UTC 2011


commit 60c11bf522c7e4c579d186783e4273a72334f359
Author: Peter Jones <pjones at redhat.com>
Date:   Thu Aug 11 10:43:57 2011 -0400

    Correctly pad the stack when doing uefi calls
    Related: rhbz#677468
    Add ability to write UEFI callbacks and drivers
    Add test harness for ABI Calling Conventions

 gnu-efi-3.0d-unwrap.patch                          |  289 ------------
 gnu-efi-3.0e-Add-.S-and-.E-rules.patch             |   25 +
 ...-to-test-our-calling-convention-shananaga.patch |  484 ++++++++++++++++++++
 ...e-Add-the-routines-to-make-callbacks-work.patch |  142 ++++++
 ...6-byte-stack-alignment-on-x86_64-efi_call.patch |  333 ++++++++++++++
 gnu-efi.spec                                       |   11 +
 6 files changed, 995 insertions(+), 289 deletions(-)
---
diff --git a/gnu-efi-3.0e-Add-.S-and-.E-rules.patch b/gnu-efi-3.0e-Add-.S-and-.E-rules.patch
new file mode 100644
index 0000000..aae632e
--- /dev/null
+++ b/gnu-efi-3.0e-Add-.S-and-.E-rules.patch
@@ -0,0 +1,25 @@
+From 44e7c2b928b8c71dfe189208e35ca49ab210f058 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones at redhat.com>
+Date: Tue, 9 Aug 2011 12:30:49 -0400
+Subject: [PATCH] Add %.S and %.E rules to make debugging easier.
+
+---
+ Make.rules |    5 +++++
+ 1 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/Make.rules b/Make.rules
+index 1f24ebd..cb029c3 100644
+--- a/Make.rules
++++ b/Make.rules
+@@ -31,3 +31,8 @@
+ %.o: %.c
+ 	$(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
+ 
++%.S: %.c
++	$(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -S $< -o $@
++
++%.E: %.c
++	$(CC) $(INCDIR) $(CFLAGS) $(CPPFLAGS) -E $< -o $@
+-- 
+1.7.6
+
diff --git a/gnu-efi-3.0e-Add-tcc.efi-to-test-our-calling-convention-shananaga.patch b/gnu-efi-3.0e-Add-tcc.efi-to-test-our-calling-convention-shananaga.patch
new file mode 100644
index 0000000..7d0fc58
--- /dev/null
+++ b/gnu-efi-3.0e-Add-tcc.efi-to-test-our-calling-convention-shananaga.patch
@@ -0,0 +1,484 @@
+From 6ae2cc94566550e2e27c791485319bd5791cc861 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones at redhat.com>
+Date: Tue, 9 Aug 2011 13:46:53 -0400
+Subject: [PATCH] Add tcc.efi to test our calling convention shananagans.
+
+Add a test case to actually make sure we've got stack alignment and
+calling conventions set up correctly.
+---
+ apps/Makefile |    3 +-
+ apps/tcc.c    |  442 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 444 insertions(+), 1 deletions(-)
+ create mode 100644 apps/tcc.c
+
+diff --git a/apps/Makefile b/apps/Makefile
+index 6b50e4f..71e738d 100644
+--- a/apps/Makefile
++++ b/apps/Makefile
+@@ -32,13 +32,14 @@ TOPDIR = $(SRCDIR)/..
+ CDIR=$(TOPDIR)/..
+ LINUX_HEADERS	= /usr/src/sys/build
+ CPPFLAGS	+= -D__KERNEL__ -I$(LINUX_HEADERS)/include
++#CFLAGS		+= -ggdb
+ CRTOBJS		= ../gnuefi/crt0-efi-$(ARCH).o
+ LDSCRIPT	= $(TOPDIR)/gnuefi/elf_$(ARCH)_efi.lds
+ LDFLAGS		+= -T $(LDSCRIPT) -shared -Bsymbolic -L../lib -L../gnuefi $(CRTOBJS)
+ LOADLIBES	= -lefi -lgnuefi $(shell $(CC) $(ARCH3264) -print-libgcc-file-name)
+ FORMAT		= efi-app-$(ARCH)
+ 
+-TARGETS = t.efi t2.efi t3.efi t4.efi t5.efi t6.efi printenv.efi t7.efi route80h.efi modelist.efi
++TARGETS = t.efi t2.efi t3.efi t4.efi t5.efi t6.efi printenv.efi t7.efi route80h.efi modelist.efi tcc.efi
+ 
+ all:	$(TARGETS)
+ 
+diff --git a/apps/tcc.c b/apps/tcc.c
+new file mode 100644
+index 0000000..546df92
+--- /dev/null
++++ b/apps/tcc.c
+@@ -0,0 +1,442 @@
++/*
++ * Test if our calling convention gymnastics actually work
++ */
++
++#include <efi.h>
++#include <efilib.h>
++
++#ifdef __x86_64__
++#include <x86_64/pe.h>
++#include <x86_64/efibind.h>
++#endif
++
++#if 0
++	asm volatile("out %0,%1" : : "a" ((uint8_t)a), "dN" (0x80));
++#endif
++
++extern void dump_stack(void);
++asm(	".globl	dump_stack\n"
++	"dump_stack:\n"
++	"	movq %rsp, %rdi\n"
++	"	jmp *dump_stack_helper at GOTPCREL(%rip)\n"
++	".size	dump_stack, .-dump_stack");
++
++void dump_stack_helper(uint64_t rsp_val)
++{
++	uint64_t *rsp = (uint64_t *)rsp_val;
++	int x;
++
++	Print(L"%%rsp: 0x%08x%08x stack:\r\n",
++					(rsp_val & 0xffffffff00000000) >>32,
++					 rsp_val & 0xffffffff);
++	for (x = 0; x < 8; x++) {
++		Print(L"%08x: ", ((uint64_t)rsp) & 0xffffffff);
++		Print(L"%016x ", *rsp++);
++		Print(L"%016x ", *rsp++);
++		Print(L"%016x ", *rsp++);
++		Print(L"%016x\r\n", *rsp++);
++	}
++}
++
++EFI_STATUS EFI_FUNCTION test_failure_callback(void)
++{
++	return EFI_UNSUPPORTED;
++}
++
++EFI_STATUS test_failure(void)
++{
++	return uefi_call_wrapper(test_failure_callback, 0);	
++}
++
++EFI_STATUS EFI_FUNCTION test_call0_callback(void)
++{
++	return EFI_SUCCESS;
++}
++
++EFI_STATUS test_call0(void)
++{
++	return uefi_call_wrapper(test_call0_callback, 0);	
++}
++
++EFI_STATUS EFI_FUNCTION test_call1_callback(UINT32 a)
++{
++	if (a != 0x12345678) {
++		return EFI_LOAD_ERROR;
++	}
++	return EFI_SUCCESS;
++}
++
++EFI_STATUS test_call1(void)
++{
++	return uefi_call_wrapper(test_call1_callback, 1,0x12345678);	
++}
++
++EFI_STATUS EFI_FUNCTION test_call2_callback(UINT32 a, UINT32 b)
++{
++	if (a != 0x12345678) {
++		return EFI_LOAD_ERROR;
++	}
++	if (b != 0x23456789) {
++		return EFI_INVALID_PARAMETER;
++	}
++	return EFI_SUCCESS;
++}
++
++EFI_STATUS test_call2(void)
++{
++	return uefi_call_wrapper(test_call2_callback, 2,
++		0x12345678, 0x23456789);	
++}
++
++EFI_STATUS EFI_FUNCTION test_call3_callback(UINT32 a, UINT32 b,
++	UINT32 c)
++{
++	if (a != 0x12345678)
++		return EFI_LOAD_ERROR;
++	if (b != 0x23456789)
++		return EFI_INVALID_PARAMETER;
++	if (c != 0x3456789a)
++		return EFI_UNSUPPORTED;
++	return EFI_SUCCESS;
++}
++
++EFI_STATUS test_call3(void)
++{
++	return uefi_call_wrapper(test_call3_callback, 3,
++		0x12345678, 0x23456789, 0x3456789a);
++}
++
++EFI_STATUS EFI_FUNCTION test_call4_callback(UINT32 a, UINT32 b,
++	UINT32 c, UINT32 d)
++{
++	if (a != 0x12345678)
++		return EFI_LOAD_ERROR;
++	if (b != 0x23456789)
++		return EFI_INVALID_PARAMETER;
++	if (c != 0x3456789a)
++		return EFI_UNSUPPORTED;
++	if (d != 0x456789ab)
++		return EFI_BAD_BUFFER_SIZE;
++
++	return EFI_SUCCESS;
++}
++
++EFI_STATUS test_call4(void)
++{
++	return uefi_call_wrapper(test_call4_callback, 4,
++		0x12345678, 0x23456789, 0x3456789a, 0x456789ab);	
++}
++
++EFI_STATUS EFI_FUNCTION test_call5_callback(UINT32 a, UINT32 b,
++	UINT32 c, UINT32 d, UINT32 e)
++{
++	if (a != 0x12345678)
++		return EFI_LOAD_ERROR;
++	if (b != 0x23456789)
++		return EFI_INVALID_PARAMETER;
++	if (c != 0x3456789a)
++		return EFI_UNSUPPORTED;
++	if (d != 0x456789ab)
++		return EFI_BAD_BUFFER_SIZE;
++	if (e != 0x56789abc)
++		return EFI_BUFFER_TOO_SMALL;
++
++	return EFI_SUCCESS;
++}
++
++EFI_STATUS test_call5(void)
++{
++	return uefi_call_wrapper(test_call5_callback, 5,
++		0x12345678, 0x23456789, 0x3456789a, 0x456789ab, 0x56789abc);	
++}
++
++EFI_STATUS EFI_FUNCTION test_call6_callback(UINT32 a, UINT32 b,
++	UINT32 c, UINT32 d, UINT32 e, UINT32 f)
++{
++	if (a != 0x12345678)
++		return EFI_LOAD_ERROR;
++	if (b != 0x23456789)
++		return EFI_INVALID_PARAMETER;
++	if (c != 0x3456789a)
++		return EFI_UNSUPPORTED;
++	if (d != 0x456789ab)
++		return EFI_BAD_BUFFER_SIZE;
++	if (e != 0x56789abc)
++		return EFI_BUFFER_TOO_SMALL;
++	if (f != 0x6789abcd)
++		return EFI_NOT_READY;
++	
++	return EFI_SUCCESS;
++}
++
++EFI_STATUS test_call6(void)
++{
++	return uefi_call_wrapper(test_call6_callback, 6,
++		0x12345678, 0x23456789, 0x3456789a, 0x456789ab, 0x56789abc,
++		0x6789abcd);	
++}
++
++EFI_STATUS EFI_FUNCTION test_call7_callback(UINT32 a, UINT32 b,
++	UINT32 c, UINT32 d, UINT32 e, UINT32 f, UINT32 g)
++{
++	if (a != 0x12345678)
++		return EFI_LOAD_ERROR;
++	if (b != 0x23456789)
++		return EFI_INVALID_PARAMETER;
++	if (c != 0x3456789a)
++		return EFI_UNSUPPORTED;
++	if (d != 0x456789ab)
++		return EFI_BAD_BUFFER_SIZE;
++	if (e != 0x56789abc)
++		return EFI_BUFFER_TOO_SMALL;
++	if (f != 0x6789abcd)
++		return EFI_NOT_READY;
++	if (g != 0x789abcde)
++		return EFI_DEVICE_ERROR;
++	
++	return EFI_SUCCESS;
++}
++
++EFI_STATUS test_call7(void)
++{
++	return uefi_call_wrapper(test_call7_callback, 7,
++		0x12345678, 0x23456789, 0x3456789a, 0x456789ab,
++		0x56789abc, 0x6789abcd, 0x789abcde);	
++}
++
++EFI_STATUS EFI_FUNCTION test_call8_callback(UINT32 a, UINT32 b,
++	UINT32 c, UINT32 d, UINT32 e, UINT32 f, UINT32 g, UINT32 h)
++{
++	if (a != 0x12345678)
++		return EFI_LOAD_ERROR;
++	if (b != 0x23456789)
++		return EFI_INVALID_PARAMETER;
++	if (c != 0x3456789a)
++		return EFI_UNSUPPORTED;
++	if (d != 0x456789ab)
++		return EFI_BAD_BUFFER_SIZE;
++	if (e != 0x56789abc)
++		return EFI_BUFFER_TOO_SMALL;
++	if (f != 0x6789abcd)
++		return EFI_NOT_READY;
++	if (g != 0x789abcde)
++		return EFI_DEVICE_ERROR;
++	if (h != 0x89abcdef)
++		return EFI_WRITE_PROTECTED;
++
++	return EFI_SUCCESS;
++}
++
++EFI_STATUS test_call8(void)
++{
++	return uefi_call_wrapper(test_call8_callback, 8,
++		0x12345678,
++		0x23456789,
++		0x3456789a,
++		0x456789ab,
++		0x56789abc,
++		0x6789abcd,
++		0x789abcde,
++		0x89abcdef);	
++}
++
++EFI_STATUS EFI_FUNCTION test_call9_callback(UINT32 a, UINT32 b,
++	UINT32 c, UINT32 d, UINT32 e, UINT32 f, UINT32 g, UINT32 h, UINT32 i)
++{
++	if (a != 0x12345678)
++		return EFI_LOAD_ERROR;
++	if (b != 0x23456789)
++		return EFI_INVALID_PARAMETER;
++	if (c != 0x3456789a)
++		return EFI_UNSUPPORTED;
++	if (d != 0x456789ab)
++		return EFI_BAD_BUFFER_SIZE;
++	if (e != 0x56789abc)
++		return EFI_BUFFER_TOO_SMALL;
++	if (f != 0x6789abcd)
++		return EFI_NOT_READY;
++	if (g != 0x789abcde)
++		return EFI_DEVICE_ERROR;
++	if (h != 0x89abcdef)
++		return EFI_WRITE_PROTECTED;
++	if (i != 0x9abcdef0)
++		return EFI_OUT_OF_RESOURCES;
++
++	return EFI_SUCCESS;
++}
++
++EFI_STATUS test_call9(void)
++{
++	return uefi_call_wrapper(test_call9_callback, 9,
++		0x12345678,
++		0x23456789,
++		0x3456789a,
++		0x456789ab,
++		0x56789abc,
++		0x6789abcd,
++		0x789abcde,
++		0x89abcdef,
++		0x9abcdef0);	
++}
++
++extern EFI_STATUS test_call10(void);
++EFI_STATUS EFI_FUNCTION test_call10_callback(UINT32 a, UINT32 b,
++	UINT32 c, UINT32 d, UINT32 e, UINT32 f, UINT32 g, UINT32 h, UINT32 i,
++	UINT32 j)
++{
++	if (a != 0x12345678)
++		return EFI_LOAD_ERROR;
++	if (b != 0x23456789)
++		return EFI_INVALID_PARAMETER;
++	if (c != 0x3456789a)
++		return EFI_UNSUPPORTED;
++	if (d != 0x456789ab)
++		return EFI_BAD_BUFFER_SIZE;
++	if (e != 0x56789abc)
++		return EFI_BUFFER_TOO_SMALL;
++	if (f != 0x6789abcd)
++		return EFI_NOT_READY;
++	if (g != 0x789abcde)
++		return EFI_DEVICE_ERROR;
++	if (h != 0x89abcdef)
++		return EFI_WRITE_PROTECTED;
++	if (i != 0x9abcdef0)
++		return EFI_OUT_OF_RESOURCES;
++	if (j != 0xabcdef01)
++		return EFI_VOLUME_CORRUPTED;
++
++	return EFI_SUCCESS;
++}
++
++EFI_STATUS test_call10(void)
++{
++	return uefi_call_wrapper(test_call10_callback, 10,
++		0x12345678,
++		0x23456789,
++		0x3456789a,
++		0x456789ab,
++		0x56789abc,
++		0x6789abcd,
++		0x789abcde,
++		0x89abcdef,
++		0x9abcdef0,
++		0xabcdef01);	
++}
++
++EFI_STATUS
++efi_main (EFI_HANDLE *image, EFI_SYSTEM_TABLE *systab)
++{
++	EFI_STATUS rc = EFI_SUCCESS;
++
++	InitializeLib(image, systab);
++	PoolAllocationType = 2; /* klooj */
++
++#ifndef __x86_64__
++	uefi_call_wrapper(systab->ConOut->OutputString, 2, systab->ConOut,
++		L"This test is only valid on x86_64\n");
++	return EFI_UNSUPPORTED;
++#endif
++
++	asm volatile("out %0,%1" : : "a" ((uint8_t)0x14), "dN" (0x80));
++
++	Print(L"Hello\r\n");
++	rc = test_failure();
++	if (EFI_ERROR(rc)) {
++		Print(L"Returning Failure works\n");
++	} else {
++		Print(L"Returning failure doesn't work.\r\n");
++		Print(L"%%rax was 0x%016x, should have been 0x%016x\n",
++			rc, EFI_UNSUPPORTED);
++		return EFI_INVALID_PARAMETER;
++	} 
++
++	rc = test_call0();
++	if (!EFI_ERROR(rc)) {
++		Print(L"0 args works just fine here.\r\n");
++	} else {
++		Print(L"0 args failed: 0x%016x\n", rc);
++		return rc;
++	}
++
++	rc = test_call1();
++	if (!EFI_ERROR(rc)) {
++		Print(L"1 arg works just fine here.\r\n");
++	} else {
++		Print(L"1 arg failed: 0x%016x\n", rc);
++		return rc;
++	}
++
++	rc = test_call2();
++	if (!EFI_ERROR(rc)) {
++		Print(L"2 args works just fine here.\r\n");
++	} else {
++		Print(L"2 args failed: 0x%016x\n", rc);
++		return rc;
++	}
++
++	rc = test_call3();
++	if (!EFI_ERROR(rc)) {
++		Print(L"3 args works just fine here.\r\n");
++	} else {
++		Print(L"3 args failed: 0x%016x\n", rc);
++		return rc;
++	}
++
++	rc = test_call4();
++	if (!EFI_ERROR(rc)) {
++		Print(L"4 args works just fine here.\r\n");
++	} else {
++		Print(L"4 args failed: 0x%016x\n", rc);
++		return rc;
++	}
++
++	rc = test_call5();
++	if (!EFI_ERROR(rc)) {
++		Print(L"5 args works just fine here.\r\n");
++	} else {
++		Print(L"5 args failed: 0x%016x\n", rc);
++		return rc;
++	}
++
++	rc = test_call6();
++	if (!EFI_ERROR(rc)) {
++		Print(L"6 args works just fine here.\r\n");
++	} else {
++		Print(L"6 args failed: 0x%016x\n", rc);
++		return rc;
++	}
++
++	rc = test_call7();
++	if (!EFI_ERROR(rc)) {
++		Print(L"7 args works just fine here.\r\n");
++	} else {
++		Print(L"7 args failed: 0x%016x\n", rc);
++		return rc;
++	}
++
++	rc = test_call8();
++	if (!EFI_ERROR(rc)) {
++		Print(L"8 args works just fine here.\r\n");
++	} else {
++		Print(L"8 args failed: 0x%016x\n", rc);
++		return rc;
++	}
++
++	rc = test_call9();
++	if (!EFI_ERROR(rc)) {
++		Print(L"9 args works just fine here.\r\n");
++	} else {
++		Print(L"9 args failed: 0x%016x\n", rc);
++		return rc;
++	}
++
++	rc = test_call10();
++	if (!EFI_ERROR(rc)) {
++		Print(L"10 args works just fine here.\r\n");
++	} else {
++		Print(L"10 args failed: 0x%016x\n", rc);
++		return rc;
++	}
++
++	return rc;
++}
+-- 
+1.7.6
+
diff --git a/gnu-efi-3.0e-Add-the-routines-to-make-callbacks-work.patch b/gnu-efi-3.0e-Add-the-routines-to-make-callbacks-work.patch
new file mode 100644
index 0000000..7108379
--- /dev/null
+++ b/gnu-efi-3.0e-Add-the-routines-to-make-callbacks-work.patch
@@ -0,0 +1,142 @@
+From 3f693b16c4f9992247e11c1f15cf0e06bbf69a93 Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones at redhat.com>
+Date: Mon, 26 Jul 2010 17:04:12 -0400
+Subject: [PATCH] Add the routines to make callbacks work.
+
+GCC on x86_64 now provides a function attribute "ms_abi" to generate
+functions using the Windows x86_64 calling conventions.  These can be
+used to write callback functions to be called from UEFI.
+---
+ Make.defaults        |    2 +-
+ inc/ia32/efibind.h   |   18 +++++++++++++++++-
+ inc/ia64/efibind.h   |   19 ++++++++++++++++++-
+ inc/x86_64/efibind.h |   22 +++++++++++++++++-----
+ 4 files changed, 53 insertions(+), 8 deletions(-)
+
+diff --git a/Make.defaults b/Make.defaults
+index 529d58c..2a981a1 100644
+--- a/Make.defaults
++++ b/Make.defaults
+@@ -59,7 +59,7 @@ ifeq ($(ARCH), ia32)
+ endif
+ 
+ ifeq ($(ARCH), x86_64)
+-  CFLAGS += -DEFI_FUNCTION_WRAPPER -mno-red-zone 
++  CFLAGS += -mno-red-zone 
+   ifeq ($(HOSTARCH), ia32)
+     ARCH3264 = -m64
+   endif
+diff --git a/inc/ia32/efibind.h b/inc/ia32/efibind.h
+index 647a63e..0201ca1 100644
+--- a/inc/ia32/efibind.h
++++ b/inc/ia32/efibind.h
+@@ -234,7 +234,22 @@ typedef uint32_t   UINTN;
+ // one big module.
+ //
+ 
+-    #define EFI_DRIVER_ENTRY_POINT(InitFunction)
++    #define EFI_DRIVER_ENTRY_POINT(InitFunction)    \
++        UINTN                                       \
++        InitializeDriver (                          \
++            VOID    *ImageHandle,                   \
++            VOID    *SystemTable                    \
++            )                                       \
++        {                                           \
++            return InitFunction(ImageHandle,        \
++                    SystemTable);                   \
++        }                                           \
++                                                    \
++        EFI_STATUS efi_main(                        \
++            EFI_HANDLE image,                       \
++            EFI_SYSTEM_TABLE *systab                \
++            ) __attribute__((weak,                  \
++                    alias ("InitializeDriver")));
+ 
+     #define LOAD_INTERNAL_DRIVER(_if, type, name, entry)    \
+             (_if)->LoadInternal(type, name, entry)
+@@ -259,6 +274,7 @@ typedef uint32_t   UINTN;
+ 
+ /* No efi call wrapper for IA32 architecture */
+ #define uefi_call_wrapper(func, va_num, ...)	func(__VA_ARGS__)
++#define EFI_FUNCTION
+ 
+ #ifdef _MSC_EXTENSIONS
+ #pragma warning ( disable : 4731 )  // Suppress warnings about modification of EBP
+diff --git a/inc/ia64/efibind.h b/inc/ia64/efibind.h
+index 83ca529..aac83b3 100644
+--- a/inc/ia64/efibind.h
++++ b/inc/ia64/efibind.h
+@@ -182,7 +182,22 @@ void __mf (void);
+ // one big module.
+ //
+ 
+-#define EFI_DRIVER_ENTRY_POINT(InitFunction)
++#define EFI_DRIVER_ENTRY_POINT(InitFunction)    \
++    UINTN                                       \
++    InitializeDriver (                          \
++        VOID    *ImageHandle,                   \
++        VOID    *SystemTable                    \
++        )                                       \
++    {                                           \
++        return InitFunction(ImageHandle,        \
++                SystemTable);                   \
++    }                                           \
++                                                \
++    EFI_STATUS efi_main(                        \
++        EFI_HANDLE image,                       \
++        EFI_SYSTEM_TABLE *systab                \
++        ) __attribute__((weak,                  \
++                alias ("InitializeDriver")));
+ 
+ #define LOAD_INTERNAL_DRIVER(_if, type, name, entry)    \
+         (_if)->LoadInternal(type, name, entry)
+@@ -205,3 +220,5 @@ void __mf (void);
+ 
+ /* No efi call wrapper for IA32 architecture */
+ #define uefi_call_wrapper(func, va_num, ...)	func(__VA_ARGS__)
++#define EFI_FUNCTION
++
+diff --git a/inc/x86_64/efibind.h b/inc/x86_64/efibind.h
+index 1f8e735..9250973 100644
+--- a/inc/x86_64/efibind.h
++++ b/inc/x86_64/efibind.h
+@@ -234,7 +234,22 @@ typedef uint64_t   UINTN;
+ // one big module.
+ //
+ 
+-    #define EFI_DRIVER_ENTRY_POINT(InitFunction)
++    #define EFI_DRIVER_ENTRY_POINT(InitFunction)    \
++        UINTN                                       \
++        InitializeDriver (                          \
++            VOID    *ImageHandle,                   \
++            VOID    *SystemTable                    \
++            )                                       \
++        {                                           \
++            return InitFunction(ImageHandle,        \
++                    SystemTable);                   \
++        }                                           \
++                                                    \
++        EFI_STATUS efi_main(                        \
++            EFI_HANDLE image,                       \
++            EFI_SYSTEM_TABLE *systab                \
++            ) __attribute__((weak,                  \
++                    alias ("InitializeDriver")));
+ 
+     #define LOAD_INTERNAL_DRIVER(_if, type, name, entry)    \
+             (_if)->LoadInternal(type, name, entry)
+@@ -258,11 +273,8 @@ typedef uint64_t   UINTN;
+ #endif
+ 
+ /* for x86_64, EFI_FUNCTION_WRAPPER must be defined */
+-#ifdef  EFI_FUNCTION_WRAPPER
+ UINTN uefi_call_wrapper(void *func, unsigned long va_num, ...);
+-#else
+-#error "EFI_FUNCTION_WRAPPER must be defined for x86_64 architecture"
+-#endif
++#define EFI_FUNCTION __attribute__((ms_abi))
+ 
+ #ifdef _MSC_EXTENSIONS
+ #pragma warning ( disable : 4731 )  // Suppress warnings about modification of EBP
+-- 
+1.7.6
+
diff --git a/gnu-efi-3.0e-Guarantee-16-byte-stack-alignment-on-x86_64-efi_call.patch b/gnu-efi-3.0e-Guarantee-16-byte-stack-alignment-on-x86_64-efi_call.patch
new file mode 100644
index 0000000..36a508c
--- /dev/null
+++ b/gnu-efi-3.0e-Guarantee-16-byte-stack-alignment-on-x86_64-efi_call.patch
@@ -0,0 +1,333 @@
+From 1c5d58b7ce7df3a68fec248f7b8f2de943eb6ffd Mon Sep 17 00:00:00 2001
+From: Peter Jones <pjones at redhat.com>
+Date: Mon, 1 Aug 2011 16:00:35 -0400
+Subject: [PATCH] Guarantee 16-byte stack alignment on x86_64 efi_callN()
+
+The Windows ABI requires 16-byte stack alignment, but the ELF/SysV ABI
+only guarantees 8-byte alignment. This causes some machines to present
+undefined behavior. To solve this, add some padding to the stack and store
+our pad amount in the padding.
+
+This (along with another patch) fixes Red Hat bugzillas 669765 and
+677468 .
+---
+ lib/x86_64/efi_stub.S |  213 ++++++++++++++++++++++++++++++++++++++++---------
+ 1 files changed, 176 insertions(+), 37 deletions(-)
+
+diff --git a/lib/x86_64/efi_stub.S b/lib/x86_64/efi_stub.S
+index f9e70d4..5607779 100644
+--- a/lib/x86_64/efi_stub.S
++++ b/lib/x86_64/efi_stub.S
+@@ -6,133 +6,272 @@
+  *	Huang Ying <ying.huang at intel.com>
+  */
+ 
++/*
++ * EFI calling conventions are documented at:
++ *   http://msdn.microsoft.com/en-us/library/ms235286%28v=vs.80%29.aspx
++ * ELF calling conventions are documented at:
++ *   http://www.x86-64.org/documentation/abi.pdf
++ *
++ * Basically here are the conversion rules:
++ * a) our function pointer is in %rdi
++ * b) ELF gives us 8-byte aligned %rsp, so we need to pad out to 16-byte
++ *    alignment.
++ * c) inside each call thunker, we can only adjust the stack by
++ *    multiples of 16 bytes. "offset" below refers to however much
++ *    we allocate inside a thunker.
++ * d) rsi through r8 (elf) aka rcx through r9 (ms) require stack space
++ *    on the MS side even though it's not getting used at all.
++ * e) arguments are as follows: (elf -> ms)
++ *   1) rdi -> rcx (32 saved)
++ *   2) rsi -> rdx (32 saved)
++ *   3) rdx -> r8 ( 32 saved)
++ *   4) rcx -> r9 (32 saved)
++ *   5) r8 -> 32(%rsp) (48 saved)
++ *   6) r9 -> 40(%rsp) (48 saved)
++ *   7) pad+offset+0(%rsp) -> 48(%rsp) (64 saved)
++ *   8) pad+offset+8(%rsp) -> 56(%rsp) (64 saved)
++ *   9) pad+offset+16(%rsp) -> 64(%rsp) (80 saved)
++ *  10) pad+offset+24(%rsp) -> 72(%rsp) (80 saved)
++ *  11) pad+offset+32(%rsp) -> 80(%rsp) (96 saved)
++ *  12) pad+offset+40(%rsp) -> 88(%rsp) (96 saved)
++ * f) because the first argument we recieve in a thunker is actually the
++ *    function to be called, arguments are offset as such:
++ *   0) rdi -> caller
++ *   1) rsi -> rcx (32 saved)
++ *   2) rdx -> rdx (32 saved)
++ *   3) rcx -> r8 (32 saved)
++ *   4) r8 -> r9 (32 saved)
++ *   5) r9 -> 32(%rsp) (48 saved)
++ *   6) pad+offset+0(%rsp) -> 40(%rsp) (48 saved)
++ *   7) pad+offset+8(%rsp) -> 48(%rsp) (64 saved)
++ *   8) pad+offset+16(%rsp) -> 56(%rsp) (64 saved)
++ *   9) pad+offset+24(%rsp) -> 64(%rsp) (80 saved)
++ *  10) pad+offset+32(%rsp) -> 72(%rsp) (80 saved)
++ *  11) pad+offset+40(%rsp) -> 80(%rsp) (96 saved)
++ *  12) pad+offset+48(%rsp) -> 88(%rsp) (96 saved)
++ * e) arguments need to be moved in opposite order to avoid clobbering
++ * f) pad_stack leaves the amount of padding it added in %r11 for functions
++ *    to use
++ * g) efi -> elf calls don't need to pad the stack, because the 16-byte
++ *    alignment is also always 8-byte aligned.
++ */
++
+ #define ENTRY(name)	\
+ 	.globl name;	\
+ 	name:
+ 
++#define out(val)		\
++	push %rax ;		\
++	mov val, %rax ;		\
++	out %al, $128 ;		\
++	pop %rax
++
++#define pad_stack							\
++	subq $8, %rsp ; /* must be a multiple of 16 - sizeof(%rip) */	\
++	/* stash some handy integers */					\
++	mov $0x8, %rax ;						\
++	mov $0x10, %r10 ;						\
++	mov $0xf, %r11 ;						\
++	/* see if we need padding */					\
++	and %rsp, %rax ;						\
++	/* store the pad amount in %r11 */				\
++	cmovnz %rax, %r11 ;						\
++	cmovz %r10, %r11 ;						\
++	/* insert the padding */					\
++	subq %r11, %rsp ;						\
++	/* add the $8 we saved above in %r11 */				\
++	addq $8, %r11 ;							\
++	/* store the pad amount */					\
++	mov %r11, (%rsp) ;						\
++	/* compensate for %rip being stored on the stack by call */	\
++	addq $8, %r11
++
++#define unpad_stack							\
++	/* fetch the pad amount	we saved (%r11 has been clobbered) */	\
++	mov (%rsp), %r11 ;						\
++	/* remove the padding */					\
++	addq %r11, %rsp
++
+ ENTRY(efi_call0)
+-	subq $40, %rsp
++	pad_stack
++	subq $32, %rsp
+ 	call *%rdi
+-	addq $40, %rsp
++	addq $32, %rsp
++	unpad_stack
+ 	ret
+ 
+ ENTRY(efi_call1)
+-	subq $40, %rsp
++	pad_stack
++	subq $32, %rsp
+ 	mov  %rsi, %rcx
+ 	call *%rdi
+-	addq $40, %rsp
++	addq $32, %rsp
++	unpad_stack
+ 	ret
+ 
+ ENTRY(efi_call2)
+-	subq $40, %rsp
++	pad_stack
++	subq $32, %rsp
++	/* mov %rdx, %rdx */
+ 	mov  %rsi, %rcx
+ 	call *%rdi
+-	addq $40, %rsp
++	addq $32, %rsp
++	unpad_stack
+ 	ret
+ 
+ ENTRY(efi_call3)
+-	subq $40, %rsp
++	pad_stack
++	subq $32, %rsp
+ 	mov  %rcx, %r8
++	/* mov %rdx, %rdx */
+ 	mov  %rsi, %rcx
+ 	call *%rdi
+-	addq $40, %rsp
++	addq $32, %rsp
++	unpad_stack
+ 	ret
+ 
+ ENTRY(efi_call4)
+-	subq $40, %rsp
++	pad_stack
++	subq $32, %rsp
+ 	mov %r8, %r9
+ 	mov %rcx, %r8
++	/* mov %rdx, %rdx */
+ 	mov %rsi, %rcx
+ 	call *%rdi
+-	addq $40, %rsp
++	addq $32, %rsp
++	unpad_stack
+ 	ret
+ 
+ ENTRY(efi_call5)
+-	subq $40, %rsp
++	pad_stack
++	subq $48, %rsp
+ 	mov %r9, 32(%rsp)
+ 	mov %r8, %r9
+ 	mov %rcx, %r8
++	/* mov %rdx, %rdx */
+ 	mov %rsi, %rcx
+ 	call *%rdi
+-	addq $40, %rsp
++	addq $48, %rsp
++	unpad_stack
+ 	ret
+ 
+ ENTRY(efi_call6)
+-	subq $56, %rsp
+-	mov 56+8(%rsp), %rax
++	pad_stack
++	subq $48, %rsp
++	addq $48, %r11
++	addq %rsp, %r11
++	mov (%r11), %rax
+ 	mov %rax, 40(%rsp)
+ 	mov %r9, 32(%rsp)
+ 	mov %r8, %r9
+ 	mov %rcx, %r8
++	/* mov %rdx, %rdx */
+ 	mov %rsi, %rcx
+ 	call *%rdi
+-	addq $56, %rsp
++	addq $48, %rsp
++	unpad_stack
+ 	ret
+ 
+ ENTRY(efi_call7)
+-	subq $56, %rsp
+-	mov 56+16(%rsp), %rax
++	pad_stack
++	subq $64, %rsp
++	addq $64, %r11
++	addq $8, %r11
++	addq %rsp, %r11
++	mov (%r11), %rax
+ 	mov %rax, 48(%rsp)
+-	mov 56+8(%rsp), %rax
++	subq $8, %r11
++	mov (%r11), %rax
+ 	mov %rax, 40(%rsp)
+ 	mov %r9, 32(%rsp)
+ 	mov %r8, %r9
+ 	mov %rcx, %r8
++	/* mov %rdx, %rdx */
+ 	mov %rsi, %rcx
+ 	call *%rdi
+-	addq $56, %rsp
++	addq $64, %rsp
++	unpad_stack
+ 	ret
+ 
+ ENTRY(efi_call8)
+-	subq $72, %rsp
+-	mov 72+24(%rsp), %rax
++	pad_stack
++	subq $64, %rsp
++	addq $64, %r11
++	addq $16, %r11
++	addq %rsp, %r11
++	mov (%r11), %rax
+ 	mov %rax, 56(%rsp)
+-	mov 72+16(%rsp), %rax
++	subq $8, %r11
++	mov (%r11), %rax
+ 	mov %rax, 48(%rsp)
+-	mov 72+8(%rsp), %rax
++	subq $8, %r11
++	mov (%r11), %rax
+ 	mov %rax, 40(%rsp)
+ 	mov %r9, 32(%rsp)
+ 	mov %r8, %r9
+ 	mov %rcx, %r8
++	/* mov %rdx, %rdx */
+ 	mov %rsi, %rcx
+ 	call *%rdi
+-	addq $72, %rsp
++	addq $64, %rsp
++	unpad_stack
+ 	ret
+ 
+ ENTRY(efi_call9)
+-	subq $72, %rsp
+-	mov 72+32(%rsp), %rax
++	pad_stack
++	subq $80, %rsp
++	addq $80, %r11
++	addq $24, %r11
++	addq %rsp, %r11
++	mov (%r11), %rax
+ 	mov %rax, 64(%rsp)
+-	mov 72+24(%rsp), %rax
++	subq $8, %r11
++	mov (%r11), %rax
+ 	mov %rax, 56(%rsp)
+-	mov 72+16(%rsp), %rax
++	subq $8, %r11
++	mov (%r11), %rax
+ 	mov %rax, 48(%rsp)
+-	mov 72+8(%rsp), %rax
++	subq $8, %r11
++	mov (%r11), %rax
+ 	mov %rax, 40(%rsp)
+ 	mov %r9, 32(%rsp)
+ 	mov %r8, %r9
+ 	mov %rcx, %r8
++	/* mov %rdx, %rdx */
+ 	mov %rsi, %rcx
+ 	call *%rdi
+-	addq $72, %rsp
++	addq $80, %rsp
++	unpad_stack
+ 	ret
+ 
+ ENTRY(efi_call10)
+-	subq $88, %rsp
+-	mov 88+40(%rsp), %rax
++	pad_stack
++	subq $80, %rsp
++	addq $80, %r11
++	addq $32, %r11
++	addq %rsp, %r11
++	mov (%r11), %rax
+ 	mov %rax, 72(%rsp)
+-	mov 88+32(%rsp), %rax
++	subq $8, %r11
++	mov (%r11), %rax
+ 	mov %rax, 64(%rsp)
+-	mov 88+24(%rsp), %rax
++	subq $8, %r11
++	mov (%r11), %rax
+ 	mov %rax, 56(%rsp)
+-	mov 88+16(%rsp), %rax
++	subq $8, %r11
++	mov (%r11), %rax
+ 	mov %rax, 48(%rsp)
+-	mov 88+8(%rsp), %rax
++	subq $8, %r11
++	mov (%r11), %rax
+ 	mov %rax, 40(%rsp)
+ 	mov %r9, 32(%rsp)
+ 	mov %r8, %r9
+ 	mov %rcx, %r8
++	/* mov %rdx, %rdx */
+ 	mov %rsi, %rcx
+ 	call *%rdi
+-	addq $88, %rsp
++	addq $80, %rsp
++	unpad_stack
+ 	ret
++
++
+-- 
+1.7.6
+
diff --git a/gnu-efi.spec b/gnu-efi.spec
index ed7ecc4..3598bd2 100644
--- a/gnu-efi.spec
+++ b/gnu-efi.spec
@@ -14,6 +14,11 @@ Patch4: gnu-efi-3.0e-add-pciio.patch
 Patch5: gnu-efi-3.0e-route80h.patch
 Patch6: gnu-efi-3.0e-modelist.patch
 Patch7: gnu-efi-3.0e-route80h-add-cougarpoint.patch
+Patch8: gnu-efi-3.0e-machine-types.patch
+Patch9: gnu-efi-3.0e-Add-.S-and-.E-rules.patch
+Patch10: gnu-efi-3.0e-Guarantee-16-byte-stack-alignment-on-x86_64-efi_call.patch
+Patch11: gnu-efi-3.0e-Add-the-routines-to-make-callbacks-work.patch
+Patch12: gnu-efi-3.0e-Add-tcc.efi-to-test-our-calling-convention-shananaga.patch
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 ExclusiveArch: i686 x86_64 ia64
 BuildRequires: git
@@ -63,6 +68,12 @@ rm -rf %{buildroot}
 %attr(0644,root,root) /boot/efi/EFI/redhat/*.efi
 
 %changelog
+* Thu Aug 11 2011 Peter Jones <pjones at redhat.com> - 3.0e-14
+- Correctly pad the stack when doing uefi calls
+  Related: rhbz#677468
+- Add ability to write UEFI callbacks and drivers
+- Add test harness for ABI Calling Conventions
+
 * Thu Jun 16 2011 Peter Jones <pjones at redhat.com> - 3.0e-14
 - Handle uninitialized GOP driver gracefully.
 


More information about the scm-commits mailing list