Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 106094
b: refs/heads/master
c: d6a61bf
h: refs/heads/master
v: v3
  • Loading branch information
Luis Machado authored and Benjamin Herrenschmidt committed Jul 25, 2008
1 parent 90a1438 commit 508c6a0
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 36 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 00bf6e906156b07cd641fe154ad0efe78f989692
refs/heads/master: d6a61bfc06d6f2248f3e75f208d64e794082013c
6 changes: 3 additions & 3 deletions trunk/arch/powerpc/kernel/entry_32.S
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ transfer_to_handler:
/* Check to see if the dbcr0 register is set up to debug. Use the
internal debug mode bit to do this. */
lwz r12,THREAD_DBCR0(r12)
andis. r12,r12,DBCR0_IDM@h
andis. r12,r12,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h
beq+ 3f
/* From user and task is ptraced - load up global dbcr0 */
li r12,-1 /* clear all pending debug events */
Expand Down Expand Up @@ -292,7 +292,7 @@ syscall_exit_cont:
/* If the process has its own DBCR0 value, load it up. The internal
debug mode bit tells us that dbcr0 should be loaded. */
lwz r0,THREAD+THREAD_DBCR0(r2)
andis. r10,r0,DBCR0_IDM@h
andis. r10,r0,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h
bnel- load_dbcr0
#endif
#ifdef CONFIG_44x
Expand Down Expand Up @@ -720,7 +720,7 @@ restore_user:
/* Check whether this process has its own DBCR0 value. The internal
debug mode bit tells us that dbcr0 should be loaded. */
lwz r0,THREAD+THREAD_DBCR0(r2)
andis. r10,r0,DBCR0_IDM@h
andis. r10,r0,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h
bnel- load_dbcr0
#endif

Expand Down
46 changes: 46 additions & 0 deletions trunk/arch/powerpc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
#ifdef CONFIG_PPC64
#include <asm/firmware.h>
#endif
#include <linux/kprobes.h>
#include <linux/kdebug.h>

extern unsigned long _get_SP(void);

Expand Down Expand Up @@ -239,6 +241,35 @@ void discard_lazy_cpu_state(void)
}
#endif /* CONFIG_SMP */

void do_dabr(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
siginfo_t info;

if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
11, SIGSEGV) == NOTIFY_STOP)
return;

if (debugger_dabr_match(regs))
return;

/* Clear the DAC and struct entries. One shot trigger */
#if (defined(CONFIG_44x) || defined(CONFIG_BOOKE))
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | DBSR_DAC1W
| DBCR0_IDM));
#endif

/* Clear the DABR */
set_dabr(0);

/* Deliver the signal to userspace */
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_HWBKPT;
info.si_addr = (void __user *)address;
force_sig_info(SIGTRAP, &info, current);
}

static DEFINE_PER_CPU(unsigned long, current_dabr);

int set_dabr(unsigned long dabr)
Expand All @@ -254,6 +285,11 @@ int set_dabr(unsigned long dabr)
#if defined(CONFIG_PPC64) || defined(CONFIG_6xx)
mtspr(SPRN_DABR, dabr);
#endif

#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)
mtspr(SPRN_DAC1, dabr);
#endif

return 0;
}

Expand Down Expand Up @@ -337,6 +373,12 @@ struct task_struct *__switch_to(struct task_struct *prev,
if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr))
set_dabr(new->thread.dabr);

#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)
/* If new thread DAC (HW breakpoint) is the same then leave it */
if (new->thread.dabr)
set_dabr(new->thread.dabr);
#endif

new_thread = &new->thread;
old_thread = &current->thread;

Expand Down Expand Up @@ -525,6 +567,10 @@ void flush_thread(void)
if (current->thread.dabr) {
current->thread.dabr = 0;
set_dabr(0);

#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)
current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W);
#endif
}
}

Expand Down
72 changes: 66 additions & 6 deletions trunk/arch/powerpc/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ void user_enable_single_step(struct task_struct *task)

if (regs != NULL) {
#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
task->thread.dbcr0 |= DBCR0_IDM | DBCR0_IC;
regs->msr |= MSR_DE;
#else
regs->msr |= MSR_SE;
Expand All @@ -716,9 +716,16 @@ void user_disable_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;


#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)
/* If DAC then do not single step, skip */
if (task->thread.dabr)
return;
#endif

if (regs != NULL) {
#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
task->thread.dbcr0 = 0;
task->thread.dbcr0 &= ~(DBCR0_IC | DBCR0_IDM);
regs->msr &= ~MSR_DE;
#else
regs->msr &= ~MSR_SE;
Expand All @@ -727,22 +734,75 @@ void user_disable_single_step(struct task_struct *task)
clear_tsk_thread_flag(task, TIF_SINGLESTEP);
}

static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
unsigned long data)
{
/* We only support one DABR and no IABRS at the moment */
/* For ppc64 we support one DABR and no IABR's at the moment (ppc64).
* For embedded processors we support one DAC and no IAC's at the
* moment.
*/
if (addr > 0)
return -EINVAL;

/* The bottom 3 bits are flags */
if ((data & ~0x7UL) >= TASK_SIZE)
return -EIO;

/* Ensure translation is on */
#ifdef CONFIG_PPC64

/* For processors using DABR (i.e. 970), the bottom 3 bits are flags.
* It was assumed, on previous implementations, that 3 bits were
* passed together with the data address, fitting the design of the
* DABR register, as follows:
*
* bit 0: Read flag
* bit 1: Write flag
* bit 2: Breakpoint translation
*
* Thus, we use them here as so.
*/

/* Ensure breakpoint translation bit is set */
if (data && !(data & DABR_TRANSLATION))
return -EIO;

/* Move contents to the DABR register */
task->thread.dabr = data;

#endif
#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)

/* As described above, it was assumed 3 bits were passed with the data
* address, but we will assume only the mode bits will be passed
* as to not cause alignment restrictions for DAC-based processors.
*/

/* DAC's hold the whole address without any mode flags */
task->thread.dabr = data & ~0x3UL;

if (task->thread.dabr == 0) {
task->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W | DBCR0_IDM);
task->thread.regs->msr &= ~MSR_DE;
return 0;
}

/* Read or Write bits must be set */

if (!(data & 0x3UL))
return -EINVAL;

/* Set the Internal Debugging flag (IDM bit 1) for the DBCR0
register */
task->thread.dbcr0 = DBCR0_IDM;

/* Check for write and read flags and set DBCR0
accordingly */
if (data & 0x1UL)
task->thread.dbcr0 |= DBSR_DAC1R;
if (data & 0x2UL)
task->thread.dbcr0 |= DBSR_DAC1W;

task->thread.regs->msr |= MSR_DE;
#endif
return 0;
}

Expand Down
6 changes: 5 additions & 1 deletion trunk/arch/powerpc/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,12 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
* user space. The DABR will have been cleared if it
* triggered inside the kernel.
*/
if (current->thread.dabr)
if (current->thread.dabr) {
set_dabr(current->thread.dabr);
#if defined(CONFIG_44x) || defined(CONFIG_BOOKE)
mtspr(SPRN_DBCR0, current->thread.dbcr0);
#endif
}

if (is32) {
if (ka.sa.sa_flags & SA_SIGINFO)
Expand Down
16 changes: 16 additions & 0 deletions trunk/arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,22 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
}

_exception(SIGTRAP, regs, TRAP_TRACE, regs->nip);
} else if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) {
regs->msr &= ~MSR_DE;

if (user_mode(regs)) {
current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W |
DBCR0_IDM);
} else {
/* Disable DAC interupts */
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R |
DBSR_DAC1W | DBCR0_IDM));

/* Clear the DAC event */
mtspr(SPRN_DBSR, (DBSR_DAC1R | DBSR_DAC1W));
}
/* Setup and send the trap to the handler */
do_dabr(regs, mfspr(SPRN_DAC1), debug_status);
}
}
#endif /* CONFIG_4xx || CONFIG_BOOKE */
Expand Down
25 changes: 0 additions & 25 deletions trunk/arch/powerpc/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,31 +100,6 @@ static int store_updates_sp(struct pt_regs *regs)
return 0;
}

#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
static void do_dabr(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
siginfo_t info;

if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
11, SIGSEGV) == NOTIFY_STOP)
return;

if (debugger_dabr_match(regs))
return;

/* Clear the DABR */
set_dabr(0);

/* Deliver the signal to userspace */
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_HWBKPT;
info.si_addr = (void __user *)address;
force_sig_info(SIGTRAP, &info, current);
}
#endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/

/*
* For 600- and 800-family processors, the error_code parameter is DSISR
* for a data fault, SRR1 for an instruction fault. For 400-family processors
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/asm-powerpc/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
#endif

extern int set_dabr(unsigned long dabr);
extern void do_dabr(struct pt_regs *regs, unsigned long address,
unsigned long error_code);
extern void print_backtrace(unsigned long *);
extern void show_regs(struct pt_regs * regs);
extern void flush_instruction_cache(void);
Expand Down

0 comments on commit 508c6a0

Please sign in to comment.