1fe89bd2bSVincent Chen // SPDX-License-Identifier: GPL-2.0-only 2fe89bd2bSVincent Chen /* 3fe89bd2bSVincent Chen * Copyright (C) 2020 SiFive 4fe89bd2bSVincent Chen */ 5fe89bd2bSVincent Chen 6fe89bd2bSVincent Chen #include <linux/ptrace.h> 7fe89bd2bSVincent Chen #include <linux/kdebug.h> 8fe89bd2bSVincent Chen #include <linux/bug.h> 9fe89bd2bSVincent Chen #include <linux/kgdb.h> 10fe89bd2bSVincent Chen #include <linux/irqflags.h> 11fe89bd2bSVincent Chen #include <linux/string.h> 12fe89bd2bSVincent Chen #include <asm/cacheflush.h> 13d9657570SVincent Chen #include <asm/gdb_xml.h> 14edde5584SVincent Chen #include <asm/parse_asm.h> 15fe89bd2bSVincent Chen 16fe89bd2bSVincent Chen enum { 17fe89bd2bSVincent Chen NOT_KGDB_BREAK = 0, 18fe89bd2bSVincent Chen KGDB_SW_BREAK, 19fe89bd2bSVincent Chen KGDB_COMPILED_BREAK, 20edde5584SVincent Chen KGDB_SW_SINGLE_STEP 21fe89bd2bSVincent Chen }; 22fe89bd2bSVincent Chen 23edde5584SVincent Chen static unsigned long stepped_address; 24edde5584SVincent Chen static unsigned int stepped_opcode; 25edde5584SVincent Chen 26edde5584SVincent Chen #if __riscv_xlen == 32 27edde5584SVincent Chen /* C.JAL is an RV32C-only instruction */ 28edde5584SVincent Chen DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) 29edde5584SVincent Chen #else 30edde5584SVincent Chen #define is_c_jal_insn(opcode) 0 31edde5584SVincent Chen #endif 32edde5584SVincent Chen DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) 33edde5584SVincent Chen DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) 34edde5584SVincent Chen DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) 35edde5584SVincent Chen DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) 36edde5584SVincent Chen DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) 37edde5584SVincent Chen DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) 38edde5584SVincent Chen DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) 39edde5584SVincent Chen DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) 40edde5584SVincent Chen DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) 41edde5584SVincent Chen DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) 42edde5584SVincent Chen DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) 43edde5584SVincent Chen DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) 44edde5584SVincent Chen DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) 45edde5584SVincent Chen DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) 46edde5584SVincent Chen 47edde5584SVincent Chen int decode_register_index(unsigned long opcode, int offset) 48edde5584SVincent Chen { 49edde5584SVincent Chen return (opcode >> offset) & 0x1F; 50edde5584SVincent Chen } 51edde5584SVincent Chen 52edde5584SVincent Chen int decode_register_index_short(unsigned long opcode, int offset) 53edde5584SVincent Chen { 54edde5584SVincent Chen return ((opcode >> offset) & 0x7) + 8; 55edde5584SVincent Chen } 56edde5584SVincent Chen 57edde5584SVincent Chen /* Calculate the new address for after a step */ 58edde5584SVincent Chen int get_step_address(struct pt_regs *regs, unsigned long *next_addr) 59edde5584SVincent Chen { 60edde5584SVincent Chen unsigned long pc = regs->epc; 61edde5584SVincent Chen unsigned long *regs_ptr = (unsigned long *)regs; 62edde5584SVincent Chen unsigned int rs1_num, rs2_num; 63edde5584SVincent Chen int op_code; 64edde5584SVincent Chen 65edde5584SVincent Chen if (probe_kernel_address((void *)pc, op_code)) 66edde5584SVincent Chen return -EINVAL; 67edde5584SVincent Chen if ((op_code & __INSN_LENGTH_MASK) != __INSN_LENGTH_GE_32) { 68edde5584SVincent Chen if (is_c_jalr_insn(op_code) || is_c_jr_insn(op_code)) { 69edde5584SVincent Chen rs1_num = decode_register_index(op_code, RVC_C2_RS1_OPOFF); 70edde5584SVincent Chen *next_addr = regs_ptr[rs1_num]; 71edde5584SVincent Chen } else if (is_c_j_insn(op_code) || is_c_jal_insn(op_code)) { 72edde5584SVincent Chen *next_addr = EXTRACT_RVC_J_IMM(op_code) + pc; 73edde5584SVincent Chen } else if (is_c_beqz_insn(op_code)) { 74edde5584SVincent Chen rs1_num = decode_register_index_short(op_code, 75edde5584SVincent Chen RVC_C1_RS1_OPOFF); 76edde5584SVincent Chen if (!rs1_num || regs_ptr[rs1_num] == 0) 77edde5584SVincent Chen *next_addr = EXTRACT_RVC_B_IMM(op_code) + pc; 78edde5584SVincent Chen else 79edde5584SVincent Chen *next_addr = pc + 2; 80edde5584SVincent Chen } else if (is_c_bnez_insn(op_code)) { 81edde5584SVincent Chen rs1_num = 82edde5584SVincent Chen decode_register_index_short(op_code, RVC_C1_RS1_OPOFF); 83edde5584SVincent Chen if (rs1_num && regs_ptr[rs1_num] != 0) 84edde5584SVincent Chen *next_addr = EXTRACT_RVC_B_IMM(op_code) + pc; 85edde5584SVincent Chen else 86edde5584SVincent Chen *next_addr = pc + 2; 87edde5584SVincent Chen } else { 88edde5584SVincent Chen *next_addr = pc + 2; 89edde5584SVincent Chen } 90edde5584SVincent Chen } else { 91edde5584SVincent Chen if ((op_code & __INSN_OPCODE_MASK) == __INSN_BRANCH_OPCODE) { 92edde5584SVincent Chen bool result = false; 93edde5584SVincent Chen long imm = EXTRACT_BTYPE_IMM(op_code); 94edde5584SVincent Chen unsigned long rs1_val = 0, rs2_val = 0; 95edde5584SVincent Chen 96edde5584SVincent Chen rs1_num = decode_register_index(op_code, RVG_RS1_OPOFF); 97edde5584SVincent Chen rs2_num = decode_register_index(op_code, RVG_RS2_OPOFF); 98edde5584SVincent Chen if (rs1_num) 99edde5584SVincent Chen rs1_val = regs_ptr[rs1_num]; 100edde5584SVincent Chen if (rs2_num) 101edde5584SVincent Chen rs2_val = regs_ptr[rs2_num]; 102edde5584SVincent Chen 103edde5584SVincent Chen if (is_beq_insn(op_code)) 104edde5584SVincent Chen result = (rs1_val == rs2_val) ? true : false; 105edde5584SVincent Chen else if (is_bne_insn(op_code)) 106edde5584SVincent Chen result = (rs1_val != rs2_val) ? true : false; 107edde5584SVincent Chen else if (is_blt_insn(op_code)) 108edde5584SVincent Chen result = 109edde5584SVincent Chen ((long)rs1_val < 110edde5584SVincent Chen (long)rs2_val) ? true : false; 111edde5584SVincent Chen else if (is_bge_insn(op_code)) 112edde5584SVincent Chen result = 113edde5584SVincent Chen ((long)rs1_val >= 114edde5584SVincent Chen (long)rs2_val) ? true : false; 115edde5584SVincent Chen else if (is_bltu_insn(op_code)) 116edde5584SVincent Chen result = (rs1_val < rs2_val) ? true : false; 117edde5584SVincent Chen else if (is_bgeu_insn(op_code)) 118edde5584SVincent Chen result = (rs1_val >= rs2_val) ? true : false; 119edde5584SVincent Chen if (result) 120edde5584SVincent Chen *next_addr = imm + pc; 121edde5584SVincent Chen else 122edde5584SVincent Chen *next_addr = pc + 4; 123edde5584SVincent Chen } else if (is_jal_insn(op_code)) { 124edde5584SVincent Chen *next_addr = EXTRACT_JTYPE_IMM(op_code) + pc; 125edde5584SVincent Chen } else if (is_jalr_insn(op_code)) { 126edde5584SVincent Chen rs1_num = decode_register_index(op_code, RVG_RS1_OPOFF); 127edde5584SVincent Chen if (rs1_num) 128edde5584SVincent Chen *next_addr = ((unsigned long *)regs)[rs1_num]; 129edde5584SVincent Chen *next_addr += EXTRACT_ITYPE_IMM(op_code); 130edde5584SVincent Chen } else if (is_sret_insn(op_code)) { 131edde5584SVincent Chen *next_addr = pc; 132edde5584SVincent Chen } else { 133edde5584SVincent Chen *next_addr = pc + 4; 134edde5584SVincent Chen } 135edde5584SVincent Chen } 136edde5584SVincent Chen return 0; 137edde5584SVincent Chen } 138edde5584SVincent Chen 139edde5584SVincent Chen int do_single_step(struct pt_regs *regs) 140edde5584SVincent Chen { 141edde5584SVincent Chen /* Determine where the target instruction will send us to */ 142edde5584SVincent Chen unsigned long addr = 0; 143edde5584SVincent Chen int error = get_step_address(regs, &addr); 144edde5584SVincent Chen 145edde5584SVincent Chen if (error) 146edde5584SVincent Chen return error; 147edde5584SVincent Chen 148edde5584SVincent Chen /* Store the op code in the stepped address */ 149edde5584SVincent Chen error = probe_kernel_address((void *)addr, stepped_opcode); 150edde5584SVincent Chen if (error) 151edde5584SVincent Chen return error; 152edde5584SVincent Chen 153edde5584SVincent Chen stepped_address = addr; 154edde5584SVincent Chen 155edde5584SVincent Chen /* Replace the op code with the break instruction */ 156fe557319SChristoph Hellwig error = copy_to_kernel_nofault((void *)stepped_address, 157edde5584SVincent Chen arch_kgdb_ops.gdb_bpt_instr, 158edde5584SVincent Chen BREAK_INSTR_SIZE); 159edde5584SVincent Chen /* Flush and return */ 160edde5584SVincent Chen if (!error) { 161edde5584SVincent Chen flush_icache_range(addr, addr + BREAK_INSTR_SIZE); 162edde5584SVincent Chen kgdb_single_step = 1; 163edde5584SVincent Chen atomic_set(&kgdb_cpu_doing_single_step, 164edde5584SVincent Chen raw_smp_processor_id()); 165edde5584SVincent Chen } else { 166edde5584SVincent Chen stepped_address = 0; 167edde5584SVincent Chen stepped_opcode = 0; 168edde5584SVincent Chen } 169edde5584SVincent Chen return error; 170edde5584SVincent Chen } 171edde5584SVincent Chen 172edde5584SVincent Chen /* Undo a single step */ 173edde5584SVincent Chen static void undo_single_step(struct pt_regs *regs) 174edde5584SVincent Chen { 175edde5584SVincent Chen if (stepped_opcode != 0) { 176fe557319SChristoph Hellwig copy_to_kernel_nofault((void *)stepped_address, 177edde5584SVincent Chen (void *)&stepped_opcode, BREAK_INSTR_SIZE); 178edde5584SVincent Chen flush_icache_range(stepped_address, 179edde5584SVincent Chen stepped_address + BREAK_INSTR_SIZE); 180edde5584SVincent Chen } 181edde5584SVincent Chen stepped_address = 0; 182edde5584SVincent Chen stepped_opcode = 0; 183edde5584SVincent Chen kgdb_single_step = 0; 184edde5584SVincent Chen atomic_set(&kgdb_cpu_doing_single_step, -1); 185edde5584SVincent Chen } 186edde5584SVincent Chen 187fe89bd2bSVincent Chen struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { 188fe89bd2bSVincent Chen {DBG_REG_ZERO, GDB_SIZEOF_REG, -1}, 189fe89bd2bSVincent Chen {DBG_REG_RA, GDB_SIZEOF_REG, offsetof(struct pt_regs, ra)}, 190fe89bd2bSVincent Chen {DBG_REG_SP, GDB_SIZEOF_REG, offsetof(struct pt_regs, sp)}, 191fe89bd2bSVincent Chen {DBG_REG_GP, GDB_SIZEOF_REG, offsetof(struct pt_regs, gp)}, 192fe89bd2bSVincent Chen {DBG_REG_TP, GDB_SIZEOF_REG, offsetof(struct pt_regs, tp)}, 193fe89bd2bSVincent Chen {DBG_REG_T0, GDB_SIZEOF_REG, offsetof(struct pt_regs, t0)}, 194fe89bd2bSVincent Chen {DBG_REG_T1, GDB_SIZEOF_REG, offsetof(struct pt_regs, t1)}, 195fe89bd2bSVincent Chen {DBG_REG_T2, GDB_SIZEOF_REG, offsetof(struct pt_regs, t2)}, 196fe89bd2bSVincent Chen {DBG_REG_FP, GDB_SIZEOF_REG, offsetof(struct pt_regs, s0)}, 197fe89bd2bSVincent Chen {DBG_REG_S1, GDB_SIZEOF_REG, offsetof(struct pt_regs, a1)}, 198fe89bd2bSVincent Chen {DBG_REG_A0, GDB_SIZEOF_REG, offsetof(struct pt_regs, a0)}, 199fe89bd2bSVincent Chen {DBG_REG_A1, GDB_SIZEOF_REG, offsetof(struct pt_regs, a1)}, 200fe89bd2bSVincent Chen {DBG_REG_A2, GDB_SIZEOF_REG, offsetof(struct pt_regs, a2)}, 201fe89bd2bSVincent Chen {DBG_REG_A3, GDB_SIZEOF_REG, offsetof(struct pt_regs, a3)}, 202fe89bd2bSVincent Chen {DBG_REG_A4, GDB_SIZEOF_REG, offsetof(struct pt_regs, a4)}, 203fe89bd2bSVincent Chen {DBG_REG_A5, GDB_SIZEOF_REG, offsetof(struct pt_regs, a5)}, 204fe89bd2bSVincent Chen {DBG_REG_A6, GDB_SIZEOF_REG, offsetof(struct pt_regs, a6)}, 205fe89bd2bSVincent Chen {DBG_REG_A7, GDB_SIZEOF_REG, offsetof(struct pt_regs, a7)}, 206fe89bd2bSVincent Chen {DBG_REG_S2, GDB_SIZEOF_REG, offsetof(struct pt_regs, s2)}, 207fe89bd2bSVincent Chen {DBG_REG_S3, GDB_SIZEOF_REG, offsetof(struct pt_regs, s3)}, 208fe89bd2bSVincent Chen {DBG_REG_S4, GDB_SIZEOF_REG, offsetof(struct pt_regs, s4)}, 209fe89bd2bSVincent Chen {DBG_REG_S5, GDB_SIZEOF_REG, offsetof(struct pt_regs, s5)}, 210fe89bd2bSVincent Chen {DBG_REG_S6, GDB_SIZEOF_REG, offsetof(struct pt_regs, s6)}, 211fe89bd2bSVincent Chen {DBG_REG_S7, GDB_SIZEOF_REG, offsetof(struct pt_regs, s7)}, 212fe89bd2bSVincent Chen {DBG_REG_S8, GDB_SIZEOF_REG, offsetof(struct pt_regs, s8)}, 213fe89bd2bSVincent Chen {DBG_REG_S9, GDB_SIZEOF_REG, offsetof(struct pt_regs, s9)}, 214fe89bd2bSVincent Chen {DBG_REG_S10, GDB_SIZEOF_REG, offsetof(struct pt_regs, s10)}, 215fe89bd2bSVincent Chen {DBG_REG_S11, GDB_SIZEOF_REG, offsetof(struct pt_regs, s11)}, 216fe89bd2bSVincent Chen {DBG_REG_T3, GDB_SIZEOF_REG, offsetof(struct pt_regs, t3)}, 217fe89bd2bSVincent Chen {DBG_REG_T4, GDB_SIZEOF_REG, offsetof(struct pt_regs, t4)}, 218fe89bd2bSVincent Chen {DBG_REG_T5, GDB_SIZEOF_REG, offsetof(struct pt_regs, t5)}, 219fe89bd2bSVincent Chen {DBG_REG_T6, GDB_SIZEOF_REG, offsetof(struct pt_regs, t6)}, 220fe89bd2bSVincent Chen {DBG_REG_EPC, GDB_SIZEOF_REG, offsetof(struct pt_regs, epc)}, 221d9657570SVincent Chen {DBG_REG_STATUS, GDB_SIZEOF_REG, offsetof(struct pt_regs, status)}, 222d9657570SVincent Chen {DBG_REG_BADADDR, GDB_SIZEOF_REG, offsetof(struct pt_regs, badaddr)}, 223d9657570SVincent Chen {DBG_REG_CAUSE, GDB_SIZEOF_REG, offsetof(struct pt_regs, cause)}, 224fe89bd2bSVincent Chen }; 225fe89bd2bSVincent Chen 226fe89bd2bSVincent Chen char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) 227fe89bd2bSVincent Chen { 228fe89bd2bSVincent Chen if (regno >= DBG_MAX_REG_NUM || regno < 0) 229fe89bd2bSVincent Chen return NULL; 230fe89bd2bSVincent Chen 231fe89bd2bSVincent Chen if (dbg_reg_def[regno].offset != -1) 232fe89bd2bSVincent Chen memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, 233fe89bd2bSVincent Chen dbg_reg_def[regno].size); 234fe89bd2bSVincent Chen else 235fe89bd2bSVincent Chen memset(mem, 0, dbg_reg_def[regno].size); 236fe89bd2bSVincent Chen return dbg_reg_def[regno].name; 237fe89bd2bSVincent Chen } 238fe89bd2bSVincent Chen 239fe89bd2bSVincent Chen int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) 240fe89bd2bSVincent Chen { 241fe89bd2bSVincent Chen if (regno >= DBG_MAX_REG_NUM || regno < 0) 242fe89bd2bSVincent Chen return -EINVAL; 243fe89bd2bSVincent Chen 244fe89bd2bSVincent Chen if (dbg_reg_def[regno].offset != -1) 245fe89bd2bSVincent Chen memcpy((void *)regs + dbg_reg_def[regno].offset, mem, 246fe89bd2bSVincent Chen dbg_reg_def[regno].size); 247fe89bd2bSVincent Chen return 0; 248fe89bd2bSVincent Chen } 249fe89bd2bSVincent Chen 250fe89bd2bSVincent Chen void 251fe89bd2bSVincent Chen sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) 252fe89bd2bSVincent Chen { 253fe89bd2bSVincent Chen /* Initialize to zero */ 254fe89bd2bSVincent Chen memset((char *)gdb_regs, 0, NUMREGBYTES); 255fe89bd2bSVincent Chen 256fe89bd2bSVincent Chen gdb_regs[DBG_REG_SP_OFF] = task->thread.sp; 257fe89bd2bSVincent Chen gdb_regs[DBG_REG_FP_OFF] = task->thread.s[0]; 258fe89bd2bSVincent Chen gdb_regs[DBG_REG_S1_OFF] = task->thread.s[1]; 259fe89bd2bSVincent Chen gdb_regs[DBG_REG_S2_OFF] = task->thread.s[2]; 260fe89bd2bSVincent Chen gdb_regs[DBG_REG_S3_OFF] = task->thread.s[3]; 261fe89bd2bSVincent Chen gdb_regs[DBG_REG_S4_OFF] = task->thread.s[4]; 262fe89bd2bSVincent Chen gdb_regs[DBG_REG_S5_OFF] = task->thread.s[5]; 263fe89bd2bSVincent Chen gdb_regs[DBG_REG_S6_OFF] = task->thread.s[6]; 264fe89bd2bSVincent Chen gdb_regs[DBG_REG_S7_OFF] = task->thread.s[7]; 265fe89bd2bSVincent Chen gdb_regs[DBG_REG_S8_OFF] = task->thread.s[8]; 266fe89bd2bSVincent Chen gdb_regs[DBG_REG_S9_OFF] = task->thread.s[10]; 267fe89bd2bSVincent Chen gdb_regs[DBG_REG_S10_OFF] = task->thread.s[11]; 268fe89bd2bSVincent Chen gdb_regs[DBG_REG_EPC_OFF] = task->thread.ra; 269fe89bd2bSVincent Chen } 270fe89bd2bSVincent Chen 271fe89bd2bSVincent Chen void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) 272fe89bd2bSVincent Chen { 273fe89bd2bSVincent Chen regs->epc = pc; 274fe89bd2bSVincent Chen } 275fe89bd2bSVincent Chen 276d9657570SVincent Chen void kgdb_arch_handle_qxfer_pkt(char *remcom_in_buffer, 277d9657570SVincent Chen char *remcom_out_buffer) 278d9657570SVincent Chen { 279d9657570SVincent Chen if (!strncmp(remcom_in_buffer, gdb_xfer_read_target, 280d9657570SVincent Chen sizeof(gdb_xfer_read_target))) 281d9657570SVincent Chen strcpy(remcom_out_buffer, riscv_gdb_stub_target_desc); 282d9657570SVincent Chen else if (!strncmp(remcom_in_buffer, gdb_xfer_read_cpuxml, 283d9657570SVincent Chen sizeof(gdb_xfer_read_cpuxml))) 284d9657570SVincent Chen strcpy(remcom_out_buffer, riscv_gdb_stub_cpuxml); 285d9657570SVincent Chen } 286d9657570SVincent Chen 287fe89bd2bSVincent Chen static inline void kgdb_arch_update_addr(struct pt_regs *regs, 288fe89bd2bSVincent Chen char *remcom_in_buffer) 289fe89bd2bSVincent Chen { 290fe89bd2bSVincent Chen unsigned long addr; 291fe89bd2bSVincent Chen char *ptr; 292fe89bd2bSVincent Chen 293fe89bd2bSVincent Chen ptr = &remcom_in_buffer[1]; 294fe89bd2bSVincent Chen if (kgdb_hex2long(&ptr, &addr)) 295fe89bd2bSVincent Chen regs->epc = addr; 296fe89bd2bSVincent Chen } 297fe89bd2bSVincent Chen 298fe89bd2bSVincent Chen int kgdb_arch_handle_exception(int vector, int signo, int err_code, 299fe89bd2bSVincent Chen char *remcom_in_buffer, char *remcom_out_buffer, 300fe89bd2bSVincent Chen struct pt_regs *regs) 301fe89bd2bSVincent Chen { 302fe89bd2bSVincent Chen int err = 0; 303fe89bd2bSVincent Chen 304edde5584SVincent Chen undo_single_step(regs); 305edde5584SVincent Chen 306fe89bd2bSVincent Chen switch (remcom_in_buffer[0]) { 307fe89bd2bSVincent Chen case 'c': 308fe89bd2bSVincent Chen case 'D': 309fe89bd2bSVincent Chen case 'k': 310fe89bd2bSVincent Chen if (remcom_in_buffer[0] == 'c') 311fe89bd2bSVincent Chen kgdb_arch_update_addr(regs, remcom_in_buffer); 312fe89bd2bSVincent Chen break; 313edde5584SVincent Chen case 's': 314edde5584SVincent Chen kgdb_arch_update_addr(regs, remcom_in_buffer); 315edde5584SVincent Chen err = do_single_step(regs); 316edde5584SVincent Chen break; 317fe89bd2bSVincent Chen default: 318fe89bd2bSVincent Chen err = -1; 319fe89bd2bSVincent Chen } 320fe89bd2bSVincent Chen return err; 321fe89bd2bSVincent Chen } 322fe89bd2bSVincent Chen 323fe89bd2bSVincent Chen int kgdb_riscv_kgdbbreak(unsigned long addr) 324fe89bd2bSVincent Chen { 325edde5584SVincent Chen if (stepped_address == addr) 326edde5584SVincent Chen return KGDB_SW_SINGLE_STEP; 327fe89bd2bSVincent Chen if (atomic_read(&kgdb_setting_breakpoint)) 328fe89bd2bSVincent Chen if (addr == (unsigned long)&kgdb_compiled_break) 329fe89bd2bSVincent Chen return KGDB_COMPILED_BREAK; 330fe89bd2bSVincent Chen 331fe89bd2bSVincent Chen return kgdb_has_hit_break(addr); 332fe89bd2bSVincent Chen } 333fe89bd2bSVincent Chen 334fe89bd2bSVincent Chen static int kgdb_riscv_notify(struct notifier_block *self, unsigned long cmd, 335fe89bd2bSVincent Chen void *ptr) 336fe89bd2bSVincent Chen { 337fe89bd2bSVincent Chen struct die_args *args = (struct die_args *)ptr; 338fe89bd2bSVincent Chen struct pt_regs *regs = args->regs; 339fe89bd2bSVincent Chen unsigned long flags; 340fe89bd2bSVincent Chen int type; 341fe89bd2bSVincent Chen 342fe89bd2bSVincent Chen if (user_mode(regs)) 343fe89bd2bSVincent Chen return NOTIFY_DONE; 344fe89bd2bSVincent Chen 345fe89bd2bSVincent Chen type = kgdb_riscv_kgdbbreak(regs->epc); 346fe89bd2bSVincent Chen if (type == NOT_KGDB_BREAK && cmd == DIE_TRAP) 347fe89bd2bSVincent Chen return NOTIFY_DONE; 348fe89bd2bSVincent Chen 349fe89bd2bSVincent Chen local_irq_save(flags); 350edde5584SVincent Chen 351edde5584SVincent Chen if (kgdb_handle_exception(type == KGDB_SW_SINGLE_STEP ? 0 : 1, 352edde5584SVincent Chen args->signr, cmd, regs)) 353fe89bd2bSVincent Chen return NOTIFY_DONE; 354fe89bd2bSVincent Chen 355fe89bd2bSVincent Chen if (type == KGDB_COMPILED_BREAK) 356fe89bd2bSVincent Chen regs->epc += 4; 357fe89bd2bSVincent Chen 358fe89bd2bSVincent Chen local_irq_restore(flags); 359fe89bd2bSVincent Chen 360fe89bd2bSVincent Chen return NOTIFY_STOP; 361fe89bd2bSVincent Chen } 362fe89bd2bSVincent Chen 363fe89bd2bSVincent Chen static struct notifier_block kgdb_notifier = { 364fe89bd2bSVincent Chen .notifier_call = kgdb_riscv_notify, 365fe89bd2bSVincent Chen }; 366fe89bd2bSVincent Chen 367fe89bd2bSVincent Chen int kgdb_arch_init(void) 368fe89bd2bSVincent Chen { 369fe89bd2bSVincent Chen register_die_notifier(&kgdb_notifier); 370fe89bd2bSVincent Chen 371fe89bd2bSVincent Chen return 0; 372fe89bd2bSVincent Chen } 373fe89bd2bSVincent Chen 374fe89bd2bSVincent Chen void kgdb_arch_exit(void) 375fe89bd2bSVincent Chen { 376fe89bd2bSVincent Chen unregister_die_notifier(&kgdb_notifier); 377fe89bd2bSVincent Chen } 378fe89bd2bSVincent Chen 379fe89bd2bSVincent Chen /* 380fe89bd2bSVincent Chen * Global data 381fe89bd2bSVincent Chen */ 382fe89bd2bSVincent Chen #ifdef CONFIG_RISCV_ISA_C 383fe89bd2bSVincent Chen const struct kgdb_arch arch_kgdb_ops = { 384fe89bd2bSVincent Chen .gdb_bpt_instr = {0x02, 0x90}, /* c.ebreak */ 385fe89bd2bSVincent Chen }; 386fe89bd2bSVincent Chen #else 387fe89bd2bSVincent Chen const struct kgdb_arch arch_kgdb_ops = { 388fe89bd2bSVincent Chen .gdb_bpt_instr = {0x73, 0x00, 0x10, 0x00}, /* ebreak */ 389fe89bd2bSVincent Chen }; 390fe89bd2bSVincent Chen #endif 391