1/* 2 * Nios2 KGDB support 3 * 4 * Copyright (C) 2015 Altera Corporation 5 * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> 6 * 7 * Based on the code posted by Kazuyasu on the Altera Forum at: 8 * http://www.alteraforum.com/forum/showpost.php?p=77003&postcount=20 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program. If not, see <http://www.gnu.org/licenses/>. 22 * 23 */ 24#include <linux/ptrace.h> 25#include <linux/kgdb.h> 26#include <linux/kdebug.h> 27#include <linux/io.h> 28 29static int wait_for_remote_debugger; 30 31struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = 32{ 33 { "zero", GDB_SIZEOF_REG, -1 }, 34 { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, r1) }, 35 { "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, r2) }, 36 { "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, r3) }, 37 { "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, r4) }, 38 { "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, r5) }, 39 { "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, r6) }, 40 { "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, r7) }, 41 { "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, r8) }, 42 { "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, r9) }, 43 { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, r10) }, 44 { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, r11) }, 45 { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, r12) }, 46 { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, r13) }, 47 { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, r14) }, 48 { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, r15) }, 49 { "r16", GDB_SIZEOF_REG, -1 }, 50 { "r17", GDB_SIZEOF_REG, -1 }, 51 { "r18", GDB_SIZEOF_REG, -1 }, 52 { "r19", GDB_SIZEOF_REG, -1 }, 53 { "r20", GDB_SIZEOF_REG, -1 }, 54 { "r21", GDB_SIZEOF_REG, -1 }, 55 { "r22", GDB_SIZEOF_REG, -1 }, 56 { "r23", GDB_SIZEOF_REG, -1 }, 57 { "et", GDB_SIZEOF_REG, -1 }, 58 { "bt", GDB_SIZEOF_REG, -1 }, 59 { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, gp) }, 60 { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, sp) }, 61 { "fp", GDB_SIZEOF_REG, offsetof(struct pt_regs, fp) }, 62 { "ea", GDB_SIZEOF_REG, -1 }, 63 { "ba", GDB_SIZEOF_REG, -1 }, 64 { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, ra) }, 65 { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, ea) }, 66 { "status", GDB_SIZEOF_REG, -1 }, 67 { "estatus", GDB_SIZEOF_REG, offsetof(struct pt_regs, estatus) }, 68 { "bstatus", GDB_SIZEOF_REG, -1 }, 69 { "ienable", GDB_SIZEOF_REG, -1 }, 70 { "ipending", GDB_SIZEOF_REG, -1}, 71 { "cpuid", GDB_SIZEOF_REG, -1 }, 72 { "ctl6", GDB_SIZEOF_REG, -1 }, 73 { "exception", GDB_SIZEOF_REG, -1 }, 74 { "pteaddr", GDB_SIZEOF_REG, -1 }, 75 { "tlbacc", GDB_SIZEOF_REG, -1 }, 76 { "tlbmisc", GDB_SIZEOF_REG, -1 }, 77 { "eccinj", GDB_SIZEOF_REG, -1 }, 78 { "badaddr", GDB_SIZEOF_REG, -1 }, 79 { "config", GDB_SIZEOF_REG, -1 }, 80 { "mpubase", GDB_SIZEOF_REG, -1 }, 81 { "mpuacc", GDB_SIZEOF_REG, -1 }, 82}; 83 84char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) 85{ 86 if (regno >= DBG_MAX_REG_NUM || regno < 0) 87 return NULL; 88 89 if (dbg_reg_def[regno].offset != -1) 90 memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, 91 dbg_reg_def[regno].size); 92 else 93 memset(mem, 0, dbg_reg_def[regno].size); 94 95 return dbg_reg_def[regno].name; 96} 97 98int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) 99{ 100 if (regno >= DBG_MAX_REG_NUM || regno < 0) 101 return -EINVAL; 102 103 if (dbg_reg_def[regno].offset != -1) 104 memcpy((void *)regs + dbg_reg_def[regno].offset, mem, 105 dbg_reg_def[regno].size); 106 107 return 0; 108} 109 110void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) 111{ 112 memset((char *)gdb_regs, 0, NUMREGBYTES); 113 gdb_regs[GDB_SP] = p->thread.kregs->sp; 114 gdb_regs[GDB_PC] = p->thread.kregs->ea; 115} 116 117void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) 118{ 119 regs->ea = pc; 120} 121 122int kgdb_arch_handle_exception(int vector, int signo, int err_code, 123 char *remcom_in_buffer, char *remcom_out_buffer, 124 struct pt_regs *regs) 125{ 126 char *ptr; 127 unsigned long addr; 128 129 switch (remcom_in_buffer[0]) { 130 case 's': 131 case 'c': 132 /* handle the optional parameters */ 133 ptr = &remcom_in_buffer[1]; 134 if (kgdb_hex2long(&ptr, &addr)) 135 regs->ea = addr; 136 137 return 0; 138 } 139 140 return -1; /* this means that we do not want to exit from the handler */ 141} 142 143asmlinkage void kgdb_breakpoint_c(struct pt_regs *regs) 144{ 145 /* 146 * The breakpoint entry code has moved the PC on by 4 bytes, so we must 147 * move it back. This could be done on the host but we do it here 148 */ 149 if (!wait_for_remote_debugger) 150 regs->ea -= 4; 151 else /* pass the first trap 30 code */ 152 wait_for_remote_debugger = 0; 153 154 kgdb_handle_exception(30, SIGTRAP, 0, regs); 155} 156 157int kgdb_arch_init(void) 158{ 159 wait_for_remote_debugger = 1; 160 return 0; 161} 162 163void kgdb_arch_exit(void) 164{ 165 /* Nothing to do */ 166} 167 168struct kgdb_arch arch_kgdb_ops = { 169 /* Breakpoint instruction: trap 30 */ 170 .gdb_bpt_instr = { 0xba, 0x6f, 0x3b, 0x00 }, 171}; 172