From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1q1Tzt-0007vT-Cx for mharc-grub-devel@gnu.org; Tue, 23 May 2023 11:32:25 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1q1Tzi-0007fW-14 for grub-devel@gnu.org; Tue, 23 May 2023 11:32:17 -0400 Received: from dfw.source.kernel.org ([2604:1380:4641:c500::1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1q1TzX-0002Qr-NA for grub-devel@gnu.org; Tue, 23 May 2023 11:32:13 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 7C748633C2; Tue, 23 May 2023 15:32:01 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id DBB40C433D2; Tue, 23 May 2023 15:31:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1684855920; bh=LruhenR9WPK+Nr/d1cIjqNsQEKBAmrNqpOJDovhAFe0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sN9Uuotcgj73q3izY0pSBA/cohMPHU7O09baCUYSBaNiuCAa5FSbIJToVnEuM7f0j yjwur50wlypWcWrqCoTQ7kh+hEqi31eyw9YWFfi+9mLX/+h8iRI9HNBSfMuL40cE9a YuRCGfBWAb4yiiBZgA/KFap1Yt63PISlzUGaoS4xA0BYRsS8TPXjXO30XmZv04DLJs f5YiZKaGs2z9D+CxwXvKWLQNOQg8dDVdc92yQkA9ZLol5GH/JsvXt1Dr1SeB7FHDCu 2WJGDzefMjQXQP9tWmTjWFR5qTmy24LJOPGPMBLvtsjIy6tqxAsKKV71OkxJOlIEvT /+4gwJix095GQ== From: Ard Biesheuvel To: grub-devel@gnu.org Cc: Ard Biesheuvel , Daniel Kiper , Glenn Washburn Subject: [PATCH v4 5/5] efi: Use generic EFI loader for x86_64 and i386 Date: Tue, 23 May 2023 17:31:45 +0200 Message-Id: <20230523153145.822782-6-ardb@kernel.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230523153145.822782-1-ardb@kernel.org> References: <20230523153145.822782-1-ardb@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=8268; i=ardb@kernel.org; h=from:subject; bh=LruhenR9WPK+Nr/d1cIjqNsQEKBAmrNqpOJDovhAFe0=; b=owGbwMvMwCFmkMcZplerG8N4Wi2JISXnTmK6/Pttf6Zu3bpSWnL9jRUsVwqbWM10Pky72p54t Csvv52po5SFQYyDQVZMkUVg9t93O09PlKp1niULM4eVCWQIAxenAEyE05jhD3f/lw0H7kzpunOr UnTW+/Xr9jjtlbGJa5f9su3m8bJPrr4M/4un/St/fea9gNiPww8jmB7+XO5w6METPeF1uvv13LM K/3EAAA== X-Developer-Key: i=ardb@kernel.org; a=openpgp; fpr=F43D03328115A198C90016883D200E9CA6329909 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=2604:1380:4641:c500::1; envelope-from=ardb@kernel.org; helo=dfw.source.kernel.org X-Spam_score_int: -70 X-Spam_score: -7.1 X-Spam_bar: ------- X-Spam_report: (-7.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_HI=-5, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 23 May 2023 15:32:19 -0000 Switch the x86 based EFI platform builds to the generic EFI loader, which exposes the initrd via the LoadFile2 protocol instead of the x86-specific setup header. This will launch the Linux kernel via its EFI stub, which performs its own initialization in the EFI boot services context before calling ExitBootServices() and performing the bare metal Linux boot. Given that only Linux kernel versions v5.8 and later support this initrd loading method, the existing x86 loader is retained as a fallback, which will also be used for Linux kernels built without the EFI stub. In this case, GRUB calls ExitBootServices() before entering the Linux kernel, and all EFI related information is provided to the kernel via struct boot_params in the setup header, as before. Note that this means that booting EFI stub kernels older than v5.8 is not supported even when not using an initrd at all. Also, the EFI handover protocol, which has no basis in the UEFI specification, is not implemented. Signed-off-by: Ard Biesheuvel --- grub-core/Makefile.core.def | 2 + grub-core/loader/efi/linux.c | 47 ++++++++++++++++++-- grub-core/loader/i386/linux.c | 8 ++++ include/grub/efi/efi.h | 2 +- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 1d88c4d1c2555f7f..e58b511242618df7 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1853,6 +1853,8 @@ module = { loongarch64 = loader/efi/linux.c; riscv32 = loader/efi/linux.c; riscv64 = loader/efi/linux.c; + i386_efi = loader/efi/linux.c; + x86_64_efi = loader/efi/linux.c; emu = loader/emu/linux.c; common = loader/linux.c; common = lib/cmdline.c; diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c index 15e0686549d7ecca..90ad1a7b82a76066 100644 --- a/grub-core/loader/efi/linux.c +++ b/grub-core/loader/efi/linux.c @@ -69,6 +69,12 @@ static initrd_media_device_path_t initrd_lf2_device_path = { } }; +extern grub_err_t +grub_cmd_linux_x86_legacy (grub_command_t cmd, int argc, char *argv[]); + +extern grub_err_t +grub_cmd_initrd_x86_legacy (grub_command_t cmd, int argc, char *argv[]); + static grub_efi_status_t __grub_efi_api grub_efi_initrd_load_file2 (grub_efi_load_file2_t *this, grub_efi_device_path_t *device_path, @@ -125,6 +131,7 @@ grub_arch_efi_linux_load_image_header (grub_file_t file, return GRUB_ERR_NONE; } +#if !defined(__i386__) && !defined(__x86_64__) static grub_err_t finalize_params_linux (void) { @@ -169,6 +176,7 @@ failure: grub_fdt_unload(); return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); } +#endif grub_err_t grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) @@ -231,8 +239,10 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) static grub_err_t grub_linux_boot (void) { +#if !defined(__i386__) && !defined(__x86_64__) if (finalize_params_linux () != GRUB_ERR_NONE) return grub_errno; +#endif return (grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, kernel_size, linux_args)); @@ -253,7 +263,9 @@ grub_linux_unload (void) if (kernel_addr) grub_efi_free_pages ((grub_addr_t) kernel_addr, GRUB_EFI_BYTES_TO_PAGES (kernel_size)); +#if !defined(__i386__) && !defined(__x86_64__) grub_fdt_unload (); +#endif if (initrd_lf2_handle != NULL) { @@ -269,6 +281,7 @@ grub_linux_unload (void) return GRUB_ERR_NONE; } +#if !defined(__i386__) && !defined(__x86_64__) /* * As per linux/Documentation/arm/Booting * ARM initrd needs to be covered by kernel linear mapping, @@ -304,6 +317,7 @@ allocate_initrd_mem (int initrd_pages) GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA); } +#endif static grub_efi_status_t __grub_efi_api grub_efi_initrd_load_file2 (grub_efi_load_file2_t *this, @@ -345,7 +359,7 @@ static grub_err_t grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { - int initrd_size, initrd_pages; + int __attribute__ ((unused)) initrd_size, initrd_pages; void *initrd_mem = NULL; grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; grub_efi_status_t status; @@ -356,6 +370,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), goto fail; } +#if defined(__i386__) || defined(__x86_64__) + if (!initrd_use_loadfile2) + return grub_cmd_initrd_x86_legacy (cmd, argc, argv); +#endif + if (!loaded) { grub_error (GRUB_ERR_BAD_ARGUMENT, @@ -391,6 +410,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), return GRUB_ERR_NONE; } +#if !defined(__i386__) && !defined(__x86_64__) initrd_size = grub_get_initrd_size (&initrd_ctx); grub_dprintf ("linux", "Loading initrd\n"); @@ -404,17 +424,19 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), } if (grub_initrd_load (&initrd_ctx, initrd_mem)) - goto fail; + { + grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages); + goto fail; + } initrd_start = (grub_addr_t) initrd_mem; initrd_end = initrd_start + initrd_size; grub_dprintf ("linux", "[addr=%p, size=0x%x]\n", (void *) initrd_start, initrd_size); +#endif fail: grub_initrd_close (&initrd_ctx); - if (initrd_mem && !initrd_start) - grub_efi_free_pages ((grub_addr_t) initrd_mem, initrd_pages); return grub_errno; } @@ -442,7 +464,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), kernel_size = grub_file_size (file); if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE) +#if !defined(__i386__) && !defined(__x86_64__) goto fail; +#else + goto fallback; + + if (!initrd_use_loadfile2) + { + /* + * This is a EFI stub image but it is too old to implement the LoadFile2 + * based initrd loading scheme, and Linux/x86 does not support the DT + * based method either. So fall back to the x86-specific loader that + * enters Linux in EFI mode but without going through its EFI stub. + */ +fallback: + grub_file_close (file); + return grub_cmd_linux_x86_legacy (cmd, argc, argv); + } +#endif grub_loader_unset(); diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index c2385d0a561a8fc4..997647a33326eeb8 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -1136,6 +1136,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), return grub_errno; } +#ifndef GRUB_MACHINE_EFI static grub_command_t cmd_linux, cmd_initrd; GRUB_MOD_INIT(linux) @@ -1152,3 +1153,10 @@ GRUB_MOD_FINI(linux) grub_unregister_command (cmd_linux); grub_unregister_command (cmd_initrd); } +#else +extern grub_err_t __attribute__((alias("grub_cmd_linux"))) +grub_cmd_linux_x86_legacy (grub_command_t cmd, int argc, char *argv[]); + +extern grub_err_t __attribute__((alias("grub_cmd_initrd"))) +grub_cmd_initrd_x86_legacy (grub_command_t cmd, int argc, char *argv[]); +#endif diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index 7c12cb9aa91040e0..d3b96761947a0944 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -113,12 +113,12 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd, #if defined(__arm__) || defined(__aarch64__) || defined(__riscv) || defined(__loongarch__) void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void); grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); +#endif #include grub_err_t grub_arch_efi_linux_load_image_header(grub_file_t file, struct linux_arch_kernel_header *lh); grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size, char *args); -#endif grub_addr_t grub_efi_modules_addr (void); -- 2.39.2