Commit | Line | Data |
---|---|---|
d16d2be1 LFT |
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 | ||
29 | static int wait_for_remote_debugger; | |
30 | ||
31 | struct 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 | ||
84 | char *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 | ||
98 | int 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 | ||
110 | void 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 | ||
117 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) | |
118 | { | |
119 | regs->ea = pc; | |
120 | } | |
121 | ||
122 | int 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 | ||
143 | asmlinkage 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 | ||
157 | int kgdb_arch_init(void) | |
158 | { | |
159 | wait_for_remote_debugger = 1; | |
160 | return 0; | |
161 | } | |
162 | ||
163 | void kgdb_arch_exit(void) | |
164 | { | |
165 | /* Nothing to do */ | |
166 | } | |
167 | ||
168 | struct kgdb_arch arch_kgdb_ops = { | |
169 | /* Breakpoint instruction: trap 30 */ | |
170 | .gdb_bpt_instr = { 0xba, 0x6f, 0x3b, 0x00 }, | |
171 | }; |