Files
kernel-zhihe-a210/arch/riscv/include/asm/hw_breakpoint.h
2025-11-19 21:14:48 +08:00

318 lines
9.2 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2025 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
#define RV_DBTR_BIT(_prefix, _name) \
RV_DBTR_##_prefix##_##_name##_BIT
#define RV_DBTR_BIT_MASK(_prefix, _name) \
RV_DBTR_##_prefix##_name##_BIT_MASK
#define RV_DBTR_BIT_MASK_VAL(_prefix, _name, _width) \
(((1UL << _width) - 1) << RV_DBTR_BIT(_prefix, _name))
#define CLEAR_DBTR_BIT(_target, _prefix, _bit_name) \
__clear_bit(RV_DBTR_BIT(_prefix, _bit_name), &_target)
#define SET_DBTR_BIT(_target, _prefix, _bit_name) \
__set_bit(RV_DBTR_BIT(_prefix, _bit_name), &_target)
enum {
RV_DBTR_BP = 0,
RV_DBTR_WP = 1,
};
enum {
RV_DBTR_TRIG_NONE = 0,
RV_DBTR_TRIG_LEGACY,
RV_DBTR_TRIG_MCONTROL,
RV_DBTR_TRIG_ICOUNT,
RV_DBTR_TRIG_ITRIGGER,
RV_DBTR_TRIG_ETRIGGER,
RV_DBTR_TRIG_MCONTROL6,
};
/* Trigger Data 1 */
enum {
RV_DBTR_BIT(TDATA1, DATA) = 0,
#if __riscv_xlen == 64
RV_DBTR_BIT(TDATA1, DMODE) = 59,
RV_DBTR_BIT(TDATA1, TYPE) = 60,
#elif __riscv_xlen == 32
RV_DBTR_BIT(TDATA1, DMODE) = 27,
RV_DBTR_BIT(TDATA1, TYPE) = 28,
#else
#error "Unknown __riscv_xlen"
#endif
};
enum {
#if __riscv_xlen == 64
RV_DBTR_BIT_MASK(TDATA1, DATA) = RV_DBTR_BIT_MASK_VAL(TDATA1, DATA, 59),
#elif __riscv_xlen == 32
RV_DBTR_BIT_MASK(TDATA1, DATA) = RV_DBTR_BIT_MASK_VAL(TDATA1, DATA, 27),
#else
#error "Unknown __riscv_xlen"
#endif
RV_DBTR_BIT_MASK(TDAT1, DMODE) = RV_DBTR_BIT_MASK_VAL(TDATA1, DMODE, 1),
RV_DBTR_BIT_MASK(TDATA1, TYPE) = RV_DBTR_BIT_MASK_VAL(TDATA1, TYPE, 4),
};
/* MC - Match Control Type Register */
enum {
RV_DBTR_BIT(MC, LOAD) = 0,
RV_DBTR_BIT(MC, STORE) = 1,
RV_DBTR_BIT(MC, EXEC) = 2,
RV_DBTR_BIT(MC, U) = 3,
RV_DBTR_BIT(MC, S) = 4,
RV_DBTR_BIT(MC, RES2) = 5,
RV_DBTR_BIT(MC, M) = 6,
RV_DBTR_BIT(MC, MATCH) = 7,
RV_DBTR_BIT(MC, CHAIN) = 11,
RV_DBTR_BIT(MC, ACTION) = 12,
RV_DBTR_BIT(MC, SIZELO) = 16,
RV_DBTR_BIT(MC, TIMING) = 18,
RV_DBTR_BIT(MC, SELECT) = 19,
RV_DBTR_BIT(MC, HIT) = 20,
#if __riscv_xlen >= 64
RV_DBTR_BIT(MC, SIZEHI) = 21,
#endif
#if __riscv_xlen == 64
RV_DBTR_BIT(MC, MASKMAX) = 53,
RV_DBTR_BIT(MC, DMODE) = 59,
RV_DBTR_BIT(MC, TYPE) = 60,
#elif __riscv_xlen == 32
RV_DBTR_BIT(MC, MASKMAX) = 21,
RV_DBTR_BIT(MC, DMODE) = 27,
RV_DBTR_BIT(MC, TYPE) = 28,
#else
#error "Unknown riscv xlen"
#endif
};
enum {
RV_DBTR_BIT_MASK(MC, LOAD) = RV_DBTR_BIT_MASK_VAL(MC, LOAD, 1),
RV_DBTR_BIT_MASK(MC, STORE) = RV_DBTR_BIT_MASK_VAL(MC, STORE, 1),
RV_DBTR_BIT_MASK(MC, EXEC) = RV_DBTR_BIT_MASK_VAL(MC, EXEC, 1),
RV_DBTR_BIT_MASK(MC, U) = RV_DBTR_BIT_MASK_VAL(MC, U, 1),
RV_DBTR_BIT_MASK(MC, S) = RV_DBTR_BIT_MASK_VAL(MC, S, 1),
RV_DBTR_BIT_MASK(MC, RES2) = RV_DBTR_BIT_MASK_VAL(MC, RES2, 1),
RV_DBTR_BIT_MASK(MC, M) = RV_DBTR_BIT_MASK_VAL(MC, M, 1),
RV_DBTR_BIT_MASK(MC, MATCH) = RV_DBTR_BIT_MASK_VAL(MC, MATCH, 4),
RV_DBTR_BIT_MASK(MC, CHAIN) = RV_DBTR_BIT_MASK_VAL(MC, CHAIN, 1),
RV_DBTR_BIT_MASK(MC, ACTION) = RV_DBTR_BIT_MASK_VAL(MC, ACTION, 4),
RV_DBTR_BIT_MASK(MC, SIZELO) = RV_DBTR_BIT_MASK_VAL(MC, SIZELO, 2),
RV_DBTR_BIT_MASK(MC, TIMING) = RV_DBTR_BIT_MASK_VAL(MC, TIMING, 1),
RV_DBTR_BIT_MASK(MC, SELECT) = RV_DBTR_BIT_MASK_VAL(MC, SELECT, 1),
RV_DBTR_BIT_MASK(MC, HIT) = RV_DBTR_BIT_MASK_VAL(MC, HIT, 1),
#if __riscv_xlen >= 64
RV_DBTR_BIT_MASK(MC, SIZEHI) = RV_DBTR_BIT_MASK_VAL(MC, SIZEHI, 2),
#endif
RV_DBTR_BIT_MASK(MC, MASKMAX) = RV_DBTR_BIT_MASK_VAL(MC, MASKMAX, 6),
RV_DBTR_BIT_MASK(MC, DMODE) = RV_DBTR_BIT_MASK_VAL(MC, DMODE, 1),
RV_DBTR_BIT_MASK(MC, TYPE) = RV_DBTR_BIT_MASK_VAL(MC, TYPE, 4),
};
/* MC6 - Match Control 6 Type Register */
enum {
RV_DBTR_BIT(MC6, LOAD) = 0,
RV_DBTR_BIT(MC6, STORE) = 1,
RV_DBTR_BIT(MC6, EXEC) = 2,
RV_DBTR_BIT(MC6, U) = 3,
RV_DBTR_BIT(MC6, S) = 4,
RV_DBTR_BIT(MC6, RES2) = 5,
RV_DBTR_BIT(MC6, M) = 6,
RV_DBTR_BIT(MC6, MATCH) = 7,
RV_DBTR_BIT(MC6, CHAIN) = 11,
RV_DBTR_BIT(MC6, ACTION) = 12,
RV_DBTR_BIT(MC6, SIZE) = 16,
RV_DBTR_BIT(MC6, TIMING) = 20,
RV_DBTR_BIT(MC6, SELECT) = 21,
RV_DBTR_BIT(MC6, HIT) = 22,
RV_DBTR_BIT(MC6, VU) = 23,
RV_DBTR_BIT(MC6, VS) = 24,
#if __riscv_xlen == 64
RV_DBTR_BIT(MC6, DMODE) = 59,
RV_DBTR_BIT(MC6, TYPE) = 60,
#elif __riscv_xlen == 32
RV_DBTR_BIT(MC6, DMODE) = 27,
RV_DBTR_BIT(MC6, TYPE) = 28,
#else
#error "Unknown riscv xlen"
#endif
};
enum {
RV_DBTR_BIT_MASK(MC6, LOAD) = RV_DBTR_BIT_MASK_VAL(MC6, LOAD, 1),
RV_DBTR_BIT_MASK(MC6, STORE) = RV_DBTR_BIT_MASK_VAL(MC6, STORE, 1),
RV_DBTR_BIT_MASK(MC6, EXEC) = RV_DBTR_BIT_MASK_VAL(MC6, EXEC, 1),
RV_DBTR_BIT_MASK(MC6, U) = RV_DBTR_BIT_MASK_VAL(MC6, U, 1),
RV_DBTR_BIT_MASK(MC6, S) = RV_DBTR_BIT_MASK_VAL(MC6, S, 1),
RV_DBTR_BIT_MASK(MC6, RES2) = RV_DBTR_BIT_MASK_VAL(MC6, RES2, 1),
RV_DBTR_BIT_MASK(MC6, M) = RV_DBTR_BIT_MASK_VAL(MC6, M, 1),
RV_DBTR_BIT_MASK(MC6, MATCH) = RV_DBTR_BIT_MASK_VAL(MC6, MATCH, 4),
RV_DBTR_BIT_MASK(MC6, CHAIN) = RV_DBTR_BIT_MASK_VAL(MC6, CHAIN, 1),
RV_DBTR_BIT_MASK(MC6, ACTION) = RV_DBTR_BIT_MASK_VAL(MC6, ACTION, 4),
RV_DBTR_BIT_MASK(MC6, SIZE) = RV_DBTR_BIT_MASK_VAL(MC6, SIZE, 4),
RV_DBTR_BIT_MASK(MC6, TIMING) = RV_DBTR_BIT_MASK_VAL(MC6, TIMING, 1),
RV_DBTR_BIT_MASK(MC6, SELECT) = RV_DBTR_BIT_MASK_VAL(MC6, SELECT, 1),
RV_DBTR_BIT_MASK(MC6, HIT) = RV_DBTR_BIT_MASK_VAL(MC6, HIT, 1),
RV_DBTR_BIT_MASK(MC6, VU) = RV_DBTR_BIT_MASK_VAL(MC6, VU, 1),
RV_DBTR_BIT_MASK(MC6, VS) = RV_DBTR_BIT_MASK_VAL(MC6, VS, 1),
#if __riscv_xlen == 64
RV_DBTR_BIT_MASK(MC6, DMODE) = RV_DBTR_BIT_MASK_VAL(MC6, DMODE, 1),
RV_DBTR_BIT_MASK(MC6, TYPE) = RV_DBTR_BIT_MASK_VAL(MC6, TYPE, 4),
#elif __riscv_xlen == 32
RV_DBTR_BIT_MASK(MC6, DMODE) = RV_DBTR_BIT_MASK_VAL(MC6, DMODE, 1),
RV_DBTR_BIT_MASK(MC6, TYPE) = RV_DBTR_BIT_MASK_VAL(MC6, TYPE, 4),
#else
#error "Unknown riscv xlen"
#endif
};
#define RV_DBTR_SET_TDATA1_TYPE(_t1, _type) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(TDATA1, TYPE); \
_t1 |= (((unsigned long)_type \
<< RV_DBTR_BIT(TDATA1, TYPE)) \
& RV_DBTR_BIT_MASK(TDATA1, TYPE)); \
} while (0)
#define RV_DBTR_SET_MC_TYPE(_t1, _type) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(MC, TYPE); \
_t1 |= (((unsigned long)_type \
<< RV_DBTR_BIT(MC, TYPE)) \
& RV_DBTR_BIT_MASK(MC, TYPE)); \
} while (0)
#define RV_DBTR_SET_MC6_TYPE(_t1, _type) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(MC6, TYPE); \
_t1 |= (((unsigned long)_type \
<< RV_DBTR_BIT(MC6, TYPE)) \
& RV_DBTR_BIT_MASK(MC6, TYPE)); \
} while (0)
#define RV_DBTR_SET_MC_EXEC(_t1) \
SET_DBTR_BIT(_t1, MC, EXEC)
#define RV_DBTR_SET_MC_LOAD(_t1) \
SET_DBTR_BIT(_t1, MC, LOAD)
#define RV_DBTR_SET_MC_STORE(_t1) \
SET_DBTR_BIT(_t1, MC, STORE)
#define RV_DBTR_SET_MC_SIZELO(_t1, _val) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(MC, SIZELO); \
_t1 |= ((_val << RV_DBTR_BIT(MC, SIZELO)) \
& RV_DBTR_BIT_MASK(MC, SIZELO)); \
} while (0)
#define RV_DBTR_SET_MC_SIZEHI(_t1, _val) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(MC, SIZEHI); \
_t1 |= ((_val << RV_DBTR_BIT(MC, SIZEHI)) \
& RV_DBTR_BIT_MASK(MC, SIZEHI)); \
} while (0)
#define RV_DBTR_SET_MC6_EXEC(_t1) \
SET_DBTR_BIT(_t1, MC6, EXEC)
#define RV_DBTR_SET_MC6_LOAD(_t1) \
SET_DBTR_BIT(_t1, MC6, LOAD)
#define RV_DBTR_SET_MC6_STORE(_t1) \
SET_DBTR_BIT(_t1, MC6, STORE)
#define RV_DBTR_SET_MC6_SIZE(_t1, _val) \
do { \
_t1 &= ~RV_DBTR_BIT_MASK(MC6, SIZE); \
_t1 |= ((_val << RV_DBTR_BIT(MC6, SIZE)) \
& RV_DBTR_BIT_MASK(MC6, SIZE)); \
} while (0)
struct arch_hw_breakpoint {
unsigned long addr;
unsigned long type;
unsigned long len;
/* Trigger configuration data */
unsigned long tdata1;
unsigned long tdata2;
unsigned long tdata3;
};
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);
void arch_enable_hw_breakpoint(struct perf_event *bp);
void arch_update_hw_breakpoint(struct perf_event *bp);
void arch_disable_hw_breakpoint(struct perf_event *bp);
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);
void clear_ptrace_hw_breakpoint(struct task_struct *tsk);
void flush_ptrace_hw_breakpoint(struct task_struct *tsk);
#else
int hw_breakpoint_slots(int type)
{
return 0;
}
static inline void clear_ptrace_hw_breakpoint(struct task_struct *tsk)
{
}
static inline void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
{
}
void arch_enable_hw_breakpoint(struct perf_event *bp)
{
}
void arch_update_hw_breakpoint(struct perf_event *bp)
{
}
void arch_disable_hw_breakpoint(struct perf_event *bp)
{
}
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
#endif /* __RISCV_HW_BREAKPOINT_H */