← Back to team overview

ubuntu-phone team mailing list archive

[PATCH 1/2] [PATCH] UBUNTU: Support copying of atags in the decompressor.

 

OriginalAuthor: Mike Kasick <mike@xxxxxxxxxx>

This is needed if this kernel is booted using kexec-hardboot[1],
because atags need to be in direct-mapped region, usually
the first 16kB of RAM.

Ported from Jens Andersen <jens.andersen@xxxxxxxxx>'s
kernel for Asus TF201 [2].

[1] Hardboot: http://forum.xda-developers.com/showthread.php?t=1266827
[2] Original repository: http://git.io/EXpn2A

Signed-off-by: Vojtech Bocek <vbocek@xxxxxxxxx>
---
 arch/arm/boot/compressed/Makefile |    3 +++
 arch/arm/boot/compressed/head.S   |   44 ++++++++++++++++++++++++++++++++++++-
 arch/arm/boot/compressed/misc.c   |   22 +++++++++++++++++++
 3 files changed, 68 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 0c74a6f..7643b37 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -111,6 +111,9 @@ endif
 ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
 LDFLAGS_vmlinux += --be8
 endif
+ifneq ($(PARAMS_PHYS),)
+LDFLAGS_vmlinux += --defsym params_phys=$(PARAMS_PHYS)
+endif
 # ?
 LDFLAGS_vmlinux += -p
 # Report unresolved symbol references
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 24701d6..5773670 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -133,7 +133,9 @@ start:
 		.word	_edata			@ zImage end address
  THUMB(		.thumb			)
 1:		mov	r7, r1			@ save architecture ID
-		mov	r8, r2			@ save atags pointer
+		teq	r0, #0			@ Check for kexec_boot_atags.
+		movne	r8, r0			@ Save kexec_boot_tags.
+		moveq	r8, r2			@ save atags pointer
 
 #ifndef __ARM_ARCH_2__
 		/*
@@ -348,6 +350,44 @@ not_relocated:	mov	r0, #0
 		add	r2, sp, #0x10000	@ 64k max
 		mov	r3, r7
 		bl	decompress_kernel
+
+/* Copy the kernel tagged list (atags):
+ *
+ * The kernel requires atags to be located in a direct-mapped region,
+ * usually below the kernel in the first 16 kB of RAM.  If they're above
+ * (the start of) the kernel, they need to be copied to a suitable
+ * location, e.g., the machine-defined params_phys.
+ *
+ * The assumption is that the tags will only be "out of place" if the
+ * decompressor code is also, so copying is implemented only in the "won't
+ * overwrite" case (which should be fixed).  Still need to make sure that
+ * the copied tags don't overwrite either the kernel or decompressor code
+ * (or rather, the remainder of it since everything up to here has already
+ * been executed).
+ *
+ * r4: zreladdr (kernel start)
+ * r8: atags */
+
+		/* No need to copy atags if they're already below kernel */
+		cmp	r8, r4
+		blo	call_kernel
+
+		/* r1: min(zreladdr, pc) */
+		mov	r1, pc
+		cmp	r4, r1
+		movlo	r1, r4
+
+		/* Compute max space for atags, if max <= 0 don't copy. */
+		ldr	r0, =params_phys	@ dest
+		subs	r2, r1, r0		@ max = min(zreladdr, pc) - dest
+		bls	call_kernel
+
+		/* Copy atags to params_phys. */
+		mov	r1, r8			@ src
+		bl	copy_atags
+		mov	r8, r0
+
+call_kernel:
 		bl	cache_clean_flush
 		bl	cache_off
 		mov	r0, #0			@ must be zero
@@ -356,6 +396,8 @@ not_relocated:	mov	r0, #0
  ARM(		mov	pc, r4	)		@ call kernel
  THUMB(		bx	r4	)		@ entry point is always ARM
 
+		.ltorg
+
 		.align	2
 		.type	LC0, #object
 LC0:		.word	LC0			@ r1
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index 832d372..c082769 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -25,6 +25,7 @@ unsigned int __machine_arch_type;
 #include <linux/stddef.h>	/* for NULL */
 #include <linux/linkage.h>
 #include <asm/string.h>
+#include <asm/setup.h>
 
 
 static void putstr(const char *ptr);
@@ -192,3 +193,24 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
 	else
 		putstr(" done, booting the kernel.\n");
 }
+
+const struct tag *copy_atags(struct tag *dest, const struct tag *src, size_t max)
+{
+	struct tag *tag;
+	size_t      size;
+
+	/* Find the last tag (ATAG_NONE). */
+	for_each_tag(tag, (struct tag *)src)
+		continue;
+
+	/* Include the last tag in copy. */
+	size = (char *)tag - (char *)src + sizeof(struct tag_header);
+
+	/* If there's not enough room, just use original and hope it works. */
+	if (size > max)
+		return src;
+
+	memcpy(dest, src, size);
+
+	return dest;
+}
-- 
1.7.10.4



References