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

parisc: add KGDB support

This patch add KGDB support to PA-RISC. It also implements
single-stepping utilizing the recovery counter.

Signed-off-by: Sven Schnelle <svens@stackframe.org>
Signed-off-by: Helge Deller <deller@gmx.de>

authored by

Sven Schnelle and committed by
Helge Deller
eacbfce1 620a53d5

+296
+1
arch/parisc/Kconfig
··· 54 54 select CPU_NO_EFFICIENT_FFS 55 55 select NEED_DMA_MAP_STATE 56 56 select NEED_SG_DMA_LENGTH 57 + select HAVE_ARCH_KGDB 57 58 58 59 help 59 60 The PA-RISC microprocessor is designed by Hewlett-Packard and used
+68
arch/parisc/include/asm/kgdb.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * PA-RISC KGDB support 4 + * 5 + * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org> 6 + * 7 + */ 8 + 9 + #ifndef __PARISC_KGDB_H__ 10 + #define __PARISC_KGDB_H__ 11 + 12 + #define BREAK_INSTR_SIZE 4 13 + #define PARISC_KGDB_COMPILED_BREAK_INSN 0x3ffc01f 14 + #define PARISC_KGDB_BREAK_INSN 0x3ffa01f 15 + 16 + 17 + #define NUMREGBYTES sizeof(struct parisc_gdb_regs) 18 + #define BUFMAX 4096 19 + 20 + #define CACHE_FLUSH_IS_SAFE 1 21 + 22 + #ifndef __ASSEMBLY__ 23 + 24 + static inline void arch_kgdb_breakpoint(void) 25 + { 26 + asm(".word %0" : : "i"(PARISC_KGDB_COMPILED_BREAK_INSN) : "memory"); 27 + } 28 + 29 + struct parisc_gdb_regs { 30 + unsigned long gpr[32]; 31 + unsigned long sar; 32 + unsigned long iaoq_f; 33 + unsigned long iasq_f; 34 + unsigned long iaoq_b; 35 + unsigned long iasq_b; 36 + unsigned long eiem; 37 + unsigned long iir; 38 + unsigned long isr; 39 + unsigned long ior; 40 + unsigned long ipsw; 41 + unsigned long __unused0; 42 + unsigned long sr4; 43 + unsigned long sr0; 44 + unsigned long sr1; 45 + unsigned long sr2; 46 + unsigned long sr3; 47 + unsigned long sr5; 48 + unsigned long sr6; 49 + unsigned long sr7; 50 + unsigned long cr0; 51 + unsigned long pid1; 52 + unsigned long pid2; 53 + unsigned long scrccr; 54 + unsigned long pid3; 55 + unsigned long pid4; 56 + unsigned long cr24; 57 + unsigned long cr25; 58 + unsigned long cr26; 59 + unsigned long cr27; 60 + unsigned long cr28; 61 + unsigned long cr29; 62 + unsigned long cr30; 63 + 64 + u64 fr[32]; 65 + }; 66 + 67 + #endif 68 + #endif
+1
arch/parisc/kernel/Makefile
··· 33 33 obj-$(CONFIG_PARISC_CPU_TOPOLOGY) += topology.o 34 34 obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o 35 35 obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o 36 + obj-$(CONFIG_KGDB) += kgdb.o
+209
arch/parisc/kernel/kgdb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * PA-RISC KGDB support 4 + * 5 + * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org> 6 + * 7 + */ 8 + 9 + #include <linux/kgdb.h> 10 + #include <linux/string.h> 11 + #include <linux/sched.h> 12 + #include <linux/notifier.h> 13 + #include <linux/kdebug.h> 14 + #include <linux/uaccess.h> 15 + #include <asm/ptrace.h> 16 + #include <asm/traps.h> 17 + #include <asm/processor.h> 18 + #include <asm/patch.h> 19 + #include <asm/cacheflush.h> 20 + 21 + const struct kgdb_arch arch_kgdb_ops = { 22 + .gdb_bpt_instr = { 0x03, 0xff, 0xa0, 0x1f } 23 + }; 24 + 25 + static int __kgdb_notify(struct die_args *args, unsigned long cmd) 26 + { 27 + struct pt_regs *regs = args->regs; 28 + 29 + if (kgdb_handle_exception(1, args->signr, cmd, regs)) 30 + return NOTIFY_DONE; 31 + return NOTIFY_STOP; 32 + } 33 + 34 + static int kgdb_notify(struct notifier_block *self, 35 + unsigned long cmd, void *ptr) 36 + { 37 + unsigned long flags; 38 + int ret; 39 + 40 + local_irq_save(flags); 41 + ret = __kgdb_notify(ptr, cmd); 42 + local_irq_restore(flags); 43 + 44 + return ret; 45 + } 46 + 47 + static struct notifier_block kgdb_notifier = { 48 + .notifier_call = kgdb_notify, 49 + .priority = -INT_MAX, 50 + }; 51 + 52 + int kgdb_arch_init(void) 53 + { 54 + return register_die_notifier(&kgdb_notifier); 55 + } 56 + 57 + void kgdb_arch_exit(void) 58 + { 59 + unregister_die_notifier(&kgdb_notifier); 60 + } 61 + 62 + void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) 63 + { 64 + struct parisc_gdb_regs *gr = (struct parisc_gdb_regs *)gdb_regs; 65 + 66 + memset(gr, 0, sizeof(struct parisc_gdb_regs)); 67 + 68 + memcpy(gr->gpr, regs->gr, sizeof(gr->gpr)); 69 + memcpy(gr->fr, regs->fr, sizeof(gr->fr)); 70 + 71 + gr->sr0 = regs->sr[0]; 72 + gr->sr1 = regs->sr[1]; 73 + gr->sr2 = regs->sr[2]; 74 + gr->sr3 = regs->sr[3]; 75 + gr->sr4 = regs->sr[4]; 76 + gr->sr5 = regs->sr[5]; 77 + gr->sr6 = regs->sr[6]; 78 + gr->sr7 = regs->sr[7]; 79 + 80 + gr->sar = regs->sar; 81 + gr->iir = regs->iir; 82 + gr->isr = regs->isr; 83 + gr->ior = regs->ior; 84 + gr->ipsw = regs->ipsw; 85 + gr->cr27 = regs->cr27; 86 + 87 + gr->iaoq_f = regs->iaoq[0]; 88 + gr->iasq_f = regs->iasq[0]; 89 + 90 + gr->iaoq_b = regs->iaoq[1]; 91 + gr->iasq_b = regs->iasq[1]; 92 + } 93 + 94 + void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) 95 + { 96 + struct parisc_gdb_regs *gr = (struct parisc_gdb_regs *)gdb_regs; 97 + 98 + 99 + memcpy(regs->gr, gr->gpr, sizeof(regs->gr)); 100 + memcpy(regs->fr, gr->fr, sizeof(regs->fr)); 101 + 102 + regs->sr[0] = gr->sr0; 103 + regs->sr[1] = gr->sr1; 104 + regs->sr[2] = gr->sr2; 105 + regs->sr[3] = gr->sr3; 106 + regs->sr[4] = gr->sr4; 107 + regs->sr[5] = gr->sr5; 108 + regs->sr[6] = gr->sr6; 109 + regs->sr[7] = gr->sr7; 110 + 111 + regs->sar = gr->sar; 112 + regs->iir = gr->iir; 113 + regs->isr = gr->isr; 114 + regs->ior = gr->ior; 115 + regs->ipsw = gr->ipsw; 116 + regs->cr27 = gr->cr27; 117 + 118 + regs->iaoq[0] = gr->iaoq_f; 119 + regs->iasq[0] = gr->iasq_f; 120 + 121 + regs->iaoq[1] = gr->iaoq_b; 122 + regs->iasq[1] = gr->iasq_b; 123 + } 124 + 125 + void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, 126 + struct task_struct *task) 127 + { 128 + struct pt_regs *regs = task_pt_regs(task); 129 + unsigned long gr30, iaoq; 130 + 131 + gr30 = regs->gr[30]; 132 + iaoq = regs->iaoq[0]; 133 + 134 + regs->gr[30] = regs->ksp; 135 + regs->iaoq[0] = regs->kpc; 136 + pt_regs_to_gdb_regs(gdb_regs, regs); 137 + 138 + regs->gr[30] = gr30; 139 + regs->iaoq[0] = iaoq; 140 + 141 + } 142 + 143 + static void step_instruction_queue(struct pt_regs *regs) 144 + { 145 + regs->iaoq[0] = regs->iaoq[1]; 146 + regs->iaoq[1] += 4; 147 + } 148 + 149 + void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip) 150 + { 151 + regs->iaoq[0] = ip; 152 + regs->iaoq[1] = ip + 4; 153 + } 154 + 155 + int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) 156 + { 157 + int ret = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, 158 + BREAK_INSTR_SIZE); 159 + if (ret) 160 + return ret; 161 + 162 + __patch_text((void *)bpt->bpt_addr, 163 + *(unsigned int *)&arch_kgdb_ops.gdb_bpt_instr); 164 + return ret; 165 + } 166 + 167 + int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) 168 + { 169 + __patch_text((void *)bpt->bpt_addr, *(unsigned int *)&bpt->saved_instr); 170 + return 0; 171 + } 172 + 173 + int kgdb_arch_handle_exception(int trap, int signo, 174 + int err_code, char *inbuf, char *outbuf, 175 + struct pt_regs *regs) 176 + { 177 + unsigned long addr; 178 + char *p = inbuf + 1; 179 + 180 + switch (inbuf[0]) { 181 + case 'D': 182 + case 'c': 183 + case 'k': 184 + kgdb_contthread = NULL; 185 + kgdb_single_step = 0; 186 + 187 + if (kgdb_hex2long(&p, &addr)) 188 + kgdb_arch_set_pc(regs, addr); 189 + else if (trap == 9 && regs->iir == 190 + PARISC_KGDB_COMPILED_BREAK_INSN) 191 + step_instruction_queue(regs); 192 + return 0; 193 + case 's': 194 + kgdb_single_step = 1; 195 + if (kgdb_hex2long(&p, &addr)) { 196 + kgdb_arch_set_pc(regs, addr); 197 + } else if (trap == 9 && regs->iir == 198 + PARISC_KGDB_COMPILED_BREAK_INSN) { 199 + step_instruction_queue(regs); 200 + mtctl(-1, 0); 201 + } else { 202 + mtctl(0, 0); 203 + } 204 + regs->gr[0] |= PSW_R; 205 + return 0; 206 + 207 + } 208 + return -1; 209 + }
+17
arch/parisc/kernel/traps.c
··· 42 42 #include <asm/unwind.h> 43 43 #include <asm/tlbflush.h> 44 44 #include <asm/cacheflush.h> 45 + #include <linux/kgdb.h> 45 46 46 47 #include "../math-emu/math-emu.h" /* for handle_fpe() */ 47 48 ··· 294 293 (tt == BUG_TRAP_TYPE_NONE) ? 9 : 0); 295 294 } 296 295 296 + #ifdef CONFIG_KGDB 297 + if (unlikely(iir == PARISC_KGDB_COMPILED_BREAK_INSN || 298 + iir == PARISC_KGDB_BREAK_INSN)) { 299 + kgdb_handle_exception(9, SIGTRAP, 0, regs); 300 + return; 301 + } 302 + #endif 303 + 297 304 if (unlikely(iir != GDB_BREAK_INSN)) 298 305 parisc_printk_ratelimited(0, regs, 299 306 KERN_DEBUG "break %d,%d: pid=%d command='%s'\n", ··· 527 518 case 3: 528 519 /* Recovery counter trap */ 529 520 regs->gr[0] &= ~PSW_R; 521 + 522 + #ifdef CONFIG_KGDB 523 + if (kgdb_single_step) { 524 + kgdb_handle_exception(0, SIGTRAP, 0, regs); 525 + return; 526 + } 527 + #endif 528 + 530 529 if (user_space(regs)) 531 530 handle_gdb_break(regs, TRAP_TRACE); 532 531 /* else this must be the start of a syscall - just let it run */