diff options
author | Anton Blanchard <anton@samba.org> | 2014-04-03 05:00:43 -0400 |
---|---|---|
committer | Anton Blanchard <anton@samba.org> | 2014-04-22 20:05:34 -0400 |
commit | 83775b85668a85036973c71264a959236e7becbd (patch) | |
tree | 3a751b74a5fa580b3371ff747a626970a52db089 | |
parent | 47f86b4e07afd4652ab0b092cbf493bf8b96559e (diff) |
powerpc/modules: Create is_module_trampoline()
ftrace has way too much knowledge of our kernel module trampoline
layout hidden inside it. Create is_module_trampoline() that can
abstract this away inside the module loader code.
Signed-off-by: Anton Blanchard <anton@samba.org>
-rw-r--r-- | arch/powerpc/include/asm/module.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/module_64.c | 51 |
2 files changed, 47 insertions, 5 deletions
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index c9c7aaaf95f5..f2711f0eb873 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h | |||
@@ -78,6 +78,7 @@ struct mod_arch_specific { | |||
78 | # endif /* MODULE */ | 78 | # endif /* MODULE */ |
79 | #endif | 79 | #endif |
80 | 80 | ||
81 | bool is_module_trampoline(u32 *insns); | ||
81 | 82 | ||
82 | struct exception_table_entry; | 83 | struct exception_table_entry; |
83 | void sort_ex_table(struct exception_table_entry *start, | 84 | void sort_ex_table(struct exception_table_entry *start, |
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 042360135260..4db5ecdc06e6 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/vmalloc.h> | 22 | #include <linux/vmalloc.h> |
23 | #include <linux/ftrace.h> | 23 | #include <linux/ftrace.h> |
24 | #include <linux/bug.h> | 24 | #include <linux/bug.h> |
25 | #include <linux/uaccess.h> | ||
25 | #include <asm/module.h> | 26 | #include <asm/module.h> |
26 | #include <asm/firmware.h> | 27 | #include <asm/firmware.h> |
27 | #include <asm/code-patching.h> | 28 | #include <asm/code-patching.h> |
@@ -102,7 +103,9 @@ static unsigned int local_entry_offset(const Elf64_Sym *sym) | |||
102 | jump, actually, to reset r2 (TOC+0x8000). */ | 103 | jump, actually, to reset r2 (TOC+0x8000). */ |
103 | struct ppc64_stub_entry | 104 | struct ppc64_stub_entry |
104 | { | 105 | { |
105 | /* 28 byte jump instruction sequence (7 instructions) */ | 106 | /* 28 byte jump instruction sequence (7 instructions). We only |
107 | * need 6 instructions on ABIv2 but we always allocate 7 so | ||
108 | * so we don't have to modify the trampoline load instruction. */ | ||
106 | u32 jump[7]; | 109 | u32 jump[7]; |
107 | u32 unused; | 110 | u32 unused; |
108 | /* Data for the above code */ | 111 | /* Data for the above code */ |
@@ -122,8 +125,8 @@ struct ppc64_stub_entry | |||
122 | * end of the stub code, and patch the stub address (32-bits relative | 125 | * end of the stub code, and patch the stub address (32-bits relative |
123 | * to the TOC ptr, r2) into the stub. | 126 | * to the TOC ptr, r2) into the stub. |
124 | */ | 127 | */ |
125 | static struct ppc64_stub_entry ppc64_stub = | 128 | |
126 | { .jump = { | 129 | static u32 ppc64_stub_insns[] = { |
127 | 0x3d620000, /* addis r11,r2, <high> */ | 130 | 0x3d620000, /* addis r11,r2, <high> */ |
128 | 0x396b0000, /* addi r11,r11, <low> */ | 131 | 0x396b0000, /* addi r11,r11, <low> */ |
129 | /* Save current r2 value in magic place on the stack. */ | 132 | /* Save current r2 value in magic place on the stack. */ |
@@ -135,7 +138,45 @@ static struct ppc64_stub_entry ppc64_stub = | |||
135 | #endif | 138 | #endif |
136 | 0x7d8903a6, /* mtctr r12 */ | 139 | 0x7d8903a6, /* mtctr r12 */ |
137 | 0x4e800420 /* bctr */ | 140 | 0x4e800420 /* bctr */ |
138 | } }; | 141 | }; |
142 | |||
143 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
144 | |||
145 | static u32 ppc64_stub_mask[] = { | ||
146 | 0xffff0000, | ||
147 | 0xffff0000, | ||
148 | 0xffffffff, | ||
149 | 0xffffffff, | ||
150 | #if !defined(_CALL_ELF) || _CALL_ELF != 2 | ||
151 | 0xffffffff, | ||
152 | #endif | ||
153 | 0xffffffff, | ||
154 | 0xffffffff | ||
155 | }; | ||
156 | |||
157 | bool is_module_trampoline(u32 *p) | ||
158 | { | ||
159 | unsigned int i; | ||
160 | u32 insns[ARRAY_SIZE(ppc64_stub_insns)]; | ||
161 | |||
162 | BUILD_BUG_ON(sizeof(ppc64_stub_insns) != sizeof(ppc64_stub_mask)); | ||
163 | |||
164 | if (probe_kernel_read(insns, p, sizeof(insns))) | ||
165 | return -EFAULT; | ||
166 | |||
167 | for (i = 0; i < ARRAY_SIZE(ppc64_stub_insns); i++) { | ||
168 | u32 insna = insns[i]; | ||
169 | u32 insnb = ppc64_stub_insns[i]; | ||
170 | u32 mask = ppc64_stub_mask[i]; | ||
171 | |||
172 | if ((insna & mask) != (insnb & mask)) | ||
173 | return false; | ||
174 | } | ||
175 | |||
176 | return true; | ||
177 | } | ||
178 | |||
179 | #endif | ||
139 | 180 | ||
140 | /* Count how many different 24-bit relocations (different symbol, | 181 | /* Count how many different 24-bit relocations (different symbol, |
141 | different addend) */ | 182 | different addend) */ |
@@ -350,7 +391,7 @@ static inline int create_stub(Elf64_Shdr *sechdrs, | |||
350 | { | 391 | { |
351 | long reladdr; | 392 | long reladdr; |
352 | 393 | ||
353 | *entry = ppc64_stub; | 394 | memcpy(entry->jump, ppc64_stub_insns, sizeof(ppc64_stub_insns)); |
354 | 395 | ||
355 | /* Stub uses address relative to r2. */ | 396 | /* Stub uses address relative to r2. */ |
356 | reladdr = (unsigned long)entry - my_r2(sechdrs, me); | 397 | reladdr = (unsigned long)entry - my_r2(sechdrs, me); |