x86/efistub: Branch straight to kernel entry point from C code
authorArd Biesheuvel <ardb@kernel.org>
Mon, 7 Aug 2023 16:27:00 +0000 (18:27 +0200)
committerBorislav Petkov (AMD) <bp@alien8.de>
Mon, 7 Aug 2023 18:36:06 +0000 (20:36 +0200)
Instead of returning to the calling code in assembler that does nothing
more than perform an indirect call with the boot_params pointer in
register ESI/RSI, perform the jump directly from the EFI stub C code.
This will allow the asm entrypoint code to be dropped entirely in
subsequent patches.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20230807162720.545787-4-ardb@kernel.org
drivers/firmware/efi/libstub/x86-stub.c

index 220be75a5cdc1f4c7e5e6fb38832fedfd15a8369..40a10db2d85e7942a66fd4e1b00a8b6c665af910 100644 (file)
@@ -290,7 +290,7 @@ adjust_memory_range_protection(unsigned long start, unsigned long size)
 #define TRAMPOLINE_PLACEMENT_BASE ((128 - 8)*1024)
 #define TRAMPOLINE_PLACEMENT_SIZE (640*1024 - (128 - 8)*1024)
 
-void startup_32(struct boot_params *boot_params);
+extern const u8 startup_32[], startup_64[];
 
 static void
 setup_memory_protection(unsigned long image_base, unsigned long image_size)
@@ -803,10 +803,19 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
        return EFI_SUCCESS;
 }
 
+static void __noreturn enter_kernel(unsigned long kernel_addr,
+                                   struct boot_params *boot_params)
+{
+       /* enter decompressed kernel with boot_params pointer in RSI/ESI */
+       asm("jmp *%0"::"r"(kernel_addr), "S"(boot_params));
+
+       unreachable();
+}
+
 /*
- * On success, we return the address of startup_32, which has potentially been
- * relocated by efi_relocate_kernel.
- * On failure, we exit to the firmware via efi_exit instead of returning.
+ * On success, this routine will jump to the relocated image directly and never
+ * return.  On failure, it will exit to the firmware via efi_exit() instead of
+ * returning.
  */
 asmlinkage unsigned long efi_main(efi_handle_t handle,
                                  efi_system_table_t *sys_table_arg,
@@ -950,7 +959,10 @@ asmlinkage unsigned long efi_main(efi_handle_t handle,
                goto fail;
        }
 
-       return bzimage_addr;
+       if (IS_ENABLED(CONFIG_X86_64))
+               bzimage_addr += startup_64 - startup_32;
+
+       enter_kernel(bzimage_addr, boot_params);
 fail:
        efi_err("efi_main() failed!\n");