mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-05-10 09:13:51 +00:00
efi/libstub/arm: Make efi_entry() an ordinary PE/COFF entrypoint
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@kernel.org>
This commit is contained in:
parent
e951a1f427
commit
9f9223778e
8 changed files with 58 additions and 126 deletions
|
@ -60,7 +60,7 @@ optional_header:
|
||||||
.long __pecoff_code_size @ SizeOfCode
|
.long __pecoff_code_size @ SizeOfCode
|
||||||
.long __pecoff_data_size @ SizeOfInitializedData
|
.long __pecoff_data_size @ SizeOfInitializedData
|
||||||
.long 0 @ SizeOfUninitializedData
|
.long 0 @ SizeOfUninitializedData
|
||||||
.long efi_stub_entry - start @ AddressOfEntryPoint
|
.long efi_entry - start @ AddressOfEntryPoint
|
||||||
.long start_offset @ BaseOfCode
|
.long start_offset @ BaseOfCode
|
||||||
.long __pecoff_data_start - start @ BaseOfData
|
.long __pecoff_data_start - start @ BaseOfData
|
||||||
|
|
||||||
|
|
|
@ -1437,33 +1437,15 @@ __enter_kernel:
|
||||||
reloc_code_end:
|
reloc_code_end:
|
||||||
|
|
||||||
#ifdef CONFIG_EFI_STUB
|
#ifdef CONFIG_EFI_STUB
|
||||||
.align 2
|
ENTRY(efi_enter_kernel)
|
||||||
_start: .long start - .
|
mov r7, r0 @ preserve image base
|
||||||
|
mov r4, r1 @ preserve DT pointer
|
||||||
|
|
||||||
ENTRY(efi_stub_entry)
|
mov r0, r4 @ DT start
|
||||||
@ allocate space on stack for passing current zImage address
|
add r1, r4, r2 @ DT end
|
||||||
@ 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
|
|
||||||
add r1, r4, #SZ_2M @ DT end
|
|
||||||
bl cache_clean_flush
|
bl cache_clean_flush
|
||||||
|
|
||||||
ldr r0, [sp] @ relocated zImage
|
mov r0, r7 @ relocated zImage
|
||||||
ldr r1, =_edata @ size of zImage
|
ldr r1, =_edata @ size of zImage
|
||||||
add r1, r1, r0 @ end of zImage
|
add r1, r1, r0 @ end of zImage
|
||||||
bl cache_clean_flush
|
bl cache_clean_flush
|
||||||
|
@ -1473,9 +1455,8 @@ ENTRY(efi_stub_entry)
|
||||||
@ inside the PE/COFF loader allocated region is unsafe. Let's
|
@ inside the PE/COFF loader allocated region is unsafe. Let's
|
||||||
@ assume our own zImage relocation code did a better job, and
|
@ assume our own zImage relocation code did a better job, and
|
||||||
@ jump into its version of this routine before proceeding.
|
@ jump into its version of this routine before proceeding.
|
||||||
ldr r0, [sp] @ relocated zImage
|
|
||||||
ldr r1, .Ljmp
|
ldr r1, .Ljmp
|
||||||
sub r1, r0, r1
|
sub r1, r7, r1
|
||||||
mov pc, r1 @ no mode switch
|
mov pc, r1 @ no mode switch
|
||||||
0:
|
0:
|
||||||
bl cache_off
|
bl cache_off
|
||||||
|
@ -1487,12 +1468,7 @@ ENTRY(efi_stub_entry)
|
||||||
mov r1, #0xFFFFFFFF
|
mov r1, #0xFFFFFFFF
|
||||||
mov r2, r4
|
mov r2, r4
|
||||||
b __efi_start
|
b __efi_start
|
||||||
|
ENDPROC(efi_enter_kernel)
|
||||||
efi_load_fail:
|
|
||||||
@ Return EFI_LOAD_ERROR to EFI firmware on error.
|
|
||||||
ldr r0, =0x80000001
|
|
||||||
ldmfd sp!, {ip, pc}
|
|
||||||
ENDPROC(efi_stub_entry)
|
|
||||||
.align 2
|
.align 2
|
||||||
.Ljmp: .long start - 0b
|
.Ljmp: .long start - 0b
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,81 +10,35 @@
|
||||||
|
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
|
|
||||||
#define EFI_LOAD_ERROR 0x8000000000000001
|
|
||||||
|
|
||||||
__INIT
|
__INIT
|
||||||
|
|
||||||
/*
|
ENTRY(efi_enter_kernel)
|
||||||
* 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
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* efi_entry() will have copied the kernel image if necessary and we
|
* efi_entry() will have copied the kernel image if necessary and we
|
||||||
* return here with device tree address in x0 and the kernel entry
|
* end up here with device tree address in x1 and the kernel entry
|
||||||
* point stored at *image_addr. Save those values in registers which
|
* point stored in x0. Save those values in registers which are
|
||||||
* are callee preserved.
|
* callee preserved.
|
||||||
*/
|
*/
|
||||||
mov x20, x0 // DTB address
|
mov x19, x0 // relocated Image address
|
||||||
ldr x0, [sp, #16] // relocated _text address
|
mov x20, x1 // DTB address
|
||||||
ldr w21, =stext_offset
|
|
||||||
add x21, x0, x21
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate size of the kernel Image (same for original and copy).
|
|
||||||
*/
|
|
||||||
adr_l x1, _text
|
|
||||||
adr_l x2, _edata
|
|
||||||
sub x1, x2, x1
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flush the copied Image to the PoC, and ensure it is not shadowed by
|
* Flush the copied Image to the PoC, and ensure it is not shadowed by
|
||||||
* stale icache entries from before relocation.
|
* stale icache entries from before relocation.
|
||||||
*/
|
*/
|
||||||
|
ldr w1, =kernel_size
|
||||||
bl __flush_dcache_area
|
bl __flush_dcache_area
|
||||||
ic ialluis
|
ic ialluis
|
||||||
|
dsb sy
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure that the rest of this function (in the original Image) is
|
* Jump across, into the copy of the image that we just cleaned
|
||||||
* visible when the caches are disabled. The I-cache can't have stale
|
* to the PoC, so that we can safely disable the MMU and caches.
|
||||||
* entries for the VA range of the current image, so no maintenance is
|
|
||||||
* necessary.
|
|
||||||
*/
|
*/
|
||||||
adr x0, entry
|
ldr w0, .Ljmp
|
||||||
adr x1, entry_end
|
sub x0, x19, w0, sxtw
|
||||||
sub x1, x1, x0
|
br x0
|
||||||
bl __flush_dcache_area
|
0:
|
||||||
|
|
||||||
/* Turn off Dcache and MMU */
|
/* Turn off Dcache and MMU */
|
||||||
mrs x0, CurrentEL
|
mrs x0, CurrentEL
|
||||||
cmp x0, #CurrentEL_EL2
|
cmp x0, #CurrentEL_EL2
|
||||||
|
@ -109,12 +63,6 @@ ENTRY(entry)
|
||||||
mov x1, xzr
|
mov x1, xzr
|
||||||
mov x2, xzr
|
mov x2, xzr
|
||||||
mov x3, xzr
|
mov x3, xzr
|
||||||
br x21
|
b stext
|
||||||
|
ENDPROC(efi_enter_kernel)
|
||||||
efi_load_fail:
|
.Ljmp: .long _text - 0b
|
||||||
mov x0, #EFI_LOAD_ERROR
|
|
||||||
ldp x29, x30, [sp], #32
|
|
||||||
ret
|
|
||||||
|
|
||||||
entry_end:
|
|
||||||
ENDPROC(entry)
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ optional_header:
|
||||||
.long __initdata_begin - efi_header_end // SizeOfCode
|
.long __initdata_begin - efi_header_end // SizeOfCode
|
||||||
.long __pecoff_data_size // SizeOfInitializedData
|
.long __pecoff_data_size // SizeOfInitializedData
|
||||||
.long 0 // SizeOfUninitializedData
|
.long 0 // SizeOfUninitializedData
|
||||||
.long __efistub_entry - _head // AddressOfEntryPoint
|
.long __efistub_efi_entry - _head // AddressOfEntryPoint
|
||||||
.long efi_header_end - _head // BaseOfCode
|
.long efi_header_end - _head // BaseOfCode
|
||||||
|
|
||||||
extra_header_fields:
|
extra_header_fields:
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
|
|
||||||
#ifdef CONFIG_EFI
|
#ifdef CONFIG_EFI
|
||||||
|
|
||||||
__efistub_stext_offset = stext - _text;
|
__efistub_kernel_size = _edata - _text;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The EFI stub has its own symbol namespace prefixed by __efistub_, to
|
* The EFI stub has its own symbol namespace prefixed by __efistub_, to
|
||||||
|
@ -42,6 +43,7 @@ __efistub___memset = __pi_memset;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__efistub__text = _text;
|
__efistub__text = _text;
|
||||||
|
__efistub_stext = stext;
|
||||||
__efistub__end = _end;
|
__efistub__end = _end;
|
||||||
__efistub__edata = _edata;
|
__efistub__edata = _edata;
|
||||||
__efistub_screen_info = screen_info;
|
__efistub_screen_info = screen_info;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/efi.h>
|
#include <linux/efi.h>
|
||||||
|
#include <linux/libfdt.h>
|
||||||
#include <linux/sort.h>
|
#include <linux/sort.h>
|
||||||
#include <asm/efi.h>
|
#include <asm/efi.h>
|
||||||
|
|
||||||
|
@ -100,17 +101,22 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
||||||
unsigned long *reserve_size,
|
unsigned long *reserve_size,
|
||||||
unsigned long dram_base,
|
unsigned long dram_base,
|
||||||
efi_loaded_image_t *image);
|
efi_loaded_image_t *image);
|
||||||
|
|
||||||
|
asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
|
||||||
|
unsigned long fdt_addr,
|
||||||
|
unsigned long fdt_size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EFI entry point for the arm/arm64 EFI stubs. This is the entrypoint
|
* 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
|
* 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
|
* for both archictectures, with the arch-specific code provided in the
|
||||||
* handle_kernel_image() function.
|
* handle_kernel_image() function.
|
||||||
*/
|
*/
|
||||||
unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
|
efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
|
||||||
unsigned long *image_addr)
|
|
||||||
{
|
{
|
||||||
efi_loaded_image_t *image;
|
efi_loaded_image_t *image;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
|
unsigned long image_addr;
|
||||||
unsigned long image_size = 0;
|
unsigned long image_size = 0;
|
||||||
unsigned long dram_base;
|
unsigned long dram_base;
|
||||||
/* addr/point and size pairs for memory management*/
|
/* addr/point and size pairs for memory management*/
|
||||||
|
@ -120,7 +126,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
|
||||||
unsigned long fdt_size = 0;
|
unsigned long fdt_size = 0;
|
||||||
char *cmdline_ptr = NULL;
|
char *cmdline_ptr = NULL;
|
||||||
int cmdline_size = 0;
|
int cmdline_size = 0;
|
||||||
unsigned long new_fdt_addr;
|
|
||||||
efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
|
efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
|
||||||
unsigned long reserve_addr = 0;
|
unsigned long reserve_addr = 0;
|
||||||
unsigned long reserve_size = 0;
|
unsigned long reserve_size = 0;
|
||||||
|
@ -130,8 +135,10 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
|
||||||
sys_table = sys_table_arg;
|
sys_table = sys_table_arg;
|
||||||
|
|
||||||
/* Check if we were booted by the EFI firmware */
|
/* 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;
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
status = check_platform_features();
|
status = check_platform_features();
|
||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
|
@ -152,6 +159,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
|
||||||
dram_base = get_dram_base();
|
dram_base = get_dram_base();
|
||||||
if (dram_base == EFI_ERROR) {
|
if (dram_base == EFI_ERROR) {
|
||||||
pr_efi_err("Failed to find DRAM base\n");
|
pr_efi_err("Failed to find DRAM base\n");
|
||||||
|
status = EFI_LOAD_ERROR;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +171,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
|
||||||
cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);
|
cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);
|
||||||
if (!cmdline_ptr) {
|
if (!cmdline_ptr) {
|
||||||
pr_efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n");
|
pr_efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n");
|
||||||
|
status = EFI_OUT_OF_RESOURCES;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +187,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
|
||||||
|
|
||||||
si = setup_graphics();
|
si = setup_graphics();
|
||||||
|
|
||||||
status = handle_kernel_image(image_addr, &image_size,
|
status = handle_kernel_image(&image_addr, &image_size,
|
||||||
&reserve_addr,
|
&reserve_addr,
|
||||||
&reserve_size,
|
&reserve_size,
|
||||||
dram_base, image);
|
dram_base, image);
|
||||||
|
@ -227,7 +236,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
|
||||||
|
|
||||||
status = handle_cmdline_files(image, cmdline_ptr, "initrd=",
|
status = handle_cmdline_files(image, cmdline_ptr, "initrd=",
|
||||||
efi_get_max_initrd_addr(dram_base,
|
efi_get_max_initrd_addr(dram_base,
|
||||||
*image_addr),
|
image_addr),
|
||||||
(unsigned long *)&initrd_addr,
|
(unsigned long *)&initrd_addr,
|
||||||
(unsigned long *)&initrd_size);
|
(unsigned long *)&initrd_size);
|
||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
|
@ -257,33 +266,30 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
|
||||||
|
|
||||||
install_memreserve_table();
|
install_memreserve_table();
|
||||||
|
|
||||||
new_fdt_addr = fdt_addr;
|
status = allocate_new_fdt_and_exit_boot(handle, &fdt_addr,
|
||||||
status = allocate_new_fdt_and_exit_boot(handle,
|
efi_get_max_fdt_addr(dram_base),
|
||||||
&new_fdt_addr, efi_get_max_fdt_addr(dram_base),
|
initrd_addr, initrd_size,
|
||||||
initrd_addr, initrd_size, cmdline_ptr,
|
cmdline_ptr, fdt_addr, fdt_size);
|
||||||
fdt_addr, fdt_size);
|
if (status != EFI_SUCCESS)
|
||||||
|
goto fail_free_initrd;
|
||||||
|
|
||||||
/*
|
efi_enter_kernel(image_addr, fdt_addr, fdt_totalsize((void *)fdt_addr));
|
||||||
* If all went well, we need to return the FDT address to the
|
/* not reached */
|
||||||
* calling function so it can be passed to kernel as part of
|
|
||||||
* the kernel boot protocol.
|
|
||||||
*/
|
|
||||||
if (status == EFI_SUCCESS)
|
|
||||||
return new_fdt_addr;
|
|
||||||
|
|
||||||
|
fail_free_initrd:
|
||||||
pr_efi_err("Failed to update FDT and exit boot services\n");
|
pr_efi_err("Failed to update FDT and exit boot services\n");
|
||||||
|
|
||||||
efi_free(initrd_size, initrd_addr);
|
efi_free(initrd_size, initrd_addr);
|
||||||
efi_free(fdt_size, fdt_addr);
|
efi_free(fdt_size, fdt_addr);
|
||||||
|
|
||||||
fail_free_image:
|
fail_free_image:
|
||||||
efi_free(image_size, *image_addr);
|
efi_free(image_size, image_addr);
|
||||||
efi_free(reserve_size, reserve_addr);
|
efi_free(reserve_size, reserve_addr);
|
||||||
fail_free_cmdline:
|
fail_free_cmdline:
|
||||||
free_screen_info(si);
|
free_screen_info(si);
|
||||||
efi_free(cmdline_size, (unsigned long)cmdline_ptr);
|
efi_free(cmdline_size, (unsigned long)cmdline_ptr);
|
||||||
fail:
|
fail:
|
||||||
return EFI_ERROR;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmp_mem_desc(const void *l, const void *r)
|
static int cmp_mem_desc(const void *l, const void *r)
|
||||||
|
|
|
@ -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
|
* Relocate the zImage, so that it appears in the lowest 128 MB
|
||||||
* memory window.
|
* memory window.
|
||||||
*/
|
*/
|
||||||
|
*image_addr = (unsigned long)image->image_base;
|
||||||
*image_size = image->image_size;
|
*image_size = image->image_size;
|
||||||
status = efi_relocate_kernel(image_addr, *image_size, *image_size,
|
status = efi_relocate_kernel(image_addr, *image_size, *image_size,
|
||||||
kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0);
|
kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0);
|
||||||
|
|
|
@ -49,7 +49,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
unsigned long kernel_size, kernel_memsize = 0;
|
unsigned long kernel_size, kernel_memsize = 0;
|
||||||
void *old_image_addr = (void *)*image_addr;
|
|
||||||
unsigned long preferred_offset;
|
unsigned long preferred_offset;
|
||||||
u64 phys_seed = 0;
|
u64 phys_seed = 0;
|
||||||
|
|
||||||
|
@ -147,7 +146,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
|
||||||
}
|
}
|
||||||
*image_addr = *reserve_addr + TEXT_OFFSET;
|
*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;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue