aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64
diff options
context:
space:
mode:
authorLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2013-08-13 05:45:19 -0400
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2013-12-16 12:17:33 -0500
commit2f04304587544dd14277413ebff12fa0f4fc932c (patch)
treea98aa6a8de4dd5f7c00f6eaeab725791ed688395 /arch/arm64
parent1fcf7ce0c60213994269fb59569ec161eb6e08d6 (diff)
arm64: kernel: refactor code to install/uninstall breakpoints
Most of the code executed to install and uninstall breakpoints is common and can be factored out in a function that through a runtime operations type provides the requested implementation. This patch creates a common function that can be used to install/uninstall breakpoints and defines the set of operations that can be carried out through it. Reviewed-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Diffstat (limited to 'arch/arm64')
-rw-r--r--arch/arm64/kernel/hw_breakpoint.c142
1 files changed, 88 insertions, 54 deletions
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index ff516f6691e4..e89459123fa3 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -169,15 +169,63 @@ static enum debug_el debug_exception_level(int privilege)
169 } 169 }
170} 170}
171 171
172/* 172enum hw_breakpoint_ops {
173 * Install a perf counter breakpoint. 173 HW_BREAKPOINT_INSTALL,
174 HW_BREAKPOINT_UNINSTALL
175};
176
177/**
178 * hw_breakpoint_slot_setup - Find and setup a perf slot according to
179 * operations
180 *
181 * @slots: pointer to array of slots
182 * @max_slots: max number of slots
183 * @bp: perf_event to setup
184 * @ops: operation to be carried out on the slot
185 *
186 * Return:
187 * slot index on success
188 * -ENOSPC if no slot is available/matches
189 * -EINVAL on wrong operations parameter
174 */ 190 */
175int arch_install_hw_breakpoint(struct perf_event *bp) 191static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots,
192 struct perf_event *bp,
193 enum hw_breakpoint_ops ops)
194{
195 int i;
196 struct perf_event **slot;
197
198 for (i = 0; i < max_slots; ++i) {
199 slot = &slots[i];
200 switch (ops) {
201 case HW_BREAKPOINT_INSTALL:
202 if (!*slot) {
203 *slot = bp;
204 return i;
205 }
206 break;
207 case HW_BREAKPOINT_UNINSTALL:
208 if (*slot == bp) {
209 *slot = NULL;
210 return i;
211 }
212 break;
213 default:
214 pr_warn_once("Unhandled hw breakpoint ops %d\n", ops);
215 return -EINVAL;
216 }
217 }
218 return -ENOSPC;
219}
220
221static int hw_breakpoint_control(struct perf_event *bp,
222 enum hw_breakpoint_ops ops)
176{ 223{
177 struct arch_hw_breakpoint *info = counter_arch_bp(bp); 224 struct arch_hw_breakpoint *info = counter_arch_bp(bp);
178 struct perf_event **slot, **slots; 225 struct perf_event **slots;
179 struct debug_info *debug_info = &current->thread.debug; 226 struct debug_info *debug_info = &current->thread.debug;
180 int i, max_slots, ctrl_reg, val_reg, reg_enable; 227 int i, max_slots, ctrl_reg, val_reg, reg_enable;
228 enum debug_el dbg_el = debug_exception_level(info->ctrl.privilege);
181 u32 ctrl; 229 u32 ctrl;
182 230
183 if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { 231 if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
@@ -196,67 +244,53 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
196 reg_enable = !debug_info->wps_disabled; 244 reg_enable = !debug_info->wps_disabled;
197 } 245 }
198 246
199 for (i = 0; i < max_slots; ++i) { 247 i = hw_breakpoint_slot_setup(slots, max_slots, bp, ops);
200 slot = &slots[i];
201 248
202 if (!*slot) { 249 if (WARN_ONCE(i < 0, "Can't find any breakpoint slot"))
203 *slot = bp; 250 return i;
204 break;
205 }
206 }
207 251
208 if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) 252 switch (ops) {
209 return -ENOSPC; 253 case HW_BREAKPOINT_INSTALL:
254 /*
255 * Ensure debug monitors are enabled at the correct exception
256 * level.
257 */
258 enable_debug_monitors(dbg_el);
210 259
211 /* Ensure debug monitors are enabled at the correct exception level. */ 260 /* Setup the address register. */
212 enable_debug_monitors(debug_exception_level(info->ctrl.privilege)); 261 write_wb_reg(val_reg, i, info->address);
213 262
214 /* Setup the address register. */ 263 /* Setup the control register. */
215 write_wb_reg(val_reg, i, info->address); 264 ctrl = encode_ctrl_reg(info->ctrl);
265 write_wb_reg(ctrl_reg, i,
266 reg_enable ? ctrl | 0x1 : ctrl & ~0x1);
267 break;
268 case HW_BREAKPOINT_UNINSTALL:
269 /* Reset the control register. */
270 write_wb_reg(ctrl_reg, i, 0);
216 271
217 /* Setup the control register. */ 272 /*
218 ctrl = encode_ctrl_reg(info->ctrl); 273 * Release the debug monitors for the correct exception
219 write_wb_reg(ctrl_reg, i, reg_enable ? ctrl | 0x1 : ctrl & ~0x1); 274 * level.
275 */
276 disable_debug_monitors(dbg_el);
277 break;
278 }
220 279
221 return 0; 280 return 0;
222} 281}
223 282
224void arch_uninstall_hw_breakpoint(struct perf_event *bp) 283/*
284 * Install a perf counter breakpoint.
285 */
286int arch_install_hw_breakpoint(struct perf_event *bp)
225{ 287{
226 struct arch_hw_breakpoint *info = counter_arch_bp(bp); 288 return hw_breakpoint_control(bp, HW_BREAKPOINT_INSTALL);
227 struct perf_event **slot, **slots; 289}
228 int i, max_slots, base;
229
230 if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
231 /* Breakpoint */
232 base = AARCH64_DBG_REG_BCR;
233 slots = this_cpu_ptr(bp_on_reg);
234 max_slots = core_num_brps;
235 } else {
236 /* Watchpoint */
237 base = AARCH64_DBG_REG_WCR;
238 slots = this_cpu_ptr(wp_on_reg);
239 max_slots = core_num_wrps;
240 }
241
242 /* Remove the breakpoint. */
243 for (i = 0; i < max_slots; ++i) {
244 slot = &slots[i];
245
246 if (*slot == bp) {
247 *slot = NULL;
248 break;
249 }
250 }
251
252 if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot"))
253 return;
254
255 /* Reset the control register. */
256 write_wb_reg(base, i, 0);
257 290
258 /* Release the debug monitors for the correct exception level. */ 291void arch_uninstall_hw_breakpoint(struct perf_event *bp)
259 disable_debug_monitors(debug_exception_level(info->ctrl.privilege)); 292{
293 hw_breakpoint_control(bp, HW_BREAKPOINT_UNINSTALL);
260} 294}
261 295
262static int get_hbp_len(u8 hbp_len) 296static int get_hbp_len(u8 hbp_len)