1 // SPDX-License-Identifier: GPL-2.0 2 /* kgdb.c: KGDB support for 32-bit sparc. 3 * 4 * Copyright (C) 2008 David S. Miller <davem@davemloft.net> 5 */ 6 7 #include <linux/kgdb.h> 8 #include <linux/kdebug.h> 9 #include <linux/sched.h> 10 11 #include <asm/kdebug.h> 12 #include <asm/ptrace.h> 13 #include <asm/irq.h> 14 #include <asm/cacheflush.h> 15 16 #include "kernel.h" 17 #include "entry.h" 18 19 void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) 20 { 21 struct reg_window32 *win; 22 int i; 23 24 gdb_regs[GDB_G0] = 0; 25 for (i = 0; i < 15; i++) 26 gdb_regs[GDB_G1 + i] = regs->u_regs[UREG_G1 + i]; 27 28 win = (struct reg_window32 *) regs->u_regs[UREG_FP]; 29 for (i = 0; i < 8; i++) 30 gdb_regs[GDB_L0 + i] = win->locals[i]; 31 for (i = 0; i < 8; i++) 32 gdb_regs[GDB_I0 + i] = win->ins[i]; 33 34 for (i = GDB_F0; i <= GDB_F31; i++) 35 gdb_regs[i] = 0; 36 37 gdb_regs[GDB_Y] = regs->y; 38 gdb_regs[GDB_PSR] = regs->psr; 39 gdb_regs[GDB_WIM] = 0; 40 gdb_regs[GDB_TBR] = (unsigned long) &trapbase[0]; 41 gdb_regs[GDB_PC] = regs->pc; 42 gdb_regs[GDB_NPC] = regs->npc; 43 gdb_regs[GDB_FSR] = 0; 44 gdb_regs[GDB_CSR] = 0; 45 } 46 47 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) 48 { 49 struct thread_info *t = task_thread_info(p); 50 struct reg_window32 *win; 51 int i; 52 53 for (i = GDB_G0; i < GDB_G6; i++) 54 gdb_regs[i] = 0; 55 gdb_regs[GDB_G6] = (unsigned long) t; 56 gdb_regs[GDB_G7] = 0; 57 for (i = GDB_O0; i < GDB_SP; i++) 58 gdb_regs[i] = 0; 59 gdb_regs[GDB_SP] = t->ksp; 60 gdb_regs[GDB_O7] = 0; 61 62 win = (struct reg_window32 *) t->ksp; 63 for (i = 0; i < 8; i++) 64 gdb_regs[GDB_L0 + i] = win->locals[i]; 65 for (i = 0; i < 8; i++) 66 gdb_regs[GDB_I0 + i] = win->ins[i]; 67 68 for (i = GDB_F0; i <= GDB_F31; i++) 69 gdb_regs[i] = 0; 70 71 gdb_regs[GDB_Y] = 0; 72 73 gdb_regs[GDB_PSR] = t->kpsr; 74 gdb_regs[GDB_WIM] = t->kwim; 75 gdb_regs[GDB_TBR] = (unsigned long) &trapbase[0]; 76 gdb_regs[GDB_PC] = t->kpc; 77 gdb_regs[GDB_NPC] = t->kpc + 4; 78 gdb_regs[GDB_FSR] = 0; 79 gdb_regs[GDB_CSR] = 0; 80 } 81 82 void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) 83 { 84 struct reg_window32 *win; 85 int i; 86 87 for (i = 0; i < 15; i++) 88 regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i]; 89 90 /* If the PSR register is changing, we have to preserve 91 * the CWP field, otherwise window save/restore explodes. 92 */ 93 if (regs->psr != gdb_regs[GDB_PSR]) { 94 unsigned long cwp = regs->psr & PSR_CWP; 95 96 regs->psr = (gdb_regs[GDB_PSR] & ~PSR_CWP) | cwp; 97 } 98 99 regs->pc = gdb_regs[GDB_PC]; 100 regs->npc = gdb_regs[GDB_NPC]; 101 regs->y = gdb_regs[GDB_Y]; 102 103 win = (struct reg_window32 *) regs->u_regs[UREG_FP]; 104 for (i = 0; i < 8; i++) 105 win->locals[i] = gdb_regs[GDB_L0 + i]; 106 for (i = 0; i < 8; i++) 107 win->ins[i] = gdb_regs[GDB_I0 + i]; 108 } 109 110 int kgdb_arch_handle_exception(int e_vector, int signo, int err_code, 111 char *remcomInBuffer, char *remcomOutBuffer, 112 struct pt_regs *linux_regs) 113 { 114 unsigned long addr; 115 char *ptr; 116 117 switch (remcomInBuffer[0]) { 118 case 'c': 119 /* try to read optional parameter, pc unchanged if no parm */ 120 ptr = &remcomInBuffer[1]; 121 if (kgdb_hex2long(&ptr, &addr)) { 122 linux_regs->pc = addr; 123 linux_regs->npc = addr + 4; 124 } 125 fallthrough; 126 127 case 'D': 128 case 'k': 129 if (linux_regs->pc == (unsigned long) arch_kgdb_breakpoint) { 130 linux_regs->pc = linux_regs->npc; 131 linux_regs->npc += 4; 132 } 133 return 0; 134 } 135 return -1; 136 } 137 138 asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs) 139 { 140 unsigned long flags; 141 142 if (user_mode(regs)) { 143 do_hw_interrupt(regs, trap_level); 144 return; 145 } 146 147 flushw_all(); 148 149 local_irq_save(flags); 150 kgdb_handle_exception(trap_level, SIGTRAP, 0, regs); 151 local_irq_restore(flags); 152 } 153 154 int kgdb_arch_init(void) 155 { 156 return 0; 157 } 158 159 void kgdb_arch_exit(void) 160 { 161 } 162 163 void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip) 164 { 165 regs->pc = ip; 166 regs->npc = regs->pc + 4; 167 } 168 169 const struct kgdb_arch arch_kgdb_ops = { 170 /* Breakpoint instruction: ta 0x7d */ 171 .gdb_bpt_instr = { 0x91, 0xd0, 0x20, 0x7d }, 172 }; 173
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.