diff options
author | Nigel Croxon <nigel.croxon@hp.com> | 2013-06-12 09:38:10 -0400 |
---|---|---|
committer | Nigel Croxon <nigel.croxon@hp.com> | 2013-06-12 09:38:10 -0400 |
commit | c0b8d974a6cb6ad6e562ebb972ae32d21671e605 (patch) | |
tree | 3c7b7959306962c311bee534852ef19b2e2df3bd | |
parent | 0ca0dacb59d71d9078604df290ea285f460b61fc (diff) | |
download | gnu-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.h | 60 | ||||
-rw-r--r-- | gnu-efi-3.0/lib/x86_64/callwrap.c | 89 |
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 */ |