Skip to content

Commit d21f5a5

Browse files
committed
x86/efistub: Add missing boot_params for mixed mode compat entry
The pure EFI stub entry point does not take a struct boot_params from the boot loader, but creates it from scratch, and populates only the fields that still have meaning in this context (command line, initrd base and size, etc) The original mixed mode implementation used the EFI handover protocol instead, where the boot loader (i.e., GRUB) populates a boot_params struct and passes it to a special Linux specific EFI entry point that takes the boot_params pointer as its third argument. When the new mixed mode implementation was introduced, using a special 32-bit PE entrypoint in the 64-bit kernel, it adopted the pure approach, and relied on the EFI stub to create the struct boot_params. This is preferred because it makes the bootloader side much easier to implement, as it does not need any x86-specific knowledge on how struct boot_params and struct setup_header are put together. This mixed mode implementation was adopted by systemd-boot version 252 and later. When commit e2ab9ea ("x86/boot/compressed: Move 32-bit entrypoint code into .text section") refactored this code and moved it out of head_64.S, the fact that ESI was populated with the address of the base of the image was overlooked, and to simplify the code flow, ESI is now zeroed and stored to memory unconditionally in shared code, so that the NULL-ness of that variable can still be used later to determine which mixed mode boot protocol is in use. With ESI pointing to the base of the image, it can serve as a struct boot_params pointer for startup_32(), which only accesses the init_data and kernel_alignment fields (and the scratch field as a temporary stack). Zeroing ESI means that those accesses produce garbage now, even though things appear to work if the first page of memory happens to be zeroed, and the region right before LOAD_PHYSICAL_ADDR (== 16 MiB) happens to be free. The solution is to pass a special, temporary struct boot_params to startup_32() via ESI, one that is sufficient for getting it to create the page tables correctly and is discarded right after. This involves setting a minimal alignment of 4k, only to get the statically allocated page tables line up correctly, and setting init_size to the executable image size (_end - startup_32). This ensures that the page tables are covered by the static footprint of the PE image. Given that EFI boot no longer calls the decompressor and no longer pads the image to permit the decompressor to execute in place, the same temporary struct boot_params should be used in the EFI handover protocol based mixed mode implementation as well, to prevent the page tables from being placed outside of allocated memory. Fixes: e2ab9ea ("x86/boot/compressed: Move 32-bit entrypoint code into .text section") Cc: <stable@kernel.org> # v6.1+ Closes: https://lore.kernel.org/all/20240321150510.GI8211@craftyguy.net/ Reported-by: Clayton Craft <clayton@craftyguy.net> Tested-by: Clayton Craft <clayton@craftyguy.net> Tested-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
1 parent 4cece76 commit d21f5a5

1 file changed

Lines changed: 15 additions & 5 deletions

File tree

arch/x86/boot/compressed/efi_mixed.S

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
*/
1616

1717
#include <linux/linkage.h>
18+
#include <asm/asm-offsets.h>
1819
#include <asm/msr.h>
1920
#include <asm/page_types.h>
2021
#include <asm/processor-flags.h>
2122
#include <asm/segment.h>
23+
#include <asm/setup.h>
2224

2325
.code64
2426
.text
@@ -149,6 +151,7 @@ SYM_FUNC_END(__efi64_thunk)
149151
SYM_FUNC_START(efi32_stub_entry)
150152
call 1f
151153
1: popl %ecx
154+
leal (efi32_boot_args - 1b)(%ecx), %ebx
152155

153156
/* Clear BSS */
154157
xorl %eax, %eax
@@ -163,6 +166,7 @@ SYM_FUNC_START(efi32_stub_entry)
163166
popl %ecx
164167
popl %edx
165168
popl %esi
169+
movl %esi, 8(%ebx)
166170
jmp efi32_entry
167171
SYM_FUNC_END(efi32_stub_entry)
168172
#endif
@@ -239,8 +243,6 @@ SYM_FUNC_END(efi_enter32)
239243
*
240244
* Arguments: %ecx image handle
241245
* %edx EFI system table pointer
242-
* %esi struct bootparams pointer (or NULL when not using
243-
* the EFI handover protocol)
244246
*
245247
* Since this is the point of no return for ordinary execution, no registers
246248
* are considered live except for the function parameters. [Note that the EFI
@@ -266,9 +268,18 @@ SYM_FUNC_START_LOCAL(efi32_entry)
266268
leal (efi32_boot_args - 1b)(%ebx), %ebx
267269
movl %ecx, 0(%ebx)
268270
movl %edx, 4(%ebx)
269-
movl %esi, 8(%ebx)
270271
movb $0x0, 12(%ebx) // efi_is64
271272

273+
/*
274+
* Allocate some memory for a temporary struct boot_params, which only
275+
* needs the minimal pieces that startup_32() relies on.
276+
*/
277+
subl $PARAM_SIZE, %esp
278+
movl %esp, %esi
279+
movl $PAGE_SIZE, BP_kernel_alignment(%esi)
280+
movl $_end - 1b, BP_init_size(%esi)
281+
subl $startup_32 - 1b, BP_init_size(%esi)
282+
272283
/* Disable paging */
273284
movl %cr0, %eax
274285
btrl $X86_CR0_PG_BIT, %eax
@@ -294,8 +305,7 @@ SYM_FUNC_START(efi32_pe_entry)
294305

295306
movl 8(%ebp), %ecx // image_handle
296307
movl 12(%ebp), %edx // sys_table
297-
xorl %esi, %esi
298-
jmp efi32_entry // pass %ecx, %edx, %esi
308+
jmp efi32_entry // pass %ecx, %edx
299309
// no other registers remain live
300310

301311
2: popl %edi // restore callee-save registers

0 commit comments

Comments
 (0)