summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNigel Croxon <nigel.croxon@hp.com>2013-06-12 09:38:10 -0400
committerNigel Croxon <nigel.croxon@hp.com>2013-06-12 09:38:10 -0400
commitc0b8d974a6cb6ad6e562ebb972ae32d21671e605 (patch)
tree3c7b7959306962c311bee534852ef19b2e2df3bd
parent0ca0dacb59d71d9078604df290ea285f460b61fc (diff)
downloadgnu-efi-3.0-c0b8d974a6cb6ad6e562ebb972ae32d21671e605.tar.gz
gnu-efi-3.0-c0b8d974a6cb6ad6e562ebb972ae32d21671e605.tar.xz
gnu-efi-3.0-c0b8d974a6cb6ad6e562ebb972ae32d21671e605.zip
fix parameter-passing corruption on x86_64 for >= 5 args
On x86_64 without HAVE_USE_MS_ABI support, uefi_call_wrapper() is a variadic function. Parameters >=5 are copied to the stack and, when passed small immediate values (and possibly other parameters), gcc would emit a movl instruction before calling uefi_call_wrapper(). As a result, only the lower 32b of these stack values are significant, the upper 32b potentially contain garbage. Considering that uefi_call_wrapper() assumes these arguments are clean 64b values before calling the efi_callX() trampolines, the latter may be passed garbage. This makes calling functions like EFI_PCI_IO_PROTOCOL.Mem.Read()/Write() or BS->OpenProtocol() quite unreliable. This patch fixes this by turning uefi_call_wrapper() into a macro that allows to expose the efi_callX() trampoline signatures to the callers, so that gcc can know upfront that it has to pass all arguments to efi_callX() as clean 64b values (eg. movq for immediates). The _cast64_efi_callX macros are just here to avoid a gcc warning, they do nothing otherwise. Signed-off-by: David Decotigny <decot@googlers.com>
-rw-r--r--gnu-efi-3.0/inc/x86_64/efibind.h60
-rw-r--r--gnu-efi-3.0/lib/x86_64/callwrap.c89
2 files changed, 59 insertions, 90 deletions
diff --git a/gnu-efi-3.0/inc/x86_64/efibind.h b/gnu-efi-3.0/inc/x86_64/efibind.h
index ee620f2..d322b6c 100644
--- a/gnu-efi-3.0/inc/x86_64/efibind.h
+++ b/gnu-efi-3.0/inc/x86_64/efibind.h
@@ -290,7 +290,64 @@ typedef uint64_t UINTN;
#if defined(HAVE_USE_MS_ABI)
#define uefi_call_wrapper(func, va_num, ...) func(__VA_ARGS__)
#else
-UINTN uefi_call_wrapper(void *func, unsigned long va_num, ...);
+/* Prototypes of EFI cdecl -> stdcall trampolines */
+UINT64 efi_call0(void *func);
+UINT64 efi_call1(void *func, UINT64 arg1);
+UINT64 efi_call2(void *func, UINT64 arg1, UINT64 arg2);
+UINT64 efi_call3(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3);
+UINT64 efi_call4(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
+ UINT64 arg4);
+UINT64 efi_call5(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
+ UINT64 arg4, UINT64 arg5);
+UINT64 efi_call6(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
+ UINT64 arg4, UINT64 arg5, UINT64 arg6);
+UINT64 efi_call7(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
+ UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7);
+UINT64 efi_call8(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
+ UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7,
+ UINT64 arg8);
+UINT64 efi_call9(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
+ UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7,
+ UINT64 arg8, UINT64 arg9);
+UINT64 efi_call10(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
+ UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7,
+ UINT64 arg8, UINT64 arg9, UINT64 arg10);
+
+/* Front-ends to efi_callX to avoid compiler warnings */
+#define _cast64_efi_call0(f) \
+ efi_call0(f)
+#define _cast64_efi_call1(f,a1) \
+ efi_call1(f, (UINT64)(a1))
+#define _cast64_efi_call2(f,a1,a2) \
+ efi_call2(f, (UINT64)(a1), (UINT64)(a2))
+#define _cast64_efi_call3(f,a1,a2,a3) \
+ efi_call3(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3))
+#define _cast64_efi_call4(f,a1,a2,a3,a4) \
+ efi_call4(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4))
+#define _cast64_efi_call5(f,a1,a2,a3,a4,a5) \
+ efi_call5(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
+ (UINT64)(a5))
+#define _cast64_efi_call6(f,a1,a2,a3,a4,a5,a6) \
+ efi_call6(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
+ (UINT64)(a5), (UINT64)(a6))
+#define _cast64_efi_call7(f,a1,a2,a3,a4,a5,a6,a7) \
+ efi_call7(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
+ (UINT64)(a5), (UINT64)(a6), (UINT64)(a7))
+#define _cast64_efi_call8(f,a1,a2,a3,a4,a5,a6,a7,a8) \
+ efi_call8(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
+ (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8))
+#define _cast64_efi_call9(f,a1,a2,a3,a4,a5,a6,a7,a8,a9) \
+ efi_call9(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
+ (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8), \
+ (UINT64)(a9))
+#define _cast64_efi_call10(f,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) \
+ efi_call10(f, (UINT64)(a1), (UINT64)(a2), (UINT64)(a3), (UINT64)(a4), \
+ (UINT64)(a5), (UINT64)(a6), (UINT64)(a7), (UINT64)(a8), \
+ (UINT64)(a9), (UINT64)(a10))
+
+#define uefi_call_wrapper(func,va_num,...) \
+ _cast64_efi_call ## va_num (func , ##__VA_ARGS__)
+
#endif
#define EFI_FUNCTION __attribute__((ms_abi))
@@ -299,4 +356,3 @@ UINTN uefi_call_wrapper(void *func, unsigned long va_num, ...);
#endif
#endif
-
diff --git a/gnu-efi-3.0/lib/x86_64/callwrap.c b/gnu-efi-3.0/lib/x86_64/callwrap.c
index d094c88..30a5322 100644
--- a/gnu-efi-3.0/lib/x86_64/callwrap.c
+++ b/gnu-efi-3.0/lib/x86_64/callwrap.c
@@ -37,91 +37,4 @@
* SUCH DAMAGE.
*/
-#include "efi.h"
-#include "efistdarg.h"
-
-#if !defined(HAVE_USE_MS_ABI)
-UINT64 efi_call0(void *func);
-UINT64 efi_call1(void *func, UINT64 arg1);
-UINT64 efi_call2(void *func, UINT64 arg1, UINT64 arg2);
-UINT64 efi_call3(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3);
-UINT64 efi_call4(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
- UINT64 arg4);
-UINT64 efi_call5(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
- UINT64 arg4, UINT64 arg5);
-UINT64 efi_call6(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
- UINT64 arg4, UINT64 arg5, UINT64 arg6);
-UINT64 efi_call7(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
- UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7);
-UINT64 efi_call8(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
- UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7,
- UINT64 arg8);
-UINT64 efi_call9(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
- UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7,
- UINT64 arg8, UINT64 arg9);
-UINT64 efi_call10(void *func, UINT64 arg1, UINT64 arg2, UINT64 arg3,
- UINT64 arg4, UINT64 arg5, UINT64 arg6, UINT64 arg7,
- UINT64 arg8, UINT64 arg9, UINT64 arg10);
-
-#define EFI_ARG_NUM_MAX 10
-
-EFI_STATUS uefi_call_wrapper(void *fp, unsigned long va_num, ...)
-{
- va_list ap;
- int i;
- unsigned long args[EFI_ARG_NUM_MAX];
-
- if (va_num > EFI_ARG_NUM_MAX || va_num < 0) {
- return EFI_LOAD_ERROR;
- }
- va_start(ap, va_num);
- for (i = 0; i < va_num; i++) {
- args[i] = va_arg(ap, UINT64);
- }
- va_end(ap);
- /* As the number of args grows extend it appropriately */
- switch (va_num) {
- case 0:
- return efi_call0(fp);
- case 1:
- return efi_call1(fp, args[0]);
- case 2:
- return efi_call2(fp,
- args[0], args[1]);
- case 3:
- return efi_call3(fp,
- args[0], args[1], args[2]);
- case 4:
- return efi_call4(fp,
- args[0], args[1], args[2], args[3]);
- case 5:
- return efi_call5(fp,
- args[0], args[1], args[2], args[3],
- args[4]);
- case 6:
- return efi_call6(fp,
- args[0], args[1], args[2], args[3],
- args[4], args[5]);
- case 7:
- return efi_call7(fp,
- args[0], args[1], args[2], args[3],
- args[4], args[5], args[6]);
- case 8:
- return efi_call8(fp,
- args[0], args[1], args[2], args[3],
- args[4], args[5], args[6], args[7]);
- case 9:
- return efi_call9(fp,
- args[0], args[1], args[2], args[3],
- args[4], args[5], args[6], args[7],
- args[8]);
- case 10:
- return efi_call10(fp,
- args[0], args[1], args[2], args[3],
- args[4], args[5], args[6], args[7],
- args[8], args[9]);
- default:
- return EFI_LOAD_ERROR;
- }
-}
-#endif
+/* uefi_call_wrapper() is a macro in efibind.h */