From: Stephen Warren <swar...@nvidia.com>

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 <swar...@nvidia.com>
---
 arch/arm/Kconfig              | 16 ++++++++++++++++
 arch/arm/cpu/armv8/start.S    | 26 ++++++++++++++++++++++++++
 arch/arm/include/asm/config.h |  4 ----
 arch/arm/lib/crt0_64.S        |  8 ++++++++
 arch/arm/lib/relocate_64.S    | 23 ++++++++++++++++++-----
 5 files changed, 68 insertions(+), 9 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 83b7aa51dc2c..294b456414bc 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 5c500be51d1f..03e744e4a673 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 5674d37c04df..9f178293818e 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 9c46c93ca4c5..da7c62cbe0aa 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 fdba004363af..04804524ed65 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 */
-- 
2.14.2

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to