blob: acd4de92c9a6a1a095de18972617e9a420c2f6d4 [file]
/*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <autoconf.h>
#include <elfloader/gen_config.h>
#ifdef CONFIG_IMAGE_BINARY
#include <image_start_addr.h>
#endif
#include <assembler.h>
.extern main
.section ".text.start"
BEGIN_FUNC(_start)
adrp x19, core_stack_alloc
add x19, x19, #0xff0
mov sp, x19
#ifdef CONFIG_IMAGE_BINARY
stp x0, x1, [sp, #-16]!
bl clear_bss
/*
* Binary images may not be loaded in the correct location.
* Try and move ourselves so we're in the right place.
*/
bl fixup_image_base
mov x2, x0
/* restore original arguments for next step */
ldp x0, x1, [sp, #-16]!
/* fixup_image_base returns 1 if no need to move */
cmp x2, #1
beq 1f
/* otherwise, jump to the start of the new elfloader */
br x2
1:
#endif
b main
END_FUNC(_start)
#ifdef CONFIG_IMAGE_BINARY
BEGIN_FUNC(fixup_image_base)
stp x29, x30, [sp, #-16]!
mov x29, sp
ldr x0, =IMAGE_START_ADDR
adr x1, _start
cmp x0, x1
beq image_ok
adrp x2, _end
add x2, x2, #:lo12:_end
sub x2, x2, x1
/* sanity check: don't want to overwrite ourselves! we assume
* everything between _start and _archive_start is important
* (i.e. code that might be run while relocating)
* but allow overlap for things after _archive_start.
*/
adrp x3, _archive_start
add x3, x3, #:lo12:_archive_start
add x4, x0, x2 /* Dest end */
/* check: if (end < archive_start && end >= _start) { abort } */
cmp x4, x3
bge 1f
cmp x4, x1
blt 1f
b cant_reloc
1:
/* check: if (dest < archive_start && dest >= _start) { abort } */
cmp x0, x3
bge 2f
cmp x0, x1
blt 2f
cant_reloc:
b abort
2:
/* x0 = desired image base */
/* x1 = current image space */
/* x2 = image size */
bl memmove
/* x0 = dest, save it to a callee-saved register while we invalidate icache */
mov x19, x0
bl flush_dcache
bl invalidate_icache
mov x0, x19
b 1f
image_ok:
/* already in the right place, just keep booting */
mov x0, #1
1:
ldp x29, x30, [sp], #16
ret
END_FUNC(fixup_image_base)
#endif
/* Move the elf loader out of the kernel's way */
BEGIN_FUNC(finish_relocation)
/*
* On aarch64 the kernel is loaded at a very high address:
* at least above 0x0000ff8080000000. We assume that
* the ELF loader will never get loaded in a way that overlaps
* with the kernel, so reaching this function is an error.
*/
b abort // should never get here!
END_FUNC(finish_relocation)
/* secondary cpu startup */
BEGIN_FUNC(secondary_startup)
/*
* secondary_data is a struct that looks like this:
* 0x0 void *entry
* 0x8 void *stack
*/
adrp x19, secondary_data
add x19, x19, #:lo12:secondary_data
ldr x0, [x19, #0x8] // load stack
mov sp, x0
ldr x1, [x19, #0x0] // load entry point
br x1
END_FUNC(secondary_startup)