On Fri, Aug 22, 2025 at 11:17 PM Jesse Taube jesse@rivosinc.com wrote:
From: Himanshu Chauhan hchauhan@ventanamicro.com
RISC-V hardware breakpoint framework is built on top of perf subsystem and uses SBI debug trigger extension to install/uninstall/update/enable/disable hardware triggers as specified in Sdtrig ISA extension.
Signed-off-by: Himanshu Chauhan hchauhan@ventanamicro.com Signed-off-by: Jesse Taube jesse@rivosinc.com
RFC -> V1:
- Add dbtr_mode to rv_init_mcontrol(6)_trigger
- Add select HAVE_MIXED_BREAKPOINTS_REGS
- Add TDATA1_MCTRL_SZ and TDATA1_MCTRL6_SZ
- Capitalize F in Fallback comment
- Fix in_callback code to allow multiple breakpoints
- Move perf_bp_event above setup_singlestep to save the correct state
- Use sbi_err_map_linux_errno for arch_smp_teardown/setup_sbi_shmem
V1 -> V2:
- No change
arch/riscv/Kconfig | 2 + arch/riscv/include/asm/hw_breakpoint.h | 59 +++ arch/riscv/include/asm/kdebug.h | 3 +- arch/riscv/include/asm/sbi.h | 4 +- arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/hw_breakpoint.c | 614 +++++++++++++++++++++++++ arch/riscv/kernel/traps.c | 6 + 7 files changed, 687 insertions(+), 2 deletions(-) create mode 100644 arch/riscv/include/asm/hw_breakpoint.h create mode 100644 arch/riscv/kernel/hw_breakpoint.c
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index bbec87b79309..fd8b62cdc6f5 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -163,6 +163,7 @@ config RISCV select HAVE_FUNCTION_ERROR_INJECTION select HAVE_GCC_PLUGINS select HAVE_GENERIC_VDSO if MMU && 64BIT
select HAVE_HW_BREAKPOINT if PERF_EVENTS && RISCV_SBI select HAVE_IRQ_TIME_ACCOUNTING select HAVE_KERNEL_BZIP2 if !XIP_KERNEL && !EFI_ZBOOT select HAVE_KERNEL_GZIP if !XIP_KERNEL && !EFI_ZBOOT
@@ -176,6 +177,7 @@ config RISCV select HAVE_KRETPROBES if !XIP_KERNEL # https://github.com/ClangBuiltLinux/linux/issues/1881 select HAVE_LD_DEAD_CODE_DATA_ELIMINATION if !LD_IS_LLD
select HAVE_MIXED_BREAKPOINTS_REGS select HAVE_MOVE_PMD select HAVE_MOVE_PUD select HAVE_PAGE_SIZE_4KB
diff --git a/arch/riscv/include/asm/hw_breakpoint.h b/arch/riscv/include/asm/hw_breakpoint.h new file mode 100644 index 000000000000..cde6688b91d2 --- /dev/null +++ b/arch/riscv/include/asm/hw_breakpoint.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/*
- Copyright (C) 2024 Ventana Micro Systems Inc.
- */
+#ifndef __RISCV_HW_BREAKPOINT_H +#define __RISCV_HW_BREAKPOINT_H
+struct task_struct;
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+#include <uapi/linux/hw_breakpoint.h>
+#if __riscv_xlen == 64 +#define cpu_to_le cpu_to_le64 +#define le_to_cpu le64_to_cpu +#elif __riscv_xlen == 32 +#define cpu_to_le cpu_to_le32 +#define le_to_cpu le32_to_cpu +#else +#error "Unexpected __riscv_xlen" +#endif
+struct arch_hw_breakpoint {
unsigned long address;
unsigned long len;
/* Callback info */
unsigned long next_addr;
bool in_callback;
/* Trigger configuration data */
unsigned long tdata1;
unsigned long tdata2;
unsigned long tdata3;
+};
+/* Maximum number of hardware breakpoints supported */ +#define RV_MAX_TRIGGERS 32
+struct perf_event_attr; +struct notifier_block; +struct perf_event; +struct pt_regs;
+int hw_breakpoint_slots(int type); +int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw); +int hw_breakpoint_arch_parse(struct perf_event *bp,
const struct perf_event_attr *attr,
struct arch_hw_breakpoint *hw);
+int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data);
+int arch_install_hw_breakpoint(struct perf_event *bp); +void arch_uninstall_hw_breakpoint(struct perf_event *bp); +void hw_breakpoint_pmu_read(struct perf_event *bp);
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */ +#endif /* __RISCV_HW_BREAKPOINT_H */ diff --git a/arch/riscv/include/asm/kdebug.h b/arch/riscv/include/asm/kdebug.h index 85ac00411f6e..53e989781aa1 100644 --- a/arch/riscv/include/asm/kdebug.h +++ b/arch/riscv/include/asm/kdebug.h @@ -6,7 +6,8 @@ enum die_val { DIE_UNUSED, DIE_TRAP,
DIE_OOPS
DIE_OOPS,
DIE_DEBUG
};
#endif diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index be2ca8e8a49e..64fa7a82aa45 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -282,7 +282,9 @@ struct sbi_sta_struct { u8 pad[47]; } __packed;
-#define SBI_SHMEM_DISABLE -1 +#define SBI_SHMEM_DISABLE (-1UL) +#define SBI_SHMEM_LO(pa) ((unsigned long)lower_32_bits(pa)) +#define SBI_SHMEM_HI(pa) ((unsigned long)upper_32_bits(pa))
These definitions of SBI_SHMEM_LO() and SBI_SHMEM_HI() are broken for RV64 platforms where a good amount of RAM is beyond first 4GB.
This should be:
#ifdef CONFIG_32BIT #define SBI_SHMEM_LO(pa) ((unsigned long)lower_32_bits(pa)) #define SBI_SHMEM_HI(pa) ((unsigned long)upper_32_bits(pa)) #else #define SBI_SHMEM_LO(pa) ((unsigned long)pa) #define SBI_SHMEM_HI(pa) 0UL #endif
Regards, Anup