ARM: PIE: Add support for updating PIE relocations
authorRuss Dill <Russ.Dill@ti.com>
Tue, 17 Sep 2013 09:58:26 +0000 (02:58 -0700)
committer黄涛 <huangtao@rock-chips.com>
Thu, 21 Nov 2013 05:39:21 +0000 (13:39 +0800)
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 [new file with mode: 0644]
arch/arm/kernel/pie.c
arch/arm/libpie/Makefile
arch/arm/libpie/relocate.S [new file with mode: 0644]

diff --git a/arch/arm/include/asm/pie.h b/arch/arm/include/asm/pie.h
new file mode 100644 (file)
index 0000000..977f11d
--- /dev/null
@@ -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
index 5dff5d671f1aa2261e2b9bea6b1f5ed0ec13531a..598562fd12eaedf75895101af7633ebd80335c46 100644 (file)
 #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);
index 5662e996881a0e6119d09c40d2edd3f48ec4f71c..b1ac52ab38daf8984414727db32c9b1f750c17e2 100644 (file)
@@ -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 (file)
index 0000000..70cc36e
--- /dev/null
@@ -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