On Mon, 2020-02-17 at 13:49 +0100, Ard Biesheuvel wrote: > Expose efi_entry() as the PE/COFF entrypoint directly, instead of > jumping into a wrapper that fiddles with stack buffers and other > stuff that the compiler is much better at. The only reason this > code exists is to obtain a pointer to the base of the image, but > we can get the same value from the loaded_image protocol, which > we already need for other reasons anyway. > > Update the return type as well, to make it consistent with what > is required for a PE/COFF executable entrypoint. > > Signed-off-by: Ard Biesheuvel <ardb@xxxxxxxxxx> > --- > Apologies to Atish for making him track a moving target, but this is > another > bit of cleanup work that I would like to merge before taking the > RISC-V > changes on top. > And I thought I am done rebasing my patches ;). Jokes apart, this is actually much cleaner approach in retrieving image base and parsing DT compared to what I currently have for RISC-V. > On RISC-V, I would expect efi_enter_kernel() to be implemented as a C > routine > that finds the hart id in the DT (which is passed as an argument), > and pass > it to the startup code of the kernel proper. > Yes. I probably won't need efi-entry.S for RISC-V at all which simplifies the RISC-V implementation. Yay!! Is there a tree with this patch ? I tried to find it in your kernel.org repo but couldn't find it. As there are 3 efi related patch set in flight, I am not sure about the order in which they should be applied. > arch/arm/boot/compressed/efi-header.S | 2 +- > arch/arm/boot/compressed/head.S | 44 +++----------- > arch/arm64/kernel/efi-entry.S | 64 +++----------------- > arch/arm64/kernel/efi-header.S | 2 +- > drivers/firmware/efi/libstub/arm-stub.c | 37 +++++------ > drivers/firmware/efi/libstub/arm32-stub.c | 1 + > drivers/firmware/efi/libstub/arm64-stub.c | 3 +- > 7 files changed, 42 insertions(+), 111 deletions(-) > > diff --git a/arch/arm/boot/compressed/efi-header.S > b/arch/arm/boot/compressed/efi-header.S > index a5983588f96b..e38fbda02b93 100644 > --- a/arch/arm/boot/compressed/efi-header.S > +++ b/arch/arm/boot/compressed/efi-header.S > @@ -60,7 +60,7 @@ optional_header: > .long __pecoff_code_size @ SizeOfCode > .long __pecoff_data_size @ > SizeOfInitializedData > .long 0 @ > SizeOfUninitializedData > - .long efi_stub_entry - start @ > AddressOfEntryPoint > + .long efi_entry - start @ > AddressOfEntryPoint > .long start_offset @ BaseOfCode > .long __pecoff_data_start - start @ BaseOfData > > diff --git a/arch/arm/boot/compressed/head.S > b/arch/arm/boot/compressed/head.S > index 088b0a060876..941cd28a13c3 100644 > --- a/arch/arm/boot/compressed/head.S > +++ b/arch/arm/boot/compressed/head.S > @@ -1437,50 +1437,22 @@ __enter_kernel: > reloc_code_end: > > #ifdef CONFIG_EFI_STUB > - .align 2 > -_start: .long start - . > - > -ENTRY(efi_stub_entry) > - @ allocate space on stack for passing current zImage > address > - @ and for the EFI stub to return of new entry point of > - @ zImage, as EFI stub may copy the kernel. Pointer > address > - @ is passed in r2. r0 and r1 are passed through from > the > - @ EFI firmware to efi_entry > - adr ip, _start > - ldr r3, [ip] > - add r3, r3, ip > - stmfd sp!, {r3, lr} > - mov r2, sp @ pass zImage address > in r2 > - bl efi_entry > - > - @ Check for error return from EFI stub. r0 has FDT > address > - @ or error code. > - cmn r0, #1 > - beq efi_load_fail > - > - @ Preserve return value of efi_entry() in r4 > - mov r4, r0 > +ENTRY(efi_enter_kernel) > + mov r4, r0 @ preserve entrypoint > + mov r5, r1 @ preserve DT pointer > bl cache_clean_flush > bl cache_off > > @ Set parameters for booting zImage according to boot > protocol > - @ put FDT address in r2, it was returned by efi_entry() > - @ r1 is the machine type, and r0 needs to be 0 > mov r0, #0 > mov r1, #0xFFFFFFFF > - mov r2, r4 > + mov r2, r5 > > - @ Branch to (possibly) relocated zImage that is in [sp] > - ldr lr, [sp] > + @ Branch to (possibly) relocated zImage @ [r4] > ldr ip, =start_offset > - add lr, lr, ip > - mov pc, lr @ no mode > switch > - > -efi_load_fail: > - @ Return EFI_LOAD_ERROR to EFI firmware on error. > - ldr r0, =0x80000001 > - ldmfd sp!, {ip, pc} > -ENDPROC(efi_stub_entry) > + add r4, r4, ip > + mov pc, r4 @ no mode switch > +ENDPROC(efi_enter_kernel) > #endif > > .align > diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi- > entry.S > index 304d5b02ca67..49e3b1ad1b36 100644 > --- a/arch/arm64/kernel/efi-entry.S > +++ b/arch/arm64/kernel/efi-entry.S > @@ -10,55 +10,18 @@ > > #include <asm/assembler.h> > > -#define EFI_LOAD_ERROR 0x8000000000000001 > - > __INIT > > - /* > - * We arrive here from the EFI boot manager with: > - * > - * * CPU in little-endian mode > - * * MMU on with identity-mapped RAM > - * * Icache and Dcache on > - * > - * We will most likely be running from some place other than > where > - * we want to be. The kernel image wants to be placed at > TEXT_OFFSET > - * from start of RAM. > - */ > -ENTRY(entry) > - /* > - * Create a stack frame to save FP/LR with extra space > - * for image_addr variable passed to efi_entry(). > - */ > - stp x29, x30, [sp, #-32]! > - mov x29, sp > - > - /* > - * Call efi_entry to do the real work. > - * x0 and x1 are already set up by firmware. Current runtime > - * address of image is calculated and passed via *image_addr. > - * > - * unsigned long efi_entry(void *handle, > - * efi_system_table_t *sys_table, > - * unsigned long *image_addr) ; > - */ > - adr_l x8, _text > - add x2, sp, 16 > - str x8, [x2] > - bl efi_entry > - cmn x0, #1 > - b.eq efi_load_fail > - > +ENTRY(efi_enter_kernel) > /* > * efi_entry() will have copied the kernel image if necessary > and we > - * return here with device tree address in x0 and the kernel > entry > - * point stored at *image_addr. Save those values in registers > which > - * are callee preserved. > + * end up here with device tree address in x1 and the kernel > entry > + * point stored in x0. Save those values in registers which are > + * callee preserved. > */ > - mov x20, x0 // DTB address > - ldr x0, [sp, #16] // relocated _text address > + mov x20, x1 // DTB address > ldr w21, =stext_offset > - add x21, x0, x21 > + add x21, x0, x21 // relocated Image address > > /* > * Calculate size of the kernel Image (same for original and > copy). > @@ -80,9 +43,8 @@ ENTRY(entry) > * entries for the VA range of the current image, so no > maintenance is > * necessary. > */ > - adr x0, entry > - adr x1, entry_end > - sub x1, x1, x0 > + adr x0, efi_enter_kernel > + mov x1, efi_enter_kernel_size > bl __flush_dcache_area > > /* Turn off Dcache and MMU */ > @@ -110,11 +72,5 @@ ENTRY(entry) > mov x2, xzr > mov x3, xzr > br x21 > - > -efi_load_fail: > - mov x0, #EFI_LOAD_ERROR > - ldp x29, x30, [sp], #32 > - ret > - > -entry_end: > -ENDPROC(entry) > +ENDPROC(efi_enter_kernel) > + .set efi_enter_kernel_size, . - efi_enter_kernel > diff --git a/arch/arm64/kernel/efi-header.S b/arch/arm64/kernel/efi- > header.S > index a7cfacce3e15..40c704c5d3a5 100644 > --- a/arch/arm64/kernel/efi-header.S > +++ b/arch/arm64/kernel/efi-header.S > @@ -27,7 +27,7 @@ optional_header: > .long __initdata_begin - efi_header_end // SizeOfCode > .long __pecoff_data_size // > SizeOfInitializedData > .long 0 // > SizeOfUninitializedData > - .long __efistub_entry - _head // > AddressOfEntryPoint > + .long __efistub_efi_entry - _head // > AddressOfEntryPoint > .long efi_header_end - _head // BaseOfCode > > extra_header_fields: > diff --git a/drivers/firmware/efi/libstub/arm-stub.c > b/drivers/firmware/efi/libstub/arm-stub.c > index 56e475c1aa55..439c094f7bf2 100644 > --- a/drivers/firmware/efi/libstub/arm-stub.c > +++ b/drivers/firmware/efi/libstub/arm-stub.c > @@ -133,17 +133,20 @@ efi_status_t handle_kernel_image(unsigned long > *image_addr, > unsigned long *reserve_size, > unsigned long dram_base, > efi_loaded_image_t *image); > + > +void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned > long fdt); > + > /* > * EFI entry point for the arm/arm64 EFI stubs. This is the > entrypoint > * that is described in the PE/COFF header. Most of the code is the > same > * for both archictectures, with the arch-specific code provided in > the > * handle_kernel_image() function. > */ > -unsigned long efi_entry(void *handle, efi_system_table_t > *sys_table_arg, > - unsigned long *image_addr) > +efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t > *sys_table_arg) > { > efi_loaded_image_t *image; > efi_status_t status; > + unsigned long image_addr; > unsigned long image_size = 0; > unsigned long dram_base; > /* addr/point and size pairs for memory management*/ > @@ -153,7 +156,6 @@ unsigned long efi_entry(void *handle, > efi_system_table_t *sys_table_arg, > unsigned long fdt_size = 0; > char *cmdline_ptr = NULL; > int cmdline_size = 0; > - unsigned long new_fdt_addr; > efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID; > unsigned long reserve_addr = 0; > unsigned long reserve_size = 0; > @@ -165,8 +167,10 @@ unsigned long efi_entry(void *handle, > efi_system_table_t *sys_table_arg, > sys_table = sys_table_arg; > > /* Check if we were booted by the EFI firmware */ > - if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) > + if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) { > + status = EFI_INVALID_PARAMETER; > goto fail; > + } > > status = check_platform_features(); > if (status != EFI_SUCCESS) > @@ -187,6 +191,7 @@ unsigned long efi_entry(void *handle, > efi_system_table_t *sys_table_arg, > dram_base = get_dram_base(); > if (dram_base == EFI_ERROR) { > pr_efi_err("Failed to find DRAM base\n"); > + status = EFI_LOAD_ERROR; > goto fail; > } > > @@ -198,6 +203,7 @@ unsigned long efi_entry(void *handle, > efi_system_table_t *sys_table_arg, > cmdline_ptr = efi_convert_cmdline(image, &cmdline_size, > ULONG_MAX); > if (!cmdline_ptr) { > pr_efi_err("getting command line via > LOADED_IMAGE_PROTOCOL\n"); > + status = EFI_OUT_OF_RESOURCES; > goto fail; > } > > @@ -213,7 +219,7 @@ unsigned long efi_entry(void *handle, > efi_system_table_t *sys_table_arg, > > si = setup_graphics(); > > - status = handle_kernel_image(image_addr, &image_size, > + status = handle_kernel_image(&image_addr, &image_size, > &reserve_addr, > &reserve_size, > dram_base, image); > @@ -260,7 +266,7 @@ unsigned long efi_entry(void *handle, > efi_system_table_t *sys_table_arg, > pr_efi("Generating empty DTB\n"); > > if (!noinitrd()) { > - max_addr = efi_get_max_initrd_addr(dram_base, > *image_addr); > + max_addr = efi_get_max_initrd_addr(dram_base, > image_addr); > status = efi_load_initrd_dev_path(&initrd_addr, > &initrd_size, > max_addr); > if (status == EFI_SUCCESS) { > @@ -311,33 +317,30 @@ unsigned long efi_entry(void *handle, > efi_system_table_t *sys_table_arg, > > install_memreserve_table(); > > - new_fdt_addr = fdt_addr; > status = allocate_new_fdt_and_exit_boot(handle, > - &new_fdt_addr, > efi_get_max_fdt_addr(dram_base), > + &fdt_addr, > efi_get_max_fdt_addr(dram_base), > initrd_addr, initrd_size, cmdline_ptr, > fdt_addr, fdt_size); > + if (status != EFI_SUCCESS) > + goto fail_free_initrd; > > - /* > - * If all went well, we need to return the FDT address to the > - * calling function so it can be passed to kernel as part of > - * the kernel boot protocol. > - */ > - if (status == EFI_SUCCESS) > - return new_fdt_addr; > + efi_enter_kernel(image_addr, fdt_addr); > + /* not reached */ > > +fail_free_initrd: > pr_efi_err("Failed to update FDT and exit boot services\n"); > > efi_free(initrd_size, initrd_addr); > efi_free(fdt_size, fdt_addr); > > fail_free_image: > - efi_free(image_size, *image_addr); > + efi_free(image_size, image_addr); > efi_free(reserve_size, reserve_addr); > fail_free_cmdline: > free_screen_info(si); > efi_free(cmdline_size, (unsigned long)cmdline_ptr); > fail: > - return EFI_ERROR; > + return status; > } > > /* > diff --git a/drivers/firmware/efi/libstub/arm32-stub.c > b/drivers/firmware/efi/libstub/arm32-stub.c > index 7b2a6382b647..113298b8ea65 100644 > --- a/drivers/firmware/efi/libstub/arm32-stub.c > +++ b/drivers/firmware/efi/libstub/arm32-stub.c > @@ -227,6 +227,7 @@ efi_status_t handle_kernel_image(unsigned long > *image_addr, > * Relocate the zImage, so that it appears in the lowest 128 MB > * memory window. > */ > + *image_addr = image->image_base; > *image_size = image->image_size; > status = efi_relocate_kernel(image_addr, *image_size, > *image_size, > kernel_base + > MAX_UNCOMP_KERNEL_SIZE, 0, 0); > diff --git a/drivers/firmware/efi/libstub/arm64-stub.c > b/drivers/firmware/efi/libstub/arm64-stub.c > index 719d03a64329..9254cd8ab2d3 100644 > --- a/drivers/firmware/efi/libstub/arm64-stub.c > +++ b/drivers/firmware/efi/libstub/arm64-stub.c > @@ -43,7 +43,6 @@ efi_status_t handle_kernel_image(unsigned long > *image_addr, > { > efi_status_t status; > unsigned long kernel_size, kernel_memsize = 0; > - void *old_image_addr = (void *)*image_addr; > unsigned long preferred_offset; > u64 phys_seed = 0; > > @@ -141,7 +140,7 @@ efi_status_t handle_kernel_image(unsigned long > *image_addr, > } > *image_addr = *reserve_addr + TEXT_OFFSET; > } > - memcpy((void *)*image_addr, old_image_addr, kernel_size); > + memcpy((void *)*image_addr, image->image_base, kernel_size); > > return EFI_SUCCESS; > } -- Regards, Atish