aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPrasanna S Panchamukhi <prasanna@in.ibm.com>2005-09-06 18:19:30 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:58:00 -0400
commit05e14cb3bafabbf08216ab5566f3cd687eba9723 (patch)
tree6320a3e9193c474571401b2c279b1ee176c29c27
parent1f7ad57b75ab0fba27455c7344a6ab7aa6bd90c5 (diff)
[PATCH] Kprobes: prevent possible race conditions sparc64 changes
This patch contains the sparc64 architecture specific changes to prevent the possible race conditions. Signed-off-by: Prasanna S Panchamukhi <prasanna@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/sparc64/kernel/kprobes.c36
-rw-r--r--arch/sparc64/kernel/vmlinux.lds.S1
-rw-r--r--arch/sparc64/mm/fault.c8
-rw-r--r--arch/sparc64/mm/init.c3
-rw-r--r--arch/sparc64/mm/ultra.S2
5 files changed, 30 insertions, 20 deletions
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index bbf11f85dab1..0d66d07c8c6e 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -8,6 +8,7 @@
8#include <linux/kprobes.h> 8#include <linux/kprobes.h>
9#include <asm/kdebug.h> 9#include <asm/kdebug.h>
10#include <asm/signal.h> 10#include <asm/signal.h>
11#include <asm/cacheflush.h>
11 12
12/* We do not have hardware single-stepping on sparc64. 13/* We do not have hardware single-stepping on sparc64.
13 * So we implement software single-stepping with breakpoint 14 * So we implement software single-stepping with breakpoint
@@ -37,31 +38,31 @@
37 * - Mark that we are no longer actively in a kprobe. 38 * - Mark that we are no longer actively in a kprobe.
38 */ 39 */
39 40
40int arch_prepare_kprobe(struct kprobe *p) 41int __kprobes arch_prepare_kprobe(struct kprobe *p)
41{ 42{
42 return 0; 43 return 0;
43} 44}
44 45
45void arch_copy_kprobe(struct kprobe *p) 46void __kprobes arch_copy_kprobe(struct kprobe *p)
46{ 47{
47 p->ainsn.insn[0] = *p->addr; 48 p->ainsn.insn[0] = *p->addr;
48 p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2; 49 p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
49 p->opcode = *p->addr; 50 p->opcode = *p->addr;
50} 51}
51 52
52void arch_arm_kprobe(struct kprobe *p) 53void __kprobes arch_arm_kprobe(struct kprobe *p)
53{ 54{
54 *p->addr = BREAKPOINT_INSTRUCTION; 55 *p->addr = BREAKPOINT_INSTRUCTION;
55 flushi(p->addr); 56 flushi(p->addr);
56} 57}
57 58
58void arch_disarm_kprobe(struct kprobe *p) 59void __kprobes arch_disarm_kprobe(struct kprobe *p)
59{ 60{
60 *p->addr = p->opcode; 61 *p->addr = p->opcode;
61 flushi(p->addr); 62 flushi(p->addr);
62} 63}
63 64
64void arch_remove_kprobe(struct kprobe *p) 65void __kprobes arch_remove_kprobe(struct kprobe *p)
65{ 66{
66} 67}
67 68
@@ -111,7 +112,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
111 } 112 }
112} 113}
113 114
114static int kprobe_handler(struct pt_regs *regs) 115static int __kprobes kprobe_handler(struct pt_regs *regs)
115{ 116{
116 struct kprobe *p; 117 struct kprobe *p;
117 void *addr = (void *) regs->tpc; 118 void *addr = (void *) regs->tpc;
@@ -191,8 +192,9 @@ no_kprobe:
191 * The original INSN location was REAL_PC, it actually 192 * The original INSN location was REAL_PC, it actually
192 * executed at PC and produced destination address NPC. 193 * executed at PC and produced destination address NPC.
193 */ 194 */
194static unsigned long relbranch_fixup(u32 insn, unsigned long real_pc, 195static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc,
195 unsigned long pc, unsigned long npc) 196 unsigned long pc,
197 unsigned long npc)
196{ 198{
197 /* Branch not taken, no mods necessary. */ 199 /* Branch not taken, no mods necessary. */
198 if (npc == pc + 0x4UL) 200 if (npc == pc + 0x4UL)
@@ -217,7 +219,8 @@ static unsigned long relbranch_fixup(u32 insn, unsigned long real_pc,
217/* If INSN is an instruction which writes it's PC location 219/* If INSN is an instruction which writes it's PC location
218 * into a destination register, fix that up. 220 * into a destination register, fix that up.
219 */ 221 */
220static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc) 222static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
223 unsigned long real_pc)
221{ 224{
222 unsigned long *slot = NULL; 225 unsigned long *slot = NULL;
223 226
@@ -257,7 +260,7 @@ static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc)
257 * This function prepares to return from the post-single-step 260 * This function prepares to return from the post-single-step
258 * breakpoint trap. 261 * breakpoint trap.
259 */ 262 */
260static void resume_execution(struct kprobe *p, struct pt_regs *regs) 263static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
261{ 264{
262 u32 insn = p->ainsn.insn[0]; 265 u32 insn = p->ainsn.insn[0];
263 266
@@ -315,8 +318,8 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
315/* 318/*
316 * Wrapper routine to for handling exceptions. 319 * Wrapper routine to for handling exceptions.
317 */ 320 */
318int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, 321int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
319 void *data) 322 unsigned long val, void *data)
320{ 323{
321 struct die_args *args = (struct die_args *)data; 324 struct die_args *args = (struct die_args *)data;
322 switch (val) { 325 switch (val) {
@@ -344,7 +347,8 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
344 return NOTIFY_DONE; 347 return NOTIFY_DONE;
345} 348}
346 349
347asmlinkage void kprobe_trap(unsigned long trap_level, struct pt_regs *regs) 350asmlinkage void __kprobes kprobe_trap(unsigned long trap_level,
351 struct pt_regs *regs)
348{ 352{
349 BUG_ON(trap_level != 0x170 && trap_level != 0x171); 353 BUG_ON(trap_level != 0x170 && trap_level != 0x171);
350 354
@@ -368,7 +372,7 @@ static struct pt_regs jprobe_saved_regs;
368static struct pt_regs *jprobe_saved_regs_location; 372static struct pt_regs *jprobe_saved_regs_location;
369static struct sparc_stackf jprobe_saved_stack; 373static struct sparc_stackf jprobe_saved_stack;
370 374
371int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) 375int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
372{ 376{
373 struct jprobe *jp = container_of(p, struct jprobe, kp); 377 struct jprobe *jp = container_of(p, struct jprobe, kp);
374 378
@@ -390,7 +394,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
390 return 1; 394 return 1;
391} 395}
392 396
393void jprobe_return(void) 397void __kprobes jprobe_return(void)
394{ 398{
395 preempt_enable_no_resched(); 399 preempt_enable_no_resched();
396 __asm__ __volatile__( 400 __asm__ __volatile__(
@@ -403,7 +407,7 @@ extern void jprobe_return_trap_instruction(void);
403 407
404extern void __show_regs(struct pt_regs * regs); 408extern void __show_regs(struct pt_regs * regs);
405 409
406int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) 410int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
407{ 411{
408 u32 *addr = (u32 *) regs->tpc; 412 u32 *addr = (u32 *) regs->tpc;
409 413
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
index 950423da8a6a..f47d0be39378 100644
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -17,6 +17,7 @@ SECTIONS
17 *(.text) 17 *(.text)
18 SCHED_TEXT 18 SCHED_TEXT
19 LOCK_TEXT 19 LOCK_TEXT
20 KPROBES_TEXT
20 *(.gnu.warning) 21 *(.gnu.warning)
21 } =0 22 } =0
22 _etext = .; 23 _etext = .;
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 52e9375288a9..db1e3310e907 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -18,6 +18,7 @@
18#include <linux/smp_lock.h> 18#include <linux/smp_lock.h>
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/kprobes.h>
21 22
22#include <asm/page.h> 23#include <asm/page.h>
23#include <asm/pgtable.h> 24#include <asm/pgtable.h>
@@ -117,8 +118,9 @@ unsigned long __init prom_probe_memory (void)
117 return tally; 118 return tally;
118} 119}
119 120
120static void unhandled_fault(unsigned long address, struct task_struct *tsk, 121static void __kprobes unhandled_fault(unsigned long address,
121 struct pt_regs *regs) 122 struct task_struct *tsk,
123 struct pt_regs *regs)
122{ 124{
123 if ((unsigned long) address < PAGE_SIZE) { 125 if ((unsigned long) address < PAGE_SIZE) {
124 printk(KERN_ALERT "Unable to handle kernel NULL " 126 printk(KERN_ALERT "Unable to handle kernel NULL "
@@ -304,7 +306,7 @@ cannot_handle:
304 unhandled_fault (address, current, regs); 306 unhandled_fault (address, current, regs);
305} 307}
306 308
307asmlinkage void do_sparc64_fault(struct pt_regs *regs) 309asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
308{ 310{
309 struct mm_struct *mm = current->mm; 311 struct mm_struct *mm = current->mm;
310 struct vm_area_struct *vma; 312 struct vm_area_struct *vma;
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 3fbaf342a452..fdb1ebb308c9 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -19,6 +19,7 @@
19#include <linux/pagemap.h> 19#include <linux/pagemap.h>
20#include <linux/fs.h> 20#include <linux/fs.h>
21#include <linux/seq_file.h> 21#include <linux/seq_file.h>
22#include <linux/kprobes.h>
22 23
23#include <asm/head.h> 24#include <asm/head.h>
24#include <asm/system.h> 25#include <asm/system.h>
@@ -250,7 +251,7 @@ out:
250 put_cpu(); 251 put_cpu();
251} 252}
252 253
253void flush_icache_range(unsigned long start, unsigned long end) 254void __kprobes flush_icache_range(unsigned long start, unsigned long end)
254{ 255{
255 /* Cheetah has coherent I-cache. */ 256 /* Cheetah has coherent I-cache. */
256 if (tlb_type == spitfire) { 257 if (tlb_type == spitfire) {
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 8dfa825eca51..78beff32b6f5 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -119,6 +119,7 @@ __spitfire_flush_tlb_mm_slow:
119#else 119#else
120#error unsupported PAGE_SIZE 120#error unsupported PAGE_SIZE
121#endif 121#endif
122 .section .kprobes.text
122 .align 32 123 .align 32
123 .globl __flush_icache_page 124 .globl __flush_icache_page
124__flush_icache_page: /* %o0 = phys_page */ 125__flush_icache_page: /* %o0 = phys_page */
@@ -201,6 +202,7 @@ dflush4:stxa %g0, [%o4] ASI_DCACHE_TAG
201 nop 202 nop
202#endif /* DCACHE_ALIASING_POSSIBLE */ 203#endif /* DCACHE_ALIASING_POSSIBLE */
203 204
205 .previous .text
204 .align 32 206 .align 32
205__prefill_dtlb: 207__prefill_dtlb:
206 rdpr %pstate, %g7 208 rdpr %pstate, %g7