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 26f7fc7528SVincent Chen static int decode_register_index(unsigned long opcode, int offset) 27edde5584SVincent Chen { 28edde5584SVincent Chen return (opcode >> offset) & 0x1F; 29edde5584SVincent Chen } 30edde5584SVincent Chen 31f7fc7528SVincent Chen static int decode_register_index_short(unsigned long opcode, int offset) 32edde5584SVincent Chen { 33edde5584SVincent Chen return ((opcode >> offset) & 0x7) + 8; 34edde5584SVincent Chen } 35edde5584SVincent Chen 36edde5584SVincent Chen /* Calculate the new address for after a step */ 37f7fc7528SVincent Chen static int get_step_address(struct pt_regs *regs, unsigned long *next_addr) 38edde5584SVincent Chen { 39edde5584SVincent Chen unsigned long pc = regs->epc; 40edde5584SVincent Chen unsigned long *regs_ptr = (unsigned long *)regs; 41edde5584SVincent Chen unsigned int rs1_num, rs2_num; 42edde5584SVincent Chen int op_code; 43edde5584SVincent Chen 4425f12ae4SChristoph Hellwig if (get_kernel_nofault(op_code, (void *)pc)) 45edde5584SVincent Chen return -EINVAL; 46edde5584SVincent Chen if ((op_code & __INSN_LENGTH_MASK) != __INSN_LENGTH_GE_32) { 47*ec5f9087SHeiko Stuebner if (riscv_insn_is_c_jalr(op_code) || 48*ec5f9087SHeiko Stuebner riscv_insn_is_c_jr(op_code)) { 49edde5584SVincent Chen rs1_num = decode_register_index(op_code, RVC_C2_RS1_OPOFF); 50edde5584SVincent Chen *next_addr = regs_ptr[rs1_num]; 51*ec5f9087SHeiko Stuebner } else if (riscv_insn_is_c_j(op_code) || 52*ec5f9087SHeiko Stuebner riscv_insn_is_c_jal(op_code)) { 53bf0cc402SHeiko Stuebner *next_addr = RVC_EXTRACT_JTYPE_IMM(op_code) + pc; 54*ec5f9087SHeiko Stuebner } else if (riscv_insn_is_c_beqz(op_code)) { 55edde5584SVincent Chen rs1_num = decode_register_index_short(op_code, 56edde5584SVincent Chen RVC_C1_RS1_OPOFF); 57edde5584SVincent Chen if (!rs1_num || regs_ptr[rs1_num] == 0) 58bf0cc402SHeiko Stuebner *next_addr = RVC_EXTRACT_BTYPE_IMM(op_code) + pc; 59edde5584SVincent Chen else 60edde5584SVincent Chen *next_addr = pc + 2; 61*ec5f9087SHeiko Stuebner } else if (riscv_insn_is_c_bnez(op_code)) { 62edde5584SVincent Chen rs1_num = 63edde5584SVincent Chen decode_register_index_short(op_code, RVC_C1_RS1_OPOFF); 64edde5584SVincent Chen if (rs1_num && regs_ptr[rs1_num] != 0) 65bf0cc402SHeiko Stuebner *next_addr = RVC_EXTRACT_BTYPE_IMM(op_code) + pc; 66edde5584SVincent Chen else 67edde5584SVincent Chen *next_addr = pc + 2; 68edde5584SVincent Chen } else { 69edde5584SVincent Chen *next_addr = pc + 2; 70edde5584SVincent Chen } 71edde5584SVincent Chen } else { 72edde5584SVincent Chen if ((op_code & __INSN_OPCODE_MASK) == __INSN_BRANCH_OPCODE) { 73edde5584SVincent Chen bool result = false; 74bf0cc402SHeiko Stuebner long imm = RV_EXTRACT_BTYPE_IMM(op_code); 75edde5584SVincent Chen unsigned long rs1_val = 0, rs2_val = 0; 76edde5584SVincent Chen 77edde5584SVincent Chen rs1_num = decode_register_index(op_code, RVG_RS1_OPOFF); 78edde5584SVincent Chen rs2_num = decode_register_index(op_code, RVG_RS2_OPOFF); 79edde5584SVincent Chen if (rs1_num) 80edde5584SVincent Chen rs1_val = regs_ptr[rs1_num]; 81edde5584SVincent Chen if (rs2_num) 82edde5584SVincent Chen rs2_val = regs_ptr[rs2_num]; 83edde5584SVincent Chen 84*ec5f9087SHeiko Stuebner if (riscv_insn_is_beq(op_code)) 85edde5584SVincent Chen result = (rs1_val == rs2_val) ? true : false; 86*ec5f9087SHeiko Stuebner else if (riscv_insn_is_bne(op_code)) 87edde5584SVincent Chen result = (rs1_val != rs2_val) ? true : false; 88*ec5f9087SHeiko Stuebner else if (riscv_insn_is_blt(op_code)) 89edde5584SVincent Chen result = 90edde5584SVincent Chen ((long)rs1_val < 91edde5584SVincent Chen (long)rs2_val) ? true : false; 92*ec5f9087SHeiko Stuebner else if (riscv_insn_is_bge(op_code)) 93edde5584SVincent Chen result = 94edde5584SVincent Chen ((long)rs1_val >= 95edde5584SVincent Chen (long)rs2_val) ? true : false; 96*ec5f9087SHeiko Stuebner else if (riscv_insn_is_bltu(op_code)) 97edde5584SVincent Chen result = (rs1_val < rs2_val) ? true : false; 98*ec5f9087SHeiko Stuebner else if (riscv_insn_is_bgeu(op_code)) 99edde5584SVincent Chen result = (rs1_val >= rs2_val) ? true : false; 100edde5584SVincent Chen if (result) 101edde5584SVincent Chen *next_addr = imm + pc; 102edde5584SVincent Chen else 103edde5584SVincent Chen *next_addr = pc + 4; 104*ec5f9087SHeiko Stuebner } else if (riscv_insn_is_jal(op_code)) { 105bf0cc402SHeiko Stuebner *next_addr = RV_EXTRACT_JTYPE_IMM(op_code) + pc; 106*ec5f9087SHeiko Stuebner } else if (riscv_insn_is_jalr(op_code)) { 107edde5584SVincent Chen rs1_num = decode_register_index(op_code, RVG_RS1_OPOFF); 108edde5584SVincent Chen if (rs1_num) 109edde5584SVincent Chen *next_addr = ((unsigned long *)regs)[rs1_num]; 110bf0cc402SHeiko Stuebner *next_addr += RV_EXTRACT_ITYPE_IMM(op_code); 111*ec5f9087SHeiko Stuebner } else if (riscv_insn_is_sret(op_code)) { 112edde5584SVincent Chen *next_addr = pc; 113edde5584SVincent Chen } else { 114edde5584SVincent Chen *next_addr = pc + 4; 115edde5584SVincent Chen } 116edde5584SVincent Chen } 117edde5584SVincent Chen return 0; 118edde5584SVincent Chen } 119edde5584SVincent Chen 120f7fc7528SVincent Chen static int do_single_step(struct pt_regs *regs) 121edde5584SVincent Chen { 122edde5584SVincent Chen /* Determine where the target instruction will send us to */ 123edde5584SVincent Chen unsigned long addr = 0; 124edde5584SVincent Chen int error = get_step_address(regs, &addr); 125edde5584SVincent Chen 126edde5584SVincent Chen if (error) 127edde5584SVincent Chen return error; 128edde5584SVincent Chen 129edde5584SVincent Chen /* Store the op code in the stepped address */ 13025f12ae4SChristoph Hellwig error = get_kernel_nofault(stepped_opcode, (void *)addr); 131edde5584SVincent Chen if (error) 132edde5584SVincent Chen return error; 133edde5584SVincent Chen 134edde5584SVincent Chen stepped_address = addr; 135edde5584SVincent Chen 136edde5584SVincent Chen /* Replace the op code with the break instruction */ 137fe557319SChristoph Hellwig error = copy_to_kernel_nofault((void *)stepped_address, 138edde5584SVincent Chen arch_kgdb_ops.gdb_bpt_instr, 139edde5584SVincent Chen BREAK_INSTR_SIZE); 140edde5584SVincent Chen /* Flush and return */ 141edde5584SVincent Chen if (!error) { 142edde5584SVincent Chen flush_icache_range(addr, addr + BREAK_INSTR_SIZE); 143edde5584SVincent Chen kgdb_single_step = 1; 144edde5584SVincent Chen atomic_set(&kgdb_cpu_doing_single_step, 145edde5584SVincent Chen raw_smp_processor_id()); 146edde5584SVincent Chen } else { 147edde5584SVincent Chen stepped_address = 0; 148edde5584SVincent Chen stepped_opcode = 0; 149edde5584SVincent Chen } 150edde5584SVincent Chen return error; 151edde5584SVincent Chen } 152edde5584SVincent Chen 153edde5584SVincent Chen /* Undo a single step */ 154edde5584SVincent Chen static void undo_single_step(struct pt_regs *regs) 155edde5584SVincent Chen { 156edde5584SVincent Chen if (stepped_opcode != 0) { 157fe557319SChristoph Hellwig copy_to_kernel_nofault((void *)stepped_address, 158edde5584SVincent Chen (void *)&stepped_opcode, BREAK_INSTR_SIZE); 159edde5584SVincent Chen flush_icache_range(stepped_address, 160edde5584SVincent Chen stepped_address + BREAK_INSTR_SIZE); 161edde5584SVincent Chen } 162edde5584SVincent Chen stepped_address = 0; 163edde5584SVincent Chen stepped_opcode = 0; 164edde5584SVincent Chen kgdb_single_step = 0; 165edde5584SVincent Chen atomic_set(&kgdb_cpu_doing_single_step, -1); 166edde5584SVincent Chen } 167edde5584SVincent Chen 168fe89bd2bSVincent Chen struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { 169fe89bd2bSVincent Chen {DBG_REG_ZERO, GDB_SIZEOF_REG, -1}, 170fe89bd2bSVincent Chen {DBG_REG_RA, GDB_SIZEOF_REG, offsetof(struct pt_regs, ra)}, 171fe89bd2bSVincent Chen {DBG_REG_SP, GDB_SIZEOF_REG, offsetof(struct pt_regs, sp)}, 172fe89bd2bSVincent Chen {DBG_REG_GP, GDB_SIZEOF_REG, offsetof(struct pt_regs, gp)}, 173fe89bd2bSVincent Chen {DBG_REG_TP, GDB_SIZEOF_REG, offsetof(struct pt_regs, tp)}, 174fe89bd2bSVincent Chen {DBG_REG_T0, GDB_SIZEOF_REG, offsetof(struct pt_regs, t0)}, 175fe89bd2bSVincent Chen {DBG_REG_T1, GDB_SIZEOF_REG, offsetof(struct pt_regs, t1)}, 176fe89bd2bSVincent Chen {DBG_REG_T2, GDB_SIZEOF_REG, offsetof(struct pt_regs, t2)}, 177fe89bd2bSVincent Chen {DBG_REG_FP, GDB_SIZEOF_REG, offsetof(struct pt_regs, s0)}, 178fe89bd2bSVincent Chen {DBG_REG_S1, GDB_SIZEOF_REG, offsetof(struct pt_regs, a1)}, 179fe89bd2bSVincent Chen {DBG_REG_A0, GDB_SIZEOF_REG, offsetof(struct pt_regs, a0)}, 180fe89bd2bSVincent Chen {DBG_REG_A1, GDB_SIZEOF_REG, offsetof(struct pt_regs, a1)}, 181fe89bd2bSVincent Chen {DBG_REG_A2, GDB_SIZEOF_REG, offsetof(struct pt_regs, a2)}, 182fe89bd2bSVincent Chen {DBG_REG_A3, GDB_SIZEOF_REG, offsetof(struct pt_regs, a3)}, 183fe89bd2bSVincent Chen {DBG_REG_A4, GDB_SIZEOF_REG, offsetof(struct pt_regs, a4)}, 184fe89bd2bSVincent Chen {DBG_REG_A5, GDB_SIZEOF_REG, offsetof(struct pt_regs, a5)}, 185fe89bd2bSVincent Chen {DBG_REG_A6, GDB_SIZEOF_REG, offsetof(struct pt_regs, a6)}, 186fe89bd2bSVincent Chen {DBG_REG_A7, GDB_SIZEOF_REG, offsetof(struct pt_regs, a7)}, 187fe89bd2bSVincent Chen {DBG_REG_S2, GDB_SIZEOF_REG, offsetof(struct pt_regs, s2)}, 188fe89bd2bSVincent Chen {DBG_REG_S3, GDB_SIZEOF_REG, offsetof(struct pt_regs, s3)}, 189fe89bd2bSVincent Chen {DBG_REG_S4, GDB_SIZEOF_REG, offsetof(struct pt_regs, s4)}, 190fe89bd2bSVincent Chen {DBG_REG_S5, GDB_SIZEOF_REG, offsetof(struct pt_regs, s5)}, 191fe89bd2bSVincent Chen {DBG_REG_S6, GDB_SIZEOF_REG, offsetof(struct pt_regs, s6)}, 192fe89bd2bSVincent Chen {DBG_REG_S7, GDB_SIZEOF_REG, offsetof(struct pt_regs, s7)}, 193fe89bd2bSVincent Chen {DBG_REG_S8, GDB_SIZEOF_REG, offsetof(struct pt_regs, s8)}, 194fe89bd2bSVincent Chen {DBG_REG_S9, GDB_SIZEOF_REG, offsetof(struct pt_regs, s9)}, 195fe89bd2bSVincent Chen {DBG_REG_S10, GDB_SIZEOF_REG, offsetof(struct pt_regs, s10)}, 196fe89bd2bSVincent Chen {DBG_REG_S11, GDB_SIZEOF_REG, offsetof(struct pt_regs, s11)}, 197fe89bd2bSVincent Chen {DBG_REG_T3, GDB_SIZEOF_REG, offsetof(struct pt_regs, t3)}, 198fe89bd2bSVincent Chen {DBG_REG_T4, GDB_SIZEOF_REG, offsetof(struct pt_regs, t4)}, 199fe89bd2bSVincent Chen {DBG_REG_T5, GDB_SIZEOF_REG, offsetof(struct pt_regs, t5)}, 200fe89bd2bSVincent Chen {DBG_REG_T6, GDB_SIZEOF_REG, offsetof(struct pt_regs, t6)}, 201fe89bd2bSVincent Chen {DBG_REG_EPC, GDB_SIZEOF_REG, offsetof(struct pt_regs, epc)}, 202d9657570SVincent Chen {DBG_REG_STATUS, GDB_SIZEOF_REG, offsetof(struct pt_regs, status)}, 203d9657570SVincent Chen {DBG_REG_BADADDR, GDB_SIZEOF_REG, offsetof(struct pt_regs, badaddr)}, 204d9657570SVincent Chen {DBG_REG_CAUSE, GDB_SIZEOF_REG, offsetof(struct pt_regs, cause)}, 205fe89bd2bSVincent Chen }; 206fe89bd2bSVincent Chen 207fe89bd2bSVincent Chen char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) 208fe89bd2bSVincent Chen { 209fe89bd2bSVincent Chen if (regno >= DBG_MAX_REG_NUM || regno < 0) 210fe89bd2bSVincent Chen return NULL; 211fe89bd2bSVincent Chen 212fe89bd2bSVincent Chen if (dbg_reg_def[regno].offset != -1) 213fe89bd2bSVincent Chen memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, 214fe89bd2bSVincent Chen dbg_reg_def[regno].size); 215fe89bd2bSVincent Chen else 216fe89bd2bSVincent Chen memset(mem, 0, dbg_reg_def[regno].size); 217fe89bd2bSVincent Chen return dbg_reg_def[regno].name; 218fe89bd2bSVincent Chen } 219fe89bd2bSVincent Chen 220fe89bd2bSVincent Chen int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) 221fe89bd2bSVincent Chen { 222fe89bd2bSVincent Chen if (regno >= DBG_MAX_REG_NUM || regno < 0) 223fe89bd2bSVincent Chen return -EINVAL; 224fe89bd2bSVincent Chen 225fe89bd2bSVincent Chen if (dbg_reg_def[regno].offset != -1) 226fe89bd2bSVincent Chen memcpy((void *)regs + dbg_reg_def[regno].offset, mem, 227fe89bd2bSVincent Chen dbg_reg_def[regno].size); 228fe89bd2bSVincent Chen return 0; 229fe89bd2bSVincent Chen } 230fe89bd2bSVincent Chen 231fe89bd2bSVincent Chen void 232fe89bd2bSVincent Chen sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) 233fe89bd2bSVincent Chen { 234fe89bd2bSVincent Chen /* Initialize to zero */ 235fe89bd2bSVincent Chen memset((char *)gdb_regs, 0, NUMREGBYTES); 236fe89bd2bSVincent Chen 237fe89bd2bSVincent Chen gdb_regs[DBG_REG_SP_OFF] = task->thread.sp; 238fe89bd2bSVincent Chen gdb_regs[DBG_REG_FP_OFF] = task->thread.s[0]; 239fe89bd2bSVincent Chen gdb_regs[DBG_REG_S1_OFF] = task->thread.s[1]; 240fe89bd2bSVincent Chen gdb_regs[DBG_REG_S2_OFF] = task->thread.s[2]; 241fe89bd2bSVincent Chen gdb_regs[DBG_REG_S3_OFF] = task->thread.s[3]; 242fe89bd2bSVincent Chen gdb_regs[DBG_REG_S4_OFF] = task->thread.s[4]; 243fe89bd2bSVincent Chen gdb_regs[DBG_REG_S5_OFF] = task->thread.s[5]; 244fe89bd2bSVincent Chen gdb_regs[DBG_REG_S6_OFF] = task->thread.s[6]; 245fe89bd2bSVincent Chen gdb_regs[DBG_REG_S7_OFF] = task->thread.s[7]; 246fe89bd2bSVincent Chen gdb_regs[DBG_REG_S8_OFF] = task->thread.s[8]; 247fe89bd2bSVincent Chen gdb_regs[DBG_REG_S9_OFF] = task->thread.s[10]; 248fe89bd2bSVincent Chen gdb_regs[DBG_REG_S10_OFF] = task->thread.s[11]; 249fe89bd2bSVincent Chen gdb_regs[DBG_REG_EPC_OFF] = task->thread.ra; 250fe89bd2bSVincent Chen } 251fe89bd2bSVincent Chen 252fe89bd2bSVincent Chen void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) 253fe89bd2bSVincent Chen { 254fe89bd2bSVincent Chen regs->epc = pc; 255fe89bd2bSVincent Chen } 256fe89bd2bSVincent Chen 257d9657570SVincent Chen void kgdb_arch_handle_qxfer_pkt(char *remcom_in_buffer, 258d9657570SVincent Chen char *remcom_out_buffer) 259d9657570SVincent Chen { 260d9657570SVincent Chen if (!strncmp(remcom_in_buffer, gdb_xfer_read_target, 261d9657570SVincent Chen sizeof(gdb_xfer_read_target))) 262d9657570SVincent Chen strcpy(remcom_out_buffer, riscv_gdb_stub_target_desc); 263d9657570SVincent Chen else if (!strncmp(remcom_in_buffer, gdb_xfer_read_cpuxml, 264d9657570SVincent Chen sizeof(gdb_xfer_read_cpuxml))) 265d9657570SVincent Chen strcpy(remcom_out_buffer, riscv_gdb_stub_cpuxml); 266d9657570SVincent Chen } 267d9657570SVincent Chen 268fe89bd2bSVincent Chen static inline void kgdb_arch_update_addr(struct pt_regs *regs, 269fe89bd2bSVincent Chen char *remcom_in_buffer) 270fe89bd2bSVincent Chen { 271fe89bd2bSVincent Chen unsigned long addr; 272fe89bd2bSVincent Chen char *ptr; 273fe89bd2bSVincent Chen 274fe89bd2bSVincent Chen ptr = &remcom_in_buffer[1]; 275fe89bd2bSVincent Chen if (kgdb_hex2long(&ptr, &addr)) 276fe89bd2bSVincent Chen regs->epc = addr; 277fe89bd2bSVincent Chen } 278fe89bd2bSVincent Chen 279fe89bd2bSVincent Chen int kgdb_arch_handle_exception(int vector, int signo, int err_code, 280fe89bd2bSVincent Chen char *remcom_in_buffer, char *remcom_out_buffer, 281fe89bd2bSVincent Chen struct pt_regs *regs) 282fe89bd2bSVincent Chen { 283fe89bd2bSVincent Chen int err = 0; 284fe89bd2bSVincent Chen 285edde5584SVincent Chen undo_single_step(regs); 286edde5584SVincent Chen 287fe89bd2bSVincent Chen switch (remcom_in_buffer[0]) { 288fe89bd2bSVincent Chen case 'c': 289fe89bd2bSVincent Chen case 'D': 290fe89bd2bSVincent Chen case 'k': 291fe89bd2bSVincent Chen if (remcom_in_buffer[0] == 'c') 292fe89bd2bSVincent Chen kgdb_arch_update_addr(regs, remcom_in_buffer); 293fe89bd2bSVincent Chen break; 294edde5584SVincent Chen case 's': 295edde5584SVincent Chen kgdb_arch_update_addr(regs, remcom_in_buffer); 296edde5584SVincent Chen err = do_single_step(regs); 297edde5584SVincent Chen break; 298fe89bd2bSVincent Chen default: 299fe89bd2bSVincent Chen err = -1; 300fe89bd2bSVincent Chen } 301fe89bd2bSVincent Chen return err; 302fe89bd2bSVincent Chen } 303fe89bd2bSVincent Chen 304f7fc7528SVincent Chen static int kgdb_riscv_kgdbbreak(unsigned long addr) 305fe89bd2bSVincent Chen { 306edde5584SVincent Chen if (stepped_address == addr) 307edde5584SVincent Chen return KGDB_SW_SINGLE_STEP; 308fe89bd2bSVincent Chen if (atomic_read(&kgdb_setting_breakpoint)) 309fe89bd2bSVincent Chen if (addr == (unsigned long)&kgdb_compiled_break) 310fe89bd2bSVincent Chen return KGDB_COMPILED_BREAK; 311fe89bd2bSVincent Chen 312fe89bd2bSVincent Chen return kgdb_has_hit_break(addr); 313fe89bd2bSVincent Chen } 314fe89bd2bSVincent Chen 315fe89bd2bSVincent Chen static int kgdb_riscv_notify(struct notifier_block *self, unsigned long cmd, 316fe89bd2bSVincent Chen void *ptr) 317fe89bd2bSVincent Chen { 318fe89bd2bSVincent Chen struct die_args *args = (struct die_args *)ptr; 319fe89bd2bSVincent Chen struct pt_regs *regs = args->regs; 320fe89bd2bSVincent Chen unsigned long flags; 321fe89bd2bSVincent Chen int type; 322fe89bd2bSVincent Chen 323fe89bd2bSVincent Chen if (user_mode(regs)) 324fe89bd2bSVincent Chen return NOTIFY_DONE; 325fe89bd2bSVincent Chen 326fe89bd2bSVincent Chen type = kgdb_riscv_kgdbbreak(regs->epc); 327fe89bd2bSVincent Chen if (type == NOT_KGDB_BREAK && cmd == DIE_TRAP) 328fe89bd2bSVincent Chen return NOTIFY_DONE; 329fe89bd2bSVincent Chen 330fe89bd2bSVincent Chen local_irq_save(flags); 331edde5584SVincent Chen 332edde5584SVincent Chen if (kgdb_handle_exception(type == KGDB_SW_SINGLE_STEP ? 0 : 1, 333edde5584SVincent Chen args->signr, cmd, regs)) 334fe89bd2bSVincent Chen return NOTIFY_DONE; 335fe89bd2bSVincent Chen 336fe89bd2bSVincent Chen if (type == KGDB_COMPILED_BREAK) 337fe89bd2bSVincent Chen regs->epc += 4; 338fe89bd2bSVincent Chen 339fe89bd2bSVincent Chen local_irq_restore(flags); 340fe89bd2bSVincent Chen 341fe89bd2bSVincent Chen return NOTIFY_STOP; 342fe89bd2bSVincent Chen } 343fe89bd2bSVincent Chen 344fe89bd2bSVincent Chen static struct notifier_block kgdb_notifier = { 345fe89bd2bSVincent Chen .notifier_call = kgdb_riscv_notify, 346fe89bd2bSVincent Chen }; 347fe89bd2bSVincent Chen 348fe89bd2bSVincent Chen int kgdb_arch_init(void) 349fe89bd2bSVincent Chen { 350fe89bd2bSVincent Chen register_die_notifier(&kgdb_notifier); 351fe89bd2bSVincent Chen 352fe89bd2bSVincent Chen return 0; 353fe89bd2bSVincent Chen } 354fe89bd2bSVincent Chen 355fe89bd2bSVincent Chen void kgdb_arch_exit(void) 356fe89bd2bSVincent Chen { 357fe89bd2bSVincent Chen unregister_die_notifier(&kgdb_notifier); 358fe89bd2bSVincent Chen } 359fe89bd2bSVincent Chen 360fe89bd2bSVincent Chen /* 361fe89bd2bSVincent Chen * Global data 362fe89bd2bSVincent Chen */ 363fe89bd2bSVincent Chen #ifdef CONFIG_RISCV_ISA_C 364fe89bd2bSVincent Chen const struct kgdb_arch arch_kgdb_ops = { 365fe89bd2bSVincent Chen .gdb_bpt_instr = {0x02, 0x90}, /* c.ebreak */ 366fe89bd2bSVincent Chen }; 367fe89bd2bSVincent Chen #else 368fe89bd2bSVincent Chen const struct kgdb_arch arch_kgdb_ops = { 369fe89bd2bSVincent Chen .gdb_bpt_instr = {0x73, 0x00, 0x10, 0x00}, /* ebreak */ 370fe89bd2bSVincent Chen }; 371fe89bd2bSVincent Chen #endif 372