All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions
@ 2019-12-30 20:00 Arvind Sankar
  2019-12-30 20:00 ` [RFC PATCH 2/2] efi/x86: Allow translating 64-bit arguments for mixed mode calls Arvind Sankar
  2019-12-30 20:10 ` [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions Arvind Sankar
  0 siblings, 2 replies; 7+ messages in thread
From: Arvind Sankar @ 2019-12-30 20:00 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: linux-efi

On x86 we need to thunk through assembler stubs to call the EFI services
in many cases. The assembler stub has limits on how many arguments it
handles. Introduce a few macros to check that we do not try to pass too
many arguments to the stubs.

Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu>
---
 arch/x86/include/asm/efi.h | 52 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index c49619a28be8..c9800802894f 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -8,6 +8,7 @@
 #include <asm/tlb.h>
 #include <asm/nospec-branch.h>
 #include <asm/mmu_context.h>
+#include <linux/build_bug.h>
 
 /*
  * We map the EFI regions needed for runtime services non-contiguously,
@@ -34,6 +35,47 @@
 
 #define ARCH_EFI_IRQ_FLAGS_MASK	X86_EFLAGS_IF
 
+/*
+ * The EFI services are called through variadic functions in many cases. These
+ * functions are implemented in assembler and support only a fixed number of
+ * arguments. The macros below allows us to check at build time that we don't
+ * try to call them with too many arguments.
+ */
+
+/*
+ * __efi_nargs() will return the number of arguments if it is 7 or less, and
+ * cause a BUILD_BUG otherwise. The limitations of the C preprocessor make it
+ * impossible to calculate the exact number of arguments beyond some
+ * pre-defined limit. The maximum number of arguments currently supported by
+ * any of the thunks is 7, so this is good enough for now and can be extended
+ * in the obvious way if we ever need more.
+ */
+
+#define __efi_nargs(...) __efi_nargs_(0, ##__VA_ARGS__)
+#define __efi_nargs_(...) __efi_nargs__(__VA_ARGS__,		\
+	__efi_arg_sentinel(7), __efi_arg_sentinel(6),		\
+	__efi_arg_sentinel(5), __efi_arg_sentinel(4),		\
+	__efi_arg_sentinel(3), __efi_arg_sentinel(2),		\
+	__efi_arg_sentinel(1), __efi_arg_sentinel(0))
+#define __efi_nargs__(_0, _1, _2, _3, _4, _5, _6, _7, n, ...)	\
+	__take_second_arg(n,					\
+		({ BUILD_BUG_ON_MSG(1, "__efi_nargs limit exceeded"); 8; }))
+#define __efi_arg_sentinel(n) , n
+
+/*
+ * __efi_nargs_check(f, n, ...) will cause a BUILD_BUG if the ellipsis
+ * represents more than n arguments.
+ */
+
+#define __efi_nargs_check(f, n, ...) \
+	__efi_nargs_check_(f, __efi_nargs(__VA_ARGS__), n, ##__VA_ARGS__)
+#define __efi_nargs_check_(...) __efi_nargs_check__(__VA_ARGS__)
+#define __efi_nargs_check__(f, p, n, ...) ({				\
+	BUILD_BUG_ON_MSG(						\
+		(p) > (n),						\
+		#f " called with too many arguments (" #p ">" #n ")");	\
+})
+
 #ifdef CONFIG_X86_32
 
 extern asmlinkage
@@ -62,6 +104,11 @@ unsigned long efi_call_phys(void *, unsigned long, unsigned long, u32, void *);
 
 extern asmlinkage u64 efi_call(void *fp, ...);
 
+#define efi_call(...) ({						\
+	__efi_nargs_check(efi_call, 7, __VA_ARGS__);			\
+	efi_call(__VA_ARGS__);						\
+})
+
 #define efi_call_phys(f, args...)		efi_call((f), args)
 
 /*
@@ -149,6 +196,11 @@ extern u64 efi_setup;
 #ifdef CONFIG_EFI
 extern efi_status_t efi64_thunk(u32, ...);
 
+#define efi64_thunk(...) ({						\
+	__efi_nargs_check(efi64_thunk, 6, __VA_ARGS__);			\
+	efi64_thunk(__VA_ARGS__);					\
+})
+
 static inline bool efi_is_mixed(void)
 {
 	if (!IS_ENABLED(CONFIG_EFI_MIXED))
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [RFC PATCH 2/2] efi/x86: Allow translating 64-bit arguments for mixed mode calls
  2019-12-30 20:00 [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions Arvind Sankar
@ 2019-12-30 20:00 ` Arvind Sankar
  2019-12-30 20:10 ` [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions Arvind Sankar
  1 sibling, 0 replies; 7+ messages in thread
From: Arvind Sankar @ 2019-12-30 20:00 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: linux-efi

When an EFI call takes 64-bit arguments, the mixed-mode call must push
the two 32-bit halves as separate arguments onto the stack.

Introduce the ability to define macros to perform this translation for
the calls that need it, and use it for free_pages.

Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu>
---
 arch/x86/boot/compressed/eboot.c              | 17 ------------
 arch/x86/include/asm/efi.h                    | 27 +++++++++++++++----
 .../firmware/efi/libstub/efi-stub-helper.c    |  5 +---
 3 files changed, 23 insertions(+), 26 deletions(-)

diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 98477f3529f6..4884483ec093 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -889,20 +889,3 @@ struct boot_params *efi_main(efi_handle_t handle,
 	for (;;)
 		asm("hlt");
 }
-
-#ifdef CONFIG_EFI_MIXED
-void efi_free_native(unsigned long size, unsigned long addr);
-
-void efi_free(unsigned long size, unsigned long addr)
-{
-	if (!size)
-		return;
-
-	if (efi_is_native())
-		efi_free_native(size, addr);
-	else
-		efi64_thunk(efi_table_attr(efi_system_table(),
-					   boottime)->mixed_mode.free_pages,
-			    addr, 0, DIV_ROUND_UP(size, EFI_PAGE_SIZE));
-}
-#endif
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index c9800802894f..5f70499803a1 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -258,22 +258,39 @@ static inline bool efi_is_native(void)
 		: (__typeof__(inst->attr))				\
 			efi_mixed_mode_cast(inst->mixed_mode.attr))
 
+#define __efi64_thunk(inst, func, ...)					\
+	efi64_thunk(inst->mixed_mode.func,				\
+		__efi64_argmap(__efi64_argmap_ ## func, __VA_ARGS__))
+
+#define __efi64_argmap(map, ...)					\
+	__PASTE(__efi64_argmap__,					\
+		__efi64_argmap_def_p(map(__VA_ARGS__)))(map, __VA_ARGS__)
+
+#define __efi64_argmap__undef(map, ...) __VA_ARGS__
+#define __efi64_argmap__def(map, ...) map(__VA_ARGS__)
+
+#define __efi64_argmap_def_p(...)					\
+	__efi64_argmap_def_p_(__VA_ARGS__, __efi_arg_sentinel(undef))
+#define __efi64_argmap_def_p_(_0, n, ...) __take_second_arg(n, def)
+
 #define efi_call_proto(inst, func, ...)					\
 	(efi_is_native()						\
 		? inst->func(inst, ##__VA_ARGS__)			\
-		: efi64_thunk(inst->mixed_mode.func, inst, ##__VA_ARGS__))
+		: __efi64_thunk(inst, func, inst, ##__VA_ARGS__))
 
 #define efi_bs_call(func, ...)						\
 	(efi_is_native()						\
 		? efi_system_table()->boottime->func(__VA_ARGS__)	\
-		: efi64_thunk(efi_table_attr(efi_system_table(),	\
-				boottime)->mixed_mode.func, __VA_ARGS__))
+		: __efi64_thunk(efi_table_attr(efi_system_table(),	\
+				boottime), func, __VA_ARGS__))
 
 #define efi_rt_call(func, ...)						\
 	(efi_is_native()						\
 		? efi_system_table()->runtime->func(__VA_ARGS__)	\
-		: efi64_thunk(efi_table_attr(efi_system_table(),	\
-				runtime)->mixed_mode.func, __VA_ARGS__))
+		: __efi64_thunk(efi_table_attr(efi_system_table(),	\
+				runtime), func, __VA_ARGS__))
+
+#define __efi64_argmap_free_pages(addr, size) (addr), 0, (size)
 
 extern bool efi_reboot_required(void);
 extern bool efi_is_table_address(unsigned long phys_addr);
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index f1b9c36934e9..fcc45ee94e02 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -344,9 +344,6 @@ efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
 }
 
 void efi_free(unsigned long size, unsigned long addr)
-	__weak __alias(efi_free_native);
-
-void efi_free_native(unsigned long size, unsigned long addr)
 {
 	unsigned long nr_pages;
 
@@ -354,7 +351,7 @@ void efi_free_native(unsigned long size, unsigned long addr)
 		return;
 
 	nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
-	efi_system_table()->boottime->free_pages(addr, nr_pages);
+	efi_bs_call(free_pages, addr, nr_pages);
 }
 
 static efi_status_t efi_file_size(void *__fh, efi_char16_t *filename_16,
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions
  2019-12-30 20:00 [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions Arvind Sankar
  2019-12-30 20:00 ` [RFC PATCH 2/2] efi/x86: Allow translating 64-bit arguments for mixed mode calls Arvind Sankar
@ 2019-12-30 20:10 ` Arvind Sankar
  2019-12-31  0:21   ` Ard Biesheuvel
  1 sibling, 1 reply; 7+ messages in thread
From: Arvind Sankar @ 2019-12-30 20:10 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: linux-efi

This is on top of https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git/log/?h=next

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions
  2019-12-30 20:10 ` [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions Arvind Sankar
@ 2019-12-31  0:21   ` Ard Biesheuvel
       [not found]     ` <DM6PR04MB5116612398311EFAB71BCFE9AA260@DM6PR04MB5116.namprd04.prod.outlook.com>
  0 siblings, 1 reply; 7+ messages in thread
From: Ard Biesheuvel @ 2019-12-31  0:21 UTC (permalink / raw)
  To: Arvind Sankar; +Cc: Ard Biesheuvel, linux-efi

On Mon, 30 Dec 2019 at 21:10, Arvind Sankar <nivedita@alum.mit.edu> wrote:
>
> This is on top of https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git/log/?h=next

Good stuff!

I'd like to make a few tweaks, but this is definitely something I'd
like to incorporate for v5.6

The macros are a bit light on documentation, and I'd prefer to avoid
macros recursively invoking C functions with the same name if we can.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions
       [not found]     ` <DM6PR04MB5116612398311EFAB71BCFE9AA260@DM6PR04MB5116.namprd04.prod.outlook.com>
@ 2019-12-31  8:12       ` Ard Biesheuvel
  2019-12-31 22:47         ` [PATCH " Arvind Sankar
  0 siblings, 1 reply; 7+ messages in thread
From: Ard Biesheuvel @ 2019-12-31  8:12 UTC (permalink / raw)
  To: niveditas98 .; +Cc: Ard Biesheuvel, linux-efi

On Tue, 31 Dec 2019 at 01:26, niveditas98 . <nivedita@alum.mit.edu> wrote:
>
> Yeah I forgot to add comments for the second one before sending.
>
> For the first one I agree on the naming. If it looks sensible otherwise I can revise that.
>

Yes please

Also, could we use the argmaps to zero init the top half of OUT pointers? E.g.,

#define __efi64_argmap_allocate_pool(type, size, buffer)  (type),
(size), efi_zi(buffer)

static inline void *efi_zi(void *p)
{
    ((u32 *)p)[1] = 0;
    return p;
}

That would make the mixed mode support in the stub much more robust.


>
> ________________________________
> From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> Sent: Monday, December 30, 2019 7:21 PM
> To: Arvind Sankar
> Cc: Ard Biesheuvel; linux-efi
> Subject: Re: [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions
>
> On Mon, 30 Dec 2019 at 21:10, Arvind Sankar <nivedita@alum.mit.edu> wrote:
> >
> > This is on top of https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git/log/?h=next
>
> Good stuff!
>
> I'd like to make a few tweaks, but this is definitely something I'd
> like to incorporate for v5.6
>
> The macros are a bit light on documentation, and I'd prefer to avoid
> macros recursively invoking C functions with the same name if we can.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] efi/x86: Check number of arguments to variadic functions
  2019-12-31  8:12       ` Ard Biesheuvel
@ 2019-12-31 22:47         ` Arvind Sankar
  2019-12-31 22:47           ` [PATCH 2/2] efi/x86: Allow translating 64-bit arguments for mixed mode calls Arvind Sankar
  0 siblings, 1 reply; 7+ messages in thread
From: Arvind Sankar @ 2019-12-31 22:47 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: linux-efi

On x86 we need to thunk through assembler stubs to call the EFI services
for mixed mode, and for runtime services in 64-bit mode. The assembler
stubs have limits on how many arguments it handles. Introduce a few
macros to check that we do not try to pass too many arguments to the
stubs.

Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu>
---
 arch/x86/boot/compressed/efi_thunk_64.S |  4 +-
 arch/x86/include/asm/efi.h              | 54 ++++++++++++++++++++++++-
 arch/x86/platform/efi/efi_stub_64.S     |  4 +-
 arch/x86/platform/efi/efi_thunk_64.S    |  4 +-
 4 files changed, 58 insertions(+), 8 deletions(-)

diff --git a/arch/x86/boot/compressed/efi_thunk_64.S b/arch/x86/boot/compressed/efi_thunk_64.S
index 6d95eb6b8912..d040ff5458e5 100644
--- a/arch/x86/boot/compressed/efi_thunk_64.S
+++ b/arch/x86/boot/compressed/efi_thunk_64.S
@@ -23,7 +23,7 @@
 
 	.code64
 	.text
-SYM_FUNC_START(efi64_thunk)
+SYM_FUNC_START(__efi64_thunk)
 	push	%rbp
 	push	%rbx
 
@@ -95,7 +95,7 @@ SYM_FUNC_START(efi64_thunk)
 	pop	%rbx
 	pop	%rbp
 	ret
-SYM_FUNC_END(efi64_thunk)
+SYM_FUNC_END(__efi64_thunk)
 
 	.code32
 /*
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index e7e9c6e057f9..cfc450085584 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -8,6 +8,7 @@
 #include <asm/tlb.h>
 #include <asm/nospec-branch.h>
 #include <asm/mmu_context.h>
+#include <linux/build_bug.h>
 
 /*
  * We map the EFI regions needed for runtime services non-contiguously,
@@ -34,6 +35,45 @@
 
 #define ARCH_EFI_IRQ_FLAGS_MASK	X86_EFLAGS_IF
 
+/*
+ * The EFI services are called through variadic functions in many cases. These
+ * functions are implemented in assembler and support only a fixed number of
+ * arguments. The macros below allows us to check at build time that we don't
+ * try to call them with too many arguments.
+ *
+ * __efi_nargs() will return the number of arguments if it is 7 or less, and
+ * cause a BUILD_BUG otherwise. The limitations of the C preprocessor make it
+ * impossible to calculate the exact number of arguments beyond some
+ * pre-defined limit. The maximum number of arguments currently supported by
+ * any of the thunks is 7, so this is good enough for now and can be extended
+ * in the obvious way if we ever need more.
+ */
+
+#define __efi_nargs(...) __efi_nargs_(__VA_ARGS__)
+#define __efi_nargs_(...) __efi_nargs__(0, ##__VA_ARGS__,	\
+	__efi_arg_sentinel(7), __efi_arg_sentinel(6),		\
+	__efi_arg_sentinel(5), __efi_arg_sentinel(4),		\
+	__efi_arg_sentinel(3), __efi_arg_sentinel(2),		\
+	__efi_arg_sentinel(1), __efi_arg_sentinel(0))
+#define __efi_nargs__(_0, _1, _2, _3, _4, _5, _6, _7, n, ...)	\
+	__take_second_arg(n,					\
+		({ BUILD_BUG_ON_MSG(1, "__efi_nargs limit exceeded"); 8; }))
+#define __efi_arg_sentinel(n) , n
+
+/*
+ * __efi_nargs_check(f, n, ...) will cause a BUILD_BUG if the ellipsis
+ * represents more than n arguments.
+ */
+
+#define __efi_nargs_check(f, n, ...)					\
+	__efi_nargs_check_(f, __efi_nargs(__VA_ARGS__), n)
+#define __efi_nargs_check_(f, p, n) __efi_nargs_check__(f, p, n)
+#define __efi_nargs_check__(f, p, n) ({					\
+	BUILD_BUG_ON_MSG(						\
+		(p) > (n),						\
+		#f " called with too many arguments (" #p ">" #n ")");	\
+})
+
 #ifdef CONFIG_X86_32
 #define arch_efi_call_virt_setup()					\
 ({									\
@@ -56,7 +96,12 @@
 
 #define EFI_LOADER_SIGNATURE	"EL64"
 
-extern asmlinkage u64 efi_call(void *fp, ...);
+extern asmlinkage u64 __efi_call(void *fp, ...);
+
+#define efi_call(...) ({						\
+	__efi_nargs_check(efi_call, 7, __VA_ARGS__);			\
+	__efi_call(__VA_ARGS__);					\
+})
 
 /*
  * struct efi_scratch - Scratch space used while switching to/from efi_mm
@@ -139,7 +184,12 @@ struct efi_setup_data {
 extern u64 efi_setup;
 
 #ifdef CONFIG_EFI
-extern efi_status_t efi64_thunk(u32, ...);
+extern efi_status_t __efi64_thunk(u32, ...);
+
+#define efi64_thunk(...) ({						\
+	__efi_nargs_check(efi64_thunk, 6, __VA_ARGS__);			\
+	__efi64_thunk(__VA_ARGS__);					\
+})
 
 static inline bool efi_is_mixed(void)
 {
diff --git a/arch/x86/platform/efi/efi_stub_64.S b/arch/x86/platform/efi/efi_stub_64.S
index e7e1020f4ccb..15da118f04f0 100644
--- a/arch/x86/platform/efi/efi_stub_64.S
+++ b/arch/x86/platform/efi/efi_stub_64.S
@@ -10,7 +10,7 @@
 #include <linux/linkage.h>
 #include <asm/nospec-branch.h>
 
-SYM_FUNC_START(efi_call)
+SYM_FUNC_START(__efi_call)
 	pushq %rbp
 	movq %rsp, %rbp
 	and $~0xf, %rsp
@@ -24,4 +24,4 @@ SYM_FUNC_START(efi_call)
 	CALL_NOSPEC %rdi
 	leave
 	ret
-SYM_FUNC_END(efi_call)
+SYM_FUNC_END(__efi_call)
diff --git a/arch/x86/platform/efi/efi_thunk_64.S b/arch/x86/platform/efi/efi_thunk_64.S
index 162b35729633..26f0da238c1c 100644
--- a/arch/x86/platform/efi/efi_thunk_64.S
+++ b/arch/x86/platform/efi/efi_thunk_64.S
@@ -25,7 +25,7 @@
 
 	.text
 	.code64
-SYM_CODE_START(efi64_thunk)
+SYM_CODE_START(__efi64_thunk)
 	push	%rbp
 	push	%rbx
 
@@ -69,4 +69,4 @@ SYM_CODE_START(efi64_thunk)
 2:	pushl	$__KERNEL_CS
 	pushl	%ebp
 	lret
-SYM_CODE_END(efi64_thunk)
+SYM_CODE_END(__efi64_thunk)
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] efi/x86: Allow translating 64-bit arguments for mixed mode calls
  2019-12-31 22:47         ` [PATCH " Arvind Sankar
@ 2019-12-31 22:47           ` Arvind Sankar
  0 siblings, 0 replies; 7+ messages in thread
From: Arvind Sankar @ 2019-12-31 22:47 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: linux-efi

Introduce the ability to define macros to perform argument translation
for the calls that need it, and define them for the boot services that
we currently use.

When calling 32-bit firmware methods in mixed mode, all output
parameters that are 32-bit according to the firmware, but 64-bit in the
kernel (ie OUT UINTN * or OUT VOID **) must be initialized in the
kernel, or the upper 32 bits may contain garbage. Define macros that
zero out the upper 32 bits of the output before invoking the firmware
method.

When a 32-bit EFI call takes 64-bit arguments, the mixed-mode call must
push the two 32-bit halves as separate arguments onto the stack. This
can be achieved by splitting the argument into its two halves when
calling the assembler thunk. Define a macro to do this for the
free_pages boot service.

Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu>
---
 arch/x86/boot/compressed/eboot.c              | 17 -----
 arch/x86/include/asm/efi.h                    | 71 +++++++++++++++++--
 .../firmware/efi/libstub/efi-stub-helper.c    |  5 +-
 3 files changed, 67 insertions(+), 26 deletions(-)

diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 98477f3529f6..4884483ec093 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -889,20 +889,3 @@ struct boot_params *efi_main(efi_handle_t handle,
 	for (;;)
 		asm("hlt");
 }
-
-#ifdef CONFIG_EFI_MIXED
-void efi_free_native(unsigned long size, unsigned long addr);
-
-void efi_free(unsigned long size, unsigned long addr)
-{
-	if (!size)
-		return;
-
-	if (efi_is_native())
-		efi_free_native(size, addr);
-	else
-		efi64_thunk(efi_table_attr(efi_system_table(),
-					   boottime)->mixed_mode.free_pages,
-			    addr, 0, DIV_ROUND_UP(size, EFI_PAGE_SIZE));
-}
-#endif
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index cfc450085584..166f0386719e 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -243,22 +243,83 @@ static inline bool efi_is_native(void)
 		: (__typeof__(inst->attr))				\
 			efi_mixed_mode_cast(inst->mixed_mode.attr))
 
+/*
+ * The following macros allow translating arguments if necessary from native to
+ * mixed mode. The use case for this is to initialize the upper 32 bits of
+ * output parameters, and where the 32-bit method requires a 64-bit argument,
+ * which must be split up into two arguments to be thunked properly.
+ *
+ * As examples, the AllocatePool boot service returns the address of the
+ * allocation, but it will not set the high 32 bits of the address. To ensure
+ * that the full 64-bit address is initialized, we zero-init the address before
+ * calling the thunk.
+ *
+ * The FreePages boot service takes a 64-bit physical address even in 32-bit
+ * mode. For the thunk to work correctly, a native 64-bit call of
+ * 	free_pages(addr, size)
+ * must be translated to
+ * 	efi64_thunk(free_pages, addr & U32_MAX, addr >> 32, size)
+ * so that the two 32-bit halves of addr get pushed onto the stack separately.
+ */
+
+static inline void *efi64_zero_upper(void *p)
+{
+	((u32 *)p)[1] = 0;
+	return p;
+}
+
+#define __efi64_argmap_free_pages(addr, size)				\
+	((addr), 0, (size))
+
+#define __efi64_argmap_get_memory_map(mm_size, mm, key, size, ver)	\
+	((mm_size), (mm), efi64_zero_upper(key), efi64_zero_upper(size), (ver))
+
+#define __efi64_argmap_allocate_pool(type, size, buffer)		\
+	((type), (size), efi64_zero_upper(buffer))
+
+#define __efi64_argmap_handle_protocol(handle, protocol, interface)	\
+	((handle), (protocol), efi64_zero_upper(interface))
+
+#define __efi64_argmap_locate_protocol(protocol, reg, interface)	\
+	((protocol), (reg), efi64_zero_upper(interface))
+
+/*
+ * The macros below handle the plumbing for the argument mapping. To add a
+ * mapping for a specific EFI method, simply define a macro
+ * __efi64_argmap_<method name>, following the examples above.
+ */
+
+#define __efi64_thunk_map(inst, func, ...)				\
+	efi64_thunk(inst->mixed_mode.func,				\
+		__efi64_argmap(__efi64_argmap_ ## func(__VA_ARGS__),	\
+			       (__VA_ARGS__)))
+
+#define __efi64_argmap(mapped, args)					\
+	__PASTE(__efi64_argmap__, __efi_nargs(__efi_eat mapped))(mapped, args)
+#define __efi64_argmap__0(mapped, args) __efi_eval mapped
+#define __efi64_argmap__1(mapped, args) __efi_eval args
+
+#define __efi_eat(...)
+#define __efi_eval(...) __VA_ARGS__
+
+/* The three macros below handle dispatching via the thunk if needed */
+
 #define efi_call_proto(inst, func, ...)					\
 	(efi_is_native()						\
 		? inst->func(inst, ##__VA_ARGS__)			\
-		: efi64_thunk(inst->mixed_mode.func, inst, ##__VA_ARGS__))
+		: __efi64_thunk_map(inst, func, inst, ##__VA_ARGS__))
 
 #define efi_bs_call(func, ...)						\
 	(efi_is_native()						\
 		? efi_system_table()->boottime->func(__VA_ARGS__)	\
-		: efi64_thunk(efi_table_attr(efi_system_table(),	\
-				boottime)->mixed_mode.func, __VA_ARGS__))
+		: __efi64_thunk_map(efi_table_attr(efi_system_table(),	\
+				boottime), func, __VA_ARGS__))
 
 #define efi_rt_call(func, ...)						\
 	(efi_is_native()						\
 		? efi_system_table()->runtime->func(__VA_ARGS__)	\
-		: efi64_thunk(efi_table_attr(efi_system_table(),	\
-				runtime)->mixed_mode.func, __VA_ARGS__))
+		: __efi64_thunk_map(efi_table_attr(efi_system_table(),	\
+				runtime), func, __VA_ARGS__))
 
 extern bool efi_reboot_required(void);
 extern bool efi_is_table_address(unsigned long phys_addr);
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index f1b9c36934e9..fcc45ee94e02 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -344,9 +344,6 @@ efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
 }
 
 void efi_free(unsigned long size, unsigned long addr)
-	__weak __alias(efi_free_native);
-
-void efi_free_native(unsigned long size, unsigned long addr)
 {
 	unsigned long nr_pages;
 
@@ -354,7 +351,7 @@ void efi_free_native(unsigned long size, unsigned long addr)
 		return;
 
 	nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
-	efi_system_table()->boottime->free_pages(addr, nr_pages);
+	efi_bs_call(free_pages, addr, nr_pages);
 }
 
 static efi_status_t efi_file_size(void *__fh, efi_char16_t *filename_16,
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-12-31 22:47 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-30 20:00 [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions Arvind Sankar
2019-12-30 20:00 ` [RFC PATCH 2/2] efi/x86: Allow translating 64-bit arguments for mixed mode calls Arvind Sankar
2019-12-30 20:10 ` [RFC PATCH 1/2] efi/x86: Check number of arguments to variadic functions Arvind Sankar
2019-12-31  0:21   ` Ard Biesheuvel
     [not found]     ` <DM6PR04MB5116612398311EFAB71BCFE9AA260@DM6PR04MB5116.namprd04.prod.outlook.com>
2019-12-31  8:12       ` Ard Biesheuvel
2019-12-31 22:47         ` [PATCH " Arvind Sankar
2019-12-31 22:47           ` [PATCH 2/2] efi/x86: Allow translating 64-bit arguments for mixed mode calls Arvind Sankar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.