diff mbox

[RFC,07/11] ARM: PIE: Add support for updating PIE relocations

Message ID 1379421817-15759-8-git-send-email-Russ.Dill@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

Russ Dill Sept. 17, 2013, 12:43 p.m. UTC
This adds support for updating PIE relocations under ARM. This
is necessary in the case that the same PIE must run both with
virtual mapping (MMU enabled) and physical mapping (MMU
disabled).

Signed-off-by: Russ Dill <Russ.Dill@ti.com>
---
 arch/arm/include/asm/pie.h | 42 +++++++++++++++++++++++++
 arch/arm/kernel/pie.c      |  9 ++++++
 arch/arm/libpie/Makefile   |  2 +-
 arch/arm/libpie/relocate.S | 76 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 128 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/include/asm/pie.h
 create mode 100644 arch/arm/libpie/relocate.S
diff mbox

Patch

diff --git a/arch/arm/include/asm/pie.h b/arch/arm/include/asm/pie.h
new file mode 100644
index 0000000..977f11d
--- /dev/null
+++ b/arch/arm/include/asm/pie.h
@@ -0,0 +1,42 @@ 
+/*
+ *  arch/arm/include/asm/pie.h
+ *
+ *  Copyright 2013 Texas Instruments, Inc
+ *	Russ Dill <russ.dill@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ASMARM_PIE_H
+#define _ASMARM_PIE_H
+
+#include <linux/pie.h>
+
+#ifdef CONFIG_PIE
+extern void __pie_relocate(void);
+extern void __pie___pie_relocate(void);
+
+#define pie_relocate_from_pie()						\
+	__asm__ __volatile__("bl __pie_relocate\n"			\
+	: : : "cc", "memory", "lr", "r4", "r5", "r6", "r7", "r8", "r9");
+
+static inline void pie_relocate_from_kern(struct pie_chunk *chunk)
+{
+	void (*fn)(void) = fn_to_pie(chunk, &__pie___pie_relocate);
+	__asm__ __volatile__("" : : : "cc", "memory", "r4", "r5", "r6",
+				"r7", "r8", "r9");
+	fn();
+}
+#else
+
+#define pie_relocate_from_pie() do {} while(0)
+
+static inline void pie_relocate_from_kern(struct pie_chunk *chunk)
+{
+}
+
+#endif
+
+#endif
diff --git a/arch/arm/kernel/pie.c b/arch/arm/kernel/pie.c
index 5dff5d6..598562f 100644
--- a/arch/arm/kernel/pie.c
+++ b/arch/arm/kernel/pie.c
@@ -12,10 +12,12 @@ 
 #include <linux/elf.h>
 
 #include <asm/elf.h>
+#include <asm/pie.h>
 
 extern char __pie_rel_dyn_start[];
 extern char __pie_rel_dyn_end[];
 extern char __pie_tail_offset[];
+extern char __pie_reloc_offset[];
 
 struct arm_pie_tail {
 	int count;
@@ -72,12 +74,19 @@  int pie_arch_fixup(struct pie_chunk *chunk, void *base, void *tail,
 						unsigned long offset)
 {
 	struct arm_pie_tail *pie_tail = tail;
+	void *reloc;
 	int i;
 
 	/* Perform relocation fixups for given offset */
 	for (i = 0; i < pie_tail->count; i++)
 		*((uintptr_t *) (pie_tail->offset[i] + base)) += offset;
 
+	/* Store the PIE offset to tail and recol func */
+	*kern_to_pie(chunk, (uintptr_t *) __pie_tail_offset) = tail - base;
+	reloc = kern_to_pie(chunk,
+				(void *) fnptr_to_addr(&__pie___pie_relocate));
+	*kern_to_pie(chunk, (uintptr_t *) __pie_reloc_offset) = reloc - base;
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(pie_arch_fixup);
diff --git a/arch/arm/libpie/Makefile b/arch/arm/libpie/Makefile
index 5662e99..b1ac52a 100644
--- a/arch/arm/libpie/Makefile
+++ b/arch/arm/libpie/Makefile
@@ -3,7 +3,7 @@ 
 #
 ccflags-y	:= -fpic -mno-single-pic-base -fno-builtin
 
-obj-y		:= empty.o
+obj-y		:= relocate.o empty.o
 obj-y		+= lib1funcs.o ashldi3.o string.o
 
 # string library code (-Os is enforced to keep it much smaller)
diff --git a/arch/arm/libpie/relocate.S b/arch/arm/libpie/relocate.S
new file mode 100644
index 0000000..70cc36e
--- /dev/null
+++ b/arch/arm/libpie/relocate.S
@@ -0,0 +1,76 @@ 
+/*
+ * arch/arm/libpie/relocate.S - Relocation updating for PIEs
+ *
+ * Copyright 2013 Texas Instruments, Inc.
+ *	Russ Dill <russ.dill@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/linkage.h>
+
+/*
+ * Update relocations based on current pc
+ *
+ * On exit:
+ *  r4-r9 corrupted
+ */
+
+ENTRY(__pie_relocate)
+	/* Calculate offset of our code compared to existing relocations */
+	ldr	r4, pie_relocate_address
+	adr	r5, __pie_relocate
+	subs	r6, r5, r4
+	moveq	pc, lr			/* 0 offset, no need to do anything */
+
+	/* Base of PIE group */
+	ldr	r7, reloc_offset
+	sub	r5, r5, r7
+
+	/* Calculate address of tail */
+	ldr	r7, tail_offset
+	add	r7, r7, r5
+
+	/* First byte of tail is number of entries */
+	ldr	r8, [r7], #4
+	add	r8, r7, r8, lsl #2
+
+	/*
+	 * r5 - current base address of PIE group
+	 * r6 - fixup offset needed for relocs
+	 * r7 - relocs start
+	 * r8 - relocs end
+	 */
+
+1:
+	cmp	r7, r8
+	ldrne	r4, [r7], #4	/* Load next reloc offset */
+
+	addne	r4, r4, r5	/* Calculate address of reloc entry */
+	ldrne	r9, [r4]
+	addne	r9, r9, r6	/* Fixup reloc entry */
+	strne	r9, [r4]
+
+	bne	1b
+
+	mov	pc, lr
+ENDPROC(__pie_relocate)
+
+/*
+ * This ends up in the .rel.dyn section and can be used to read the current
+ * relocation offset
+ */
+pie_relocate_address:
+	.long 	__pie_relocate
+
+/* Offset from PIE section start to reloc function */
+.global reloc_offset
+reloc_offset:
+	.space	4
+
+/* Offset from PIE section start to tail */
+.globl tail_offset
+tail_offset:
+	.space	4