aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig16
-rw-r--r--arch/arm/cpu/armv8/start.S26
-rw-r--r--arch/arm/include/asm/config.h4
-rw-r--r--arch/arm/lib/crt0_64.S8
-rw-r--r--arch/arm/lib/relocate_64.S23
5 files changed, 68 insertions, 9 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2607fed..94ad805 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 5c500be..03e744e 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 5674d37..9f17829 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 9c46c93..da7c62c 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 fdba004..0480452 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 */