1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/ptrace.h>
26#include <linux/kgdb.h>
27#include <linux/kdebug.h>
28#include <linux/sched.h>
29#include <asm/inst.h>
30#include <asm/fpu.h>
31#include <asm/cacheflush.h>
32#include <asm/processor.h>
33#include <asm/sigcontext.h>
34
35static struct hard_trap_info {
36 unsigned char tt;
37 unsigned char signo;
38} hard_trap_info[] = {
39 { 6, SIGBUS },
40 { 7, SIGBUS },
41 { 9, SIGTRAP },
42
43 { 12, SIGFPE },
44 { 13, SIGTRAP },
45 { 14, SIGSEGV },
46 { 15, SIGFPE },
47 { 23, SIGSEGV },
48 { 31, SIGSEGV },
49 { 0, 0}
50};
51
52void arch_kgdb_breakpoint(void)
53{
54 __asm__ __volatile__(
55 ".globl breakinst\n\t"
56 ".set\tnoreorder\n\t"
57 "nop\n"
58 "breakinst:\tbreak\n\t"
59 "nop\n\t"
60 ".set\treorder");
61}
62
63static void kgdb_call_nmi_hook(void *ignored)
64{
65 kgdb_nmicallback(raw_smp_processor_id(), NULL);
66}
67
68void kgdb_roundup_cpus(unsigned long flags)
69{
70 local_irq_enable();
71 smp_call_function(kgdb_call_nmi_hook, NULL, 0);
72 local_irq_disable();
73}
74
75static int compute_signal(int tt)
76{
77 struct hard_trap_info *ht;
78
79 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
80 if (ht->tt == tt)
81 return ht->signo;
82
83 return SIGHUP;
84}
85
86void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
87{
88 int reg;
89
90#if (KGDB_GDB_REG_SIZE == 32)
91 u32 *ptr = (u32 *)gdb_regs;
92#else
93 u64 *ptr = (u64 *)gdb_regs;
94#endif
95
96 for (reg = 0; reg < 32; reg++)
97 *(ptr++) = regs->regs[reg];
98
99 *(ptr++) = regs->cp0_status;
100 *(ptr++) = regs->lo;
101 *(ptr++) = regs->hi;
102 *(ptr++) = regs->cp0_badvaddr;
103 *(ptr++) = regs->cp0_cause;
104 *(ptr++) = regs->cp0_epc;
105
106
107 if (!(current && (regs->cp0_status & ST0_CU1)))
108 return;
109
110 save_fp(current);
111 for (reg = 0; reg < 32; reg++)
112 *(ptr++) = current->thread.fpu.fpr[reg];
113}
114
115void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
116{
117 int reg;
118
119#if (KGDB_GDB_REG_SIZE == 32)
120 const u32 *ptr = (u32 *)gdb_regs;
121#else
122 const u64 *ptr = (u64 *)gdb_regs;
123#endif
124
125 for (reg = 0; reg < 32; reg++)
126 regs->regs[reg] = *(ptr++);
127
128 regs->cp0_status = *(ptr++);
129 regs->lo = *(ptr++);
130 regs->hi = *(ptr++);
131 regs->cp0_badvaddr = *(ptr++);
132 regs->cp0_cause = *(ptr++);
133 regs->cp0_epc = *(ptr++);
134
135
136 if (!(current && (regs->cp0_status & ST0_CU1)))
137 return;
138
139 for (reg = 0; reg < 32; reg++)
140 current->thread.fpu.fpr[reg] = *(ptr++);
141 restore_fp(current);
142}
143
144
145
146
147
148void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
149{
150 int reg;
151 struct thread_info *ti = task_thread_info(p);
152 unsigned long ksp = (unsigned long)ti + THREAD_SIZE - 32;
153 struct pt_regs *regs = (struct pt_regs *)ksp - 1;
154#if (KGDB_GDB_REG_SIZE == 32)
155 u32 *ptr = (u32 *)gdb_regs;
156#else
157 u64 *ptr = (u64 *)gdb_regs;
158#endif
159
160 for (reg = 0; reg < 16; reg++)
161 *(ptr++) = regs->regs[reg];
162
163
164 for (reg = 16; reg < 24; reg++)
165 *(ptr++) = regs->regs[reg];
166
167 for (reg = 24; reg < 28; reg++)
168 *(ptr++) = 0;
169
170
171 for (reg = 28; reg < 32; reg++)
172 *(ptr++) = regs->regs[reg];
173
174 *(ptr++) = regs->cp0_status;
175 *(ptr++) = regs->lo;
176 *(ptr++) = regs->hi;
177 *(ptr++) = regs->cp0_badvaddr;
178 *(ptr++) = regs->cp0_cause;
179 *(ptr++) = regs->cp0_epc;
180}
181
182
183
184
185
186static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
187 void *ptr)
188{
189 struct die_args *args = (struct die_args *)ptr;
190 struct pt_regs *regs = args->regs;
191 int trap = (regs->cp0_cause & 0x7c) >> 2;
192
193
194 if (user_mode(regs))
195 return NOTIFY_DONE;
196
197 if (atomic_read(&kgdb_active) != -1)
198 kgdb_nmicallback(smp_processor_id(), regs);
199
200 if (kgdb_handle_exception(trap, compute_signal(trap), 0, regs))
201 return NOTIFY_DONE;
202
203 if (atomic_read(&kgdb_setting_breakpoint))
204 if ((trap == 9) && (regs->cp0_epc == (unsigned long)breakinst))
205 regs->cp0_epc += 4;
206
207
208 local_irq_enable();
209 __flush_cache_all();
210
211 return NOTIFY_STOP;
212}
213
214static struct notifier_block kgdb_notifier = {
215 .notifier_call = kgdb_mips_notify,
216};
217
218
219
220
221int kgdb_arch_handle_exception(int vector, int signo, int err_code,
222 char *remcom_in_buffer, char *remcom_out_buffer,
223 struct pt_regs *regs)
224{
225 char *ptr;
226 unsigned long address;
227 int cpu = smp_processor_id();
228
229 switch (remcom_in_buffer[0]) {
230 case 's':
231 case 'c':
232
233 ptr = &remcom_in_buffer[1];
234 if (kgdb_hex2long(&ptr, &address))
235 regs->cp0_epc = address;
236
237 atomic_set(&kgdb_cpu_doing_single_step, -1);
238 if (remcom_in_buffer[0] == 's')
239 atomic_set(&kgdb_cpu_doing_single_step, cpu);
240
241 return 0;
242 }
243
244 return -1;
245}
246
247struct kgdb_arch arch_kgdb_ops;
248
249
250
251
252
253int kgdb_arch_init(void)
254{
255 union mips_instruction insn = {
256 .r_format = {
257 .opcode = spec_op,
258 .func = break_op,
259 }
260 };
261 memcpy(arch_kgdb_ops.gdb_bpt_instr, insn.byte, BREAK_INSTR_SIZE);
262
263 register_die_notifier(&kgdb_notifier);
264
265 return 0;
266}
267
268
269
270
271
272
273
274void kgdb_arch_exit(void)
275{
276 unregister_die_notifier(&kgdb_notifier);
277}
278