Commit 05e14cb3 authored by Prasanna S Panchamukhi's avatar Prasanna S Panchamukhi Committed by Linus Torvalds

[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: default avatarPrasanna S Panchamukhi <prasanna@in.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 1f7ad57b
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <asm/kdebug.h> #include <asm/kdebug.h>
#include <asm/signal.h> #include <asm/signal.h>
#include <asm/cacheflush.h>
/* We do not have hardware single-stepping on sparc64. /* We do not have hardware single-stepping on sparc64.
* So we implement software single-stepping with breakpoint * So we implement software single-stepping with breakpoint
...@@ -37,31 +38,31 @@ ...@@ -37,31 +38,31 @@
* - Mark that we are no longer actively in a kprobe. * - Mark that we are no longer actively in a kprobe.
*/ */
int arch_prepare_kprobe(struct kprobe *p) int __kprobes arch_prepare_kprobe(struct kprobe *p)
{ {
return 0; return 0;
} }
void arch_copy_kprobe(struct kprobe *p) void __kprobes arch_copy_kprobe(struct kprobe *p)
{ {
p->ainsn.insn[0] = *p->addr; p->ainsn.insn[0] = *p->addr;
p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2; p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
p->opcode = *p->addr; p->opcode = *p->addr;
} }
void arch_arm_kprobe(struct kprobe *p) void __kprobes arch_arm_kprobe(struct kprobe *p)
{ {
*p->addr = BREAKPOINT_INSTRUCTION; *p->addr = BREAKPOINT_INSTRUCTION;
flushi(p->addr); flushi(p->addr);
} }
void arch_disarm_kprobe(struct kprobe *p) void __kprobes arch_disarm_kprobe(struct kprobe *p)
{ {
*p->addr = p->opcode; *p->addr = p->opcode;
flushi(p->addr); flushi(p->addr);
} }
void arch_remove_kprobe(struct kprobe *p) void __kprobes arch_remove_kprobe(struct kprobe *p)
{ {
} }
...@@ -111,7 +112,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs) ...@@ -111,7 +112,7 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
} }
} }
static int kprobe_handler(struct pt_regs *regs) static int __kprobes kprobe_handler(struct pt_regs *regs)
{ {
struct kprobe *p; struct kprobe *p;
void *addr = (void *) regs->tpc; void *addr = (void *) regs->tpc;
...@@ -191,8 +192,9 @@ static int kprobe_handler(struct pt_regs *regs) ...@@ -191,8 +192,9 @@ static int kprobe_handler(struct pt_regs *regs)
* The original INSN location was REAL_PC, it actually * The original INSN location was REAL_PC, it actually
* executed at PC and produced destination address NPC. * executed at PC and produced destination address NPC.
*/ */
static unsigned long relbranch_fixup(u32 insn, unsigned long real_pc, static unsigned long __kprobes relbranch_fixup(u32 insn, unsigned long real_pc,
unsigned long pc, unsigned long npc) unsigned long pc,
unsigned long npc)
{ {
/* Branch not taken, no mods necessary. */ /* Branch not taken, no mods necessary. */
if (npc == pc + 0x4UL) if (npc == pc + 0x4UL)
...@@ -217,7 +219,8 @@ static unsigned long relbranch_fixup(u32 insn, unsigned long real_pc, ...@@ -217,7 +219,8 @@ static unsigned long relbranch_fixup(u32 insn, unsigned long real_pc,
/* If INSN is an instruction which writes it's PC location /* If INSN is an instruction which writes it's PC location
* into a destination register, fix that up. * into a destination register, fix that up.
*/ */
static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc) static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
unsigned long real_pc)
{ {
unsigned long *slot = NULL; unsigned long *slot = NULL;
...@@ -257,7 +260,7 @@ static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc) ...@@ -257,7 +260,7 @@ static void retpc_fixup(struct pt_regs *regs, u32 insn, unsigned long real_pc)
* This function prepares to return from the post-single-step * This function prepares to return from the post-single-step
* breakpoint trap. * breakpoint trap.
*/ */
static void resume_execution(struct kprobe *p, struct pt_regs *regs) static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
{ {
u32 insn = p->ainsn.insn[0]; u32 insn = p->ainsn.insn[0];
...@@ -315,8 +318,8 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) ...@@ -315,8 +318,8 @@ static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
/* /*
* Wrapper routine to for handling exceptions. * Wrapper routine to for handling exceptions.
*/ */
int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
void *data) unsigned long val, void *data)
{ {
struct die_args *args = (struct die_args *)data; struct die_args *args = (struct die_args *)data;
switch (val) { switch (val) {
...@@ -344,7 +347,8 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, ...@@ -344,7 +347,8 @@ int kprobe_exceptions_notify(struct notifier_block *self, unsigned long val,
return NOTIFY_DONE; return NOTIFY_DONE;
} }
asmlinkage void kprobe_trap(unsigned long trap_level, struct pt_regs *regs) asmlinkage void __kprobes kprobe_trap(unsigned long trap_level,
struct pt_regs *regs)
{ {
BUG_ON(trap_level != 0x170 && trap_level != 0x171); BUG_ON(trap_level != 0x170 && trap_level != 0x171);
...@@ -368,7 +372,7 @@ static struct pt_regs jprobe_saved_regs; ...@@ -368,7 +372,7 @@ static struct pt_regs jprobe_saved_regs;
static struct pt_regs *jprobe_saved_regs_location; static struct pt_regs *jprobe_saved_regs_location;
static struct sparc_stackf jprobe_saved_stack; static struct sparc_stackf jprobe_saved_stack;
int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{ {
struct jprobe *jp = container_of(p, struct jprobe, kp); struct jprobe *jp = container_of(p, struct jprobe, kp);
...@@ -390,7 +394,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) ...@@ -390,7 +394,7 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
return 1; return 1;
} }
void jprobe_return(void) void __kprobes jprobe_return(void)
{ {
preempt_enable_no_resched(); preempt_enable_no_resched();
__asm__ __volatile__( __asm__ __volatile__(
...@@ -403,7 +407,7 @@ extern void jprobe_return_trap_instruction(void); ...@@ -403,7 +407,7 @@ extern void jprobe_return_trap_instruction(void);
extern void __show_regs(struct pt_regs * regs); extern void __show_regs(struct pt_regs * regs);
int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
{ {
u32 *addr = (u32 *) regs->tpc; u32 *addr = (u32 *) regs->tpc;
......
...@@ -17,6 +17,7 @@ SECTIONS ...@@ -17,6 +17,7 @@ SECTIONS
*(.text) *(.text)
SCHED_TEXT SCHED_TEXT
LOCK_TEXT LOCK_TEXT
KPROBES_TEXT
*(.gnu.warning) *(.gnu.warning)
} =0 } =0
_etext = .; _etext = .;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kprobes.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
...@@ -117,8 +118,9 @@ unsigned long __init prom_probe_memory (void) ...@@ -117,8 +118,9 @@ unsigned long __init prom_probe_memory (void)
return tally; return tally;
} }
static void unhandled_fault(unsigned long address, struct task_struct *tsk, static void __kprobes unhandled_fault(unsigned long address,
struct pt_regs *regs) struct task_struct *tsk,
struct pt_regs *regs)
{ {
if ((unsigned long) address < PAGE_SIZE) { if ((unsigned long) address < PAGE_SIZE) {
printk(KERN_ALERT "Unable to handle kernel NULL " printk(KERN_ALERT "Unable to handle kernel NULL "
...@@ -304,7 +306,7 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, ...@@ -304,7 +306,7 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
unhandled_fault (address, current, regs); unhandled_fault (address, current, regs);
} }
asmlinkage void do_sparc64_fault(struct pt_regs *regs) asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
{ {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
struct vm_area_struct *vma; struct vm_area_struct *vma;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/kprobes.h>
#include <asm/head.h> #include <asm/head.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -250,7 +251,7 @@ void flush_dcache_page(struct page *page) ...@@ -250,7 +251,7 @@ void flush_dcache_page(struct page *page)
put_cpu(); put_cpu();
} }
void flush_icache_range(unsigned long start, unsigned long end) void __kprobes flush_icache_range(unsigned long start, unsigned long end)
{ {
/* Cheetah has coherent I-cache. */ /* Cheetah has coherent I-cache. */
if (tlb_type == spitfire) { if (tlb_type == spitfire) {
......
...@@ -119,6 +119,7 @@ __spitfire_flush_tlb_mm_slow: ...@@ -119,6 +119,7 @@ __spitfire_flush_tlb_mm_slow:
#else #else
#error unsupported PAGE_SIZE #error unsupported PAGE_SIZE
#endif #endif
.section .kprobes.text
.align 32 .align 32
.globl __flush_icache_page .globl __flush_icache_page
__flush_icache_page: /* %o0 = phys_page */ __flush_icache_page: /* %o0 = phys_page */
...@@ -201,6 +202,7 @@ dflush4:stxa %g0, [%o4] ASI_DCACHE_TAG ...@@ -201,6 +202,7 @@ dflush4:stxa %g0, [%o4] ASI_DCACHE_TAG
nop nop
#endif /* DCACHE_ALIASING_POSSIBLE */ #endif /* DCACHE_ALIASING_POSSIBLE */
.previous .text
.align 32 .align 32
__prefill_dtlb: __prefill_dtlb:
rdpr %pstate, %g7 rdpr %pstate, %g7
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment