diff options
| -rw-r--r-- | arch/arm64/include/asm/hw_breakpoint.h | 2 | ||||
| -rw-r--r-- | arch/arm64/kernel/hw_breakpoint.c | 47 | ||||
| -rw-r--r-- | arch/arm64/kernel/ptrace.c | 7 |
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; | |||
| 119 | struct pmu; | 119 | struct pmu; |
| 120 | 120 | ||
| 121 | extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, | 121 | extern 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); |
| 123 | extern int arch_check_bp_in_kernelspace(struct perf_event *bp); | 123 | extern int arch_check_bp_in_kernelspace(struct perf_event *bp); |
| 124 | extern int arch_validate_hwbkpt_settings(struct perf_event *bp); | 124 | extern int arch_validate_hwbkpt_settings(struct perf_event *bp); |
| 125 | extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, | 125 | extern 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 | */ |
| 351 | int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, | 351 | int 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 | ||
