[PATCH 3/4] ARM: module support for CONFIG_ARM_PATCH_PHYS_VIRT
Nicolas Pitre
nico at fluxnic.net
Tue Jan 4 03:20:07 EST 2011
Thanks to Russell King for his contribution to this patch.
Signed-off-by: Nicolas Pitre <nicolas.pitre at linaro.org>
---
arch/arm/include/asm/memory.h | 4 ++++
arch/arm/kernel/head.S | 35 +++++++++++++++++++++++++++++------
arch/arm/kernel/module.c | 13 +++++++++++++
3 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index acc3126..f83be97 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -185,6 +185,10 @@ static inline unsigned long __phys_to_virt(unsigned long x)
#undef PHYS_OFFSET
#define PHYS_OFFSET __virt_to_phys(PAGE_OFFSET)
+extern void fixup_pv_table(void *table_start, void *table_end, long v2p_offset);
+#define fixup_pv_table(start, end) \
+ fixup_pv_table(start, end, PHYS_OFFSET - PAGE_OFFSET)
+
#else
#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index eaaf0ad..621c792 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -447,12 +447,22 @@ __fixup_pv_table:
adr r0, 1f
ldmia r0, {r3-r5}
sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET
+ add r4, r4, r3
+ add r5, r5, r3
mov r6, r3, lsr #24 @ constant for add/sub instructions
teq r3, r6, lsl #24 @ must be 16MiB aligned
bne __error
+ b __fixup_pv_table_loop
+ENDPROC(__fixup_phys_virt)
+
+1: .word .
+ .word __pv_table_begin
+ .word __pv_table_end
+
+ .pushsection .text
+
+ENTRY(__fixup_pv_table_loop)
orr r6, r6, #0x400 @ mask in rotate right 8 bits
- add r4, r4, r3
- add r5, r5, r3
2: cmp r4, r5
ldrlo r7, [r4], #4
ldrlo ip, [r7, r3]
@@ -461,11 +471,24 @@ __fixup_pv_table:
strlo ip, [r7, r3]
blo 2b
mov pc, lr
-ENDPROC(__fixup_phys_virt)
+ENDPROC(__fixup_phys_virt_loop)
+
+/*
+ * This is the C callable version used to fixup modules.
+ * void fixup_pv_table(void *table_start, void *table_end, long v2p_offset)
+ */
+ENTRY(fixup_pv_table)
+ stmfd sp!, {r4 - r7, lr}
+ mov r3, #0 @ offset (zero as we're in virtual space)
+ mov r4, r0 @ loop start
+ mov r5, r1 @ loop end
+ mov r6, r2, lsr #24 @ constant for add/sub instructions
+ bl __fixup_pv_table_loop
+ ldmfd sp!, {r4 - r7, pc}
+ENDPROC(fixup_pv_table)
+
+ .popsection
-1: .word .
- .word __pv_table_begin
- .word __pv_table_end
#endif
#include "head-common.S"
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index d9bd786..6fef8d2 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -329,6 +329,19 @@ int
module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
struct module *module)
{
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
+ char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+ const Elf_Shdr *s;
+
+ for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++)
+ if (!strcmp(".pv_table", secstrings + s->sh_name)) {
+ void *pv_table_begin = (void *)s->sh_addr;
+ void *pv_table_end = pv_table_begin + s->sh_size;
+ fixup_pv_table(pv_table_begin, pv_table_end);
+ break;
+ }
+#endif
+
register_unwind_tables(module);
return 0;
}
--
1.7.3.2.193.g78bbb
More information about the linux-arm-kernel
mailing list