diff options
Diffstat (limited to 'arch/mn10300/kernel/kgdb.c')
-rw-r--r-- | arch/mn10300/kernel/kgdb.c | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/arch/mn10300/kernel/kgdb.c b/arch/mn10300/kernel/kgdb.c new file mode 100644 index 000000000000..f6c981db2a36 --- /dev/null +++ b/arch/mn10300/kernel/kgdb.c | |||
@@ -0,0 +1,502 @@ | |||
1 | /* kgdb support for MN10300 | ||
2 | * | ||
3 | * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/slab.h> | ||
13 | #include <linux/ptrace.h> | ||
14 | #include <linux/kgdb.h> | ||
15 | #include <linux/uaccess.h> | ||
16 | #include <unit/leds.h> | ||
17 | #include <unit/serial.h> | ||
18 | #include <asm/debugger.h> | ||
19 | #include <asm/serial-regs.h> | ||
20 | #include "internal.h" | ||
21 | |||
22 | /* | ||
23 | * Software single-stepping breakpoint save (used by __switch_to()) | ||
24 | */ | ||
25 | static struct thread_info *kgdb_sstep_thread; | ||
26 | u8 *kgdb_sstep_bp_addr[2]; | ||
27 | u8 kgdb_sstep_bp[2]; | ||
28 | |||
29 | /* | ||
30 | * Copy kernel exception frame registers to the GDB register file | ||
31 | */ | ||
32 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
33 | { | ||
34 | unsigned long ssp = (unsigned long) (regs + 1); | ||
35 | |||
36 | gdb_regs[GDB_FR_D0] = regs->d0; | ||
37 | gdb_regs[GDB_FR_D1] = regs->d1; | ||
38 | gdb_regs[GDB_FR_D2] = regs->d2; | ||
39 | gdb_regs[GDB_FR_D3] = regs->d3; | ||
40 | gdb_regs[GDB_FR_A0] = regs->a0; | ||
41 | gdb_regs[GDB_FR_A1] = regs->a1; | ||
42 | gdb_regs[GDB_FR_A2] = regs->a2; | ||
43 | gdb_regs[GDB_FR_A3] = regs->a3; | ||
44 | gdb_regs[GDB_FR_SP] = (regs->epsw & EPSW_nSL) ? regs->sp : ssp; | ||
45 | gdb_regs[GDB_FR_PC] = regs->pc; | ||
46 | gdb_regs[GDB_FR_MDR] = regs->mdr; | ||
47 | gdb_regs[GDB_FR_EPSW] = regs->epsw; | ||
48 | gdb_regs[GDB_FR_LIR] = regs->lir; | ||
49 | gdb_regs[GDB_FR_LAR] = regs->lar; | ||
50 | gdb_regs[GDB_FR_MDRQ] = regs->mdrq; | ||
51 | gdb_regs[GDB_FR_E0] = regs->e0; | ||
52 | gdb_regs[GDB_FR_E1] = regs->e1; | ||
53 | gdb_regs[GDB_FR_E2] = regs->e2; | ||
54 | gdb_regs[GDB_FR_E3] = regs->e3; | ||
55 | gdb_regs[GDB_FR_E4] = regs->e4; | ||
56 | gdb_regs[GDB_FR_E5] = regs->e5; | ||
57 | gdb_regs[GDB_FR_E6] = regs->e6; | ||
58 | gdb_regs[GDB_FR_E7] = regs->e7; | ||
59 | gdb_regs[GDB_FR_SSP] = ssp; | ||
60 | gdb_regs[GDB_FR_MSP] = 0; | ||
61 | gdb_regs[GDB_FR_USP] = regs->sp; | ||
62 | gdb_regs[GDB_FR_MCRH] = regs->mcrh; | ||
63 | gdb_regs[GDB_FR_MCRL] = regs->mcrl; | ||
64 | gdb_regs[GDB_FR_MCVF] = regs->mcvf; | ||
65 | gdb_regs[GDB_FR_DUMMY0] = 0; | ||
66 | gdb_regs[GDB_FR_DUMMY1] = 0; | ||
67 | gdb_regs[GDB_FR_FS0] = 0; | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * Extracts kernel SP/PC values understandable by gdb from the values | ||
72 | * saved by switch_to(). | ||
73 | */ | ||
74 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | ||
75 | { | ||
76 | gdb_regs[GDB_FR_SSP] = p->thread.sp; | ||
77 | gdb_regs[GDB_FR_PC] = p->thread.pc; | ||
78 | gdb_regs[GDB_FR_A3] = p->thread.a3; | ||
79 | gdb_regs[GDB_FR_USP] = p->thread.usp; | ||
80 | gdb_regs[GDB_FR_FPCR] = p->thread.fpu_state.fpcr; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Fill kernel exception frame registers from the GDB register file | ||
85 | */ | ||
86 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
87 | { | ||
88 | regs->d0 = gdb_regs[GDB_FR_D0]; | ||
89 | regs->d1 = gdb_regs[GDB_FR_D1]; | ||
90 | regs->d2 = gdb_regs[GDB_FR_D2]; | ||
91 | regs->d3 = gdb_regs[GDB_FR_D3]; | ||
92 | regs->a0 = gdb_regs[GDB_FR_A0]; | ||
93 | regs->a1 = gdb_regs[GDB_FR_A1]; | ||
94 | regs->a2 = gdb_regs[GDB_FR_A2]; | ||
95 | regs->a3 = gdb_regs[GDB_FR_A3]; | ||
96 | regs->sp = gdb_regs[GDB_FR_SP]; | ||
97 | regs->pc = gdb_regs[GDB_FR_PC]; | ||
98 | regs->mdr = gdb_regs[GDB_FR_MDR]; | ||
99 | regs->epsw = gdb_regs[GDB_FR_EPSW]; | ||
100 | regs->lir = gdb_regs[GDB_FR_LIR]; | ||
101 | regs->lar = gdb_regs[GDB_FR_LAR]; | ||
102 | regs->mdrq = gdb_regs[GDB_FR_MDRQ]; | ||
103 | regs->e0 = gdb_regs[GDB_FR_E0]; | ||
104 | regs->e1 = gdb_regs[GDB_FR_E1]; | ||
105 | regs->e2 = gdb_regs[GDB_FR_E2]; | ||
106 | regs->e3 = gdb_regs[GDB_FR_E3]; | ||
107 | regs->e4 = gdb_regs[GDB_FR_E4]; | ||
108 | regs->e5 = gdb_regs[GDB_FR_E5]; | ||
109 | regs->e6 = gdb_regs[GDB_FR_E6]; | ||
110 | regs->e7 = gdb_regs[GDB_FR_E7]; | ||
111 | regs->sp = gdb_regs[GDB_FR_SSP]; | ||
112 | /* gdb_regs[GDB_FR_MSP]; */ | ||
113 | // regs->usp = gdb_regs[GDB_FR_USP]; | ||
114 | regs->mcrh = gdb_regs[GDB_FR_MCRH]; | ||
115 | regs->mcrl = gdb_regs[GDB_FR_MCRL]; | ||
116 | regs->mcvf = gdb_regs[GDB_FR_MCVF]; | ||
117 | /* gdb_regs[GDB_FR_DUMMY0]; */ | ||
118 | /* gdb_regs[GDB_FR_DUMMY1]; */ | ||
119 | |||
120 | // regs->fpcr = gdb_regs[GDB_FR_FPCR]; | ||
121 | // regs->fs0 = gdb_regs[GDB_FR_FS0]; | ||
122 | } | ||
123 | |||
124 | struct kgdb_arch arch_kgdb_ops = { | ||
125 | .gdb_bpt_instr = { 0xff }, | ||
126 | .flags = KGDB_HW_BREAKPOINT, | ||
127 | }; | ||
128 | |||
129 | static const unsigned char mn10300_kgdb_insn_sizes[256] = | ||
130 | { | ||
131 | /* 1 2 3 4 5 6 7 8 9 a b c d e f */ | ||
132 | 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, /* 0 */ | ||
133 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */ | ||
134 | 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, /* 2 */ | ||
135 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, /* 3 */ | ||
136 | 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, /* 4 */ | ||
137 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, /* 5 */ | ||
138 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ | ||
139 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ | ||
140 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 8 */ | ||
141 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 9 */ | ||
142 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* a */ | ||
143 | 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* b */ | ||
144 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, /* c */ | ||
145 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */ | ||
146 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */ | ||
147 | 0, 2, 2, 2, 2, 2, 2, 4, 0, 3, 0, 4, 0, 6, 7, 1 /* f */ | ||
148 | }; | ||
149 | |||
150 | /* | ||
151 | * Attempt to emulate single stepping by means of breakpoint instructions. | ||
152 | * Although there is a single-step trace flag in EPSW, its use is not | ||
153 | * sufficiently documented and is only intended for use with the JTAG debugger. | ||
154 | */ | ||
155 | static int kgdb_arch_do_singlestep(struct pt_regs *regs) | ||
156 | { | ||
157 | unsigned long arg; | ||
158 | unsigned size; | ||
159 | u8 *pc = (u8 *)regs->pc, *sp = (u8 *)(regs + 1), cur; | ||
160 | u8 *x = NULL, *y = NULL; | ||
161 | int ret; | ||
162 | |||
163 | ret = probe_kernel_read(&cur, pc, 1); | ||
164 | if (ret < 0) | ||
165 | return ret; | ||
166 | |||
167 | size = mn10300_kgdb_insn_sizes[cur]; | ||
168 | if (size > 0) { | ||
169 | x = pc + size; | ||
170 | goto set_x; | ||
171 | } | ||
172 | |||
173 | switch (cur) { | ||
174 | /* Bxx (d8,PC) */ | ||
175 | case 0xc0 ... 0xca: | ||
176 | ret = probe_kernel_read(&arg, pc + 1, 1); | ||
177 | if (ret < 0) | ||
178 | return ret; | ||
179 | x = pc + 2; | ||
180 | if (arg >= 0 && arg <= 2) | ||
181 | goto set_x; | ||
182 | y = pc + (s8)arg; | ||
183 | goto set_x_and_y; | ||
184 | |||
185 | /* LXX (d8,PC) */ | ||
186 | case 0xd0 ... 0xda: | ||
187 | x = pc + 1; | ||
188 | if (regs->pc == regs->lar) | ||
189 | goto set_x; | ||
190 | y = (u8 *)regs->lar; | ||
191 | goto set_x_and_y; | ||
192 | |||
193 | /* SETLB - loads the next four bytes into the LIR register | ||
194 | * (which mustn't include a breakpoint instruction) */ | ||
195 | case 0xdb: | ||
196 | x = pc + 5; | ||
197 | goto set_x; | ||
198 | |||
199 | /* JMP (d16,PC) or CALL (d16,PC) */ | ||
200 | case 0xcc: | ||
201 | case 0xcd: | ||
202 | ret = probe_kernel_read(&arg, pc + 1, 2); | ||
203 | if (ret < 0) | ||
204 | return ret; | ||
205 | x = pc + (s16)arg; | ||
206 | goto set_x; | ||
207 | |||
208 | /* JMP (d32,PC) or CALL (d32,PC) */ | ||
209 | case 0xdc: | ||
210 | case 0xdd: | ||
211 | ret = probe_kernel_read(&arg, pc + 1, 4); | ||
212 | if (ret < 0) | ||
213 | return ret; | ||
214 | x = pc + (s32)arg; | ||
215 | goto set_x; | ||
216 | |||
217 | /* RETF */ | ||
218 | case 0xde: | ||
219 | x = (u8 *)regs->mdr; | ||
220 | goto set_x; | ||
221 | |||
222 | /* RET */ | ||
223 | case 0xdf: | ||
224 | ret = probe_kernel_read(&arg, pc + 2, 1); | ||
225 | if (ret < 0) | ||
226 | return ret; | ||
227 | ret = probe_kernel_read(&x, sp + (s8)arg, 4); | ||
228 | if (ret < 0) | ||
229 | return ret; | ||
230 | goto set_x; | ||
231 | |||
232 | case 0xf0: | ||
233 | ret = probe_kernel_read(&cur, pc + 1, 1); | ||
234 | if (ret < 0) | ||
235 | return ret; | ||
236 | |||
237 | if (cur >= 0xf0 && cur <= 0xf7) { | ||
238 | /* JMP (An) / CALLS (An) */ | ||
239 | switch (cur & 3) { | ||
240 | case 0: x = (u8 *)regs->a0; break; | ||
241 | case 1: x = (u8 *)regs->a1; break; | ||
242 | case 2: x = (u8 *)regs->a2; break; | ||
243 | case 3: x = (u8 *)regs->a3; break; | ||
244 | } | ||
245 | goto set_x; | ||
246 | } else if (cur == 0xfc) { | ||
247 | /* RETS */ | ||
248 | ret = probe_kernel_read(&x, sp, 4); | ||
249 | if (ret < 0) | ||
250 | return ret; | ||
251 | goto set_x; | ||
252 | } else if (cur == 0xfd) { | ||
253 | /* RTI */ | ||
254 | ret = probe_kernel_read(&x, sp + 4, 4); | ||
255 | if (ret < 0) | ||
256 | return ret; | ||
257 | goto set_x; | ||
258 | } else { | ||
259 | x = pc + 2; | ||
260 | goto set_x; | ||
261 | } | ||
262 | break; | ||
263 | |||
264 | /* potential 3-byte conditional branches */ | ||
265 | case 0xf8: | ||
266 | ret = probe_kernel_read(&cur, pc + 1, 1); | ||
267 | if (ret < 0) | ||
268 | return ret; | ||
269 | x = pc + 3; | ||
270 | |||
271 | if (cur >= 0xe8 && cur <= 0xeb) { | ||
272 | ret = probe_kernel_read(&arg, pc + 2, 1); | ||
273 | if (ret < 0) | ||
274 | return ret; | ||
275 | if (arg >= 0 && arg <= 3) | ||
276 | goto set_x; | ||
277 | y = pc + (s8)arg; | ||
278 | goto set_x_and_y; | ||
279 | } | ||
280 | goto set_x; | ||
281 | |||
282 | case 0xfa: | ||
283 | ret = probe_kernel_read(&cur, pc + 1, 1); | ||
284 | if (ret < 0) | ||
285 | return ret; | ||
286 | |||
287 | if (cur == 0xff) { | ||
288 | /* CALLS (d16,PC) */ | ||
289 | ret = probe_kernel_read(&arg, pc + 2, 2); | ||
290 | if (ret < 0) | ||
291 | return ret; | ||
292 | x = pc + (s16)arg; | ||
293 | goto set_x; | ||
294 | } | ||
295 | |||
296 | x = pc + 4; | ||
297 | goto set_x; | ||
298 | |||
299 | case 0xfc: | ||
300 | ret = probe_kernel_read(&cur, pc + 1, 1); | ||
301 | if (ret < 0) | ||
302 | return ret; | ||
303 | |||
304 | if (cur == 0xff) { | ||
305 | /* CALLS (d32,PC) */ | ||
306 | ret = probe_kernel_read(&arg, pc + 2, 4); | ||
307 | if (ret < 0) | ||
308 | return ret; | ||
309 | x = pc + (s32)arg; | ||
310 | goto set_x; | ||
311 | } | ||
312 | |||
313 | x = pc + 6; | ||
314 | goto set_x; | ||
315 | } | ||
316 | |||
317 | return 0; | ||
318 | |||
319 | set_x: | ||
320 | kgdb_sstep_bp_addr[0] = x; | ||
321 | kgdb_sstep_bp_addr[1] = NULL; | ||
322 | ret = probe_kernel_read(&kgdb_sstep_bp[0], x, 1); | ||
323 | if (ret < 0) | ||
324 | return ret; | ||
325 | ret = probe_kernel_write(x, &arch_kgdb_ops.gdb_bpt_instr, 1); | ||
326 | if (ret < 0) | ||
327 | return ret; | ||
328 | kgdb_sstep_thread = current_thread_info(); | ||
329 | debugger_local_cache_flushinv_one(x); | ||
330 | return ret; | ||
331 | |||
332 | set_x_and_y: | ||
333 | kgdb_sstep_bp_addr[0] = x; | ||
334 | kgdb_sstep_bp_addr[1] = y; | ||
335 | ret = probe_kernel_read(&kgdb_sstep_bp[0], x, 1); | ||
336 | if (ret < 0) | ||
337 | return ret; | ||
338 | ret = probe_kernel_read(&kgdb_sstep_bp[1], y, 1); | ||
339 | if (ret < 0) | ||
340 | return ret; | ||
341 | ret = probe_kernel_write(x, &arch_kgdb_ops.gdb_bpt_instr, 1); | ||
342 | if (ret < 0) | ||
343 | return ret; | ||
344 | ret = probe_kernel_write(y, &arch_kgdb_ops.gdb_bpt_instr, 1); | ||
345 | if (ret < 0) { | ||
346 | probe_kernel_write(kgdb_sstep_bp_addr[0], | ||
347 | &kgdb_sstep_bp[0], 1); | ||
348 | } else { | ||
349 | kgdb_sstep_thread = current_thread_info(); | ||
350 | } | ||
351 | debugger_local_cache_flushinv_one(x); | ||
352 | debugger_local_cache_flushinv_one(y); | ||
353 | return ret; | ||
354 | } | ||
355 | |||
356 | /* | ||
357 | * Remove emplaced single-step breakpoints, returning true if we hit one of | ||
358 | * them. | ||
359 | */ | ||
360 | static bool kgdb_arch_undo_singlestep(struct pt_regs *regs) | ||
361 | { | ||
362 | bool hit = false; | ||
363 | u8 *x = kgdb_sstep_bp_addr[0], *y = kgdb_sstep_bp_addr[1]; | ||
364 | u8 opcode; | ||
365 | |||
366 | if (kgdb_sstep_thread == current_thread_info()) { | ||
367 | if (x) { | ||
368 | if (x == (u8 *)regs->pc) | ||
369 | hit = true; | ||
370 | if (probe_kernel_read(&opcode, x, | ||
371 | 1) < 0 || | ||
372 | opcode != 0xff) | ||
373 | BUG(); | ||
374 | probe_kernel_write(x, &kgdb_sstep_bp[0], 1); | ||
375 | debugger_local_cache_flushinv_one(x); | ||
376 | } | ||
377 | if (y) { | ||
378 | if (y == (u8 *)regs->pc) | ||
379 | hit = true; | ||
380 | if (probe_kernel_read(&opcode, y, | ||
381 | 1) < 0 || | ||
382 | opcode != 0xff) | ||
383 | BUG(); | ||
384 | probe_kernel_write(y, &kgdb_sstep_bp[1], 1); | ||
385 | debugger_local_cache_flushinv_one(y); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | kgdb_sstep_bp_addr[0] = NULL; | ||
390 | kgdb_sstep_bp_addr[1] = NULL; | ||
391 | kgdb_sstep_thread = NULL; | ||
392 | return hit; | ||
393 | } | ||
394 | |||
395 | /* | ||
396 | * Catch a single-step-pending thread being deleted and make sure the global | ||
397 | * single-step state is cleared. At this point the breakpoints should have | ||
398 | * been removed by __switch_to(). | ||
399 | */ | ||
400 | void free_thread_info(struct thread_info *ti) | ||
401 | { | ||
402 | if (kgdb_sstep_thread == ti) { | ||
403 | kgdb_sstep_thread = NULL; | ||
404 | |||
405 | /* However, we may now be running in degraded mode, with most | ||
406 | * of the CPUs disabled until such a time as KGDB is reentered, | ||
407 | * so force immediate reentry */ | ||
408 | kgdb_breakpoint(); | ||
409 | } | ||
410 | kfree(ti); | ||
411 | } | ||
412 | |||
413 | /* | ||
414 | * Handle unknown packets and [CcsDk] packets | ||
415 | * - at this point breakpoints have been installed | ||
416 | */ | ||
417 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, | ||
418 | char *remcom_in_buffer, char *remcom_out_buffer, | ||
419 | struct pt_regs *regs) | ||
420 | { | ||
421 | long addr; | ||
422 | char *ptr; | ||
423 | |||
424 | switch (remcom_in_buffer[0]) { | ||
425 | case 'c': | ||
426 | case 's': | ||
427 | /* try to read optional parameter, pc unchanged if no parm */ | ||
428 | ptr = &remcom_in_buffer[1]; | ||
429 | if (kgdb_hex2long(&ptr, &addr)) | ||
430 | regs->pc = addr; | ||
431 | case 'D': | ||
432 | case 'k': | ||
433 | atomic_set(&kgdb_cpu_doing_single_step, -1); | ||
434 | |||
435 | if (remcom_in_buffer[0] == 's') { | ||
436 | kgdb_arch_do_singlestep(regs); | ||
437 | kgdb_single_step = 1; | ||
438 | atomic_set(&kgdb_cpu_doing_single_step, | ||
439 | raw_smp_processor_id()); | ||
440 | } | ||
441 | return 0; | ||
442 | } | ||
443 | return -1; /* this means that we do not want to exit from the handler */ | ||
444 | } | ||
445 | |||
446 | /* | ||
447 | * Handle event interception | ||
448 | * - returns 0 if the exception should be skipped, -ERROR otherwise. | ||
449 | */ | ||
450 | int debugger_intercept(enum exception_code excep, int signo, int si_code, | ||
451 | struct pt_regs *regs) | ||
452 | { | ||
453 | int ret; | ||
454 | |||
455 | if (kgdb_arch_undo_singlestep(regs)) { | ||
456 | excep = EXCEP_TRAP; | ||
457 | signo = SIGTRAP; | ||
458 | si_code = TRAP_TRACE; | ||
459 | } | ||
460 | |||
461 | ret = kgdb_handle_exception(excep, signo, si_code, regs); | ||
462 | |||
463 | debugger_local_cache_flushinv(); | ||
464 | |||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | /* | ||
469 | * Determine if we've hit a debugger special breakpoint | ||
470 | */ | ||
471 | int at_debugger_breakpoint(struct pt_regs *regs) | ||
472 | { | ||
473 | return regs->pc == (unsigned long)&__arch_kgdb_breakpoint; | ||
474 | } | ||
475 | |||
476 | /* | ||
477 | * Initialise kgdb | ||
478 | */ | ||
479 | int kgdb_arch_init(void) | ||
480 | { | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | /* | ||
485 | * Do something, perhaps, but don't know what. | ||
486 | */ | ||
487 | void kgdb_arch_exit(void) | ||
488 | { | ||
489 | } | ||
490 | |||
491 | #ifdef CONFIG_SMP | ||
492 | void debugger_nmi_interrupt(struct pt_regs *regs, enum exception_code code) | ||
493 | { | ||
494 | kgdb_nmicallback(arch_smp_processor_id(), regs); | ||
495 | debugger_local_cache_flushinv(); | ||
496 | } | ||
497 | |||
498 | void kgdb_roundup_cpus(unsigned long flags) | ||
499 | { | ||
500 | smp_jump_to_debugger(); | ||
501 | } | ||
502 | #endif | ||