[U-Boot] [PATCH] MIPS: Fix cache maintenance in relocate_code & simplify

Paul Burton paul.burton at imgtec.com
Wed Sep 21 12:11:06 CEST 2016


The relocate_code function was handling cache maintenance incorrectly.
It copied U-Boot to its new location, flushed the caches & then
proceeded to apply relocations & jump to the new code without flushing
the caches again. This is problematic as the instruction cache could
potentially have already fetched instructions that hadn't had relocs
applied.

Rework this to perform the flush_cache call using the code in the
original copy of U-Boot, after having applied relocations to the new
copy of U-Boot. The new U-Boot can then be jumped to safely once that
cache flush has been performed.

As part of this, since the old U-Boot is used up until after that cache
flush, complexity around loading values from the GOT using a jump & link
instruction & loads from a table is removed. Instead we can simply load
the needed values with PTR_LA fromt the original GOT.

Signed-off-by: Paul Burton <paul.burton at imgtec.com>
---

 arch/mips/cpu/start.S    | 45 +++++++++++++++++++--------------------------
 arch/mips/cpu/u-boot.lds |  2 ++
 2 files changed, 21 insertions(+), 26 deletions(-)

diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S
index 8f85ede..cbc02fa 100644
--- a/arch/mips/cpu/start.S
+++ b/arch/mips/cpu/start.S
@@ -223,12 +223,9 @@ ENTRY(relocate_code)
 	PTR_LI	t0, CONFIG_SYS_MONITOR_BASE
 	PTR_SUB	s1, s2, t0		# s1 <-- relocation offset
 
-	PTR_LA	t3, in_ram
-	PTR_L	t2, -(3 * PTRSIZE)(t3)	# t2 <-- __image_copy_end
+	PTR_LA	t2, __image_copy_end
 	move	t1, a2
 
-	PTR_ADD	gp, s1			# adjust gp
-
 	/*
 	 * t0 = source address
 	 * t1 = target address
@@ -241,32 +238,14 @@ ENTRY(relocate_code)
 	blt	t0, t2, 1b
 	 PTR_ADDU t1, PTRSIZE
 
-	/* If caches were enabled, we would have to flush them here. */
-	PTR_SUB	a1, t1, s2		# a1 <-- size
-	PTR_LA	t9, flush_cache
-	jalr	t9
-	 move	a0, s2			# a0 <-- destination address
-
-	/* Jump to where we've relocated ourselves */
-	PTR_ADDIU t0, s2, in_ram - _start
-	jr	t0
-	 nop
-
-	PTR	__rel_dyn_end
-	PTR	__rel_dyn_start
-	PTR	__image_copy_end
-	PTR	_GLOBAL_OFFSET_TABLE_
-	PTR	num_got_entries
-
-in_ram:
 	/*
 	 * Now we want to update GOT.
 	 *
 	 * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object
 	 * generated by GNU ld. Skip these reserved entries from relocation.
 	 */
-	PTR_L	t3, -(1 * PTRSIZE)(t0)	# t3 <-- num_got_entries
-	PTR_L	t8, -(2 * PTRSIZE)(t0)	# t8 <-- _GLOBAL_OFFSET_TABLE_
+	PTR_LA	t3, num_got_entries
+	PTR_LA	t8, _GLOBAL_OFFSET_TABLE_
 	PTR_ADD	t8, s1			# t8 now holds relocated _G_O_T_
 	PTR_ADDIU t8, t8, 2 * PTRSIZE	# skipping first two entries
 	PTR_LI	t2, 2
@@ -281,8 +260,8 @@ in_ram:
 	 PTR_ADDIU t8, PTRSIZE
 
 	/* Update dynamic relocations */
-	PTR_L	t1, -(4 * PTRSIZE)(t0)	# t1 <-- __rel_dyn_start
-	PTR_L	t2, -(5 * PTRSIZE)(t0)	# t2 <-- __rel_dyn_end
+	PTR_LA	t1, __rel_dyn_start
+	PTR_LA	t2, __rel_dyn_end
 
 	b	2f			# skip first reserved entry
 	 PTR_ADDIU t1, 2 * PTRSIZE
@@ -307,6 +286,20 @@ in_ram:
 	 PTR_ADDIU t1, 2 * PTRSIZE	# each rel.dyn entry is 2*PTRSIZE bytes
 
 	/*
+	 * Flush caches to ensure our newly modified instructions are visible
+	 * to the instruction cache. We're still running with the old GOT, so
+	 * apply the reloc offset to the start address.
+	 */
+	PTR_LA	a0, __text_start
+	PTR_LA	a1, __text_end
+	PTR_SUB	a1, a1, a0
+	PTR_LA	t9, flush_cache
+	jalr	t9
+	 PTR_ADD	a0, s1
+
+	PTR_ADD	gp, s1			# adjust gp
+
+	/*
 	 * Clear BSS
 	 *
 	 * GOT is now relocated. Thus __bss_start and __bss_end can be
diff --git a/arch/mips/cpu/u-boot.lds b/arch/mips/cpu/u-boot.lds
index 7d71c11..0129c99 100644
--- a/arch/mips/cpu/u-boot.lds
+++ b/arch/mips/cpu/u-boot.lds
@@ -19,7 +19,9 @@ SECTIONS
 
 	. = ALIGN(4);
 	.text : {
+		__text_start = .;
 		*(.text*)
+		__text_end = .;
 	}
 
 	. = ALIGN(4);
-- 
2.10.0



More information about the U-Boot mailing list