diff options
author | Michael Neuling <mikey@neuling.org> | 2012-12-20 09:06:44 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-01-10 01:01:44 -0500 |
commit | 9422de3e953d0e60eb95f5430a9dd803eec1c6d7 (patch) | |
tree | 7255a4a2b873a0c3daf7b312a0845202edf6b2d5 /arch/powerpc | |
parent | a8190a59e7440a7e3f7c0889d72a13e157988b3c (diff) |
powerpc: Hardware breakpoints rewrite to handle non DABR breakpoint registers
This is a rewrite so that we don't assume we are using the DABR throughout the
code. We now use the arch_hw_breakpoint to store the breakpoint in a generic
manner in the thread_struct, rather than storing the raw DABR value.
The ptrace GET/SET_DEBUGREG interface currently passes the raw DABR in from
userspace. We keep this functionality, so that future changes (like the POWER8
DAWR), will still fake the DABR to userspace.
Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/debug.h | 15 | ||||
-rw-r--r-- | arch/powerpc/include/asm/hw_breakpoint.h | 33 | ||||
-rw-r--r-- | arch/powerpc/include/asm/processor.h | 4 | ||||
-rw-r--r-- | arch/powerpc/include/asm/reg.h | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/exceptions-64s.S | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/hw_breakpoint.c | 72 | ||||
-rw-r--r-- | arch/powerpc/kernel/kgdb.c | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/process.c | 75 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 60 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace32.c | 8 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal.c | 5 | ||||
-rw-r--r-- | arch/powerpc/kernel/traps.c | 4 | ||||
-rw-r--r-- | arch/powerpc/mm/fault.c | 4 | ||||
-rw-r--r-- | arch/powerpc/xmon/xmon.c | 21 |
14 files changed, 187 insertions, 129 deletions
diff --git a/arch/powerpc/include/asm/debug.h b/arch/powerpc/include/asm/debug.h index 32de2577bb6d..8d85ffb03e61 100644 --- a/arch/powerpc/include/asm/debug.h +++ b/arch/powerpc/include/asm/debug.h | |||
@@ -4,6 +4,8 @@ | |||
4 | #ifndef _ASM_POWERPC_DEBUG_H | 4 | #ifndef _ASM_POWERPC_DEBUG_H |
5 | #define _ASM_POWERPC_DEBUG_H | 5 | #define _ASM_POWERPC_DEBUG_H |
6 | 6 | ||
7 | #include <asm/hw_breakpoint.h> | ||
8 | |||
7 | struct pt_regs; | 9 | struct pt_regs; |
8 | 10 | ||
9 | extern struct dentry *powerpc_debugfs_root; | 11 | extern struct dentry *powerpc_debugfs_root; |
@@ -15,7 +17,7 @@ extern int (*__debugger_ipi)(struct pt_regs *regs); | |||
15 | extern int (*__debugger_bpt)(struct pt_regs *regs); | 17 | extern int (*__debugger_bpt)(struct pt_regs *regs); |
16 | extern int (*__debugger_sstep)(struct pt_regs *regs); | 18 | extern int (*__debugger_sstep)(struct pt_regs *regs); |
17 | extern int (*__debugger_iabr_match)(struct pt_regs *regs); | 19 | extern int (*__debugger_iabr_match)(struct pt_regs *regs); |
18 | extern int (*__debugger_dabr_match)(struct pt_regs *regs); | 20 | extern int (*__debugger_break_match)(struct pt_regs *regs); |
19 | extern int (*__debugger_fault_handler)(struct pt_regs *regs); | 21 | extern int (*__debugger_fault_handler)(struct pt_regs *regs); |
20 | 22 | ||
21 | #define DEBUGGER_BOILERPLATE(__NAME) \ | 23 | #define DEBUGGER_BOILERPLATE(__NAME) \ |
@@ -31,7 +33,7 @@ DEBUGGER_BOILERPLATE(debugger_ipi) | |||
31 | DEBUGGER_BOILERPLATE(debugger_bpt) | 33 | DEBUGGER_BOILERPLATE(debugger_bpt) |
32 | DEBUGGER_BOILERPLATE(debugger_sstep) | 34 | DEBUGGER_BOILERPLATE(debugger_sstep) |
33 | DEBUGGER_BOILERPLATE(debugger_iabr_match) | 35 | DEBUGGER_BOILERPLATE(debugger_iabr_match) |
34 | DEBUGGER_BOILERPLATE(debugger_dabr_match) | 36 | DEBUGGER_BOILERPLATE(debugger_break_match) |
35 | DEBUGGER_BOILERPLATE(debugger_fault_handler) | 37 | DEBUGGER_BOILERPLATE(debugger_fault_handler) |
36 | 38 | ||
37 | #else | 39 | #else |
@@ -40,17 +42,18 @@ static inline int debugger_ipi(struct pt_regs *regs) { return 0; } | |||
40 | static inline int debugger_bpt(struct pt_regs *regs) { return 0; } | 42 | static inline int debugger_bpt(struct pt_regs *regs) { return 0; } |
41 | static inline int debugger_sstep(struct pt_regs *regs) { return 0; } | 43 | static inline int debugger_sstep(struct pt_regs *regs) { return 0; } |
42 | static inline int debugger_iabr_match(struct pt_regs *regs) { return 0; } | 44 | static inline int debugger_iabr_match(struct pt_regs *regs) { return 0; } |
43 | static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; } | 45 | static inline int debugger_break_match(struct pt_regs *regs) { return 0; } |
44 | static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } | 46 | static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } |
45 | #endif | 47 | #endif |
46 | 48 | ||
47 | extern int set_dabr(unsigned long dabr, unsigned long dabrx); | 49 | int set_break(struct arch_hw_breakpoint *brk); |
48 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | 50 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
49 | extern void do_send_trap(struct pt_regs *regs, unsigned long address, | 51 | extern void do_send_trap(struct pt_regs *regs, unsigned long address, |
50 | unsigned long error_code, int signal_code, int brkpt); | 52 | unsigned long error_code, int signal_code, int brkpt); |
51 | #else | 53 | #else |
52 | extern void do_dabr(struct pt_regs *regs, unsigned long address, | 54 | |
53 | unsigned long error_code); | 55 | extern void do_break(struct pt_regs *regs, unsigned long address, |
56 | unsigned long error_code); | ||
54 | #endif | 57 | #endif |
55 | 58 | ||
56 | #endif /* _ASM_POWERPC_DEBUG_H */ | 59 | #endif /* _ASM_POWERPC_DEBUG_H */ |
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h index 423424599dad..2c91faf981db 100644 --- a/arch/powerpc/include/asm/hw_breakpoint.h +++ b/arch/powerpc/include/asm/hw_breakpoint.h | |||
@@ -24,16 +24,30 @@ | |||
24 | #define _PPC_BOOK3S_64_HW_BREAKPOINT_H | 24 | #define _PPC_BOOK3S_64_HW_BREAKPOINT_H |
25 | 25 | ||
26 | #ifdef __KERNEL__ | 26 | #ifdef __KERNEL__ |
27 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
28 | |||
29 | struct arch_hw_breakpoint { | 27 | struct arch_hw_breakpoint { |
30 | unsigned long address; | 28 | unsigned long address; |
31 | unsigned long dabrx; | 29 | u16 type; |
32 | int type; | 30 | u16 len; /* length of the target data symbol */ |
33 | u8 len; /* length of the target data symbol */ | ||
34 | bool extraneous_interrupt; | ||
35 | }; | 31 | }; |
36 | 32 | ||
33 | /* Note: Don't change the the first 6 bits below as they are in the same order | ||
34 | * as the dabr and dabrx. | ||
35 | */ | ||
36 | #define HW_BRK_TYPE_READ 0x01 | ||
37 | #define HW_BRK_TYPE_WRITE 0x02 | ||
38 | #define HW_BRK_TYPE_TRANSLATE 0x04 | ||
39 | #define HW_BRK_TYPE_USER 0x08 | ||
40 | #define HW_BRK_TYPE_KERNEL 0x10 | ||
41 | #define HW_BRK_TYPE_HYP 0x20 | ||
42 | #define HW_BRK_TYPE_EXTRANEOUS_IRQ 0x80 | ||
43 | |||
44 | /* bits that overlap with the bottom 3 bits of the dabr */ | ||
45 | #define HW_BRK_TYPE_RDWR (HW_BRK_TYPE_READ | HW_BRK_TYPE_WRITE) | ||
46 | #define HW_BRK_TYPE_DABR (HW_BRK_TYPE_RDWR | HW_BRK_TYPE_TRANSLATE) | ||
47 | #define HW_BRK_TYPE_PRIV_ALL (HW_BRK_TYPE_USER | HW_BRK_TYPE_KERNEL | \ | ||
48 | HW_BRK_TYPE_HYP) | ||
49 | |||
50 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
37 | #include <linux/kdebug.h> | 51 | #include <linux/kdebug.h> |
38 | #include <asm/reg.h> | 52 | #include <asm/reg.h> |
39 | #include <asm/debug.h> | 53 | #include <asm/debug.h> |
@@ -62,7 +76,12 @@ extern void ptrace_triggered(struct perf_event *bp, | |||
62 | struct perf_sample_data *data, struct pt_regs *regs); | 76 | struct perf_sample_data *data, struct pt_regs *regs); |
63 | static inline void hw_breakpoint_disable(void) | 77 | static inline void hw_breakpoint_disable(void) |
64 | { | 78 | { |
65 | set_dabr(0, 0); | 79 | struct arch_hw_breakpoint brk; |
80 | |||
81 | brk.address = 0; | ||
82 | brk.type = 0; | ||
83 | brk.len = 0; | ||
84 | set_break(&brk); | ||
66 | } | 85 | } |
67 | extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs); | 86 | extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs); |
68 | 87 | ||
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 37f87f069cbf..7938658c168d 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/cache.h> | 33 | #include <linux/cache.h> |
34 | #include <asm/ptrace.h> | 34 | #include <asm/ptrace.h> |
35 | #include <asm/types.h> | 35 | #include <asm/types.h> |
36 | #include <asm/hw_breakpoint.h> | ||
36 | 37 | ||
37 | /* We do _not_ want to define new machine types at all, those must die | 38 | /* We do _not_ want to define new machine types at all, those must die |
38 | * in favor of using the device-tree | 39 | * in favor of using the device-tree |
@@ -225,8 +226,7 @@ struct thread_struct { | |||
225 | struct perf_event *last_hit_ubp; | 226 | struct perf_event *last_hit_ubp; |
226 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | 227 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
227 | #endif | 228 | #endif |
228 | unsigned long dabr; /* Data address breakpoint register */ | 229 | struct arch_hw_breakpoint hw_brk; /* info on the hardware breakpoint */ |
229 | unsigned long dabrx; /* ... extension */ | ||
230 | unsigned long trap_nr; /* last trap # on this thread */ | 230 | unsigned long trap_nr; /* last trap # on this thread */ |
231 | #ifdef CONFIG_ALTIVEC | 231 | #ifdef CONFIG_ALTIVEC |
232 | /* Complete AltiVec register set */ | 232 | /* Complete AltiVec register set */ |
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index d111beb1acdb..1f59fbb7b054 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h | |||
@@ -206,9 +206,6 @@ | |||
206 | #define DAWRX_KERNEL (1UL << 1) | 206 | #define DAWRX_KERNEL (1UL << 1) |
207 | #define DAWRX_HYP (1UL << 2) | 207 | #define DAWRX_HYP (1UL << 2) |
208 | #define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */ | 208 | #define SPRN_DABR 0x3F5 /* Data Address Breakpoint Register */ |
209 | #define DABR_TRANSLATION (1UL << 2) | ||
210 | #define DABR_DATA_WRITE (1UL << 1) | ||
211 | #define DABR_DATA_READ (1UL << 0) | ||
212 | #define SPRN_DABR2 0x13D /* e300 */ | 209 | #define SPRN_DABR2 0x13D /* e300 */ |
213 | #define SPRN_DABRX 0x3F7 /* Data Address Breakpoint Register Extension */ | 210 | #define SPRN_DABRX 0x3F7 /* Data Address Breakpoint Register Extension */ |
214 | #define DABRX_USER (1UL << 0) | 211 | #define DABRX_USER (1UL << 0) |
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 3425aba8da51..a28a65fd0f07 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S | |||
@@ -1251,7 +1251,7 @@ handle_dabr_fault: | |||
1251 | ld r4,_DAR(r1) | 1251 | ld r4,_DAR(r1) |
1252 | ld r5,_DSISR(r1) | 1252 | ld r5,_DSISR(r1) |
1253 | addi r3,r1,STACK_FRAME_OVERHEAD | 1253 | addi r3,r1,STACK_FRAME_OVERHEAD |
1254 | bl .do_dabr | 1254 | bl .do_break |
1255 | 12: b .ret_from_except_lite | 1255 | 12: b .ret_from_except_lite |
1256 | 1256 | ||
1257 | 1257 | ||
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index a89cae481b04..c7483d09fdd0 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c | |||
@@ -73,7 +73,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp) | |||
73 | * If so, DABR will be populated in single_step_dabr_instruction(). | 73 | * If so, DABR will be populated in single_step_dabr_instruction(). |
74 | */ | 74 | */ |
75 | if (current->thread.last_hit_ubp != bp) | 75 | if (current->thread.last_hit_ubp != bp) |
76 | set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx); | 76 | set_break(info); |
77 | 77 | ||
78 | return 0; | 78 | return 0; |
79 | } | 79 | } |
@@ -97,7 +97,7 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) | |||
97 | } | 97 | } |
98 | 98 | ||
99 | *slot = NULL; | 99 | *slot = NULL; |
100 | set_dabr(0, 0); | 100 | hw_breakpoint_disable(); |
101 | } | 101 | } |
102 | 102 | ||
103 | /* | 103 | /* |
@@ -127,19 +127,13 @@ int arch_check_bp_in_kernelspace(struct perf_event *bp) | |||
127 | 127 | ||
128 | int arch_bp_generic_fields(int type, int *gen_bp_type) | 128 | int arch_bp_generic_fields(int type, int *gen_bp_type) |
129 | { | 129 | { |
130 | switch (type) { | 130 | *gen_bp_type = 0; |
131 | case DABR_DATA_READ: | 131 | if (type & HW_BRK_TYPE_READ) |
132 | *gen_bp_type = HW_BREAKPOINT_R; | 132 | *gen_bp_type |= HW_BREAKPOINT_R; |
133 | break; | 133 | if (type & HW_BRK_TYPE_WRITE) |
134 | case DABR_DATA_WRITE: | 134 | *gen_bp_type |= HW_BREAKPOINT_W; |
135 | *gen_bp_type = HW_BREAKPOINT_W; | 135 | if (*gen_bp_type == 0) |
136 | break; | ||
137 | case (DABR_DATA_WRITE | DABR_DATA_READ): | ||
138 | *gen_bp_type = (HW_BREAKPOINT_W | HW_BREAKPOINT_R); | ||
139 | break; | ||
140 | default: | ||
141 | return -EINVAL; | 136 | return -EINVAL; |
142 | } | ||
143 | return 0; | 137 | return 0; |
144 | } | 138 | } |
145 | 139 | ||
@@ -154,29 +148,22 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) | |||
154 | if (!bp) | 148 | if (!bp) |
155 | return ret; | 149 | return ret; |
156 | 150 | ||
157 | switch (bp->attr.bp_type) { | 151 | info->type = HW_BRK_TYPE_TRANSLATE; |
158 | case HW_BREAKPOINT_R: | 152 | if (bp->attr.bp_type & HW_BREAKPOINT_R) |
159 | info->type = DABR_DATA_READ; | 153 | info->type |= HW_BRK_TYPE_READ; |
160 | break; | 154 | if (bp->attr.bp_type & HW_BREAKPOINT_W) |
161 | case HW_BREAKPOINT_W: | 155 | info->type |= HW_BRK_TYPE_WRITE; |
162 | info->type = DABR_DATA_WRITE; | 156 | if (info->type == HW_BRK_TYPE_TRANSLATE) |
163 | break; | 157 | /* must set alteast read or write */ |
164 | case HW_BREAKPOINT_R | HW_BREAKPOINT_W: | ||
165 | info->type = (DABR_DATA_READ | DABR_DATA_WRITE); | ||
166 | break; | ||
167 | default: | ||
168 | return ret; | 158 | return ret; |
169 | } | 159 | if (!(bp->attr.exclude_user)) |
170 | 160 | info->type |= HW_BRK_TYPE_USER; | |
161 | if (!(bp->attr.exclude_kernel)) | ||
162 | info->type |= HW_BRK_TYPE_KERNEL; | ||
163 | if (!(bp->attr.exclude_hv)) | ||
164 | info->type |= HW_BRK_TYPE_HYP; | ||
171 | info->address = bp->attr.bp_addr; | 165 | info->address = bp->attr.bp_addr; |
172 | info->len = bp->attr.bp_len; | 166 | info->len = bp->attr.bp_len; |
173 | info->dabrx = DABRX_ALL; | ||
174 | if (bp->attr.exclude_user) | ||
175 | info->dabrx &= ~DABRX_USER; | ||
176 | if (bp->attr.exclude_kernel) | ||
177 | info->dabrx &= ~DABRX_KERNEL; | ||
178 | if (bp->attr.exclude_hv) | ||
179 | info->dabrx &= ~DABRX_HYP; | ||
180 | 167 | ||
181 | /* | 168 | /* |
182 | * Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8) | 169 | * Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8) |
@@ -204,7 +191,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs) | |||
204 | 191 | ||
205 | info = counter_arch_bp(tsk->thread.last_hit_ubp); | 192 | info = counter_arch_bp(tsk->thread.last_hit_ubp); |
206 | regs->msr &= ~MSR_SE; | 193 | regs->msr &= ~MSR_SE; |
207 | set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx); | 194 | set_break(info); |
208 | tsk->thread.last_hit_ubp = NULL; | 195 | tsk->thread.last_hit_ubp = NULL; |
209 | } | 196 | } |
210 | 197 | ||
@@ -222,7 +209,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) | |||
222 | unsigned long dar = regs->dar; | 209 | unsigned long dar = regs->dar; |
223 | 210 | ||
224 | /* Disable breakpoints during exception handling */ | 211 | /* Disable breakpoints during exception handling */ |
225 | set_dabr(0, 0); | 212 | hw_breakpoint_disable(); |
226 | 213 | ||
227 | /* | 214 | /* |
228 | * The counter may be concurrently released but that can only | 215 | * The counter may be concurrently released but that can only |
@@ -255,8 +242,9 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) | |||
255 | * we still need to single-step the instruction, but we don't | 242 | * we still need to single-step the instruction, but we don't |
256 | * generate an event. | 243 | * generate an event. |
257 | */ | 244 | */ |
258 | info->extraneous_interrupt = !((bp->attr.bp_addr <= dar) && | 245 | if (!((bp->attr.bp_addr <= dar) && |
259 | (dar - bp->attr.bp_addr < bp->attr.bp_len)); | 246 | (dar - bp->attr.bp_addr < bp->attr.bp_len))) |
247 | info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ; | ||
260 | 248 | ||
261 | /* Do not emulate user-space instructions, instead single-step them */ | 249 | /* Do not emulate user-space instructions, instead single-step them */ |
262 | if (user_mode(regs)) { | 250 | if (user_mode(regs)) { |
@@ -285,10 +273,10 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) | |||
285 | * As a policy, the callback is invoked in a 'trigger-after-execute' | 273 | * As a policy, the callback is invoked in a 'trigger-after-execute' |
286 | * fashion | 274 | * fashion |
287 | */ | 275 | */ |
288 | if (!info->extraneous_interrupt) | 276 | if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ)) |
289 | perf_bp_event(bp, regs); | 277 | perf_bp_event(bp, regs); |
290 | 278 | ||
291 | set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx); | 279 | set_break(info); |
292 | out: | 280 | out: |
293 | rcu_read_unlock(); | 281 | rcu_read_unlock(); |
294 | return rc; | 282 | return rc; |
@@ -317,10 +305,10 @@ int __kprobes single_step_dabr_instruction(struct die_args *args) | |||
317 | * We shall invoke the user-defined callback function in the single | 305 | * We shall invoke the user-defined callback function in the single |
318 | * stepping handler to confirm to 'trigger-after-execute' semantics | 306 | * stepping handler to confirm to 'trigger-after-execute' semantics |
319 | */ | 307 | */ |
320 | if (!info->extraneous_interrupt) | 308 | if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ)) |
321 | perf_bp_event(bp, regs); | 309 | perf_bp_event(bp, regs); |
322 | 310 | ||
323 | set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx); | 311 | set_break(info); |
324 | current->thread.last_hit_ubp = NULL; | 312 | current->thread.last_hit_ubp = NULL; |
325 | 313 | ||
326 | /* | 314 | /* |
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index c470a40b29f5..a05f0e4a9d38 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c | |||
@@ -198,7 +198,7 @@ static int kgdb_iabr_match(struct pt_regs *regs) | |||
198 | return 1; | 198 | return 1; |
199 | } | 199 | } |
200 | 200 | ||
201 | static int kgdb_dabr_match(struct pt_regs *regs) | 201 | static int kgdb_break_match(struct pt_regs *regs) |
202 | { | 202 | { |
203 | if (user_mode(regs)) | 203 | if (user_mode(regs)) |
204 | return 0; | 204 | return 0; |
@@ -458,7 +458,7 @@ static void *old__debugger; | |||
458 | static void *old__debugger_bpt; | 458 | static void *old__debugger_bpt; |
459 | static void *old__debugger_sstep; | 459 | static void *old__debugger_sstep; |
460 | static void *old__debugger_iabr_match; | 460 | static void *old__debugger_iabr_match; |
461 | static void *old__debugger_dabr_match; | 461 | static void *old__debugger_break_match; |
462 | static void *old__debugger_fault_handler; | 462 | static void *old__debugger_fault_handler; |
463 | 463 | ||
464 | int kgdb_arch_init(void) | 464 | int kgdb_arch_init(void) |
@@ -468,7 +468,7 @@ int kgdb_arch_init(void) | |||
468 | old__debugger_bpt = __debugger_bpt; | 468 | old__debugger_bpt = __debugger_bpt; |
469 | old__debugger_sstep = __debugger_sstep; | 469 | old__debugger_sstep = __debugger_sstep; |
470 | old__debugger_iabr_match = __debugger_iabr_match; | 470 | old__debugger_iabr_match = __debugger_iabr_match; |
471 | old__debugger_dabr_match = __debugger_dabr_match; | 471 | old__debugger_break_match = __debugger_break_match; |
472 | old__debugger_fault_handler = __debugger_fault_handler; | 472 | old__debugger_fault_handler = __debugger_fault_handler; |
473 | 473 | ||
474 | __debugger_ipi = kgdb_call_nmi_hook; | 474 | __debugger_ipi = kgdb_call_nmi_hook; |
@@ -476,7 +476,7 @@ int kgdb_arch_init(void) | |||
476 | __debugger_bpt = kgdb_handle_breakpoint; | 476 | __debugger_bpt = kgdb_handle_breakpoint; |
477 | __debugger_sstep = kgdb_singlestep; | 477 | __debugger_sstep = kgdb_singlestep; |
478 | __debugger_iabr_match = kgdb_iabr_match; | 478 | __debugger_iabr_match = kgdb_iabr_match; |
479 | __debugger_dabr_match = kgdb_dabr_match; | 479 | __debugger_break_match = kgdb_break_match; |
480 | __debugger_fault_handler = kgdb_not_implemented; | 480 | __debugger_fault_handler = kgdb_not_implemented; |
481 | 481 | ||
482 | return 0; | 482 | return 0; |
@@ -489,6 +489,6 @@ void kgdb_arch_exit(void) | |||
489 | __debugger_bpt = old__debugger_bpt; | 489 | __debugger_bpt = old__debugger_bpt; |
490 | __debugger_sstep = old__debugger_sstep; | 490 | __debugger_sstep = old__debugger_sstep; |
491 | __debugger_iabr_match = old__debugger_iabr_match; | 491 | __debugger_iabr_match = old__debugger_iabr_match; |
492 | __debugger_dabr_match = old__debugger_dabr_match; | 492 | __debugger_breakx_match = old__debugger_break_match; |
493 | __debugger_fault_handler = old__debugger_fault_handler; | 493 | __debugger_fault_handler = old__debugger_fault_handler; |
494 | } | 494 | } |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 3065d17f3606..c16c1c2abeea 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -271,7 +271,7 @@ void do_send_trap(struct pt_regs *regs, unsigned long address, | |||
271 | force_sig_info(SIGTRAP, &info, current); | 271 | force_sig_info(SIGTRAP, &info, current); |
272 | } | 272 | } |
273 | #else /* !CONFIG_PPC_ADV_DEBUG_REGS */ | 273 | #else /* !CONFIG_PPC_ADV_DEBUG_REGS */ |
274 | void do_dabr(struct pt_regs *regs, unsigned long address, | 274 | void do_break (struct pt_regs *regs, unsigned long address, |
275 | unsigned long error_code) | 275 | unsigned long error_code) |
276 | { | 276 | { |
277 | siginfo_t info; | 277 | siginfo_t info; |
@@ -281,11 +281,11 @@ void do_dabr(struct pt_regs *regs, unsigned long address, | |||
281 | 11, SIGSEGV) == NOTIFY_STOP) | 281 | 11, SIGSEGV) == NOTIFY_STOP) |
282 | return; | 282 | return; |
283 | 283 | ||
284 | if (debugger_dabr_match(regs)) | 284 | if (debugger_break_match(regs)) |
285 | return; | 285 | return; |
286 | 286 | ||
287 | /* Clear the DABR */ | 287 | /* Clear the breakpoint */ |
288 | set_dabr(0, 0); | 288 | hw_breakpoint_disable(); |
289 | 289 | ||
290 | /* Deliver the signal to userspace */ | 290 | /* Deliver the signal to userspace */ |
291 | info.si_signo = SIGTRAP; | 291 | info.si_signo = SIGTRAP; |
@@ -296,7 +296,7 @@ void do_dabr(struct pt_regs *regs, unsigned long address, | |||
296 | } | 296 | } |
297 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ | 297 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ |
298 | 298 | ||
299 | static DEFINE_PER_CPU(unsigned long, current_dabr); | 299 | static DEFINE_PER_CPU(struct arch_hw_breakpoint, current_brk); |
300 | 300 | ||
301 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | 301 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
302 | /* | 302 | /* |
@@ -364,39 +364,72 @@ static void switch_booke_debug_regs(struct thread_struct *new_thread) | |||
364 | #ifndef CONFIG_HAVE_HW_BREAKPOINT | 364 | #ifndef CONFIG_HAVE_HW_BREAKPOINT |
365 | static void set_debug_reg_defaults(struct thread_struct *thread) | 365 | static void set_debug_reg_defaults(struct thread_struct *thread) |
366 | { | 366 | { |
367 | if (thread->dabr) { | 367 | thread->hw_brk.address = 0; |
368 | thread->dabr = 0; | 368 | thread->hw_brk.type = 0; |
369 | thread->dabrx = 0; | 369 | set_break(&thread->hw_brk); |
370 | set_dabr(0, 0); | ||
371 | } | ||
372 | } | 370 | } |
373 | #endif /* !CONFIG_HAVE_HW_BREAKPOINT */ | 371 | #endif /* !CONFIG_HAVE_HW_BREAKPOINT */ |
374 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ | 372 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ |
375 | 373 | ||
376 | int set_dabr(unsigned long dabr, unsigned long dabrx) | ||
377 | { | ||
378 | __get_cpu_var(current_dabr) = dabr; | ||
379 | |||
380 | if (ppc_md.set_dabr) | ||
381 | return ppc_md.set_dabr(dabr, dabrx); | ||
382 | |||
383 | /* XXX should we have a CPU_FTR_HAS_DABR ? */ | ||
384 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | 374 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
375 | static inline int __set_dabr(unsigned long dabr, unsigned long dabrx) | ||
376 | { | ||
385 | mtspr(SPRN_DAC1, dabr); | 377 | mtspr(SPRN_DAC1, dabr); |
386 | #ifdef CONFIG_PPC_47x | 378 | #ifdef CONFIG_PPC_47x |
387 | isync(); | 379 | isync(); |
388 | #endif | 380 | #endif |
381 | return 0; | ||
382 | } | ||
389 | #elif defined(CONFIG_PPC_BOOK3S) | 383 | #elif defined(CONFIG_PPC_BOOK3S) |
384 | static inline int __set_dabr(unsigned long dabr, unsigned long dabrx) | ||
385 | { | ||
390 | mtspr(SPRN_DABR, dabr); | 386 | mtspr(SPRN_DABR, dabr); |
391 | mtspr(SPRN_DABRX, dabrx); | 387 | mtspr(SPRN_DABRX, dabrx); |
392 | #endif | ||
393 | return 0; | 388 | return 0; |
394 | } | 389 | } |
390 | #else | ||
391 | static inline int __set_dabr(unsigned long dabr, unsigned long dabrx) | ||
392 | { | ||
393 | return -EINVAL; | ||
394 | } | ||
395 | #endif | ||
396 | |||
397 | static inline int set_dabr(struct arch_hw_breakpoint *brk) | ||
398 | { | ||
399 | unsigned long dabr, dabrx; | ||
400 | |||
401 | dabr = brk->address | (brk->type & HW_BRK_TYPE_DABR); | ||
402 | dabrx = ((brk->type >> 3) & 0x7); | ||
403 | |||
404 | if (ppc_md.set_dabr) | ||
405 | return ppc_md.set_dabr(dabr, dabrx); | ||
406 | |||
407 | return __set_dabr(dabr, dabrx); | ||
408 | } | ||
409 | |||
410 | int set_break(struct arch_hw_breakpoint *brk) | ||
411 | { | ||
412 | __get_cpu_var(current_brk) = *brk; | ||
413 | |||
414 | return set_dabr(brk); | ||
415 | } | ||
395 | 416 | ||
396 | #ifdef CONFIG_PPC64 | 417 | #ifdef CONFIG_PPC64 |
397 | DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); | 418 | DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array); |
398 | #endif | 419 | #endif |
399 | 420 | ||
421 | static inline bool hw_brk_match(struct arch_hw_breakpoint *a, | ||
422 | struct arch_hw_breakpoint *b) | ||
423 | { | ||
424 | if (a->address != b->address) | ||
425 | return false; | ||
426 | if (a->type != b->type) | ||
427 | return false; | ||
428 | if (a->len != b->len) | ||
429 | return false; | ||
430 | return true; | ||
431 | } | ||
432 | |||
400 | struct task_struct *__switch_to(struct task_struct *prev, | 433 | struct task_struct *__switch_to(struct task_struct *prev, |
401 | struct task_struct *new) | 434 | struct task_struct *new) |
402 | { | 435 | { |
@@ -481,8 +514,8 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
481 | * schedule DABR | 514 | * schedule DABR |
482 | */ | 515 | */ |
483 | #ifndef CONFIG_HAVE_HW_BREAKPOINT | 516 | #ifndef CONFIG_HAVE_HW_BREAKPOINT |
484 | if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) | 517 | if (unlikely(hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk))) |
485 | set_dabr(new->thread.dabr, new->thread.dabrx); | 518 | set_break(&new->thread.hw_brk); |
486 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | 519 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
487 | #endif | 520 | #endif |
488 | 521 | ||
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index c4970004d44d..d4afcccf1238 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -905,6 +905,9 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
905 | struct perf_event *bp; | 905 | struct perf_event *bp; |
906 | struct perf_event_attr attr; | 906 | struct perf_event_attr attr; |
907 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | 907 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
908 | #ifndef CONFIG_PPC_ADV_DEBUG_REGS | ||
909 | struct arch_hw_breakpoint hw_brk; | ||
910 | #endif | ||
908 | 911 | ||
909 | /* For ppc64 we support one DABR and no IABR's at the moment (ppc64). | 912 | /* For ppc64 we support one DABR and no IABR's at the moment (ppc64). |
910 | * For embedded processors we support one DAC and no IAC's at the | 913 | * For embedded processors we support one DAC and no IAC's at the |
@@ -931,14 +934,17 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
931 | */ | 934 | */ |
932 | 935 | ||
933 | /* Ensure breakpoint translation bit is set */ | 936 | /* Ensure breakpoint translation bit is set */ |
934 | if (data && !(data & DABR_TRANSLATION)) | 937 | if (data && !(data & HW_BRK_TYPE_TRANSLATE)) |
935 | return -EIO; | 938 | return -EIO; |
939 | hw_brk.address = data & (~HW_BRK_TYPE_DABR); | ||
940 | hw_brk.type = (data & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL; | ||
941 | hw_brk.len = 8; | ||
936 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 942 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
937 | if (ptrace_get_breakpoints(task) < 0) | 943 | if (ptrace_get_breakpoints(task) < 0) |
938 | return -ESRCH; | 944 | return -ESRCH; |
939 | 945 | ||
940 | bp = thread->ptrace_bps[0]; | 946 | bp = thread->ptrace_bps[0]; |
941 | if ((!data) || !(data & (DABR_DATA_WRITE | DABR_DATA_READ))) { | 947 | if ((!data) || !(hw_brk.type & HW_BRK_TYPE_RDWR)) { |
942 | if (bp) { | 948 | if (bp) { |
943 | unregister_hw_breakpoint(bp); | 949 | unregister_hw_breakpoint(bp); |
944 | thread->ptrace_bps[0] = NULL; | 950 | thread->ptrace_bps[0] = NULL; |
@@ -948,10 +954,8 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
948 | } | 954 | } |
949 | if (bp) { | 955 | if (bp) { |
950 | attr = bp->attr; | 956 | attr = bp->attr; |
951 | attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN; | 957 | attr.bp_addr = hw_brk.address; |
952 | arch_bp_generic_fields(data & | 958 | arch_bp_generic_fields(hw_brk.type, &attr.bp_type); |
953 | (DABR_DATA_WRITE | DABR_DATA_READ), | ||
954 | &attr.bp_type); | ||
955 | 959 | ||
956 | /* Enable breakpoint */ | 960 | /* Enable breakpoint */ |
957 | attr.disabled = false; | 961 | attr.disabled = false; |
@@ -963,16 +967,15 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
963 | } | 967 | } |
964 | thread->ptrace_bps[0] = bp; | 968 | thread->ptrace_bps[0] = bp; |
965 | ptrace_put_breakpoints(task); | 969 | ptrace_put_breakpoints(task); |
966 | thread->dabr = data; | 970 | thread->hw_brk = hw_brk; |
967 | thread->dabrx = DABRX_ALL; | ||
968 | return 0; | 971 | return 0; |
969 | } | 972 | } |
970 | 973 | ||
971 | /* Create a new breakpoint request if one doesn't exist already */ | 974 | /* Create a new breakpoint request if one doesn't exist already */ |
972 | hw_breakpoint_init(&attr); | 975 | hw_breakpoint_init(&attr); |
973 | attr.bp_addr = data & ~HW_BREAKPOINT_ALIGN; | 976 | attr.bp_addr = hw_brk.address; |
974 | arch_bp_generic_fields(data & (DABR_DATA_WRITE | DABR_DATA_READ), | 977 | arch_bp_generic_fields(hw_brk.type, |
975 | &attr.bp_type); | 978 | &attr.bp_type); |
976 | 979 | ||
977 | thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr, | 980 | thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr, |
978 | ptrace_triggered, NULL, task); | 981 | ptrace_triggered, NULL, task); |
@@ -985,10 +988,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, | |||
985 | ptrace_put_breakpoints(task); | 988 | ptrace_put_breakpoints(task); |
986 | 989 | ||
987 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | 990 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
988 | 991 | task->thread.hw_brk = hw_brk; | |
989 | /* Move contents to the DABR register */ | ||
990 | task->thread.dabr = data; | ||
991 | task->thread.dabrx = DABRX_ALL; | ||
992 | #else /* CONFIG_PPC_ADV_DEBUG_REGS */ | 992 | #else /* CONFIG_PPC_ADV_DEBUG_REGS */ |
993 | /* As described above, it was assumed 3 bits were passed with the data | 993 | /* As described above, it was assumed 3 bits were passed with the data |
994 | * address, but we will assume only the mode bits will be passed | 994 | * address, but we will assume only the mode bits will be passed |
@@ -1349,7 +1349,7 @@ static long ppc_set_hwdebug(struct task_struct *child, | |||
1349 | struct perf_event_attr attr; | 1349 | struct perf_event_attr attr; |
1350 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | 1350 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
1351 | #ifndef CONFIG_PPC_ADV_DEBUG_REGS | 1351 | #ifndef CONFIG_PPC_ADV_DEBUG_REGS |
1352 | unsigned long dabr; | 1352 | struct arch_hw_breakpoint brk; |
1353 | #endif | 1353 | #endif |
1354 | 1354 | ||
1355 | if (bp_info->version != 1) | 1355 | if (bp_info->version != 1) |
@@ -1397,12 +1397,12 @@ static long ppc_set_hwdebug(struct task_struct *child, | |||
1397 | if ((unsigned long)bp_info->addr >= TASK_SIZE) | 1397 | if ((unsigned long)bp_info->addr >= TASK_SIZE) |
1398 | return -EIO; | 1398 | return -EIO; |
1399 | 1399 | ||
1400 | dabr = (unsigned long)bp_info->addr & ~7UL; | 1400 | brk.address = bp_info->addr & ~7UL; |
1401 | dabr |= DABR_TRANSLATION; | 1401 | brk.type = HW_BRK_TYPE_TRANSLATE; |
1402 | if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ) | 1402 | if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_READ) |
1403 | dabr |= DABR_DATA_READ; | 1403 | brk.type |= HW_BRK_TYPE_READ; |
1404 | if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE) | 1404 | if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE) |
1405 | dabr |= DABR_DATA_WRITE; | 1405 | brk.type |= HW_BRK_TYPE_WRITE; |
1406 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 1406 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
1407 | if (ptrace_get_breakpoints(child) < 0) | 1407 | if (ptrace_get_breakpoints(child) < 0) |
1408 | return -ESRCH; | 1408 | return -ESRCH; |
@@ -1427,8 +1427,7 @@ static long ppc_set_hwdebug(struct task_struct *child, | |||
1427 | hw_breakpoint_init(&attr); | 1427 | hw_breakpoint_init(&attr); |
1428 | attr.bp_addr = (unsigned long)bp_info->addr & ~HW_BREAKPOINT_ALIGN; | 1428 | attr.bp_addr = (unsigned long)bp_info->addr & ~HW_BREAKPOINT_ALIGN; |
1429 | attr.bp_len = len; | 1429 | attr.bp_len = len; |
1430 | arch_bp_generic_fields(dabr & (DABR_DATA_WRITE | DABR_DATA_READ), | 1430 | arch_bp_generic_fields(brk.type, &attr.bp_type); |
1431 | &attr.bp_type); | ||
1432 | 1431 | ||
1433 | thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr, | 1432 | thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr, |
1434 | ptrace_triggered, NULL, child); | 1433 | ptrace_triggered, NULL, child); |
@@ -1445,11 +1444,10 @@ static long ppc_set_hwdebug(struct task_struct *child, | |||
1445 | if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) | 1444 | if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) |
1446 | return -EINVAL; | 1445 | return -EINVAL; |
1447 | 1446 | ||
1448 | if (child->thread.dabr) | 1447 | if (child->thread.hw_brk.address) |
1449 | return -ENOSPC; | 1448 | return -ENOSPC; |
1450 | 1449 | ||
1451 | child->thread.dabr = dabr; | 1450 | child->thread.hw_brk = brk; |
1452 | child->thread.dabrx = DABRX_ALL; | ||
1453 | 1451 | ||
1454 | return 1; | 1452 | return 1; |
1455 | #endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */ | 1453 | #endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */ |
@@ -1495,10 +1493,11 @@ static long ppc_del_hwdebug(struct task_struct *child, long data) | |||
1495 | ptrace_put_breakpoints(child); | 1493 | ptrace_put_breakpoints(child); |
1496 | return ret; | 1494 | return ret; |
1497 | #else /* CONFIG_HAVE_HW_BREAKPOINT */ | 1495 | #else /* CONFIG_HAVE_HW_BREAKPOINT */ |
1498 | if (child->thread.dabr == 0) | 1496 | if (child->thread.hw_brk.address == 0) |
1499 | return -ENOENT; | 1497 | return -ENOENT; |
1500 | 1498 | ||
1501 | child->thread.dabr = 0; | 1499 | child->thread.hw_brk.address = 0; |
1500 | child->thread.hw_brk.type = 0; | ||
1502 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | 1501 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ |
1503 | 1502 | ||
1504 | return 0; | 1503 | return 0; |
@@ -1642,6 +1641,9 @@ long arch_ptrace(struct task_struct *child, long request, | |||
1642 | } | 1641 | } |
1643 | 1642 | ||
1644 | case PTRACE_GET_DEBUGREG: { | 1643 | case PTRACE_GET_DEBUGREG: { |
1644 | #ifndef CONFIG_PPC_ADV_DEBUG_REGS | ||
1645 | unsigned long dabr_fake; | ||
1646 | #endif | ||
1645 | ret = -EINVAL; | 1647 | ret = -EINVAL; |
1646 | /* We only support one DABR and no IABRS at the moment */ | 1648 | /* We only support one DABR and no IABRS at the moment */ |
1647 | if (addr > 0) | 1649 | if (addr > 0) |
@@ -1649,7 +1651,9 @@ long arch_ptrace(struct task_struct *child, long request, | |||
1649 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | 1651 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
1650 | ret = put_user(child->thread.dac1, datalp); | 1652 | ret = put_user(child->thread.dac1, datalp); |
1651 | #else | 1653 | #else |
1652 | ret = put_user(child->thread.dabr, datalp); | 1654 | dabr_fake = ((child->thread.hw_brk.address & (~HW_BRK_TYPE_DABR)) | |
1655 | (child->thread.hw_brk.type & HW_BRK_TYPE_DABR)); | ||
1656 | ret = put_user(dabr_fake, datalp); | ||
1653 | #endif | 1657 | #endif |
1654 | break; | 1658 | break; |
1655 | } | 1659 | } |
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 8c21658719d9..c0244e766834 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c | |||
@@ -252,6 +252,9 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
252 | } | 252 | } |
253 | 253 | ||
254 | case PTRACE_GET_DEBUGREG: { | 254 | case PTRACE_GET_DEBUGREG: { |
255 | #ifndef CONFIG_PPC_ADV_DEBUG_REGS | ||
256 | unsigned long dabr_fake; | ||
257 | #endif | ||
255 | ret = -EINVAL; | 258 | ret = -EINVAL; |
256 | /* We only support one DABR and no IABRS at the moment */ | 259 | /* We only support one DABR and no IABRS at the moment */ |
257 | if (addr > 0) | 260 | if (addr > 0) |
@@ -259,7 +262,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
259 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS | 262 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
260 | ret = put_user(child->thread.dac1, (u32 __user *)data); | 263 | ret = put_user(child->thread.dac1, (u32 __user *)data); |
261 | #else | 264 | #else |
262 | ret = put_user(child->thread.dabr, (u32 __user *)data); | 265 | dabr_fake = ( |
266 | (child->thread.hw_brk.address & (~HW_BRK_TYPE_DABR)) | | ||
267 | (child->thread.hw_brk.type & HW_BRK_TYPE_DABR)); | ||
268 | ret = put_user(dabr_fake, (u32 __user *)data); | ||
263 | #endif | 269 | #endif |
264 | break; | 270 | break; |
265 | } | 271 | } |
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index 3b997118df50..1f26956d3913 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c | |||
@@ -130,8 +130,9 @@ static int do_signal(struct pt_regs *regs) | |||
130 | * user space. The DABR will have been cleared if it | 130 | * user space. The DABR will have been cleared if it |
131 | * triggered inside the kernel. | 131 | * triggered inside the kernel. |
132 | */ | 132 | */ |
133 | if (current->thread.dabr) | 133 | if (current->thread.hw_brk.address && |
134 | set_dabr(current->thread.dabr, current->thread.dabrx); | 134 | current->thread.hw_brk.type) |
135 | set_break(¤t->thread.hw_brk); | ||
135 | #endif | 136 | #endif |
136 | /* Re-enable the breakpoints for the signal stack */ | 137 | /* Re-enable the breakpoints for the signal stack */ |
137 | thread_change_pc(current, regs); | 138 | thread_change_pc(current, regs); |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 114ea241916f..a008cf5c0fce 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -66,7 +66,7 @@ int (*__debugger_ipi)(struct pt_regs *regs) __read_mostly; | |||
66 | int (*__debugger_bpt)(struct pt_regs *regs) __read_mostly; | 66 | int (*__debugger_bpt)(struct pt_regs *regs) __read_mostly; |
67 | int (*__debugger_sstep)(struct pt_regs *regs) __read_mostly; | 67 | int (*__debugger_sstep)(struct pt_regs *regs) __read_mostly; |
68 | int (*__debugger_iabr_match)(struct pt_regs *regs) __read_mostly; | 68 | int (*__debugger_iabr_match)(struct pt_regs *regs) __read_mostly; |
69 | int (*__debugger_dabr_match)(struct pt_regs *regs) __read_mostly; | 69 | int (*__debugger_break_match)(struct pt_regs *regs) __read_mostly; |
70 | int (*__debugger_fault_handler)(struct pt_regs *regs) __read_mostly; | 70 | int (*__debugger_fault_handler)(struct pt_regs *regs) __read_mostly; |
71 | 71 | ||
72 | EXPORT_SYMBOL(__debugger); | 72 | EXPORT_SYMBOL(__debugger); |
@@ -74,7 +74,7 @@ EXPORT_SYMBOL(__debugger_ipi); | |||
74 | EXPORT_SYMBOL(__debugger_bpt); | 74 | EXPORT_SYMBOL(__debugger_bpt); |
75 | EXPORT_SYMBOL(__debugger_sstep); | 75 | EXPORT_SYMBOL(__debugger_sstep); |
76 | EXPORT_SYMBOL(__debugger_iabr_match); | 76 | EXPORT_SYMBOL(__debugger_iabr_match); |
77 | EXPORT_SYMBOL(__debugger_dabr_match); | 77 | EXPORT_SYMBOL(__debugger_break_match); |
78 | EXPORT_SYMBOL(__debugger_fault_handler); | 78 | EXPORT_SYMBOL(__debugger_fault_handler); |
79 | #endif | 79 | #endif |
80 | 80 | ||
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 3a8489a354e9..229951ffc351 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c | |||
@@ -249,8 +249,8 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
249 | #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE) || \ | 249 | #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE) || \ |
250 | defined(CONFIG_PPC_BOOK3S_64)) | 250 | defined(CONFIG_PPC_BOOK3S_64)) |
251 | if (error_code & DSISR_DABRMATCH) { | 251 | if (error_code & DSISR_DABRMATCH) { |
252 | /* DABR match */ | 252 | /* breakpoint match */ |
253 | do_dabr(regs, address, error_code); | 253 | do_break(regs, address, error_code); |
254 | return 0; | 254 | return 0; |
255 | } | 255 | } |
256 | #endif | 256 | #endif |
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 1f8d2f10a432..529c1ed7f59f 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <asm/setjmp.h> | 43 | #include <asm/setjmp.h> |
44 | #include <asm/reg.h> | 44 | #include <asm/reg.h> |
45 | #include <asm/debug.h> | 45 | #include <asm/debug.h> |
46 | #include <asm/hw_breakpoint.h> | ||
46 | 47 | ||
47 | #ifdef CONFIG_PPC64 | 48 | #ifdef CONFIG_PPC64 |
48 | #include <asm/hvcall.h> | 49 | #include <asm/hvcall.h> |
@@ -607,7 +608,7 @@ static int xmon_sstep(struct pt_regs *regs) | |||
607 | return 1; | 608 | return 1; |
608 | } | 609 | } |
609 | 610 | ||
610 | static int xmon_dabr_match(struct pt_regs *regs) | 611 | static int xmon_break_match(struct pt_regs *regs) |
611 | { | 612 | { |
612 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT)) | 613 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT)) |
613 | return 0; | 614 | return 0; |
@@ -740,8 +741,14 @@ static void insert_bpts(void) | |||
740 | 741 | ||
741 | static void insert_cpu_bpts(void) | 742 | static void insert_cpu_bpts(void) |
742 | { | 743 | { |
743 | if (dabr.enabled) | 744 | struct arch_hw_breakpoint brk; |
744 | set_dabr(dabr.address | (dabr.enabled & 7), DABRX_ALL); | 745 | |
746 | if (dabr.enabled) { | ||
747 | brk.address = dabr.address; | ||
748 | brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL; | ||
749 | brk.len = 8; | ||
750 | set_break(&brk); | ||
751 | } | ||
745 | if (iabr && cpu_has_feature(CPU_FTR_IABR)) | 752 | if (iabr && cpu_has_feature(CPU_FTR_IABR)) |
746 | mtspr(SPRN_IABR, iabr->address | 753 | mtspr(SPRN_IABR, iabr->address |
747 | | (iabr->enabled & (BP_IABR|BP_IABR_TE))); | 754 | | (iabr->enabled & (BP_IABR|BP_IABR_TE))); |
@@ -769,7 +776,7 @@ static void remove_bpts(void) | |||
769 | 776 | ||
770 | static void remove_cpu_bpts(void) | 777 | static void remove_cpu_bpts(void) |
771 | { | 778 | { |
772 | set_dabr(0, 0); | 779 | hw_breakpoint_disable(); |
773 | if (cpu_has_feature(CPU_FTR_IABR)) | 780 | if (cpu_has_feature(CPU_FTR_IABR)) |
774 | mtspr(SPRN_IABR, 0); | 781 | mtspr(SPRN_IABR, 0); |
775 | } | 782 | } |
@@ -1138,7 +1145,7 @@ bpt_cmds(void) | |||
1138 | printf(badaddr); | 1145 | printf(badaddr); |
1139 | break; | 1146 | break; |
1140 | } | 1147 | } |
1141 | dabr.address &= ~7; | 1148 | dabr.address &= ~HW_BRK_TYPE_DABR; |
1142 | dabr.enabled = mode | BP_DABR; | 1149 | dabr.enabled = mode | BP_DABR; |
1143 | } | 1150 | } |
1144 | break; | 1151 | break; |
@@ -2917,7 +2924,7 @@ static void xmon_init(int enable) | |||
2917 | __debugger_bpt = xmon_bpt; | 2924 | __debugger_bpt = xmon_bpt; |
2918 | __debugger_sstep = xmon_sstep; | 2925 | __debugger_sstep = xmon_sstep; |
2919 | __debugger_iabr_match = xmon_iabr_match; | 2926 | __debugger_iabr_match = xmon_iabr_match; |
2920 | __debugger_dabr_match = xmon_dabr_match; | 2927 | __debugger_break_match = xmon_break_match; |
2921 | __debugger_fault_handler = xmon_fault_handler; | 2928 | __debugger_fault_handler = xmon_fault_handler; |
2922 | } else { | 2929 | } else { |
2923 | __debugger = NULL; | 2930 | __debugger = NULL; |
@@ -2925,7 +2932,7 @@ static void xmon_init(int enable) | |||
2925 | __debugger_bpt = NULL; | 2932 | __debugger_bpt = NULL; |
2926 | __debugger_sstep = NULL; | 2933 | __debugger_sstep = NULL; |
2927 | __debugger_iabr_match = NULL; | 2934 | __debugger_iabr_match = NULL; |
2928 | __debugger_dabr_match = NULL; | 2935 | __debugger_break_match = NULL; |
2929 | __debugger_fault_handler = NULL; | 2936 | __debugger_fault_handler = NULL; |
2930 | } | 2937 | } |
2931 | } | 2938 | } |