From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.1 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9B398C2D0CE for ; Fri, 3 Jan 2020 11:41:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 67F9B21835 for ; Fri, 3 Jan 2020 11:41:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1578051667; bh=WzvkVJw16gcw6hemFqW6TdkXxe+wQNU4zcPETDM7LaI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-ID:From; b=ytq6Zw+TFTFEJVz4c3+aVYhVtwuMh7SAo+OJA8qVaNI/1lKk/EDHoH77UFpbNHIUQ UhYNeL7oRb5I+3aCiTDkk+xg7Qsm9SEDW1UpTEJ4zWLDKuTUI/6+UIy57xU6P2K0TS L2CAbpjWA6ZRNtZD/lQroELbIVVMbiZe/9spSFYk= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727867AbgACLku (ORCPT ); Fri, 3 Jan 2020 06:40:50 -0500 Received: from mail.kernel.org ([198.145.29.99]:40644 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727876AbgACLku (ORCPT ); Fri, 3 Jan 2020 06:40:50 -0500 Received: from localhost.localdomain (amontpellier-657-1-18-247.w109-210.abo.wanadoo.fr [109.210.65.247]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 5758C2464E; Fri, 3 Jan 2020 11:40:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1578051649; bh=WzvkVJw16gcw6hemFqW6TdkXxe+wQNU4zcPETDM7LaI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dZ2yUKhucLq1wHv0KO4hMuVe57X/etT+PrLRVUWI0WxTrLidCBlzzNe6FhIScy9Nd AwjdNjldZQenDB1Qc8e6M7B3CrJQwFCzAbZUMzbwAxJ9yZNkQLUnTPoNsg+PftJ9xu hldK26SVZmmS+rjzpNMo+CoLnBhAxWc/hZLFB++4= From: Ard Biesheuvel To: linux-efi@vger.kernel.org, Ingo Molnar , Thomas Gleixner Cc: Ard Biesheuvel , Ard Biesheuvel , linux-kernel@vger.kernel.org, Andy Lutomirski , Arvind Sankar , Matthew Garrett 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> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200103113953.9571-1-ardb@kernel.org> References: <20200103113953.9571-1-ardb@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-efi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-efi@vger.kernel.org From: Arvind Sankar 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 Signed-off-by: Ard Biesheuvel --- 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_, 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