[PATCH v1 5/6] LoongArch: Fix perf hardware breakpoint failure via installation
Tiezhu Yang <[email protected]>
| Newsgroups | dev.linux.lists.loongarch,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
In hw_breakpoint_control(), the logic to enable CSR_PRMD_PWE (global
watchpoint enable) incorrectly relies on TIF_LOAD_WATCH. This thread
flag is only set during ptrace operations, meaning that the standard
hardware breakpoints created via perf_event_open() will never have
this flag set.
As a result, the CSR_PRMD_PWE switch is skipped, leaving the hardware
breakpoint completely inactive in perf usage.
Fix this by decoupling the CSR_PRMD_PWE from the ptrace specific flag
TIF_LOAD_WATCH, which ensures that CSR_PRMD_PWE is enabled whenever a
hardware breakpoint is installed.
Here is a user-space reproducer to demonstrate the issue:
(1) Test program (test_perf_install.c):
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
static int var = 0;
int main(void)
{
size_t count = 0;
struct perf_event_attr attr = {
.type = PERF_TYPE_BREAKPOINT,
.size = sizeof(attr),
.bp_type = HW_BREAKPOINT_W,
.bp_addr = (unsigned long)&var,
.bp_len = HW_BREAKPOINT_LEN_1,
.exclude_kernel = 1,
};
int fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
asm volatile("st.b %1, %0" : "=m"(var) : "r"(11) : "memory");
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
read(fd, &count, sizeof(size_t));
printf("Watchpoint counts: expected = 1, actual = %zu\n", count);
close(fd);
return 0;
}
(2) Test steps:
$ gcc test_perf_install.c -o test_perf_install
$ ./test_perf_install
(3) Test results:
Without this patch:
Watchpoint counts: expected = 1, actual = 0
With this patch:
Watchpoint counts: expected = 1, actual = 1
Fixes: 3892b11eac5a ("LoongArch: Check TIF_LOAD_WATCH to enable user space watchpoint")
Cc: [email protected]
Signed-off-by: Tiezhu Yang <[email protected]>
---
arch/loongarch/kernel/hw_breakpoint.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/loongarch/kernel/hw_breakpoint.c b/arch/loongarch/kernel/hw_breakpoint.c
index 3683a52b2368..9dcb122218c2 100644
--- a/arch/loongarch/kernel/hw_breakpoint.c
+++ b/arch/loongarch/kernel/hw_breakpoint.c
@@ -233,7 +233,7 @@ static int hw_breakpoint_control(struct perf_event *bp,
}
enable = csr_read64(LOONGARCH_CSR_CRMD);
csr_write64(CSR_CRMD_WE | enable, LOONGARCH_CSR_CRMD);
- if (bp->hw.target && test_tsk_thread_flag(bp->hw.target, TIF_LOAD_WATCH))
+ if (bp->hw.target)
regs->csr_prmd |= CSR_PRMD_PWE;
break;
case HW_BREAKPOINT_UNINSTALL:
--
2.42.0