xref: /linux/arch/nios2/kernel/kgdb.c (revision d16d2be111a61baf3a4696f07bfc7a8e36697cec)
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