diff options
| author | Anton Blanchard <anton@samba.org> | 2005-09-10 02:01:11 -0400 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2005-09-12 03:19:12 -0400 |
| commit | fd9648dff6f9797ecc509bcd181706a274dc074d (patch) | |
| tree | 845b99905dc4f54171d554c14e45b55f1cfe48e2 | |
| parent | a94d308513bdb2b926b45c11d7ce7fac6d6ca865 (diff) | |
[PATCH] ppc64: Add ptrace data breakpoint support
Add hardware data breakpoint support.
Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
| -rw-r--r-- | arch/ppc64/kernel/process.c | 34 | ||||
| -rw-r--r-- | arch/ppc64/kernel/ptrace.c | 13 | ||||
| -rw-r--r-- | arch/ppc64/kernel/ptrace32.c | 13 | ||||
| -rw-r--r-- | arch/ppc64/kernel/ras.c | 2 | ||||
| -rw-r--r-- | arch/ppc64/kernel/signal.c | 9 | ||||
| -rw-r--r-- | arch/ppc64/kernel/signal32.c | 8 | ||||
| -rw-r--r-- | arch/ppc64/mm/fault.c | 31 | ||||
| -rw-r--r-- | arch/ppc64/xmon/privinst.h | 1 | ||||
| -rw-r--r-- | arch/ppc64/xmon/xmon.c | 20 | ||||
| -rw-r--r-- | include/asm-ppc64/hvcall.h | 6 | ||||
| -rw-r--r-- | include/asm-ppc64/plpar_wrappers.h | 9 | ||||
| -rw-r--r-- | include/asm-ppc64/processor.h | 1 | ||||
| -rw-r--r-- | include/asm-ppc64/ptrace-common.h | 20 | ||||
| -rw-r--r-- | include/asm-ppc64/system.h | 3 |
14 files changed, 145 insertions, 25 deletions
diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index 7a7e027653ad..887005358eb1 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c | |||
| @@ -54,6 +54,7 @@ | |||
| 54 | #include <asm/sections.h> | 54 | #include <asm/sections.h> |
| 55 | #include <asm/tlbflush.h> | 55 | #include <asm/tlbflush.h> |
| 56 | #include <asm/time.h> | 56 | #include <asm/time.h> |
| 57 | #include <asm/plpar_wrappers.h> | ||
| 57 | 58 | ||
| 58 | #ifndef CONFIG_SMP | 59 | #ifndef CONFIG_SMP |
| 59 | struct task_struct *last_task_used_math = NULL; | 60 | struct task_struct *last_task_used_math = NULL; |
| @@ -163,7 +164,30 @@ int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs) | |||
| 163 | 164 | ||
| 164 | #endif /* CONFIG_ALTIVEC */ | 165 | #endif /* CONFIG_ALTIVEC */ |
| 165 | 166 | ||
| 167 | static void set_dabr_spr(unsigned long val) | ||
| 168 | { | ||
| 169 | mtspr(SPRN_DABR, val); | ||
| 170 | } | ||
| 171 | |||
| 172 | int set_dabr(unsigned long dabr) | ||
| 173 | { | ||
| 174 | int ret = 0; | ||
| 175 | |||
| 176 | if (firmware_has_feature(FW_FEATURE_XDABR)) { | ||
| 177 | /* We want to catch accesses from kernel and userspace */ | ||
| 178 | unsigned long flags = H_DABRX_KERNEL|H_DABRX_USER; | ||
| 179 | ret = plpar_set_xdabr(dabr, flags); | ||
| 180 | } else if (firmware_has_feature(FW_FEATURE_DABR)) { | ||
| 181 | ret = plpar_set_dabr(dabr); | ||
| 182 | } else { | ||
| 183 | set_dabr_spr(dabr); | ||
| 184 | } | ||
| 185 | |||
| 186 | return ret; | ||
| 187 | } | ||
| 188 | |||
| 166 | DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); | 189 | DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); |
| 190 | static DEFINE_PER_CPU(unsigned long, current_dabr); | ||
| 167 | 191 | ||
| 168 | struct task_struct *__switch_to(struct task_struct *prev, | 192 | struct task_struct *__switch_to(struct task_struct *prev, |
| 169 | struct task_struct *new) | 193 | struct task_struct *new) |
| @@ -198,6 +222,11 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
| 198 | new->thread.regs->msr |= MSR_VEC; | 222 | new->thread.regs->msr |= MSR_VEC; |
| 199 | #endif /* CONFIG_ALTIVEC */ | 223 | #endif /* CONFIG_ALTIVEC */ |
| 200 | 224 | ||
| 225 | if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) { | ||
| 226 | set_dabr(new->thread.dabr); | ||
| 227 | __get_cpu_var(current_dabr) = new->thread.dabr; | ||
| 228 | } | ||
| 229 | |||
| 201 | flush_tlb_pending(); | 230 | flush_tlb_pending(); |
| 202 | 231 | ||
| 203 | new_thread = &new->thread; | 232 | new_thread = &new->thread; |
| @@ -334,6 +363,11 @@ void flush_thread(void) | |||
| 334 | last_task_used_altivec = NULL; | 363 | last_task_used_altivec = NULL; |
| 335 | #endif /* CONFIG_ALTIVEC */ | 364 | #endif /* CONFIG_ALTIVEC */ |
| 336 | #endif /* CONFIG_SMP */ | 365 | #endif /* CONFIG_SMP */ |
| 366 | |||
| 367 | if (current->thread.dabr) { | ||
| 368 | current->thread.dabr = 0; | ||
| 369 | set_dabr(0); | ||
| 370 | } | ||
| 337 | } | 371 | } |
| 338 | 372 | ||
| 339 | void | 373 | void |
diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index bf7116d4c4c2..85ed3188a91d 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c | |||
| @@ -207,6 +207,19 @@ int sys_ptrace(long request, long pid, long addr, long data) | |||
| 207 | break; | 207 | break; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | case PTRACE_GET_DEBUGREG: { | ||
| 211 | ret = -EINVAL; | ||
| 212 | /* We only support one DABR and no IABRS at the moment */ | ||
| 213 | if (addr > 0) | ||
| 214 | break; | ||
| 215 | ret = put_user(child->thread.dabr, | ||
| 216 | (unsigned long __user *)data); | ||
| 217 | break; | ||
| 218 | } | ||
| 219 | |||
| 220 | case PTRACE_SET_DEBUGREG: | ||
| 221 | ret = ptrace_set_debugreg(child, addr, data); | ||
| 222 | |||
| 210 | case PTRACE_DETACH: | 223 | case PTRACE_DETACH: |
| 211 | ret = ptrace_detach(child, data); | 224 | ret = ptrace_detach(child, data); |
| 212 | break; | 225 | break; |
diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c index cbb1e0fb8813..fb8c22d6084a 100644 --- a/arch/ppc64/kernel/ptrace32.c +++ b/arch/ppc64/kernel/ptrace32.c | |||
| @@ -338,6 +338,19 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) | |||
| 338 | break; | 338 | break; |
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | case PTRACE_GET_DEBUGREG: { | ||
| 342 | ret = -EINVAL; | ||
| 343 | /* We only support one DABR and no IABRS at the moment */ | ||
| 344 | if (addr > 0) | ||
| 345 | break; | ||
| 346 | ret = put_user(child->thread.dabr, (u32 __user *)data); | ||
| 347 | break; | ||
| 348 | } | ||
| 349 | |||
| 350 | case PTRACE_SET_DEBUGREG: | ||
| 351 | ret = ptrace_set_debugreg(child, addr, data); | ||
| 352 | break; | ||
| 353 | |||
| 341 | case PTRACE_DETACH: | 354 | case PTRACE_DETACH: |
| 342 | ret = ptrace_detach(child, data); | 355 | ret = ptrace_detach(child, data); |
| 343 | break; | 356 | break; |
diff --git a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c index 3c00f7bfc1b5..41b97dc9cc0a 100644 --- a/arch/ppc64/kernel/ras.c +++ b/arch/ppc64/kernel/ras.c | |||
| @@ -59,8 +59,6 @@ char mce_data_buf[RTAS_ERROR_LOG_MAX] | |||
| 59 | /* This is true if we are using the firmware NMI handler (typically LPAR) */ | 59 | /* This is true if we are using the firmware NMI handler (typically LPAR) */ |
| 60 | extern int fwnmi_active; | 60 | extern int fwnmi_active; |
| 61 | 61 | ||
| 62 | extern void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr); | ||
| 63 | |||
| 64 | static int ras_get_sensor_state_token; | 62 | static int ras_get_sensor_state_token; |
| 65 | static int ras_check_exception_token; | 63 | static int ras_check_exception_token; |
| 66 | 64 | ||
diff --git a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c index 49a79a55c32d..347112cca3c0 100644 --- a/arch/ppc64/kernel/signal.c +++ b/arch/ppc64/kernel/signal.c | |||
| @@ -550,6 +550,15 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
| 550 | /* Whee! Actually deliver the signal. */ | 550 | /* Whee! Actually deliver the signal. */ |
| 551 | if (TRAP(regs) == 0x0C00) | 551 | if (TRAP(regs) == 0x0C00) |
| 552 | syscall_restart(regs, &ka); | 552 | syscall_restart(regs, &ka); |
| 553 | |||
| 554 | /* | ||
| 555 | * Reenable the DABR before delivering the signal to | ||
| 556 | * user space. The DABR will have been cleared if it | ||
| 557 | * triggered inside the kernel. | ||
| 558 | */ | ||
| 559 | if (current->thread.dabr) | ||
| 560 | set_dabr(current->thread.dabr); | ||
| 561 | |||
| 553 | return handle_signal(signr, &ka, &info, oldset, regs); | 562 | return handle_signal(signr, &ka, &info, oldset, regs); |
| 554 | } | 563 | } |
| 555 | 564 | ||
diff --git a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c index 46f4d6cc7fc9..a8b7a5a56bb4 100644 --- a/arch/ppc64/kernel/signal32.c +++ b/arch/ppc64/kernel/signal32.c | |||
| @@ -970,6 +970,14 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs) | |||
| 970 | newsp = regs->gpr[1]; | 970 | newsp = regs->gpr[1]; |
| 971 | newsp &= ~0xfUL; | 971 | newsp &= ~0xfUL; |
| 972 | 972 | ||
| 973 | /* | ||
| 974 | * Reenable the DABR before delivering the signal to | ||
| 975 | * user space. The DABR will have been cleared if it | ||
| 976 | * triggered inside the kernel. | ||
| 977 | */ | ||
| 978 | if (current->thread.dabr) | ||
| 979 | set_dabr(current->thread.dabr); | ||
| 980 | |||
| 973 | /* Whee! Actually deliver the signal. */ | 981 | /* Whee! Actually deliver the signal. */ |
| 974 | if (ka.sa.sa_flags & SA_SIGINFO) | 982 | if (ka.sa.sa_flags & SA_SIGINFO) |
| 975 | ret = handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp); | 983 | ret = handle_rt_signal32(signr, &ka, &info, oldset, regs, newsp); |
diff --git a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c index 772f0714a5b7..7fbc68bbb739 100644 --- a/arch/ppc64/mm/fault.c +++ b/arch/ppc64/mm/fault.c | |||
| @@ -77,6 +77,28 @@ static int store_updates_sp(struct pt_regs *regs) | |||
| 77 | return 0; | 77 | return 0; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | static void do_dabr(struct pt_regs *regs, unsigned long error_code) | ||
| 81 | { | ||
| 82 | siginfo_t info; | ||
| 83 | |||
| 84 | if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, | ||
| 85 | 11, SIGSEGV) == NOTIFY_STOP) | ||
| 86 | return; | ||
| 87 | |||
| 88 | if (debugger_dabr_match(regs)) | ||
| 89 | return; | ||
| 90 | |||
| 91 | /* Clear the DABR */ | ||
| 92 | set_dabr(0); | ||
| 93 | |||
| 94 | /* Deliver the signal to userspace */ | ||
| 95 | info.si_signo = SIGTRAP; | ||
| 96 | info.si_errno = 0; | ||
| 97 | info.si_code = TRAP_HWBKPT; | ||
| 98 | info.si_addr = (void __user *)regs->nip; | ||
| 99 | force_sig_info(SIGTRAP, &info, current); | ||
| 100 | } | ||
| 101 | |||
| 80 | /* | 102 | /* |
| 81 | * The error_code parameter is | 103 | * The error_code parameter is |
| 82 | * - DSISR for a non-SLB data access fault, | 104 | * - DSISR for a non-SLB data access fault, |
| @@ -111,12 +133,9 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
| 111 | if (!user_mode(regs) && (address >= TASK_SIZE)) | 133 | if (!user_mode(regs) && (address >= TASK_SIZE)) |
| 112 | return SIGSEGV; | 134 | return SIGSEGV; |
| 113 | 135 | ||
| 114 | if (error_code & DSISR_DABRMATCH) { | 136 | if (error_code & DSISR_DABRMATCH) { |
| 115 | if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code, | 137 | do_dabr(regs, error_code); |
| 116 | 11, SIGSEGV) == NOTIFY_STOP) | 138 | return 0; |
| 117 | return 0; | ||
| 118 | if (debugger_dabr_match(regs)) | ||
| 119 | return 0; | ||
| 120 | } | 139 | } |
| 121 | 140 | ||
| 122 | if (in_atomic() || mm == NULL) { | 141 | if (in_atomic() || mm == NULL) { |
diff --git a/arch/ppc64/xmon/privinst.h b/arch/ppc64/xmon/privinst.h index 183c3e400258..02eb40dac0b3 100644 --- a/arch/ppc64/xmon/privinst.h +++ b/arch/ppc64/xmon/privinst.h | |||
| @@ -46,7 +46,6 @@ GSETSPR(287, pvr) | |||
| 46 | GSETSPR(1008, hid0) | 46 | GSETSPR(1008, hid0) |
| 47 | GSETSPR(1009, hid1) | 47 | GSETSPR(1009, hid1) |
| 48 | GSETSPR(1010, iabr) | 48 | GSETSPR(1010, iabr) |
| 49 | GSETSPR(1013, dabr) | ||
| 50 | GSETSPR(1023, pir) | 49 | GSETSPR(1023, pir) |
| 51 | 50 | ||
| 52 | static inline void store_inst(void *p) | 51 | static inline void store_inst(void *p) |
diff --git a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c index 45908b10acd3..74e63a886a69 100644 --- a/arch/ppc64/xmon/xmon.c +++ b/arch/ppc64/xmon/xmon.c | |||
| @@ -586,6 +586,8 @@ int xmon_dabr_match(struct pt_regs *regs) | |||
| 586 | { | 586 | { |
| 587 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) | 587 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) |
| 588 | return 0; | 588 | return 0; |
| 589 | if (dabr.enabled == 0) | ||
| 590 | return 0; | ||
| 589 | xmon_core(regs, 0); | 591 | xmon_core(regs, 0); |
| 590 | return 1; | 592 | return 1; |
| 591 | } | 593 | } |
| @@ -628,20 +630,6 @@ int xmon_fault_handler(struct pt_regs *regs) | |||
| 628 | return 0; | 630 | return 0; |
| 629 | } | 631 | } |
| 630 | 632 | ||
| 631 | /* On systems with a hypervisor, we can't set the DABR | ||
| 632 | (data address breakpoint register) directly. */ | ||
| 633 | static void set_controlled_dabr(unsigned long val) | ||
| 634 | { | ||
| 635 | #ifdef CONFIG_PPC_PSERIES | ||
| 636 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { | ||
| 637 | int rc = plpar_hcall_norets(H_SET_DABR, val); | ||
| 638 | if (rc != H_Success) | ||
| 639 | xmon_printf("Warning: setting DABR failed (%d)\n", rc); | ||
| 640 | } else | ||
| 641 | #endif | ||
| 642 | set_dabr(val); | ||
| 643 | } | ||
| 644 | |||
| 645 | static struct bpt *at_breakpoint(unsigned long pc) | 633 | static struct bpt *at_breakpoint(unsigned long pc) |
| 646 | { | 634 | { |
| 647 | int i; | 635 | int i; |
| @@ -728,7 +716,7 @@ static void insert_bpts(void) | |||
| 728 | static void insert_cpu_bpts(void) | 716 | static void insert_cpu_bpts(void) |
| 729 | { | 717 | { |
| 730 | if (dabr.enabled) | 718 | if (dabr.enabled) |
| 731 | set_controlled_dabr(dabr.address | (dabr.enabled & 7)); | 719 | set_dabr(dabr.address | (dabr.enabled & 7)); |
| 732 | if (iabr && cpu_has_feature(CPU_FTR_IABR)) | 720 | if (iabr && cpu_has_feature(CPU_FTR_IABR)) |
| 733 | set_iabr(iabr->address | 721 | set_iabr(iabr->address |
| 734 | | (iabr->enabled & (BP_IABR|BP_IABR_TE))); | 722 | | (iabr->enabled & (BP_IABR|BP_IABR_TE))); |
| @@ -756,7 +744,7 @@ static void remove_bpts(void) | |||
| 756 | 744 | ||
| 757 | static void remove_cpu_bpts(void) | 745 | static void remove_cpu_bpts(void) |
| 758 | { | 746 | { |
| 759 | set_controlled_dabr(0); | 747 | set_dabr(0); |
| 760 | if (cpu_has_feature(CPU_FTR_IABR)) | 748 | if (cpu_has_feature(CPU_FTR_IABR)) |
| 761 | set_iabr(0); | 749 | set_iabr(0); |
| 762 | } | 750 | } |
diff --git a/include/asm-ppc64/hvcall.h b/include/asm-ppc64/hvcall.h index 4f668a4baff0..ab7c3cf24888 100644 --- a/include/asm-ppc64/hvcall.h +++ b/include/asm-ppc64/hvcall.h | |||
| @@ -56,6 +56,11 @@ | |||
| 56 | #define H_PP1 (1UL<<(63-62)) | 56 | #define H_PP1 (1UL<<(63-62)) |
| 57 | #define H_PP2 (1UL<<(63-63)) | 57 | #define H_PP2 (1UL<<(63-63)) |
| 58 | 58 | ||
| 59 | /* DABRX flags */ | ||
| 60 | #define H_DABRX_HYPERVISOR (1UL<<(63-61)) | ||
| 61 | #define H_DABRX_KERNEL (1UL<<(63-62)) | ||
| 62 | #define H_DABRX_USER (1UL<<(63-63)) | ||
| 63 | |||
| 59 | /* pSeries hypervisor opcodes */ | 64 | /* pSeries hypervisor opcodes */ |
| 60 | #define H_REMOVE 0x04 | 65 | #define H_REMOVE 0x04 |
| 61 | #define H_ENTER 0x08 | 66 | #define H_ENTER 0x08 |
| @@ -101,6 +106,7 @@ | |||
| 101 | #define H_VIO_SIGNAL 0x104 | 106 | #define H_VIO_SIGNAL 0x104 |
| 102 | #define H_SEND_CRQ 0x108 | 107 | #define H_SEND_CRQ 0x108 |
| 103 | #define H_COPY_RDMA 0x110 | 108 | #define H_COPY_RDMA 0x110 |
| 109 | #define H_SET_XDABR 0x134 | ||
| 104 | #define H_STUFF_TCE 0x138 | 110 | #define H_STUFF_TCE 0x138 |
| 105 | #define H_PUT_TCE_INDIRECT 0x13C | 111 | #define H_PUT_TCE_INDIRECT 0x13C |
| 106 | #define H_VTERM_PARTNER_INFO 0x150 | 112 | #define H_VTERM_PARTNER_INFO 0x150 |
diff --git a/include/asm-ppc64/plpar_wrappers.h b/include/asm-ppc64/plpar_wrappers.h index f4a5fb7d67c7..72dd2449ee76 100644 --- a/include/asm-ppc64/plpar_wrappers.h +++ b/include/asm-ppc64/plpar_wrappers.h | |||
| @@ -107,5 +107,14 @@ static inline long plpar_put_term_char(unsigned long termno, | |||
| 107 | lbuf[1]); | 107 | lbuf[1]); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static inline long plpar_set_xdabr(unsigned long address, unsigned long flags) | ||
| 111 | { | ||
| 112 | return plpar_hcall_norets(H_SET_XDABR, address, flags); | ||
| 113 | } | ||
| 114 | |||
| 115 | static inline long plpar_set_dabr(unsigned long val) | ||
| 116 | { | ||
| 117 | return plpar_hcall_norets(H_SET_DABR, val); | ||
| 118 | } | ||
| 110 | 119 | ||
| 111 | #endif /* _PPC64_PLPAR_WRAPPERS_H */ | 120 | #endif /* _PPC64_PLPAR_WRAPPERS_H */ |
diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h index 8bd7aa959385..4146189006e3 100644 --- a/include/asm-ppc64/processor.h +++ b/include/asm-ppc64/processor.h | |||
| @@ -433,6 +433,7 @@ struct thread_struct { | |||
| 433 | unsigned long start_tb; /* Start purr when proc switched in */ | 433 | unsigned long start_tb; /* Start purr when proc switched in */ |
| 434 | unsigned long accum_tb; /* Total accumilated purr for process */ | 434 | unsigned long accum_tb; /* Total accumilated purr for process */ |
| 435 | unsigned long vdso_base; /* base of the vDSO library */ | 435 | unsigned long vdso_base; /* base of the vDSO library */ |
| 436 | unsigned long dabr; /* Data address breakpoint register */ | ||
| 436 | #ifdef CONFIG_ALTIVEC | 437 | #ifdef CONFIG_ALTIVEC |
| 437 | /* Complete AltiVec register set */ | 438 | /* Complete AltiVec register set */ |
| 438 | vector128 vr[32] __attribute((aligned(16))); | 439 | vector128 vr[32] __attribute((aligned(16))); |
diff --git a/include/asm-ppc64/ptrace-common.h b/include/asm-ppc64/ptrace-common.h index bd0f84c27bd0..b1babb729673 100644 --- a/include/asm-ppc64/ptrace-common.h +++ b/include/asm-ppc64/ptrace-common.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #define _PPC64_PTRACE_COMMON_H | 13 | #define _PPC64_PTRACE_COMMON_H |
| 14 | 14 | ||
| 15 | #include <linux/config.h> | 15 | #include <linux/config.h> |
| 16 | #include <asm/system.h> | ||
| 16 | 17 | ||
| 17 | /* | 18 | /* |
| 18 | * Set of msr bits that gdb can change on behalf of a process. | 19 | * Set of msr bits that gdb can change on behalf of a process. |
| @@ -141,4 +142,23 @@ static inline int set_vrregs(struct task_struct *task, | |||
| 141 | } | 142 | } |
| 142 | #endif | 143 | #endif |
| 143 | 144 | ||
| 145 | static inline int ptrace_set_debugreg(struct task_struct *task, | ||
| 146 | unsigned long addr, unsigned long data) | ||
| 147 | { | ||
| 148 | /* We only support one DABR and no IABRS at the moment */ | ||
| 149 | if (addr > 0) | ||
| 150 | return -EINVAL; | ||
| 151 | |||
| 152 | /* The bottom 3 bits are flags */ | ||
| 153 | if ((data & ~0x7UL) >= TASK_SIZE) | ||
| 154 | return -EIO; | ||
| 155 | |||
| 156 | /* Ensure translation is on */ | ||
| 157 | if (data && !(data & DABR_TRANSLATION)) | ||
| 158 | return -EIO; | ||
| 159 | |||
| 160 | task->thread.dabr = data; | ||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | |||
| 144 | #endif /* _PPC64_PTRACE_COMMON_H */ | 164 | #endif /* _PPC64_PTRACE_COMMON_H */ |
diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index c0396428cc3c..375015c62f20 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h | |||
| @@ -101,6 +101,9 @@ static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; } | |||
| 101 | static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } | 101 | static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } |
| 102 | #endif | 102 | #endif |
| 103 | 103 | ||
| 104 | extern int set_dabr(unsigned long dabr); | ||
| 105 | extern void _exception(int signr, struct pt_regs *regs, int code, | ||
| 106 | unsigned long addr); | ||
| 104 | extern int fix_alignment(struct pt_regs *regs); | 107 | extern int fix_alignment(struct pt_regs *regs); |
| 105 | extern void bad_page_fault(struct pt_regs *regs, unsigned long address, | 108 | extern void bad_page_fault(struct pt_regs *regs, unsigned long address, |
| 106 | int sig); | 109 | int sig); |
