1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * Copyright (C) 2022-2023 Loongson Technology Corporation Limited 4 */ 5#ifndef __ASM_HW_BREAKPOINT_H 6#define __ASM_HW_BREAKPOINT_H 7 8#include <asm/loongarch.h> 9 10#ifdef __KERNEL__ 11 12/* Breakpoint */ 13#define LOONGARCH_BREAKPOINT_EXECUTE (0 << 0) 14 15/* Watchpoints */ 16#define LOONGARCH_BREAKPOINT_LOAD (1 << 0) 17#define LOONGARCH_BREAKPOINT_STORE (1 << 1) 18 19struct arch_hw_breakpoint_ctrl { 20 u32 __reserved : 28, 21 len : 2, 22 type : 2; 23}; 24 25struct arch_hw_breakpoint { 26 u64 address; 27 u64 mask; 28 struct arch_hw_breakpoint_ctrl ctrl; 29}; 30 31/* Lengths */ 32#define LOONGARCH_BREAKPOINT_LEN_1 0b11 33#define LOONGARCH_BREAKPOINT_LEN_2 0b10 34#define LOONGARCH_BREAKPOINT_LEN_4 0b01 35#define LOONGARCH_BREAKPOINT_LEN_8 0b00 36 37/* 38 * Limits. 39 * Changing these will require modifications to the register accessors. 40 */ 41#define LOONGARCH_MAX_BRP 8 42#define LOONGARCH_MAX_WRP 8 43 44/* Virtual debug register bases. */ 45#define CSR_CFG_ADDR 0 46#define CSR_CFG_MASK (CSR_CFG_ADDR + LOONGARCH_MAX_BRP) 47#define CSR_CFG_CTRL (CSR_CFG_MASK + LOONGARCH_MAX_BRP) 48#define CSR_CFG_ASID (CSR_CFG_CTRL + LOONGARCH_MAX_WRP) 49 50/* Debug register names. */ 51#define LOONGARCH_CSR_NAME_ADDR ADDR 52#define LOONGARCH_CSR_NAME_MASK MASK 53#define LOONGARCH_CSR_NAME_CTRL CTRL 54#define LOONGARCH_CSR_NAME_ASID ASID 55 56/* Accessor macros for the debug registers. */ 57#define LOONGARCH_CSR_WATCH_READ(N, REG, T, VAL) \ 58do { \ 59 if (T == 0) \ 60 VAL = csr_read64(LOONGARCH_CSR_##IB##N##REG); \ 61 else \ 62 VAL = csr_read64(LOONGARCH_CSR_##DB##N##REG); \ 63} while (0) 64 65#define LOONGARCH_CSR_WATCH_WRITE(N, REG, T, VAL) \ 66do { \ 67 if (T == 0) \ 68 csr_write64(VAL, LOONGARCH_CSR_##IB##N##REG); \ 69 else \ 70 csr_write64(VAL, LOONGARCH_CSR_##DB##N##REG); \ 71} while (0) 72 73/* Exact number */ 74#define CSR_FWPC_NUM 0x3f 75#define CSR_MWPC_NUM 0x3f 76 77#define CTRL_PLV_ENABLE 0x1e 78 79#define MWPnCFG3_LoadEn 8 80#define MWPnCFG3_StoreEn 9 81 82#define MWPnCFG3_Type_mask 0x3 83#define MWPnCFG3_Size_mask 0x3 84 85static inline u32 encode_ctrl_reg(struct arch_hw_breakpoint_ctrl ctrl) 86{ 87 return (ctrl.len << 10) | (ctrl.type << 8); 88} 89 90static inline void decode_ctrl_reg(u32 reg, struct arch_hw_breakpoint_ctrl *ctrl) 91{ 92 reg >>= 8; 93 ctrl->type = reg & MWPnCFG3_Type_mask; 94 reg >>= 2; 95 ctrl->len = reg & MWPnCFG3_Size_mask; 96} 97 98struct task_struct; 99struct notifier_block; 100struct perf_event; 101struct perf_event_attr; 102 103extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, 104 int *gen_len, int *gen_type, int *offset); 105extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw); 106extern int hw_breakpoint_arch_parse(struct perf_event *bp, 107 const struct perf_event_attr *attr, 108 struct arch_hw_breakpoint *hw); 109extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, 110 unsigned long val, void *data); 111 112extern int arch_install_hw_breakpoint(struct perf_event *bp); 113extern void arch_uninstall_hw_breakpoint(struct perf_event *bp); 114extern int hw_breakpoint_slots(int type); 115extern void hw_breakpoint_pmu_read(struct perf_event *bp); 116 117void breakpoint_handler(struct pt_regs *regs); 118void watchpoint_handler(struct pt_regs *regs); 119 120#ifdef CONFIG_HAVE_HW_BREAKPOINT 121extern void ptrace_hw_copy_thread(struct task_struct *task); 122extern void hw_breakpoint_thread_switch(struct task_struct *next); 123#else 124static inline void ptrace_hw_copy_thread(struct task_struct *task) 125{ 126} 127static inline void hw_breakpoint_thread_switch(struct task_struct *next) 128{ 129} 130#endif 131 132/* Determine number of BRP registers available. */ 133static inline int get_num_brps(void) 134{ 135 return csr_read64(LOONGARCH_CSR_FWPC) & CSR_FWPC_NUM; 136} 137 138/* Determine number of WRP registers available. */ 139static inline int get_num_wrps(void) 140{ 141 return csr_read64(LOONGARCH_CSR_MWPC) & CSR_MWPC_NUM; 142} 143 144#endif /* __KERNEL__ */ 145#endif /* __ASM_BREAKPOINT_H */ 146