diff options
Diffstat (limited to 'arch/powerpc/kernel/hw_breakpoint.c')
-rw-r--r-- | arch/powerpc/kernel/hw_breakpoint.c | 72 |
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 | ||
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 | /* |