Linux-EFI Archive on lore.kernel.org
 help / color / Atom feed
From: Ard Biesheuvel <ardb@kernel.org>
To: linux-efi@vger.kernel.org, Ingo Molnar <mingo@kernel.org>,
	Thomas Gleixner <tglx@linutronix.de>
Cc: Ard Biesheuvel <ardb@kernel.org>,
	Ard Biesheuvel <ard.biesheuvel@linaro.org>,
	linux-kernel@vger.kernel.org, Andy Lutomirski <luto@kernel.org>,
	Arvind Sankar <nivedita@alum.mit.edu>,
	Matthew Garrett <mjg59@google.com>
Subject: [PATCH 16/20] efi/x86: Allow translating 64-bit arguments for mixed mode calls
Date: Fri,  3 Jan 2020 12:39:49 +0100
Message-ID: <20200103113953.9571-17-ardb@kernel.org> (raw)
In-Reply-To: <20200103113953.9571-1-ardb@kernel.org>

From: Arvind Sankar <nivedita@alum.mit.edu>

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>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/x86/boot/compressed/eboot.c              | 16 -----
 arch/x86/include/asm/efi.h                    | 71 +++++++++++++++++--
 .../firmware/efi/libstub/efi-stub-helper.c    |  5 +-
 3 files changed, 67 insertions(+), 25 deletions(-)

diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 565ee4733579..4afd29eb5b34 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -891,19 +891,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_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.20.1


  parent reply index

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-03 11:39 [GIT PULL 00/20] More EFI updates for v5.6 Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 01/20] efi/libstub: fix boot argument handling in mixed mode entry code Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 02/20] efi/libstub/x86: force 'hidden' visibility for extern declarations Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 03/20] efi/x86: re-disable RT services for 32-bit kernels running on 64-bit EFI Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 04/20] efi/x86: map the entire EFI vendor string before copying it Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 05/20] efi/x86: avoid redundant cast of EFI firmware service pointer Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 06/20] efi/x86: split off some old memmap handling into separate routines Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 07/20] efi/x86: split SetVirtualAddresMap() wrappers into 32 and 64 bit versions Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 08/20] efi/x86: simplify i386 efi_call_phys() firmware call wrapper Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 09/20] efi/x86: simplify 64-bit EFI " Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 10/20] efi/x86: simplify mixed mode " Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 11/20] efi/x86: drop two near identical versions of efi_runtime_init() Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 12/20] efi/x86: clean up efi_systab_init() routine for legibility Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 13/20] efi/x86: don't panic or BUG() on non-critical error conditions Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 14/20] efi/x86: remove unreachable code in kexec_enter_virtual_mode() Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 15/20] efi/x86: Check number of arguments to variadic functions Ard Biesheuvel
2020-01-03 11:39 ` Ard Biesheuvel [this message]
2020-01-03 11:39 ` [PATCH 17/20] efi: Allow disabling PCI busmastering on bridges during boot Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 18/20] x86/mm: fix NX bit clearing issue in kernel_map_pages_in_pgd Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 19/20] efi/x86: don't map the entire kernel text RW for mixed mode Ard Biesheuvel
2020-01-03 11:39 ` [PATCH 20/20] efi/x86: avoid RWX mappings for all of DRAM Ard Biesheuvel
2020-01-09  9:37 ` [GIT PULL 00/20] More EFI updates for v5.6 Ard Biesheuvel
2020-01-10 18:13   ` Ingo Molnar
2020-01-13  7:29     ` Ard Biesheuvel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200103113953.9571-17-ardb@kernel.org \
    --to=ardb@kernel.org \
    --cc=ard.biesheuvel@linaro.org \
    --cc=linux-efi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luto@kernel.org \
    --cc=mingo@kernel.org \
    --cc=mjg59@google.com \
    --cc=nivedita@alum.mit.edu \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Linux-EFI Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-efi/0 linux-efi/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-efi linux-efi/ https://lore.kernel.org/linux-efi \
		linux-efi@vger.kernel.org
	public-inbox-index linux-efi

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-efi


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git