Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

LoongArch: Add basic KGDB & KDB support

KGDB is intended to be used as a source level debugger for the Linux
kernel. It is used along with gdb to debug a Linux kernel. GDB can be
used to "break in" to the kernel to inspect memory, variables and regs
similar to the way an application developer would use GDB to debug an
application. KDB is a frontend of KGDB which is similar to GDB.

By now, in addition to the generic KGDB features, the LoongArch KGDB
implements the following features:
- Hardware breakpoints/watchpoints;
- Software single-step support for KDB.

Signed-off-by: Qing Zhang <zhangqing@loongson.cn> # Framework & CoreFeature
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> # BreakPoint & SingleStep
Signed-off-by: Hui Li <lihui@loongson.cn> # Some Minor Improvements
Signed-off-by: Randy Dunlap <rdunlap@infradead.org> # Some Build Error Fixes
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>

authored by

Qing Zhang and committed by
Huacai Chen
e14dd076 bd3c5798

+845 -1
+1 -1
Documentation/features/debug/kgdb/arch-support.txt
··· 13 13 | csky: | TODO | 14 14 | hexagon: | ok | 15 15 | ia64: | TODO | 16 - | loongarch: | TODO | 16 + | loongarch: | ok | 17 17 | m68k: | TODO | 18 18 | microblaze: | ok | 19 19 | mips: | ok |
+1
arch/loongarch/Kconfig
··· 91 91 select HAVE_ARCH_AUDITSYSCALL 92 92 select HAVE_ARCH_JUMP_LABEL 93 93 select HAVE_ARCH_JUMP_LABEL_RELATIVE 94 + select HAVE_ARCH_KGDB if PERF_EVENTS 94 95 select HAVE_ARCH_MMAP_RND_BITS if MMU 95 96 select HAVE_ARCH_SECCOMP_FILTER 96 97 select HAVE_ARCH_TRACEHOOK
+97
arch/loongarch/include/asm/kgdb.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2023 Loongson Technology Corporation Limited 4 + */ 5 + 6 + #ifndef _ASM_LOONGARCH_KGDB_H 7 + #define _ASM_LOONGARCH_KGDB_H 8 + 9 + #define GDB_SIZEOF_REG sizeof(u64) 10 + 11 + /* gdb remote procotol expects the following register layout. */ 12 + 13 + /* 14 + * General purpose registers: 15 + * r0-r31: 64 bit 16 + * orig_a0: 64 bit 17 + * pc : 64 bit 18 + * csr_badvaddr: 64 bit 19 + */ 20 + #define DBG_PT_REGS_BASE 0 21 + #define DBG_PT_REGS_NUM 35 22 + #define DBG_PT_REGS_END (DBG_PT_REGS_BASE + DBG_PT_REGS_NUM - 1) 23 + 24 + /* 25 + * Floating point registers: 26 + * f0-f31: 64 bit 27 + */ 28 + #define DBG_FPR_BASE (DBG_PT_REGS_END + 1) 29 + #define DBG_FPR_NUM 32 30 + #define DBG_FPR_END (DBG_FPR_BASE + DBG_FPR_NUM - 1) 31 + 32 + /* 33 + * Condition Flag registers: 34 + * fcc0-fcc8: 8 bit 35 + */ 36 + #define DBG_FCC_BASE (DBG_FPR_END + 1) 37 + #define DBG_FCC_NUM 8 38 + #define DBG_FCC_END (DBG_FCC_BASE + DBG_FCC_NUM - 1) 39 + 40 + /* 41 + * Floating-point Control and Status registers: 42 + * fcsr: 32 bit 43 + */ 44 + #define DBG_FCSR_NUM 1 45 + #define DBG_FCSR (DBG_FCC_END + 1) 46 + 47 + #define DBG_MAX_REG_NUM (DBG_FCSR + 1) 48 + 49 + /* 50 + * Size of I/O buffer for gdb packet. 51 + * considering to hold all register contents, size is set 52 + */ 53 + #define BUFMAX 2048 54 + 55 + /* 56 + * Number of bytes required for gdb_regs buffer. 57 + * PT_REGS and FPR: 8 bytes; FCSR: 4 bytes; FCC: 1 bytes. 58 + * GDB fails to connect for size beyond this with error 59 + * "'g' packet reply is too long" 60 + */ 61 + #define NUMREGBYTES ((DBG_PT_REGS_NUM + DBG_FPR_NUM) * GDB_SIZEOF_REG + DBG_FCC_NUM * 1 + DBG_FCSR_NUM * 4) 62 + 63 + #define BREAK_INSTR_SIZE 4 64 + #define CACHE_FLUSH_IS_SAFE 0 65 + 66 + /* Register numbers of various important registers. */ 67 + enum dbg_loongarch_regnum { 68 + DBG_LOONGARCH_ZERO = 0, 69 + DBG_LOONGARCH_RA, 70 + DBG_LOONGARCH_TP, 71 + DBG_LOONGARCH_SP, 72 + DBG_LOONGARCH_A0, 73 + DBG_LOONGARCH_FP = 22, 74 + DBG_LOONGARCH_S0, 75 + DBG_LOONGARCH_S1, 76 + DBG_LOONGARCH_S2, 77 + DBG_LOONGARCH_S3, 78 + DBG_LOONGARCH_S4, 79 + DBG_LOONGARCH_S5, 80 + DBG_LOONGARCH_S6, 81 + DBG_LOONGARCH_S7, 82 + DBG_LOONGARCH_S8, 83 + DBG_LOONGARCH_ORIG_A0, 84 + DBG_LOONGARCH_PC, 85 + DBG_LOONGARCH_BADV 86 + }; 87 + 88 + void kgdb_breakinst(void); 89 + void arch_kgdb_breakpoint(void); 90 + 91 + #ifdef CONFIG_KGDB 92 + bool kgdb_breakpoint_handler(struct pt_regs *regs); 93 + #else /* !CONFIG_KGDB */ 94 + static inline bool kgdb_breakpoint_handler(struct pt_regs *regs) { return false; } 95 + #endif /* CONFIG_KGDB */ 96 + 97 + #endif /* __ASM_KGDB_H_ */
+4
arch/loongarch/include/asm/stackframe.h
··· 158 158 cfi_st u0, PT_R21, \docfi 159 159 csrrd u0, PERCPU_BASE_KS 160 160 9: 161 + #ifdef CONFIG_KGDB 162 + li.w t0, CSR_CRMD_WE 163 + csrxchg t0, t0, LOONGARCH_CSR_CRMD 164 + #endif 161 165 .endm 162 166 163 167 .macro SAVE_ALL docfi=0
+1
arch/loongarch/kernel/Makefile
··· 56 56 obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_regs.o 57 57 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o 58 58 59 + obj-$(CONFIG_KGDB) += kgdb.o 59 60 obj-$(CONFIG_KPROBES) += kprobes.o 60 61 obj-$(CONFIG_RETHOOK) += rethook.o rethook_trampoline.o 61 62 obj-$(CONFIG_UPROBES) += uprobes.o
+5
arch/loongarch/kernel/entry.S
··· 58 58 59 59 SAVE_STATIC 60 60 61 + #ifdef CONFIG_KGDB 62 + li.w t1, CSR_CRMD_WE 63 + csrxchg t1, t1, LOONGARCH_CSR_CRMD 64 + #endif 65 + 61 66 move u0, t0 62 67 li.d tp, ~_THREAD_MASK 63 68 and tp, tp, sp
+727
arch/loongarch/kernel/kgdb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * LoongArch KGDB support 4 + * 5 + * Copyright (C) 2023 Loongson Technology Corporation Limited 6 + */ 7 + 8 + #include <linux/hw_breakpoint.h> 9 + #include <linux/kdebug.h> 10 + #include <linux/kgdb.h> 11 + #include <linux/processor.h> 12 + #include <linux/ptrace.h> 13 + #include <linux/sched.h> 14 + #include <linux/smp.h> 15 + 16 + #include <asm/cacheflush.h> 17 + #include <asm/fpu.h> 18 + #include <asm/hw_breakpoint.h> 19 + #include <asm/inst.h> 20 + #include <asm/irq_regs.h> 21 + #include <asm/ptrace.h> 22 + #include <asm/sigcontext.h> 23 + 24 + int kgdb_watch_activated; 25 + static unsigned int stepped_opcode; 26 + static unsigned long stepped_address; 27 + 28 + struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { 29 + { "r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) }, 30 + { "r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) }, 31 + { "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) }, 32 + { "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) }, 33 + { "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) }, 34 + { "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) }, 35 + { "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) }, 36 + { "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) }, 37 + { "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) }, 38 + { "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) }, 39 + { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) }, 40 + { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) }, 41 + { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) }, 42 + { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) }, 43 + { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) }, 44 + { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) }, 45 + { "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) }, 46 + { "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) }, 47 + { "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) }, 48 + { "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) }, 49 + { "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) }, 50 + { "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) }, 51 + { "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) }, 52 + { "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) }, 53 + { "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) }, 54 + { "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) }, 55 + { "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) }, 56 + { "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) }, 57 + { "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) }, 58 + { "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) }, 59 + { "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) }, 60 + { "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) }, 61 + { "orig_a0", GDB_SIZEOF_REG, offsetof(struct pt_regs, orig_a0) }, 62 + { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, csr_era) }, 63 + { "badv", GDB_SIZEOF_REG, offsetof(struct pt_regs, csr_badvaddr) }, 64 + { "f0", GDB_SIZEOF_REG, 0 }, 65 + { "f1", GDB_SIZEOF_REG, 1 }, 66 + { "f2", GDB_SIZEOF_REG, 2 }, 67 + { "f3", GDB_SIZEOF_REG, 3 }, 68 + { "f4", GDB_SIZEOF_REG, 4 }, 69 + { "f5", GDB_SIZEOF_REG, 5 }, 70 + { "f6", GDB_SIZEOF_REG, 6 }, 71 + { "f7", GDB_SIZEOF_REG, 7 }, 72 + { "f8", GDB_SIZEOF_REG, 8 }, 73 + { "f9", GDB_SIZEOF_REG, 9 }, 74 + { "f10", GDB_SIZEOF_REG, 10 }, 75 + { "f11", GDB_SIZEOF_REG, 11 }, 76 + { "f12", GDB_SIZEOF_REG, 12 }, 77 + { "f13", GDB_SIZEOF_REG, 13 }, 78 + { "f14", GDB_SIZEOF_REG, 14 }, 79 + { "f15", GDB_SIZEOF_REG, 15 }, 80 + { "f16", GDB_SIZEOF_REG, 16 }, 81 + { "f17", GDB_SIZEOF_REG, 17 }, 82 + { "f18", GDB_SIZEOF_REG, 18 }, 83 + { "f19", GDB_SIZEOF_REG, 19 }, 84 + { "f20", GDB_SIZEOF_REG, 20 }, 85 + { "f21", GDB_SIZEOF_REG, 21 }, 86 + { "f22", GDB_SIZEOF_REG, 22 }, 87 + { "f23", GDB_SIZEOF_REG, 23 }, 88 + { "f24", GDB_SIZEOF_REG, 24 }, 89 + { "f25", GDB_SIZEOF_REG, 25 }, 90 + { "f26", GDB_SIZEOF_REG, 26 }, 91 + { "f27", GDB_SIZEOF_REG, 27 }, 92 + { "f28", GDB_SIZEOF_REG, 28 }, 93 + { "f29", GDB_SIZEOF_REG, 29 }, 94 + { "f30", GDB_SIZEOF_REG, 30 }, 95 + { "f31", GDB_SIZEOF_REG, 31 }, 96 + { "fcc0", 1, 0 }, 97 + { "fcc1", 1, 1 }, 98 + { "fcc2", 1, 2 }, 99 + { "fcc3", 1, 3 }, 100 + { "fcc4", 1, 4 }, 101 + { "fcc5", 1, 5 }, 102 + { "fcc6", 1, 6 }, 103 + { "fcc7", 1, 7 }, 104 + { "fcsr", 4, 0 }, 105 + }; 106 + 107 + char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) 108 + { 109 + int reg_offset, reg_size; 110 + 111 + if (regno < 0 || regno >= DBG_MAX_REG_NUM) 112 + return NULL; 113 + 114 + reg_offset = dbg_reg_def[regno].offset; 115 + reg_size = dbg_reg_def[regno].size; 116 + 117 + if (reg_offset == -1) 118 + goto out; 119 + 120 + /* Handle general-purpose/orig_a0/pc/badv registers */ 121 + if (regno <= DBG_PT_REGS_END) { 122 + memcpy(mem, (void *)regs + reg_offset, reg_size); 123 + goto out; 124 + } 125 + 126 + if (!(regs->csr_euen & CSR_EUEN_FPEN)) 127 + goto out; 128 + 129 + save_fp(current); 130 + 131 + /* Handle FP registers */ 132 + switch (regno) { 133 + case DBG_FCSR: /* Process the fcsr */ 134 + memcpy(mem, (void *)&current->thread.fpu.fcsr, reg_size); 135 + break; 136 + case DBG_FCC_BASE ... DBG_FCC_END: /* Process the fcc */ 137 + memcpy(mem, (void *)&current->thread.fpu.fcc + reg_offset, reg_size); 138 + break; 139 + case DBG_FPR_BASE ... DBG_FPR_END: /* Process the fpr */ 140 + memcpy(mem, (void *)&current->thread.fpu.fpr[reg_offset], reg_size); 141 + break; 142 + default: 143 + break; 144 + } 145 + 146 + out: 147 + return dbg_reg_def[regno].name; 148 + } 149 + 150 + int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) 151 + { 152 + int reg_offset, reg_size; 153 + 154 + if (regno < 0 || regno >= DBG_MAX_REG_NUM) 155 + return -EINVAL; 156 + 157 + reg_offset = dbg_reg_def[regno].offset; 158 + reg_size = dbg_reg_def[regno].size; 159 + 160 + if (reg_offset == -1) 161 + return 0; 162 + 163 + /* Handle general-purpose/orig_a0/pc/badv registers */ 164 + if (regno <= DBG_PT_REGS_END) { 165 + memcpy((void *)regs + reg_offset, mem, reg_size); 166 + return 0; 167 + } 168 + 169 + if (!(regs->csr_euen & CSR_EUEN_FPEN)) 170 + return 0; 171 + 172 + /* Handle FP registers */ 173 + switch (regno) { 174 + case DBG_FCSR: /* Process the fcsr */ 175 + memcpy((void *)&current->thread.fpu.fcsr, mem, reg_size); 176 + break; 177 + case DBG_FCC_BASE ... DBG_FCC_END: /* Process the fcc */ 178 + memcpy((void *)&current->thread.fpu.fcc + reg_offset, mem, reg_size); 179 + break; 180 + case DBG_FPR_BASE ... DBG_FPR_END: /* Process the fpr */ 181 + memcpy((void *)&current->thread.fpu.fpr[reg_offset], mem, reg_size); 182 + break; 183 + default: 184 + break; 185 + } 186 + 187 + restore_fp(current); 188 + 189 + return 0; 190 + } 191 + 192 + /* 193 + * Similar to regs_to_gdb_regs() except that process is sleeping and so 194 + * we may not be able to get all the info. 195 + */ 196 + void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) 197 + { 198 + /* Initialize to zero */ 199 + memset((char *)gdb_regs, 0, NUMREGBYTES); 200 + 201 + gdb_regs[DBG_LOONGARCH_RA] = p->thread.reg01; 202 + gdb_regs[DBG_LOONGARCH_TP] = (long)p; 203 + gdb_regs[DBG_LOONGARCH_SP] = p->thread.reg03; 204 + 205 + /* S0 - S8 */ 206 + gdb_regs[DBG_LOONGARCH_S0] = p->thread.reg23; 207 + gdb_regs[DBG_LOONGARCH_S1] = p->thread.reg24; 208 + gdb_regs[DBG_LOONGARCH_S2] = p->thread.reg25; 209 + gdb_regs[DBG_LOONGARCH_S3] = p->thread.reg26; 210 + gdb_regs[DBG_LOONGARCH_S4] = p->thread.reg27; 211 + gdb_regs[DBG_LOONGARCH_S5] = p->thread.reg28; 212 + gdb_regs[DBG_LOONGARCH_S6] = p->thread.reg29; 213 + gdb_regs[DBG_LOONGARCH_S7] = p->thread.reg30; 214 + gdb_regs[DBG_LOONGARCH_S8] = p->thread.reg31; 215 + 216 + /* 217 + * PC use return address (RA), i.e. the moment after return from __switch_to() 218 + */ 219 + gdb_regs[DBG_LOONGARCH_PC] = p->thread.reg01; 220 + } 221 + 222 + void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) 223 + { 224 + regs->csr_era = pc; 225 + } 226 + 227 + void arch_kgdb_breakpoint(void) 228 + { 229 + __asm__ __volatile__ ( \ 230 + ".globl kgdb_breakinst\n\t" \ 231 + "nop\n" \ 232 + "kgdb_breakinst:\tbreak 2\n\t"); /* BRK_KDB = 2 */ 233 + } 234 + 235 + /* 236 + * Calls linux_debug_hook before the kernel dies. If KGDB is enabled, 237 + * then try to fall into the debugger 238 + */ 239 + static int kgdb_loongarch_notify(struct notifier_block *self, unsigned long cmd, void *ptr) 240 + { 241 + struct die_args *args = (struct die_args *)ptr; 242 + struct pt_regs *regs = args->regs; 243 + 244 + /* Userspace events, ignore. */ 245 + if (user_mode(regs)) 246 + return NOTIFY_DONE; 247 + 248 + if (!kgdb_io_module_registered) 249 + return NOTIFY_DONE; 250 + 251 + if (atomic_read(&kgdb_active) != -1) 252 + kgdb_nmicallback(smp_processor_id(), regs); 253 + 254 + if (kgdb_handle_exception(args->trapnr, args->signr, cmd, regs)) 255 + return NOTIFY_DONE; 256 + 257 + if (atomic_read(&kgdb_setting_breakpoint)) 258 + if (regs->csr_era == (unsigned long)&kgdb_breakinst) 259 + regs->csr_era += LOONGARCH_INSN_SIZE; 260 + 261 + return NOTIFY_STOP; 262 + } 263 + 264 + bool kgdb_breakpoint_handler(struct pt_regs *regs) 265 + { 266 + struct die_args args = { 267 + .regs = regs, 268 + .str = "Break", 269 + .err = BRK_KDB, 270 + .trapnr = read_csr_excode(), 271 + .signr = SIGTRAP, 272 + 273 + }; 274 + 275 + return (kgdb_loongarch_notify(NULL, DIE_TRAP, &args) == NOTIFY_STOP) ? true : false; 276 + } 277 + 278 + static struct notifier_block kgdb_notifier = { 279 + .notifier_call = kgdb_loongarch_notify, 280 + }; 281 + 282 + static inline void kgdb_arch_update_addr(struct pt_regs *regs, 283 + char *remcom_in_buffer) 284 + { 285 + unsigned long addr; 286 + char *ptr; 287 + 288 + ptr = &remcom_in_buffer[1]; 289 + if (kgdb_hex2long(&ptr, &addr)) 290 + regs->csr_era = addr; 291 + } 292 + 293 + /* Calculate the new address for after a step */ 294 + static int get_step_address(struct pt_regs *regs, unsigned long *next_addr) 295 + { 296 + char cj_val; 297 + unsigned int si, si_l, si_h, rd, rj, cj; 298 + unsigned long pc = instruction_pointer(regs); 299 + union loongarch_instruction *ip = (union loongarch_instruction *)pc; 300 + 301 + if (pc & 3) { 302 + pr_warn("%s: invalid pc 0x%lx\n", __func__, pc); 303 + return -EINVAL; 304 + } 305 + 306 + *next_addr = pc + LOONGARCH_INSN_SIZE; 307 + 308 + si_h = ip->reg0i26_format.immediate_h; 309 + si_l = ip->reg0i26_format.immediate_l; 310 + switch (ip->reg0i26_format.opcode) { 311 + case b_op: 312 + *next_addr = pc + sign_extend64((si_h << 16 | si_l) << 2, 27); 313 + return 0; 314 + case bl_op: 315 + *next_addr = pc + sign_extend64((si_h << 16 | si_l) << 2, 27); 316 + regs->regs[1] = pc + LOONGARCH_INSN_SIZE; 317 + return 0; 318 + } 319 + 320 + rj = ip->reg1i21_format.rj; 321 + cj = (rj & 0x07) + DBG_FCC_BASE; 322 + si_l = ip->reg1i21_format.immediate_l; 323 + si_h = ip->reg1i21_format.immediate_h; 324 + dbg_get_reg(cj, &cj_val, regs); 325 + switch (ip->reg1i21_format.opcode) { 326 + case beqz_op: 327 + if (regs->regs[rj] == 0) 328 + *next_addr = pc + sign_extend64((si_h << 16 | si_l) << 2, 22); 329 + return 0; 330 + case bnez_op: 331 + if (regs->regs[rj] != 0) 332 + *next_addr = pc + sign_extend64((si_h << 16 | si_l) << 2, 22); 333 + return 0; 334 + case bceqz_op: /* bceqz_op = bcnez_op */ 335 + if (((rj & 0x18) == 0x00) && !cj_val) /* bceqz */ 336 + *next_addr = pc + sign_extend64((si_h << 16 | si_l) << 2, 22); 337 + if (((rj & 0x18) == 0x08) && cj_val) /* bcnez */ 338 + *next_addr = pc + sign_extend64((si_h << 16 | si_l) << 2, 22); 339 + return 0; 340 + } 341 + 342 + rj = ip->reg2i16_format.rj; 343 + rd = ip->reg2i16_format.rd; 344 + si = ip->reg2i16_format.immediate; 345 + switch (ip->reg2i16_format.opcode) { 346 + case beq_op: 347 + if (regs->regs[rj] == regs->regs[rd]) 348 + *next_addr = pc + sign_extend64(si << 2, 17); 349 + return 0; 350 + case bne_op: 351 + if (regs->regs[rj] != regs->regs[rd]) 352 + *next_addr = pc + sign_extend64(si << 2, 17); 353 + return 0; 354 + case blt_op: 355 + if ((long)regs->regs[rj] < (long)regs->regs[rd]) 356 + *next_addr = pc + sign_extend64(si << 2, 17); 357 + return 0; 358 + case bge_op: 359 + if ((long)regs->regs[rj] >= (long)regs->regs[rd]) 360 + *next_addr = pc + sign_extend64(si << 2, 17); 361 + return 0; 362 + case bltu_op: 363 + if (regs->regs[rj] < regs->regs[rd]) 364 + *next_addr = pc + sign_extend64(si << 2, 17); 365 + return 0; 366 + case bgeu_op: 367 + if (regs->regs[rj] >= regs->regs[rd]) 368 + *next_addr = pc + sign_extend64(si << 2, 17); 369 + return 0; 370 + case jirl_op: 371 + regs->regs[rd] = pc + LOONGARCH_INSN_SIZE; 372 + *next_addr = regs->regs[rj] + sign_extend64(si << 2, 17); 373 + return 0; 374 + } 375 + 376 + return 0; 377 + } 378 + 379 + static int do_single_step(struct pt_regs *regs) 380 + { 381 + int error = 0; 382 + unsigned long addr = 0; /* Determine where the target instruction will send us to */ 383 + 384 + error = get_step_address(regs, &addr); 385 + if (error) 386 + return error; 387 + 388 + /* Store the opcode in the stepped address */ 389 + error = get_kernel_nofault(stepped_opcode, (void *)addr); 390 + if (error) 391 + return error; 392 + 393 + stepped_address = addr; 394 + 395 + /* Replace the opcode with the break instruction */ 396 + error = copy_to_kernel_nofault((void *)stepped_address, 397 + arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); 398 + flush_icache_range(addr, addr + BREAK_INSTR_SIZE); 399 + 400 + if (error) { 401 + stepped_opcode = 0; 402 + stepped_address = 0; 403 + } else { 404 + kgdb_single_step = 1; 405 + atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id()); 406 + } 407 + 408 + return error; 409 + } 410 + 411 + /* Undo a single step */ 412 + static void undo_single_step(struct pt_regs *regs) 413 + { 414 + if (stepped_opcode) { 415 + copy_to_kernel_nofault((void *)stepped_address, 416 + (void *)&stepped_opcode, BREAK_INSTR_SIZE); 417 + flush_icache_range(stepped_address, stepped_address + BREAK_INSTR_SIZE); 418 + } 419 + 420 + stepped_opcode = 0; 421 + stepped_address = 0; 422 + kgdb_single_step = 0; 423 + atomic_set(&kgdb_cpu_doing_single_step, -1); 424 + } 425 + 426 + int kgdb_arch_handle_exception(int vector, int signo, int err_code, 427 + char *remcom_in_buffer, char *remcom_out_buffer, 428 + struct pt_regs *regs) 429 + { 430 + int ret = 0; 431 + 432 + undo_single_step(regs); 433 + regs->csr_prmd |= CSR_PRMD_PWE; 434 + 435 + switch (remcom_in_buffer[0]) { 436 + case 'D': 437 + case 'k': 438 + regs->csr_prmd &= ~CSR_PRMD_PWE; 439 + fallthrough; 440 + case 'c': 441 + kgdb_arch_update_addr(regs, remcom_in_buffer); 442 + break; 443 + case 's': 444 + kgdb_arch_update_addr(regs, remcom_in_buffer); 445 + ret = do_single_step(regs); 446 + break; 447 + default: 448 + ret = -1; 449 + } 450 + 451 + return ret; 452 + } 453 + 454 + static struct hw_breakpoint { 455 + unsigned int enabled; 456 + unsigned long addr; 457 + int len; 458 + int type; 459 + struct perf_event * __percpu *pev; 460 + } breakinfo[LOONGARCH_MAX_BRP]; 461 + 462 + static int hw_break_reserve_slot(int breakno) 463 + { 464 + int cpu, cnt = 0; 465 + struct perf_event **pevent; 466 + 467 + for_each_online_cpu(cpu) { 468 + cnt++; 469 + pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); 470 + if (dbg_reserve_bp_slot(*pevent)) 471 + goto fail; 472 + } 473 + 474 + return 0; 475 + 476 + fail: 477 + for_each_online_cpu(cpu) { 478 + cnt--; 479 + if (!cnt) 480 + break; 481 + pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); 482 + dbg_release_bp_slot(*pevent); 483 + } 484 + 485 + return -1; 486 + } 487 + 488 + static int hw_break_release_slot(int breakno) 489 + { 490 + int cpu; 491 + struct perf_event **pevent; 492 + 493 + if (dbg_is_early) 494 + return 0; 495 + 496 + for_each_online_cpu(cpu) { 497 + pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu); 498 + if (dbg_release_bp_slot(*pevent)) 499 + /* 500 + * The debugger is responsible for handing the retry on 501 + * remove failure. 502 + */ 503 + return -1; 504 + } 505 + 506 + return 0; 507 + } 508 + 509 + static int kgdb_set_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) 510 + { 511 + int i; 512 + 513 + for (i = 0; i < LOONGARCH_MAX_BRP; i++) 514 + if (!breakinfo[i].enabled) 515 + break; 516 + 517 + if (i == LOONGARCH_MAX_BRP) 518 + return -1; 519 + 520 + switch (bptype) { 521 + case BP_HARDWARE_BREAKPOINT: 522 + breakinfo[i].type = HW_BREAKPOINT_X; 523 + break; 524 + case BP_READ_WATCHPOINT: 525 + breakinfo[i].type = HW_BREAKPOINT_R; 526 + break; 527 + case BP_WRITE_WATCHPOINT: 528 + breakinfo[i].type = HW_BREAKPOINT_W; 529 + break; 530 + case BP_ACCESS_WATCHPOINT: 531 + breakinfo[i].type = HW_BREAKPOINT_RW; 532 + break; 533 + default: 534 + return -1; 535 + } 536 + 537 + switch (len) { 538 + case 1: 539 + breakinfo[i].len = HW_BREAKPOINT_LEN_1; 540 + break; 541 + case 2: 542 + breakinfo[i].len = HW_BREAKPOINT_LEN_2; 543 + break; 544 + case 4: 545 + breakinfo[i].len = HW_BREAKPOINT_LEN_4; 546 + break; 547 + case 8: 548 + breakinfo[i].len = HW_BREAKPOINT_LEN_8; 549 + break; 550 + default: 551 + return -1; 552 + } 553 + 554 + breakinfo[i].addr = addr; 555 + if (hw_break_reserve_slot(i)) { 556 + breakinfo[i].addr = 0; 557 + return -1; 558 + } 559 + breakinfo[i].enabled = 1; 560 + 561 + return 0; 562 + } 563 + 564 + static int kgdb_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype bptype) 565 + { 566 + int i; 567 + 568 + for (i = 0; i < LOONGARCH_MAX_BRP; i++) 569 + if (breakinfo[i].addr == addr && breakinfo[i].enabled) 570 + break; 571 + 572 + if (i == LOONGARCH_MAX_BRP) 573 + return -1; 574 + 575 + if (hw_break_release_slot(i)) { 576 + pr_err("Cannot remove hw breakpoint at %lx\n", addr); 577 + return -1; 578 + } 579 + breakinfo[i].enabled = 0; 580 + 581 + return 0; 582 + } 583 + 584 + static void kgdb_disable_hw_break(struct pt_regs *regs) 585 + { 586 + int i; 587 + int cpu = raw_smp_processor_id(); 588 + struct perf_event *bp; 589 + 590 + for (i = 0; i < LOONGARCH_MAX_BRP; i++) { 591 + if (!breakinfo[i].enabled) 592 + continue; 593 + 594 + bp = *per_cpu_ptr(breakinfo[i].pev, cpu); 595 + if (bp->attr.disabled == 1) 596 + continue; 597 + 598 + arch_uninstall_hw_breakpoint(bp); 599 + bp->attr.disabled = 1; 600 + } 601 + 602 + /* Disable hardware debugging while we are in kgdb */ 603 + csr_xchg32(0, CSR_CRMD_WE, LOONGARCH_CSR_CRMD); 604 + } 605 + 606 + static void kgdb_remove_all_hw_break(void) 607 + { 608 + int i; 609 + int cpu = raw_smp_processor_id(); 610 + struct perf_event *bp; 611 + 612 + for (i = 0; i < LOONGARCH_MAX_BRP; i++) { 613 + if (!breakinfo[i].enabled) 614 + continue; 615 + 616 + bp = *per_cpu_ptr(breakinfo[i].pev, cpu); 617 + if (!bp->attr.disabled) { 618 + arch_uninstall_hw_breakpoint(bp); 619 + bp->attr.disabled = 1; 620 + continue; 621 + } 622 + 623 + if (hw_break_release_slot(i)) 624 + pr_err("KGDB: hw bpt remove failed %lx\n", breakinfo[i].addr); 625 + breakinfo[i].enabled = 0; 626 + } 627 + 628 + csr_xchg32(0, CSR_CRMD_WE, LOONGARCH_CSR_CRMD); 629 + kgdb_watch_activated = 0; 630 + } 631 + 632 + static void kgdb_correct_hw_break(void) 633 + { 634 + int i, activated = 0; 635 + 636 + for (i = 0; i < LOONGARCH_MAX_BRP; i++) { 637 + struct perf_event *bp; 638 + int val; 639 + int cpu = raw_smp_processor_id(); 640 + 641 + if (!breakinfo[i].enabled) 642 + continue; 643 + 644 + bp = *per_cpu_ptr(breakinfo[i].pev, cpu); 645 + if (bp->attr.disabled != 1) 646 + continue; 647 + 648 + bp->attr.bp_addr = breakinfo[i].addr; 649 + bp->attr.bp_len = breakinfo[i].len; 650 + bp->attr.bp_type = breakinfo[i].type; 651 + 652 + val = hw_breakpoint_arch_parse(bp, &bp->attr, counter_arch_bp(bp)); 653 + if (val) 654 + return; 655 + 656 + val = arch_install_hw_breakpoint(bp); 657 + if (!val) 658 + bp->attr.disabled = 0; 659 + activated = 1; 660 + } 661 + 662 + csr_xchg32(activated ? CSR_CRMD_WE : 0, CSR_CRMD_WE, LOONGARCH_CSR_CRMD); 663 + kgdb_watch_activated = activated; 664 + } 665 + 666 + const struct kgdb_arch arch_kgdb_ops = { 667 + .gdb_bpt_instr = {0x02, 0x00, break_op >> 1, 0x00}, /* BRK_KDB = 2 */ 668 + .flags = KGDB_HW_BREAKPOINT, 669 + .set_hw_breakpoint = kgdb_set_hw_break, 670 + .remove_hw_breakpoint = kgdb_remove_hw_break, 671 + .disable_hw_break = kgdb_disable_hw_break, 672 + .remove_all_hw_break = kgdb_remove_all_hw_break, 673 + .correct_hw_break = kgdb_correct_hw_break, 674 + }; 675 + 676 + int kgdb_arch_init(void) 677 + { 678 + return register_die_notifier(&kgdb_notifier); 679 + } 680 + 681 + void kgdb_arch_late(void) 682 + { 683 + int i, cpu; 684 + struct perf_event_attr attr; 685 + struct perf_event **pevent; 686 + 687 + hw_breakpoint_init(&attr); 688 + 689 + attr.bp_addr = (unsigned long)kgdb_arch_init; 690 + attr.bp_len = HW_BREAKPOINT_LEN_4; 691 + attr.bp_type = HW_BREAKPOINT_W; 692 + attr.disabled = 1; 693 + 694 + for (i = 0; i < LOONGARCH_MAX_BRP; i++) { 695 + if (breakinfo[i].pev) 696 + continue; 697 + 698 + breakinfo[i].pev = register_wide_hw_breakpoint(&attr, NULL, NULL); 699 + if (IS_ERR((void * __force)breakinfo[i].pev)) { 700 + pr_err("kgdb: Could not allocate hw breakpoints.\n"); 701 + breakinfo[i].pev = NULL; 702 + return; 703 + } 704 + 705 + for_each_online_cpu(cpu) { 706 + pevent = per_cpu_ptr(breakinfo[i].pev, cpu); 707 + if (pevent[0]->destroy) { 708 + pevent[0]->destroy = NULL; 709 + release_bp_slot(*pevent); 710 + } 711 + } 712 + } 713 + } 714 + 715 + void kgdb_arch_exit(void) 716 + { 717 + int i; 718 + 719 + for (i = 0; i < LOONGARCH_MAX_BRP; i++) { 720 + if (breakinfo[i].pev) { 721 + unregister_wide_hw_breakpoint(breakinfo[i].pev); 722 + breakinfo[i].pev = NULL; 723 + } 724 + } 725 + 726 + unregister_die_notifier(&kgdb_notifier); 727 + }
+9
arch/loongarch/kernel/traps.c
··· 38 38 #include <asm/fpu.h> 39 39 #include <asm/lbt.h> 40 40 #include <asm/inst.h> 41 + #include <asm/kgdb.h> 41 42 #include <asm/loongarch.h> 42 43 #include <asm/mmu_context.h> 43 44 #include <asm/pgtable.h> ··· 704 703 * pertain to them. 705 704 */ 706 705 switch (bcode) { 706 + case BRK_KDB: 707 + if (kgdb_breakpoint_handler(regs)) 708 + goto out; 709 + else 710 + break; 707 711 case BRK_KPROBE_BP: 708 712 if (kprobe_breakpoint_handler(regs)) 709 713 goto out; ··· 775 769 #ifndef CONFIG_HAVE_HW_BREAKPOINT 776 770 pr_warn("Hardware watch point handler not implemented!\n"); 777 771 #else 772 + if (kgdb_breakpoint_handler(regs)) 773 + goto out; 774 + 778 775 if (test_tsk_thread_flag(current, TIF_SINGLESTEP)) { 779 776 int llbit = (csr_read32(LOONGARCH_CSR_LLBCTL) & 0x1); 780 777 unsigned long pc = instruction_pointer(regs);