[PATCH] armv7: Add Position Independent Execution support

Chia-Wei Wang chiawei_wang at aspeedtech.com
Mon Aug 2 12:44:57 CEST 2021


A U-Boot image could be loaded and executed at a different
location than it was linked at.

For example, Aspeed takes a stable release version of U-Boot image
as the golden one for recovery purposes. When the primary storage
such as flash is corrupted, the golden image could be loaded to any
SRAM/DRAM address on demands through ethernet/UART/etc.

To deal with this condition, the PIE is needed as there is only one
signed, golden image, which could be however executed at different
places.

This patch adds the PIE support for ARMv7 platform.

Signed-off-by: Chia-Wei Wang <chiawei_wang at aspeedtech.com>
---
 arch/arm/Kconfig           |  4 +++-
 arch/arm/cpu/armv7/start.S | 43 ++++++++++++++++++++++++++++++++++++++
 arch/arm/lib/crt0.S        | 11 ++++++++++
 arch/arm/lib/relocate.S    | 35 ++++++++++++++++++++++---------
 4 files changed, 82 insertions(+), 11 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2b7b625705..45879c9f06 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
 	  almost any 4K aligned address. This logic relies on the relocation
 	  information that is embedded in the binary to support U-Boot
 	  relocating itself to the top-of-RAM later during execution.
+endif
 
+if ARM64
 config INIT_SP_RELATIVE
 	bool "Specify the early stack pointer relative to the .bss section"
 	default n if ARCH_QEMU
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
index dcb4195d7b..3c0b2d6a71 100644
--- a/arch/arm/cpu/armv7/start.S
+++ b/arch/arm/cpu/armv7/start.S
@@ -39,6 +39,42 @@ 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 label */
+	ldr	r1, =reset	/* r1 <- Linked value of reset label */
+	subs	r4, r0, r1	/* r4 <- Runtime-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_end */
+
+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 offset */
+	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 +376,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 46b6be21a8..956d258c9d 100644
--- a/arch/arm/lib/crt0.S
+++ b/arch/arm/lib/crt0.S
@@ -130,6 +130,14 @@ ENTRY(_main)
 	ldr	r9, [r9, #GD_NEW_GD]		/* r9 <- gd->new_gd */
 
 	adr	lr, here
+#if defined(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)
@@ -180,3 +188,6 @@ here:
 #endif
 
 ENDPROC(_main)
+
+_start_ofs:
+	.word	_start - _main
diff --git a/arch/arm/lib/relocate.S b/arch/arm/lib/relocate.S
index e5f7267be1..14b7f61c1a 100644
--- a/arch/arm/lib/relocate.S
+++ b/arch/arm/lib/relocate.S
@@ -78,22 +78,28 @@ 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) */
 	and	r1, r1, #0xff
@@ -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
-- 
2.17.1



More information about the U-Boot mailing list