aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/hw_breakpoint.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm64/kernel/hw_breakpoint.c')
-rw-r--r--arch/arm64/kernel/hw_breakpoint.c203
1 files changed, 136 insertions, 67 deletions
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index ff516f6691e4..f17f581116fc 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -20,6 +20,7 @@
20 20
21#define pr_fmt(fmt) "hw-breakpoint: " fmt 21#define pr_fmt(fmt) "hw-breakpoint: " fmt
22 22
23#include <linux/cpu_pm.h>
23#include <linux/errno.h> 24#include <linux/errno.h>
24#include <linux/hw_breakpoint.h> 25#include <linux/hw_breakpoint.h>
25#include <linux/perf_event.h> 26#include <linux/perf_event.h>
@@ -169,15 +170,68 @@ static enum debug_el debug_exception_level(int privilege)
169 } 170 }
170} 171}
171 172
172/* 173enum hw_breakpoint_ops {
173 * Install a perf counter breakpoint. 174 HW_BREAKPOINT_INSTALL,
175 HW_BREAKPOINT_UNINSTALL,
176 HW_BREAKPOINT_RESTORE
177};
178
179/**
180 * hw_breakpoint_slot_setup - Find and setup a perf slot according to
181 * operations
182 *
183 * @slots: pointer to array of slots
184 * @max_slots: max number of slots
185 * @bp: perf_event to setup
186 * @ops: operation to be carried out on the slot
187 *
188 * Return:
189 * slot index on success
190 * -ENOSPC if no slot is available/matches
191 * -EINVAL on wrong operations parameter
174 */ 192 */
175int arch_install_hw_breakpoint(struct perf_event *bp) 193static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots,
194 struct perf_event *bp,
195 enum hw_breakpoint_ops ops)
196{
197 int i;
198 struct perf_event **slot;
199
200 for (i = 0; i < max_slots; ++i) {
201 slot = &slots[i];
202 switch (ops) {
203 case HW_BREAKPOINT_INSTALL:
204 if (!*slot) {
205 *slot = bp;
206 return i;
207 }
208 break;
209 case HW_BREAKPOINT_UNINSTALL:
210 if (*slot == bp) {
211 *slot = NULL;
212 return i;
213 }
214 break;
215 case HW_BREAKPOINT_RESTORE:
216 if (*slot == bp)
217 return i;
218 break;
219 default:
220 pr_warn_once("Unhandled hw breakpoint ops %d\n", ops);
221 return -EINVAL;
222 }
223 }
224 return -ENOSPC;
225}
226
227static int hw_breakpoint_control(struct perf_event *bp,
228 enum hw_breakpoint_ops ops)
176{ 229{
177 struct arch_hw_breakpoint *info = counter_arch_bp(bp); 230 struct arch_hw_breakpoint *info = counter_arch_bp(bp);
178 struct perf_event **slot, **slots; 231 struct perf_event **slots;
179 struct debug_info *debug_info = &current->thread.debug; 232 struct debug_info *debug_info = &current->thread.debug;
180 int i, max_slots, ctrl_reg, val_reg, reg_enable; 233 int i, max_slots, ctrl_reg, val_reg, reg_enable;
234 enum debug_el dbg_el = debug_exception_level(info->ctrl.privilege);
181 u32 ctrl; 235 u32 ctrl;
182 236
183 if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { 237 if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
@@ -196,67 +250,54 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
196 reg_enable = !debug_info->wps_disabled; 250 reg_enable = !debug_info->wps_disabled;
197 } 251 }
198 252
199 for (i = 0; i < max_slots; ++i) { 253 i = hw_breakpoint_slot_setup(slots, max_slots, bp, ops);
200 slot = &slots[i];
201
202 if (!*slot) {
203 *slot = bp;
204 break;
205 }
206 }
207
208 if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot"))
209 return -ENOSPC;
210 254
211 /* Ensure debug monitors are enabled at the correct exception level. */ 255 if (WARN_ONCE(i < 0, "Can't find any breakpoint slot"))
212 enable_debug_monitors(debug_exception_level(info->ctrl.privilege)); 256 return i;
213 257
214 /* Setup the address register. */ 258 switch (ops) {
215 write_wb_reg(val_reg, i, info->address); 259 case HW_BREAKPOINT_INSTALL:
260 /*
261 * Ensure debug monitors are enabled at the correct exception
262 * level.
263 */
264 enable_debug_monitors(dbg_el);
265 /* Fall through */
266 case HW_BREAKPOINT_RESTORE:
267 /* Setup the address register. */
268 write_wb_reg(val_reg, i, info->address);
269
270 /* Setup the control register. */
271 ctrl = encode_ctrl_reg(info->ctrl);
272 write_wb_reg(ctrl_reg, i,
273 reg_enable ? ctrl | 0x1 : ctrl & ~0x1);
274 break;
275 case HW_BREAKPOINT_UNINSTALL:
276 /* Reset the control register. */
277 write_wb_reg(ctrl_reg, i, 0);
216 278
217 /* Setup the control register. */ 279 /*
218 ctrl = encode_ctrl_reg(info->ctrl); 280 * Release the debug monitors for the correct exception
219 write_wb_reg(ctrl_reg, i, reg_enable ? ctrl | 0x1 : ctrl & ~0x1); 281 * level.
282 */
283 disable_debug_monitors(dbg_el);
284 break;
285 }
220 286
221 return 0; 287 return 0;
222} 288}
223 289
224void arch_uninstall_hw_breakpoint(struct perf_event *bp) 290/*
291 * Install a perf counter breakpoint.
292 */
293int arch_install_hw_breakpoint(struct perf_event *bp)
225{ 294{
226 struct arch_hw_breakpoint *info = counter_arch_bp(bp); 295 return hw_breakpoint_control(bp, HW_BREAKPOINT_INSTALL);
227 struct perf_event **slot, **slots; 296}
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 297
258 /* Release the debug monitors for the correct exception level. */ 298void arch_uninstall_hw_breakpoint(struct perf_event *bp)
259 disable_debug_monitors(debug_exception_level(info->ctrl.privilege)); 299{
300 hw_breakpoint_control(bp, HW_BREAKPOINT_UNINSTALL);
260} 301}
261 302
262static int get_hbp_len(u8 hbp_len) 303static int get_hbp_len(u8 hbp_len)
@@ -806,18 +847,36 @@ void hw_breakpoint_thread_switch(struct task_struct *next)
806/* 847/*
807 * CPU initialisation. 848 * CPU initialisation.
808 */ 849 */
809static void reset_ctrl_regs(void *unused) 850static void hw_breakpoint_reset(void *unused)
810{ 851{
811 int i; 852 int i;
812 853 struct perf_event **slots;
813 for (i = 0; i < core_num_brps; ++i) { 854 /*
814 write_wb_reg(AARCH64_DBG_REG_BCR, i, 0UL); 855 * When a CPU goes through cold-boot, it does not have any installed
815 write_wb_reg(AARCH64_DBG_REG_BVR, i, 0UL); 856 * slot, so it is safe to share the same function for restoring and
857 * resetting breakpoints; when a CPU is hotplugged in, it goes
858 * through the slots, which are all empty, hence it just resets control
859 * and value for debug registers.
860 * When this function is triggered on warm-boot through a CPU PM
861 * notifier some slots might be initialized; if so they are
862 * reprogrammed according to the debug slots content.
863 */
864 for (slots = this_cpu_ptr(bp_on_reg), i = 0; i < core_num_brps; ++i) {
865 if (slots[i]) {
866 hw_breakpoint_control(slots[i], HW_BREAKPOINT_RESTORE);
867 } else {
868 write_wb_reg(AARCH64_DBG_REG_BCR, i, 0UL);
869 write_wb_reg(AARCH64_DBG_REG_BVR, i, 0UL);
870 }
816 } 871 }
817 872
818 for (i = 0; i < core_num_wrps; ++i) { 873 for (slots = this_cpu_ptr(wp_on_reg), i = 0; i < core_num_wrps; ++i) {
819 write_wb_reg(AARCH64_DBG_REG_WCR, i, 0UL); 874 if (slots[i]) {
820 write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL); 875 hw_breakpoint_control(slots[i], HW_BREAKPOINT_RESTORE);
876 } else {
877 write_wb_reg(AARCH64_DBG_REG_WCR, i, 0UL);
878 write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL);
879 }
821 } 880 }
822} 881}
823 882
@@ -827,7 +886,7 @@ static int hw_breakpoint_reset_notify(struct notifier_block *self,
827{ 886{
828 int cpu = (long)hcpu; 887 int cpu = (long)hcpu;
829 if (action == CPU_ONLINE) 888 if (action == CPU_ONLINE)
830 smp_call_function_single(cpu, reset_ctrl_regs, NULL, 1); 889 smp_call_function_single(cpu, hw_breakpoint_reset, NULL, 1);
831 return NOTIFY_OK; 890 return NOTIFY_OK;
832} 891}
833 892
@@ -835,6 +894,14 @@ static struct notifier_block hw_breakpoint_reset_nb = {
835 .notifier_call = hw_breakpoint_reset_notify, 894 .notifier_call = hw_breakpoint_reset_notify,
836}; 895};
837 896
897#ifdef CONFIG_ARM64_CPU_SUSPEND
898extern void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *));
899#else
900static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
901{
902}
903#endif
904
838/* 905/*
839 * One-time initialisation. 906 * One-time initialisation.
840 */ 907 */
@@ -850,8 +917,8 @@ static int __init arch_hw_breakpoint_init(void)
850 * Reset the breakpoint resources. We assume that a halting 917 * Reset the breakpoint resources. We assume that a halting
851 * debugger will leave the world in a nice state for us. 918 * debugger will leave the world in a nice state for us.
852 */ 919 */
853 smp_call_function(reset_ctrl_regs, NULL, 1); 920 smp_call_function(hw_breakpoint_reset, NULL, 1);
854 reset_ctrl_regs(NULL); 921 hw_breakpoint_reset(NULL);
855 922
856 /* Register debug fault handlers. */ 923 /* Register debug fault handlers. */
857 hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP, 924 hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP,
@@ -861,6 +928,8 @@ static int __init arch_hw_breakpoint_init(void)
861 928
862 /* Register hotplug notifier. */ 929 /* Register hotplug notifier. */
863 register_cpu_notifier(&hw_breakpoint_reset_nb); 930 register_cpu_notifier(&hw_breakpoint_reset_nb);
931 /* Register cpu_suspend hw breakpoint restore hook */
932 cpu_suspend_set_dbg_restorer(hw_breakpoint_reset);
864 933
865 return 0; 934 return 0;
866} 935}