aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/hw_breakpoint.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/hw_breakpoint.c')
-rw-r--r--arch/powerpc/kernel/hw_breakpoint.c72
1 files changed, 30 insertions, 42 deletions
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
128int arch_bp_generic_fields(int type, int *gen_bp_type) 128int 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);
292out: 280out:
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 /*