[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>
This commit is contained in:
Родитель
1f7ad57b75
Коммит
05e14cb3ba
|
@ -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 @@
|
||||||
* - 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 @@ no_kprobe:
|
||||||
* 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,
|
||||||
/* 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)
|
||||||
* 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)
|
||||||
/*
|
/*
|
||||||
* 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,
|
||||||
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;
|
||||||
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)
|
||||||
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);
|
||||||
|
|
||||||
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
|
||||||
*(.text)
|
*(.text)
|
||||||
SCHED_TEXT
|
SCHED_TEXT
|
||||||
LOCK_TEXT
|
LOCK_TEXT
|
||||||
|
KPROBES_TEXT
|
||||||
*(.gnu.warning)
|
*(.gnu.warning)
|
||||||
} =0
|
} =0
|
||||||
_etext = .;
|
_etext = .;
|
||||||
|
|
|
@ -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)
|
||||||
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 @@ cannot_handle:
|
||||||
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 @@
|
||||||
#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 @@ out:
|
||||||
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:
|
||||||
#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
|
||||||
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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче