[U-Boot] [PATCH] armv7: Support running at address other than linked to

Typically an U-Boot image is loaded at a specific address to run (e.g. flash mem-mapped space). However, for some reasons such as recovery purposes, the U-Boot has to start executing at aother address (e.g. DRAM space).
This patch allows an U-Boot image to be loaded and run at addresses other than linked to, eliminating the need of duplicated images with merely different link addresses.
Signed-off-by: Chia-Wei, Wang chiawei_wang@aspeedtech.com --- arch/arm/Kconfig | 4 +++- arch/arm/cpu/armv7/start.S | 45 ++++++++++++++++++++++++++++++++++++++ arch/arm/lib/crt0.S | 11 ++++++++++ arch/arm/lib/relocate.S | 37 +++++++++++++++++++++---------- 4 files changed, 85 insertions(+), 12 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index abdd699869..5fc167276c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -9,7 +9,7 @@ config ARM64 select PHYS_64BIT select SYS_CACHE_SHIFT_6
-if ARM64 +if ARM64 || CPU_V7A config POSITION_INDEPENDENT bool "Generate position-independent pre-relocation code" help @@ -19,7 +19,9 @@ config POSITION_INDEPENDENT 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
+if ARM64 config SYS_INIT_SP_BSS_OFFSET int help diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S index 0cb6dd39cc..65ddec1798 100644 --- a/arch/arm/cpu/armv7/start.S +++ b/arch/arm/cpu/armv7/start.S @@ -39,6 +39,44 @@ reset: /* Allow the board to save important registers */ b save_boot_params save_boot_params_ret: + +#ifdef CONFIG_POSITION_INDEPENDENT + /* + * Fix .rela.dyn relocations. This allows U-Boot to loaded to and + * executed at a different address than it was linked at. + */ +pie_fixup: + adr r0, reset /* r0 <- Runtime value of reset */ + ldr r1, =reset /* r1 <- Linked value of reset */ + subs r4, r0, r1 /* r4 <- Run-vs-link offset */ + beq pie_fixup_done + + adr r0, pie_fixup + ldr r1, _rel_dyn_start_ofs + add r2, r0, r1 /* r2 <- Runtime &__rel_dyn_start */ + ldr r1, _rel_dyn_end_ofs + add r3, r0, r1 /* r3 <- Runtime &__rel_dyn_start */ + +pie_fix_loop: + ldr r0, [r2] /* r0 <- Link location */ + ldr r1, [r2, #4] /* r1 <- fixup */ + cmp r1, #23 /* relative fixup? */ + bne pie_skip_reloc + + /* relative fix: increase location by offet */ + add r0, r4 + ldr r1, [r0] + add r1, r4 + str r1, [r0] + str r0, [r2] + add r2, #8 +pie_skip_reloc: + cmp r2, r3 + blo pie_fix_loop + +pie_fixup_done: +#endif + #ifdef CONFIG_ARMV7_LPAE /* * check for Hypervisor support @@ -340,3 +378,10 @@ ENTRY(cpu_init_crit) b lowlevel_init @ go setup pll,mux,memory ENDPROC(cpu_init_crit) #endif + +#if CONFIG_POSITION_INDEPENDENT +_rel_dyn_start_ofs: + .word __rel_dyn_start - pie_fixup +_rel_dyn_end_ofs: + .word __rel_dyn_end - pie_fixup +#endif diff --git a/arch/arm/lib/crt0.S b/arch/arm/lib/crt0.S index fe312db690..06173d412a 100644 --- a/arch/arm/lib/crt0.S +++ b/arch/arm/lib/crt0.S @@ -98,6 +98,14 @@ ENTRY(_main) sub r9, r9, #GD_SIZE /* new GD is below bd */
adr lr, here +#ifdef CONFIG_POSITION_INDEPENDENT + adr r0, _main + ldr r1, _start_ofs + add r0, r1 + ldr r1, =CONFIG_SYS_TEXT_BASE + sub r1, r0 + add lr, r1 +#endif ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */ add lr, lr, r0 #if defined(CONFIG_CPU_V7M) @@ -160,3 +168,6 @@ clbss_l:cmp r0, r1 /* while not at end of BSS */ #endif
ENDPROC(_main) + +_start_ofs: + .word _start - _main diff --git a/arch/arm/lib/relocate.S b/arch/arm/lib/relocate.S index e5f7267be1..3d838b381b 100644 --- a/arch/arm/lib/relocate.S +++ b/arch/arm/lib/relocate.S @@ -78,24 +78,30 @@ ENDPROC(relocate_vectors) */
ENTRY(relocate_code) - ldr r1, =__image_copy_start /* r1 <- SRC &__image_copy_start */ - subs r4, r0, r1 /* r4 <- relocation offset */ - beq relocate_done /* skip relocation */ - ldr r2, =__image_copy_end /* r2 <- SRC &__image_copy_end */ - + adr r3, relocate_code + ldr r1, _image_copy_start_ofs + add r1, r3 /* r1 <- Run &__image_copy_start */ + subs r4, r0, r1 /* r4 <- Run to copy offset */ + beq relocate_done /* skip relocation */ + ldr r1, _image_copy_start_ofs + add r1, r3 /* r1 <- Run &__image_copy_start */ + ldr r2, _image_copy_end_ofs + add r2, r3 /* r2 <- Run &__image_copy_end */ copy_loop: - ldmia r1!, {r10-r11} /* copy from source address [r1] */ - stmia r0!, {r10-r11} /* copy to target address [r0] */ - cmp r1, r2 /* until source end address [r2] */ + ldmia r1!, {r10-r11} /* copy from source address [r1] */ + stmia r0!, {r10-r11} /* copy to target address [r0] */ + cmp r1, r2 /* until source end address [r2] */ blo copy_loop
/* * fix .rel.dyn relocations */ - ldr r2, =__rel_dyn_start /* r2 <- SRC &__rel_dyn_start */ - ldr r3, =__rel_dyn_end /* r3 <- SRC &__rel_dyn_end */ + ldr r1, _rel_dyn_start_ofs + add r2, r1, r3 /* r2 <- Run &__rel_dyn_start */ + ldr r1, _rel_dyn_end_ofs + add r3, r1, r3 /* r3 <- Run &__rel_dyn_end */ fixloop: - ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */ + ldmia r2!, {r0-r1} /* (r0,r1) <- (SRC location,fixup) */ and r1, r1, #0xff cmp r1, #R_ARM_RELATIVE bne fixnext @@ -129,3 +135,12 @@ relocate_done: #endif
ENDPROC(relocate_code) + +_image_copy_start_ofs: + .word __image_copy_start - relocate_code +_image_copy_end_ofs: + .word __image_copy_end - relocate_code +_rel_dyn_start_ofs: + .word __rel_dyn_start - relocate_code +_rel_dyn_end_ofs: + .word __rel_dyn_end - relocate_code
participants (1)
-
Chia-Wei, Wang