diff options
Diffstat (limited to 'arch/powerpc/kernel/process.c')
-rw-r--r-- | arch/powerpc/kernel/process.c | 116 |
1 files changed, 96 insertions, 20 deletions
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 7b816daf3eba..e4d71ced97ef 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -245,6 +245,24 @@ void discard_lazy_cpu_state(void) | |||
245 | } | 245 | } |
246 | #endif /* CONFIG_SMP */ | 246 | #endif /* CONFIG_SMP */ |
247 | 247 | ||
248 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | ||
249 | void do_send_trap(struct pt_regs *regs, unsigned long address, | ||
250 | unsigned long error_code, int signal_code, int breakpt) | ||
251 | { | ||
252 | siginfo_t info; | ||
253 | |||
254 | if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, | ||
255 | 11, SIGSEGV) == NOTIFY_STOP) | ||
256 | return; | ||
257 | |||
258 | /* Deliver the signal to userspace */ | ||
259 | info.si_signo = SIGTRAP; | ||
260 | info.si_errno = breakpt; /* breakpoint or watchpoint id */ | ||
261 | info.si_code = signal_code; | ||
262 | info.si_addr = (void __user *)address; | ||
263 | force_sig_info(SIGTRAP, &info, current); | ||
264 | } | ||
265 | #else /* !CONFIG_PPC_ADV_DEBUG_REGS */ | ||
248 | void do_dabr(struct pt_regs *regs, unsigned long address, | 266 | void do_dabr(struct pt_regs *regs, unsigned long address, |
249 | unsigned long error_code) | 267 | unsigned long error_code) |
250 | { | 268 | { |
@@ -257,12 +275,6 @@ void do_dabr(struct pt_regs *regs, unsigned long address, | |||
257 | if (debugger_dabr_match(regs)) | 275 | if (debugger_dabr_match(regs)) |
258 | return; | 276 | return; |
259 | 277 | ||
260 | /* Clear the DAC and struct entries. One shot trigger */ | ||
261 | #if defined(CONFIG_BOOKE) | ||
262 | mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | DBSR_DAC1W | ||
263 | | DBCR0_IDM)); | ||
264 | #endif | ||
265 | |||
266 | /* Clear the DABR */ | 278 | /* Clear the DABR */ |
267 | set_dabr(0); | 279 | set_dabr(0); |
268 | 280 | ||
@@ -273,9 +285,82 @@ void do_dabr(struct pt_regs *regs, unsigned long address, | |||
273 | info.si_addr = (void __user *)address; | 285 | info.si_addr = (void __user *)address; |
274 | force_sig_info(SIGTRAP, &info, current); | 286 | force_sig_info(SIGTRAP, &info, current); |
275 | } | 287 | } |
288 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ | ||
276 | 289 | ||
277 | static DEFINE_PER_CPU(unsigned long, current_dabr); | 290 | static DEFINE_PER_CPU(unsigned long, current_dabr); |
278 | 291 | ||
292 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | ||
293 | /* | ||
294 | * Set the debug registers back to their default "safe" values. | ||
295 | */ | ||
296 | static void set_debug_reg_defaults(struct thread_struct *thread) | ||
297 | { | ||
298 | thread->iac1 = thread->iac2 = 0; | ||
299 | #if CONFIG_PPC_ADV_DEBUG_IACS > 2 | ||
300 | thread->iac3 = thread->iac4 = 0; | ||
301 | #endif | ||
302 | thread->dac1 = thread->dac2 = 0; | ||
303 | #if CONFIG_PPC_ADV_DEBUG_DVCS > 0 | ||
304 | thread->dvc1 = thread->dvc2 = 0; | ||
305 | #endif | ||
306 | thread->dbcr0 = 0; | ||
307 | #ifdef CONFIG_BOOKE | ||
308 | /* | ||
309 | * Force User/Supervisor bits to b11 (user-only MSR[PR]=1) | ||
310 | */ | ||
311 | thread->dbcr1 = DBCR1_IAC1US | DBCR1_IAC2US | \ | ||
312 | DBCR1_IAC3US | DBCR1_IAC4US; | ||
313 | /* | ||
314 | * Force Data Address Compare User/Supervisor bits to be User-only | ||
315 | * (0b11 MSR[PR]=1) and set all other bits in DBCR2 register to be 0. | ||
316 | */ | ||
317 | thread->dbcr2 = DBCR2_DAC1US | DBCR2_DAC2US; | ||
318 | #else | ||
319 | thread->dbcr1 = 0; | ||
320 | #endif | ||
321 | } | ||
322 | |||
323 | static void prime_debug_regs(struct thread_struct *thread) | ||
324 | { | ||
325 | mtspr(SPRN_IAC1, thread->iac1); | ||
326 | mtspr(SPRN_IAC2, thread->iac2); | ||
327 | #if CONFIG_PPC_ADV_DEBUG_IACS > 2 | ||
328 | mtspr(SPRN_IAC3, thread->iac3); | ||
329 | mtspr(SPRN_IAC4, thread->iac4); | ||
330 | #endif | ||
331 | mtspr(SPRN_DAC1, thread->dac1); | ||
332 | mtspr(SPRN_DAC2, thread->dac2); | ||
333 | #if CONFIG_PPC_ADV_DEBUG_DVCS > 0 | ||
334 | mtspr(SPRN_DVC1, thread->dvc1); | ||
335 | mtspr(SPRN_DVC2, thread->dvc2); | ||
336 | #endif | ||
337 | mtspr(SPRN_DBCR0, thread->dbcr0); | ||
338 | mtspr(SPRN_DBCR1, thread->dbcr1); | ||
339 | #ifdef CONFIG_BOOKE | ||
340 | mtspr(SPRN_DBCR2, thread->dbcr2); | ||
341 | #endif | ||
342 | } | ||
343 | /* | ||
344 | * Unless neither the old or new thread are making use of the | ||
345 | * debug registers, set the debug registers from the values | ||
346 | * stored in the new thread. | ||
347 | */ | ||
348 | static void switch_booke_debug_regs(struct thread_struct *new_thread) | ||
349 | { | ||
350 | if ((current->thread.dbcr0 & DBCR0_IDM) | ||
351 | || (new_thread->dbcr0 & DBCR0_IDM)) | ||
352 | prime_debug_regs(new_thread); | ||
353 | } | ||
354 | #else /* !CONFIG_PPC_ADV_DEBUG_REGS */ | ||
355 | static void set_debug_reg_defaults(struct thread_struct *thread) | ||
356 | { | ||
357 | if (thread->dabr) { | ||
358 | thread->dabr = 0; | ||
359 | set_dabr(0); | ||
360 | } | ||
361 | } | ||
362 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ | ||
363 | |||
279 | int set_dabr(unsigned long dabr) | 364 | int set_dabr(unsigned long dabr) |
280 | { | 365 | { |
281 | __get_cpu_var(current_dabr) = dabr; | 366 | __get_cpu_var(current_dabr) = dabr; |
@@ -284,7 +369,7 @@ int set_dabr(unsigned long dabr) | |||
284 | return ppc_md.set_dabr(dabr); | 369 | return ppc_md.set_dabr(dabr); |
285 | 370 | ||
286 | /* XXX should we have a CPU_FTR_HAS_DABR ? */ | 371 | /* XXX should we have a CPU_FTR_HAS_DABR ? */ |
287 | #if defined(CONFIG_BOOKE) | 372 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
288 | mtspr(SPRN_DAC1, dabr); | 373 | mtspr(SPRN_DAC1, dabr); |
289 | #elif defined(CONFIG_PPC_BOOK3S) | 374 | #elif defined(CONFIG_PPC_BOOK3S) |
290 | mtspr(SPRN_DABR, dabr); | 375 | mtspr(SPRN_DABR, dabr); |
@@ -371,10 +456,8 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
371 | 456 | ||
372 | #endif /* CONFIG_SMP */ | 457 | #endif /* CONFIG_SMP */ |
373 | 458 | ||
374 | #if defined(CONFIG_BOOKE) | 459 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
375 | /* If new thread DAC (HW breakpoint) is the same then leave it */ | 460 | switch_booke_debug_regs(&new->thread); |
376 | if (new->thread.dabr) | ||
377 | set_dabr(new->thread.dabr); | ||
378 | #else | 461 | #else |
379 | if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) | 462 | if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) |
380 | set_dabr(new->thread.dabr); | 463 | set_dabr(new->thread.dabr); |
@@ -514,7 +597,7 @@ void show_regs(struct pt_regs * regs) | |||
514 | printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer); | 597 | printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer); |
515 | trap = TRAP(regs); | 598 | trap = TRAP(regs); |
516 | if (trap == 0x300 || trap == 0x600) | 599 | if (trap == 0x300 || trap == 0x600) |
517 | #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) | 600 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
518 | printk("DEAR: "REG", ESR: "REG"\n", regs->dar, regs->dsisr); | 601 | printk("DEAR: "REG", ESR: "REG"\n", regs->dar, regs->dsisr); |
519 | #else | 602 | #else |
520 | printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr); | 603 | printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr); |
@@ -556,14 +639,7 @@ void flush_thread(void) | |||
556 | { | 639 | { |
557 | discard_lazy_cpu_state(); | 640 | discard_lazy_cpu_state(); |
558 | 641 | ||
559 | if (current->thread.dabr) { | 642 | set_debug_reg_defaults(¤t->thread); |
560 | current->thread.dabr = 0; | ||
561 | set_dabr(0); | ||
562 | |||
563 | #if defined(CONFIG_BOOKE) | ||
564 | current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W); | ||
565 | #endif | ||
566 | } | ||
567 | } | 643 | } |
568 | 644 | ||
569 | void | 645 | void |