aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/hw_breakpoint.h2
-rw-r--r--arch/arm64/kernel/hw_breakpoint.c47
-rw-r--r--arch/arm64/kernel/ptrace.c7
3 files changed, 28 insertions, 28 deletions
diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h
index 9510ace570e2..d1c3b06ad307 100644
--- a/arch/arm64/include/asm/hw_breakpoint.h
+++ b/arch/arm64/include/asm/hw_breakpoint.h
@@ -119,7 +119,7 @@ struct perf_event;
119struct pmu; 119struct pmu;
120 120
121extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, 121extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
122 int *gen_len, int *gen_type); 122 int *gen_len, int *gen_type, int *offset);
123extern int arch_check_bp_in_kernelspace(struct perf_event *bp); 123extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
124extern int arch_validate_hwbkpt_settings(struct perf_event *bp); 124extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
125extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, 125extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index 948b73148d56..3f7bc65e7ef6 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -349,7 +349,7 @@ int arch_check_bp_in_kernelspace(struct perf_event *bp)
349 * to generic breakpoint descriptions. 349 * to generic breakpoint descriptions.
350 */ 350 */
351int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, 351int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
352 int *gen_len, int *gen_type) 352 int *gen_len, int *gen_type, int *offset)
353{ 353{
354 /* Type */ 354 /* Type */
355 switch (ctrl.type) { 355 switch (ctrl.type) {
@@ -369,8 +369,12 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
369 return -EINVAL; 369 return -EINVAL;
370 } 370 }
371 371
372 if (!ctrl.len)
373 return -EINVAL;
374 *offset = __ffs(ctrl.len);
375
372 /* Len */ 376 /* Len */
373 switch (ctrl.len) { 377 switch (ctrl.len >> *offset) {
374 case ARM_BREAKPOINT_LEN_1: 378 case ARM_BREAKPOINT_LEN_1:
375 *gen_len = HW_BREAKPOINT_LEN_1; 379 *gen_len = HW_BREAKPOINT_LEN_1;
376 break; 380 break;
@@ -517,18 +521,17 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
517 default: 521 default:
518 return -EINVAL; 522 return -EINVAL;
519 } 523 }
520
521 info->address &= ~alignment_mask;
522 info->ctrl.len <<= offset;
523 } else { 524 } else {
524 if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) 525 if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE)
525 alignment_mask = 0x3; 526 alignment_mask = 0x3;
526 else 527 else
527 alignment_mask = 0x7; 528 alignment_mask = 0x7;
528 if (info->address & alignment_mask) 529 offset = info->address & alignment_mask;
529 return -EINVAL;
530 } 530 }
531 531
532 info->address &= ~alignment_mask;
533 info->ctrl.len <<= offset;
534
532 /* 535 /*
533 * Disallow per-task kernel breakpoints since these would 536 * Disallow per-task kernel breakpoints since these would
534 * complicate the stepping code. 537 * complicate the stepping code.
@@ -665,8 +668,8 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr,
665 struct pt_regs *regs) 668 struct pt_regs *regs)
666{ 669{
667 int i, step = 0, *kernel_step, access; 670 int i, step = 0, *kernel_step, access;
668 u32 ctrl_reg; 671 u32 ctrl_reg, lens, lene;
669 u64 val, alignment_mask; 672 u64 val;
670 struct perf_event *wp, **slots; 673 struct perf_event *wp, **slots;
671 struct debug_info *debug_info; 674 struct debug_info *debug_info;
672 struct arch_hw_breakpoint *info; 675 struct arch_hw_breakpoint *info;
@@ -684,25 +687,21 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr,
684 goto unlock; 687 goto unlock;
685 688
686 info = counter_arch_bp(wp); 689 info = counter_arch_bp(wp);
687 /* AArch32 watchpoints are either 4 or 8 bytes aligned. */
688 if (is_compat_task()) {
689 if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
690 alignment_mask = 0x7;
691 else
692 alignment_mask = 0x3;
693 } else {
694 alignment_mask = 0x7;
695 }
696 690
697 /* Check if the watchpoint value matches. */ 691 /* Check if the watchpoint value and byte select match. */
698 val = read_wb_reg(AARCH64_DBG_REG_WVR, i); 692 val = read_wb_reg(AARCH64_DBG_REG_WVR, i);
699 if (val != (addr & ~alignment_mask))
700 goto unlock;
701
702 /* Possible match, check the byte address select to confirm. */
703 ctrl_reg = read_wb_reg(AARCH64_DBG_REG_WCR, i); 693 ctrl_reg = read_wb_reg(AARCH64_DBG_REG_WCR, i);
704 decode_ctrl_reg(ctrl_reg, &ctrl); 694 decode_ctrl_reg(ctrl_reg, &ctrl);
705 if (!((1 << (addr & alignment_mask)) & ctrl.len)) 695 lens = ffs(ctrl.len) - 1;
696 lene = fls(ctrl.len) - 1;
697 /*
698 * FIXME: reported address can be anywhere between "the
699 * lowest address accessed by the memory access that
700 * triggered the watchpoint" and "the highest watchpointed
701 * address accessed by the memory access". So, it may not
702 * lie in the interval of watchpoint address range.
703 */
704 if (addr < val + lens || addr > val + lene)
706 goto unlock; 705 goto unlock;
707 706
708 /* 707 /*
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index e0c81da60f76..fc35e06ccaac 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -327,13 +327,13 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
327 struct arch_hw_breakpoint_ctrl ctrl, 327 struct arch_hw_breakpoint_ctrl ctrl,
328 struct perf_event_attr *attr) 328 struct perf_event_attr *attr)
329{ 329{
330 int err, len, type, disabled = !ctrl.enabled; 330 int err, len, type, offset, disabled = !ctrl.enabled;
331 331
332 attr->disabled = disabled; 332 attr->disabled = disabled;
333 if (disabled) 333 if (disabled)
334 return 0; 334 return 0;
335 335
336 err = arch_bp_generic_fields(ctrl, &len, &type); 336 err = arch_bp_generic_fields(ctrl, &len, &type, &offset);
337 if (err) 337 if (err)
338 return err; 338 return err;
339 339
@@ -352,6 +352,7 @@ static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
352 352
353 attr->bp_len = len; 353 attr->bp_len = len;
354 attr->bp_type = type; 354 attr->bp_type = type;
355 attr->bp_addr += offset;
355 356
356 return 0; 357 return 0;
357} 358}
@@ -404,7 +405,7 @@ static int ptrace_hbp_get_addr(unsigned int note_type,
404 if (IS_ERR(bp)) 405 if (IS_ERR(bp))
405 return PTR_ERR(bp); 406 return PTR_ERR(bp);
406 407
407 *addr = bp ? bp->attr.bp_addr : 0; 408 *addr = bp ? counter_arch_bp(bp)->address : 0;
408 return 0; 409 return 0;
409} 410}
410 411