diff options
Diffstat (limited to 'arch/ppc64')
-rw-r--r-- | arch/ppc64/kernel/kprobes.c | 125 | ||||
-rw-r--r-- | arch/ppc64/kernel/ppc_ksyms.c | 1 | ||||
-rw-r--r-- | arch/ppc64/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/ppc64/kernel/time.c | 1 |
4 files changed, 127 insertions, 4 deletions
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c index 782ce3efa2c1..1d2ff6d6b0b3 100644 --- a/arch/ppc64/kernel/kprobes.c +++ b/arch/ppc64/kernel/kprobes.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <asm/kdebug.h> | 36 | #include <asm/kdebug.h> |
37 | #include <asm/sstep.h> | 37 | #include <asm/sstep.h> |
38 | 38 | ||
39 | static DECLARE_MUTEX(kprobe_mutex); | ||
40 | |||
39 | static struct kprobe *current_kprobe; | 41 | static struct kprobe *current_kprobe; |
40 | static unsigned long kprobe_status, kprobe_saved_msr; | 42 | static unsigned long kprobe_status, kprobe_saved_msr; |
41 | static struct kprobe *kprobe_prev; | 43 | static struct kprobe *kprobe_prev; |
@@ -54,6 +56,15 @@ int arch_prepare_kprobe(struct kprobe *p) | |||
54 | printk("Cannot register a kprobe on rfid or mtmsrd\n"); | 56 | printk("Cannot register a kprobe on rfid or mtmsrd\n"); |
55 | ret = -EINVAL; | 57 | ret = -EINVAL; |
56 | } | 58 | } |
59 | |||
60 | /* insn must be on a special executable page on ppc64 */ | ||
61 | if (!ret) { | ||
62 | up(&kprobe_mutex); | ||
63 | p->ainsn.insn = get_insn_slot(); | ||
64 | down(&kprobe_mutex); | ||
65 | if (!p->ainsn.insn) | ||
66 | ret = -ENOMEM; | ||
67 | } | ||
57 | return ret; | 68 | return ret; |
58 | } | 69 | } |
59 | 70 | ||
@@ -79,16 +90,22 @@ void arch_disarm_kprobe(struct kprobe *p) | |||
79 | 90 | ||
80 | void arch_remove_kprobe(struct kprobe *p) | 91 | void arch_remove_kprobe(struct kprobe *p) |
81 | { | 92 | { |
93 | up(&kprobe_mutex); | ||
94 | free_insn_slot(p->ainsn.insn); | ||
95 | down(&kprobe_mutex); | ||
82 | } | 96 | } |
83 | 97 | ||
84 | static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | 98 | static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) |
85 | { | 99 | { |
100 | kprobe_opcode_t insn = *p->ainsn.insn; | ||
101 | |||
86 | regs->msr |= MSR_SE; | 102 | regs->msr |= MSR_SE; |
87 | /*single step inline if it a breakpoint instruction*/ | 103 | |
88 | if (p->opcode == BREAKPOINT_INSTRUCTION) | 104 | /* single step inline if it is a trap variant */ |
105 | if (IS_TW(insn) || IS_TD(insn) || IS_TWI(insn) || IS_TDI(insn)) | ||
89 | regs->nip = (unsigned long)p->addr; | 106 | regs->nip = (unsigned long)p->addr; |
90 | else | 107 | else |
91 | regs->nip = (unsigned long)&p->ainsn.insn; | 108 | regs->nip = (unsigned long)p->ainsn.insn; |
92 | } | 109 | } |
93 | 110 | ||
94 | static inline void save_previous_kprobe(void) | 111 | static inline void save_previous_kprobe(void) |
@@ -105,6 +122,23 @@ static inline void restore_previous_kprobe(void) | |||
105 | kprobe_saved_msr = kprobe_saved_msr_prev; | 122 | kprobe_saved_msr = kprobe_saved_msr_prev; |
106 | } | 123 | } |
107 | 124 | ||
125 | void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) | ||
126 | { | ||
127 | struct kretprobe_instance *ri; | ||
128 | |||
129 | if ((ri = get_free_rp_inst(rp)) != NULL) { | ||
130 | ri->rp = rp; | ||
131 | ri->task = current; | ||
132 | ri->ret_addr = (kprobe_opcode_t *)regs->link; | ||
133 | |||
134 | /* Replace the return addr with trampoline addr */ | ||
135 | regs->link = (unsigned long)kretprobe_trampoline; | ||
136 | add_rp_inst(ri); | ||
137 | } else { | ||
138 | rp->nmissed++; | ||
139 | } | ||
140 | } | ||
141 | |||
108 | static inline int kprobe_handler(struct pt_regs *regs) | 142 | static inline int kprobe_handler(struct pt_regs *regs) |
109 | { | 143 | { |
110 | struct kprobe *p; | 144 | struct kprobe *p; |
@@ -195,6 +229,78 @@ no_kprobe: | |||
195 | } | 229 | } |
196 | 230 | ||
197 | /* | 231 | /* |
232 | * Function return probe trampoline: | ||
233 | * - init_kprobes() establishes a probepoint here | ||
234 | * - When the probed function returns, this probe | ||
235 | * causes the handlers to fire | ||
236 | */ | ||
237 | void kretprobe_trampoline_holder(void) | ||
238 | { | ||
239 | asm volatile(".global kretprobe_trampoline\n" | ||
240 | "kretprobe_trampoline:\n" | ||
241 | "nop\n"); | ||
242 | } | ||
243 | |||
244 | /* | ||
245 | * Called when the probe at kretprobe trampoline is hit | ||
246 | */ | ||
247 | int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | ||
248 | { | ||
249 | struct kretprobe_instance *ri = NULL; | ||
250 | struct hlist_head *head; | ||
251 | struct hlist_node *node, *tmp; | ||
252 | unsigned long orig_ret_address = 0; | ||
253 | unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; | ||
254 | |||
255 | head = kretprobe_inst_table_head(current); | ||
256 | |||
257 | /* | ||
258 | * It is possible to have multiple instances associated with a given | ||
259 | * task either because an multiple functions in the call path | ||
260 | * have a return probe installed on them, and/or more then one return | ||
261 | * return probe was registered for a target function. | ||
262 | * | ||
263 | * We can handle this because: | ||
264 | * - instances are always inserted at the head of the list | ||
265 | * - when multiple return probes are registered for the same | ||
266 | * function, the first instance's ret_addr will point to the | ||
267 | * real return address, and all the rest will point to | ||
268 | * kretprobe_trampoline | ||
269 | */ | ||
270 | hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { | ||
271 | if (ri->task != current) | ||
272 | /* another task is sharing our hash bucket */ | ||
273 | continue; | ||
274 | |||
275 | if (ri->rp && ri->rp->handler) | ||
276 | ri->rp->handler(ri, regs); | ||
277 | |||
278 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
279 | recycle_rp_inst(ri); | ||
280 | |||
281 | if (orig_ret_address != trampoline_address) | ||
282 | /* | ||
283 | * This is the real return address. Any other | ||
284 | * instances associated with this task are for | ||
285 | * other calls deeper on the call stack | ||
286 | */ | ||
287 | break; | ||
288 | } | ||
289 | |||
290 | BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); | ||
291 | regs->nip = orig_ret_address; | ||
292 | |||
293 | unlock_kprobes(); | ||
294 | |||
295 | /* | ||
296 | * By returning a non-zero value, we are telling | ||
297 | * kprobe_handler() that we have handled unlocking | ||
298 | * and re-enabling preemption. | ||
299 | */ | ||
300 | return 1; | ||
301 | } | ||
302 | |||
303 | /* | ||
198 | * Called after single-stepping. p->addr is the address of the | 304 | * Called after single-stepping. p->addr is the address of the |
199 | * instruction whose first byte has been replaced by the "breakpoint" | 305 | * instruction whose first byte has been replaced by the "breakpoint" |
200 | * instruction. To avoid the SMP problems that can occur when we | 306 | * instruction. To avoid the SMP problems that can occur when we |
@@ -205,9 +311,10 @@ no_kprobe: | |||
205 | static void resume_execution(struct kprobe *p, struct pt_regs *regs) | 311 | static void resume_execution(struct kprobe *p, struct pt_regs *regs) |
206 | { | 312 | { |
207 | int ret; | 313 | int ret; |
314 | unsigned int insn = *p->ainsn.insn; | ||
208 | 315 | ||
209 | regs->nip = (unsigned long)p->addr; | 316 | regs->nip = (unsigned long)p->addr; |
210 | ret = emulate_step(regs, p->ainsn.insn[0]); | 317 | ret = emulate_step(regs, insn); |
211 | if (ret == 0) | 318 | if (ret == 0) |
212 | regs->nip = (unsigned long)p->addr + 4; | 319 | regs->nip = (unsigned long)p->addr + 4; |
213 | } | 320 | } |
@@ -331,3 +438,13 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | |||
331 | memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs)); | 438 | memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs)); |
332 | return 1; | 439 | return 1; |
333 | } | 440 | } |
441 | |||
442 | static struct kprobe trampoline_p = { | ||
443 | .addr = (kprobe_opcode_t *) &kretprobe_trampoline, | ||
444 | .pre_handler = trampoline_probe_handler | ||
445 | }; | ||
446 | |||
447 | int __init arch_init(void) | ||
448 | { | ||
449 | return register_kprobe(&trampoline_p); | ||
450 | } | ||
diff --git a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c index b230a63fe4c8..705742f4eec6 100644 --- a/arch/ppc64/kernel/ppc_ksyms.c +++ b/arch/ppc64/kernel/ppc_ksyms.c | |||
@@ -75,6 +75,7 @@ EXPORT_SYMBOL(giveup_fpu); | |||
75 | EXPORT_SYMBOL(giveup_altivec); | 75 | EXPORT_SYMBOL(giveup_altivec); |
76 | #endif | 76 | #endif |
77 | EXPORT_SYMBOL(__flush_icache_range); | 77 | EXPORT_SYMBOL(__flush_icache_range); |
78 | EXPORT_SYMBOL(flush_dcache_range); | ||
78 | 79 | ||
79 | #ifdef CONFIG_SMP | 80 | #ifdef CONFIG_SMP |
80 | #ifdef CONFIG_PPC_ISERIES | 81 | #ifdef CONFIG_PPC_ISERIES |
diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index aba89554d89d..f7cae05e40fb 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/kallsyms.h> | 36 | #include <linux/kallsyms.h> |
37 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
38 | #include <linux/utsname.h> | 38 | #include <linux/utsname.h> |
39 | #include <linux/kprobes.h> | ||
39 | 40 | ||
40 | #include <asm/pgtable.h> | 41 | #include <asm/pgtable.h> |
41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
@@ -307,6 +308,8 @@ void show_regs(struct pt_regs * regs) | |||
307 | 308 | ||
308 | void exit_thread(void) | 309 | void exit_thread(void) |
309 | { | 310 | { |
311 | kprobe_flush_task(current); | ||
312 | |||
310 | #ifndef CONFIG_SMP | 313 | #ifndef CONFIG_SMP |
311 | if (last_task_used_math == current) | 314 | if (last_task_used_math == current) |
312 | last_task_used_math = NULL; | 315 | last_task_used_math = NULL; |
@@ -321,6 +324,7 @@ void flush_thread(void) | |||
321 | { | 324 | { |
322 | struct thread_info *t = current_thread_info(); | 325 | struct thread_info *t = current_thread_info(); |
323 | 326 | ||
327 | kprobe_flush_task(current); | ||
324 | if (t->flags & _TIF_ABI_PENDING) | 328 | if (t->flags & _TIF_ABI_PENDING) |
325 | t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); | 329 | t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); |
326 | 330 | ||
diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 2348a75e050d..2a532db9138a 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c | |||
@@ -91,6 +91,7 @@ unsigned long tb_to_xs; | |||
91 | unsigned tb_to_us; | 91 | unsigned tb_to_us; |
92 | unsigned long processor_freq; | 92 | unsigned long processor_freq; |
93 | DEFINE_SPINLOCK(rtc_lock); | 93 | DEFINE_SPINLOCK(rtc_lock); |
94 | EXPORT_SYMBOL_GPL(rtc_lock); | ||
94 | 95 | ||
95 | unsigned long tb_to_ns_scale; | 96 | unsigned long tb_to_ns_scale; |
96 | unsigned long tb_to_ns_shift; | 97 | unsigned long tb_to_ns_shift; |