summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2017-11-02 18:11:27 -0600
committerTom Rini <trini@konsulko.com>2017-11-17 07:44:13 -0500
commit49e93875a62fb9e96a4a7483b9bd5d8ae27ea76e (patch)
tree8daa16b3ccae7e5fa772f32e9b2f0b76d532f17e
parent9679d339ad2d4c495d734bad3a0fb7be6c4215eb (diff)
arm64: support running at addr other than linked to
This is required in the case where U-Boot is typically loaded and run at a particular address, but for some reason the RAM at that location is not available, e.g. due to memory fragmentation loading other boot binaries or firmware, splitting an SMP complex between various different OSs without using e.g. the EL2 second-stage page tables to hide the memory asignments, or due to known ECC failures. Signed-off-by: Stephen Warren <swarren@nvidia.com>
-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 2607fedaed6..94ad8056844 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 5c500be51d1..03e744e4a67 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 5674d37c04d..9f178293818 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 9c46c93ca4c..da7c62cbe0a 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 fdba004363a..04804524ed6 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 */