diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 2607fedaed..94ad805684 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -9,6 +9,22 @@ config ARM64 select PHYS_64BIT select SYS_CACHE_SHIFT_6 +if ARM64 +config POSITION_INDEPENDENT + bool "Generate position-independent pre-relocation code" + help + U-Boot expects to be linked to a specific hard-coded address, and to + be loaded to and run from that address. This option lifts that + restriction, thus allowing the code to be loaded to and executed + from almost any address. This logic relies on the relocation + information that is embedded into the binary to support U-Boot + relocating itself to the top-of-RAM later during execution. +endif + +config STATIC_RELA + bool + default y if ARM64 && !POSITION_INDEPENDENT + config DMA_ADDR_T_64BIT bool default y if ARM64 diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S index 5c500be51d..03e744e4a6 100644 --- a/arch/arm/cpu/armv8/start.S +++ b/arch/arm/cpu/armv8/start.S @@ -57,6 +57,32 @@ reset: .globl save_boot_params_ret save_boot_params_ret: +#if CONFIG_POSITION_INDEPENDENT + /* + * Fix .rela.dyn relocations. This allows U-Boot to be loaded to and + * executed at a different address than it was linked at. + */ +pie_fixup: + adr x0, _start /* x0 <- Runtime value of _start */ + ldr x1, _TEXT_BASE /* x1 <- Linked value of _start */ + sub x9, x0, x1 /* x9 <- Run-vs-link offset */ + adr x2, __rel_dyn_start /* x2 <- Runtime &__rel_dyn_start */ + adr x3, __rel_dyn_end /* x3 <- Runtime &__rel_dyn_end */ +pie_fix_loop: + ldp x0, x1, [x2], #16 /* (x0, x1) <- (Link location, fixup) */ + ldr x4, [x2], #8 /* x4 <- addend */ + cmp w1, #1027 /* relative fixup? */ + bne pie_skip_reloc + /* relative fix: store addend plus offset at dest location */ + add x0, x0, x9 + add x4, x4, x9 + str x4, [x0] +pie_skip_reloc: + cmp x2, x3 + b.lo pie_fix_loop +pie_fixup_done: +#endif + #ifdef CONFIG_SYS_RESET_SCTRL bl reset_sctrl #endif diff --git a/arch/arm/include/asm/config.h b/arch/arm/include/asm/config.h index 5674d37c04..9f17829381 100644 --- a/arch/arm/include/asm/config.h +++ b/arch/arm/include/asm/config.h @@ -10,10 +10,6 @@ #define CONFIG_LMB #define CONFIG_SYS_BOOT_RAMDISK_HIGH -#ifdef CONFIG_ARM64 -#define CONFIG_STATIC_RELA -#endif - #if defined(CONFIG_ARCH_LS1021A) || \ defined(CONFIG_CPU_PXA27X) || \ defined(CONFIG_CPU_MONAHANS) || \ diff --git a/arch/arm/lib/crt0_64.S b/arch/arm/lib/crt0_64.S index 9c46c93ca4..da7c62cbe0 100644 --- a/arch/arm/lib/crt0_64.S +++ b/arch/arm/lib/crt0_64.S @@ -98,6 +98,14 @@ ENTRY(_main) ldr x18, [x18, #GD_NEW_GD] /* x18 <- gd->new_gd */ adr lr, relocation_return +#if CONFIG_POSITION_INDEPENDENT + /* Add in link-vs-runtime offset */ + adr x0, _start /* x0 <- Runtime value of _start */ + ldr x9, _TEXT_BASE /* x9 <- Linked value of _start */ + sub x9, x9, x0 /* x9 <- Run-vs-link offset */ + add lr, lr, x9 +#endif + /* Add in link-vs-relocation offset */ ldr x9, [x18, #GD_RELOC_OFF] /* x9 <- gd->reloc_off */ add lr, lr, x9 /* new return address after relocation */ ldr x0, [x18, #GD_RELOCADDR] /* x0 <- gd->relocaddr */ diff --git a/arch/arm/lib/relocate_64.S b/arch/arm/lib/relocate_64.S index fdba004363..04804524ed 100644 --- a/arch/arm/lib/relocate_64.S +++ b/arch/arm/lib/relocate_64.S @@ -27,11 +27,24 @@ ENTRY(relocate_code) /* * Copy u-boot from flash to RAM */ - ldr x1, =__image_copy_start /* x1 <- SRC &__image_copy_start */ - subs x9, x0, x1 /* x9 <- relocation offset */ + adr x1, __image_copy_start /* x1 <- Run &__image_copy_start */ + subs x9, x0, x1 /* x8 <- Run to copy offset */ b.eq relocate_done /* skip relocation */ - ldr x2, =__image_copy_end /* x2 <- SRC &__image_copy_end */ + /* + * Don't ldr x1, __image_copy_start here, since if the code is already + * running at an address other than it was linked to, that instruction + * will load the relocated value of __image_copy_start. To + * correctly apply relocations, we need to know the linked value. + * + * Linked &__image_copy_start, which we know was at + * CONFIG_SYS_TEXT_BASE, which is stored in _TEXT_BASE, as a non- + * relocated value, since it isn't a symbol reference. + */ + ldr x1, _TEXT_BASE /* x1 <- Linked &__image_copy_start */ + subs x9, x0, x1 /* x9 <- Link to copy offset */ + adr x1, __image_copy_start /* x1 <- Run &__image_copy_start */ + adr x2, __image_copy_end /* x2 <- Run &__image_copy_end */ copy_loop: ldp x10, x11, [x1], #16 /* copy from source address [x1] */ stp x10, x11, [x0], #16 /* copy to target address [x0] */ @@ -42,8 +55,8 @@ copy_loop: /* * Fix .rela.dyn relocations */ - ldr x2, =__rel_dyn_start /* x2 <- SRC &__rel_dyn_start */ - ldr x3, =__rel_dyn_end /* x3 <- SRC &__rel_dyn_end */ + adr x2, __rel_dyn_start /* x2 <- Run &__rel_dyn_start */ + adr x3, __rel_dyn_end /* x3 <- Run &__rel_dyn_end */ fixloop: ldp x0, x1, [x2], #16 /* (x0,x1) <- (SRC location, fixup) */ ldr x4, [x2], #8 /* x4 <- addend */