[PATCH] Clean up ARM compressed loader

hector at marcansoft.com hector at marcansoft.com
Tue Feb 23 08:57:17 EST 2010


From: Hector Martin <hector at marcansoft.com>

The -Dstatic= stuff in the Makefile is a hack and subtly breaks the
current inflate implementation, because the fixed inflate tables are
included into a function and removing static places them in the stack,
which bloats the stack and breaks references after the function returns.
So get rid of the hack.

Instead, clean up the stub loader so PIC vs ROM mode is handled sanely
now. You can build two notably different versions now:

CONFIG_ZBOOT_ROM=y
 - Non-PIC: loader will halt if it finds itself at the wrong address.
 - Separate ROM and RAM bases (CONFIG_ZBOOT_ROM_TEXT and
   CONFIG_ZBOOT_ROM_BSS, the latter being a slight misnomer now).
 - Proper initialized data handling. Initialized data is copied from ROM
   to RAM on boot (VMA != LMA in linker script).
 - Assumes that the decompressed kernel will not overlap with the
   RAM used by the decompressor itself (CONFIG_ZBOOT_ROM_BSS should be
   somewhere after the loaded kernel address, e.g. near the end of RAM).
   No post-decompression relocation is done.

CONFIG_ZBOOT_ROM=n
 - PIC code: you can load this anywhere
 - Single blob, data follows code.
 - The loaded kernel may overlap with the loader, in which case it is
   relocated after compression as usual.

As far as I can tell, ROM PIC would've never worked with the existing
code (because, among other things, the GOT ends up in ROM), so this
shouldn't break anything.

This is untested on a real ROM platform, but has been tested using RAM
as fake ROM.

Cc: Segher Boessenkool <segher at kernel.crashing.org>
Signed-off-by: Hector Martin <hector at marcansoft.com>
---
 arch/arm/Kconfig                        |   10 ++-
 arch/arm/boot/compressed/Makefile       |   25 +++----
 arch/arm/boot/compressed/head.S         |  129 ++++++++++++++++--------------
 arch/arm/boot/compressed/misc.c         |    3 +-
 arch/arm/boot/compressed/vmlinux.lds.in |   29 ++++++--
 5 files changed, 110 insertions(+), 86 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 184a6bd..deb9eef 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1278,8 +1278,8 @@ config ZBOOT_ROM_BSS
 	help
 	  The base address of an area of read/write memory in the target
 	  for the ROM-able zImage which must be available while the
-	  decompressor is running. It must be large enough to hold the
-	  entire decompressed kernel plus an additional 128 KiB.
+	  decompressor is running. It must be able to hold at least 128 KiB
+	  of data and it must not overlap with the loaded kernel.
 	  Platforms which normally make use of ROM-able zImage formats
 	  normally set this to a suitable value in their defconfig file.
 
@@ -1290,7 +1290,11 @@ config ZBOOT_ROM
 	depends on ZBOOT_ROM_TEXT != ZBOOT_ROM_BSS
 	help
 	  Say Y here if you intend to execute your compressed kernel image
-	  (zImage) directly from ROM or flash.  If unsure, say N.
+	  (zImage) directly from ROM or flash. If you say Y, then the zImage
+	  will only run from the ZBOOT_ROM_TEXT address (it will not be
+	  position-independent).
+
+	  If unsure, say N.
 
 config CMDLINE
 	string "Default kernel command string"
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 2d4d88b..acfd324 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -48,20 +48,22 @@ else
 endif
 endif
 
-#
-# We now have a PIC decompressor implementation.  Decompressors running
-# from RAM should not define ZTEXTADDR.  Decompressors running directly
-# from ROM or Flash must define ZTEXTADDR (preferably via the config)
-# FIXME: Previous assignment to ztextaddr-y is lost here. See SHARK
+# RAM builds should disable CONFIG_ZBOOT_ROM. The decompressor will be
+# built as position independent code and can be loaded at any address.
+# ROM builds should enable CONFIG_ZBOOT_ROM and set CONFIG_ZBOOT_ROM_TEXT
+# and CONFIG_ZBOOT_ROM_BSS. They will be built as position dependent code
+# and will only run when loaded at CONFIG_ZBOOT_ROM_TEXT.
 ifeq ($(CONFIG_ZBOOT_ROM),y)
 ZTEXTADDR	:= $(CONFIG_ZBOOT_ROM_TEXT)
-ZBSSADDR	:= $(CONFIG_ZBOOT_ROM_BSS)
+ZDATAADDR	:= $(CONFIG_ZBOOT_ROM_BSS)
+EXTRA_CFLAGS	:= -fno-builtin
 else
 ZTEXTADDR	:= 0
-ZBSSADDR	:= ALIGN(4)
+ZDATAADDR	:= ALIGN(4)
+EXTRA_CFLAGS	:= -fpic -fno-builtin
 endif
 
-SEDFLAGS	= s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
+SEDFLAGS	= s/TEXT_START/$(ZTEXTADDR)/;s/DATA_START/$(ZDATAADDR)/
 
 suffix_$(CONFIG_KERNEL_GZIP) = gzip
 suffix_$(CONFIG_KERNEL_LZO)  = lzo
@@ -75,7 +77,6 @@ ORIG_CFLAGS := $(KBUILD_CFLAGS)
 KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
 endif
 
-EXTRA_CFLAGS  := -fpic -fno-builtin
 EXTRA_AFLAGS  := -Wa,-march=all
 
 # Supply ZRELADDR, INITRD_PHYS and PARAMS_PHYS to the decompressor via
@@ -106,10 +107,6 @@ lib1funcs = $(obj)/lib1funcs.o
 $(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S FORCE
 	$(call cmd,shipped)
 
-# Don't allow any static data in misc.o, which
-# would otherwise mess up our GOT table
-CFLAGS_misc.o := -Dstatic=
-
 $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
 	 	$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
 	$(call if_changed,ld)
@@ -120,8 +117,6 @@ $(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE
 
 $(obj)/piggy.$(suffix_y).o:  $(obj)/piggy.$(suffix_y) FORCE
 
-CFLAGS_font.o := -Dstatic=
-
 $(obj)/font.c: $(FONTC)
 	$(call cmd,shipped)
 
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 4fddc50..dd7050b 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -169,69 +169,79 @@ not_angel:
 		 */
 
 		.text
-		adr	r0, LC0
- ARM(		ldmia	r0, {r1, r2, r3, r4, r5, r6, ip, sp}	)
- THUMB(		ldmia	r0, {r1, r2, r3, r4, r5, r6, ip}	)
- THUMB(		ldr	sp, [r0, #28]				)
-		subs	r0, r0, r1		@ calculate the delta offset
+		ldr	sp, =__stack_end
+
+here:
+		adr	r0, here
+		ldr	r1, =here
+		subs	r12, r0, r1		@ calculate the delta offset
 
 						@ if delta is zero, we are
 		beq	not_relocated		@ running at the address we
 						@ were linked at.
 
+#ifndef CONFIG_ZBOOT_ROM
+
 		/*
-		 * We're running at a different address.  We need to fix
-		 * up various pointers:
-		 *   r5 - zImage base address
-		 *   r6 - GOT start
-		 *   ip - GOT end
+		 * We're running at a different address. Fix up the stack.
 		 */
-		add	r5, r5, r0
-		add	r6, r6, r0
-		add	ip, ip, r0
+		add	sp, sp, r12
 
-#ifndef CONFIG_ZBOOT_ROM
 		/*
-		 * If we're running fully PIC === CONFIG_ZBOOT_ROM = n,
-		 * we need to fix up pointers into the BSS region.
-		 *   r2 - BSS start
-		 *   r3 - BSS end
-		 *   sp - stack pointer
+		 * Fix up the GOT address
 		 */
-		add	r2, r2, r0
-		add	r3, r3, r0
-		add	sp, sp, r0
+		ldr	r1, =_got_start
+		add	r1, r1, r12
+		ldr	r2, =_got_end
+		add	r2, r2, r12
 
 		/*
 		 * Relocate all entries in the GOT table.
 		 */
-1:		ldr	r1, [r6, #0]		@ relocate entries in the GOT
-		add	r1, r1, r0		@ table.  This fixes up the
-		str	r1, [r6], #4		@ C references.
-		cmp	r6, ip
+1:		ldr	r0, [r1]		@ relocate entries in the GOT
+		add	r0, r0, r12		@ table.  This fixes up the
+		str	r0, [r1], #4		@ C references.
+		cmp	r1, r2
 		blo	1b
+
 #else
+		/*
+		 * This ROM build is running from the wrong address, panic
+		 */
+		b	.
+#endif
+
+not_relocated:
+		ldr	r1, =__bss_start
+		add	r1, r1, r12
+		ldr	r2, =__bss_end
+		add	r2, r2, r12
 
+		mov	r0, #0
+1:		str	r0, [r1], #4		@ clear bss
+		str	r0, [r1], #4
+		str	r0, [r1], #4
+		str	r0, [r1], #4
+		cmp	r1, r2
+		blo	1b
+
+#ifdef CONFIG_ZBOOT_ROM
 		/*
-		 * Relocate entries in the GOT table.  We only relocate
-		 * the entries that are outside the (relocated) BSS region.
+		 * Copy the initialized data from ROM to RAM (LMA to VMA)
 		 */
-1:		ldr	r1, [r6, #0]		@ relocate entries in the GOT
-		cmp	r1, r2			@ entry < bss_start ||
-		cmphs	r3, r1			@ _end < entry
-		addlo	r1, r1, r0		@ table.  This fixes up the
-		str	r1, [r6], #4		@ C references.
-		cmp	r6, ip
+		ldr	r1, =__data_start
+		ldr	r2, =__data_end
+		ldr	r3, =__data_lma
+
+1:
+		ldmia	r3!, {r0, r4, r5, r6}
+		stmia	r1!, {r0, r4, r5, r6}
+		cmp	r1, r2
 		blo	1b
+
 #endif
 
-not_relocated:	mov	r0, #0
-1:		str	r0, [r2], #4		@ clear bss
-		str	r0, [r2], #4
-		str	r0, [r2], #4
-		str	r0, [r2], #4
-		cmp	r2, r3
-		blo	1b
+		ldr	r4, =zreladdr
 
 		/*
 		 * The C runtime environment should now be setup
@@ -244,6 +254,12 @@ not_relocated:	mov	r0, #0
 		add	r2, sp, #0x10000	@ 64k max
 
 /*
+ * It is assumed that in ROM builds the decompressed kernel will not overwrite
+ * our RAM .data/.bss/stack/malloc area
+ */
+#ifndef CONFIG_ZBOOT_ROM
+
+/*
  * Check to see if we will overwrite ourselves.
  *   r4 = final kernel address
  *   r5 = start of this image
@@ -252,6 +268,8 @@ not_relocated:	mov	r0, #0
  *   r4 >= r2 -> OK
  *   r4 + image length <= r5 -> OK
  */
+		ldr	r5, =_start
+		add	r5, r5, r12
 		cmp	r4, r2
 		bhs	wont_overwrite
 		sub	r3, sp, r5		@ > compressed kernel size
@@ -278,7 +296,7 @@ not_relocated:	mov	r0, #0
  */
 		add	r1, r5, r0		@ end of decompressed kernel
 		adr	r2, reloc_start
-		ldr	r3, LC1
+		ldr	r3, reloc_size
 		add	r3, r2, r3
 1:		ldmia	r2!, {r9 - r12, r14}	@ copy relocation code
 		stmia	r1!, {r9 - r12, r14}
@@ -294,6 +312,11 @@ not_relocated:	mov	r0, #0
  THUMB(		add	r12, r5, r0		)
  THUMB(		mov	pc, r12			) @ call relocation code
 
+reloc_size:
+		.word reloc_end - reloc_start
+
+#endif
+
 /*
  * We're not in danger of overwriting ourselves.  Do this the simple way.
  *
@@ -305,26 +328,13 @@ wont_overwrite:	mov	r0, r4
 		bl	decompress_kernel
 		b	call_kernel
 
-		.align	2
-		.type	LC0, #object
-LC0:		.word	LC0			@ r1
-		.word	__bss_start		@ r2
-		.word	_end			@ r3
-		.word	zreladdr		@ r4
-		.word	_start			@ r5
-		.word	_got_start		@ r6
-		.word	_got_end		@ ip
-		.word	user_stack+4096		@ sp
-LC1:		.word	reloc_end - reloc_start
-		.size	LC0, . - LC0
-
 #ifdef CONFIG_ARCH_RPC
 		.globl	params
 params:		ldr	r0, =params_phys
 		mov	pc, lr
-		.ltorg
 		.align
 #endif
+		.ltorg
 
 /*
  * Turn on the cache.  We need to setup some page tables so that we
@@ -548,6 +558,8 @@ __common_mmu_cache_on:
  * r9-r12,r14 = corrupted
  */
 		.align	5
+
+#ifndef CONFIG_ZBOOT_ROM
 reloc_start:	add	r9, r5, r0
 		sub	r9, r9, #128		@ do not copy the stack
 		debug_reloc_start
@@ -563,6 +575,7 @@ reloc_start:	add	r9, r5, r0
 		mov	sp, r1
 		add	sp, sp, #128		@ relocate the stack
 		debug_reloc_end
+#endif
 
 call_kernel:	bl	cache_clean_flush
 		bl	cache_off
@@ -1076,7 +1089,3 @@ memdump:	mov	r12, r0
 
 		.ltorg
 reloc_end:
-
-		.align
-		.section ".stack", "w"
-user_stack:	.space	4096
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index 56a0d11..97018f8 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -23,7 +23,6 @@ unsigned int __machine_arch_type;
 #include <linux/compiler.h>	/* for inline */
 #include <linux/types.h>	/* for size_t */
 #include <linux/stddef.h>	/* for NULL */
-#include <asm/string.h>
 #include <linux/linkage.h>
 
 #include <asm/unaligned.h>
@@ -166,7 +165,7 @@ void __memzero (__ptr_t s, size_t n)
 		*u.ucp++ = 0;
 }
 
-static inline __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
+static __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
 			    size_t __n)
 {
 	int i = 0;
diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in
index a5924b9..46efdf4 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.in
+++ b/arch/arm/boot/compressed/vmlinux.lds.in
@@ -36,19 +36,36 @@ SECTIONS
 
   _etext = .;
 
+  /* The GOT is only for PIC builds, so it should not exist in the ROM build */
   _got_start = .;
   .got			: { *(.got) }
   _got_end = .;
   .got.plt		: { *(.got.plt) }
-  .data			: { *(.data) }
-  _edata = .;
 
-  . = BSS_START;
+  . = ALIGN(16);
+
+  __data_lma = .;
+
+  . = DATA_START;
+
+  __data_start = .;
+  .data : AT(__data_lma) {
+    *(.data)
+    . = ALIGN(16);
+  }
+  __data_end = .;
+  _edata = __data_lma + __data_end - __data_start;
+
   __bss_start = .;
-  .bss			: { *(.bss) }
-  _end = .;
+  .bss : { *(.bss) }
+  . = ALIGN(16);
+  __bss_end = .;
 
-  .stack (NOLOAD)	: { *(.stack) }
+  .stack : {
+    __stack_start = .;
+    . += 4096;
+    __stack_end = .;
+  }
 
   .stab 0		: { *(.stab) }
   .stabstr 0		: { *(.stabstr) }
-- 
1.6.4.4




More information about the linux-arm-kernel mailing list