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