Commit | Line | Data |
---|---|---|
e460d644 DH |
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/ptrace.h> | |
13 | #include <linux/kgdb.h> | |
14 | #include <linux/uaccess.h> | |
15 | #include <unit/leds.h> | |
16 | #include <unit/serial.h> | |
17 | #include <asm/debugger.h> | |
18 | #include <asm/serial-regs.h> | |
19 | #include "internal.h" | |
20 | ||
21 | /* | |
22 | * Copy kernel exception frame registers to the GDB register file | |
23 | */ | |
24 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |
25 | { | |
26 | unsigned long ssp = (unsigned long) (regs + 1); | |
27 | ||
28 | gdb_regs[GDB_FR_D0] = regs->d0; | |
29 | gdb_regs[GDB_FR_D1] = regs->d1; | |
30 | gdb_regs[GDB_FR_D2] = regs->d2; | |
31 | gdb_regs[GDB_FR_D3] = regs->d3; | |
32 | gdb_regs[GDB_FR_A0] = regs->a0; | |
33 | gdb_regs[GDB_FR_A1] = regs->a1; | |
34 | gdb_regs[GDB_FR_A2] = regs->a2; | |
35 | gdb_regs[GDB_FR_A3] = regs->a3; | |
36 | gdb_regs[GDB_FR_SP] = (regs->epsw & EPSW_nSL) ? regs->sp : ssp; | |
37 | gdb_regs[GDB_FR_PC] = regs->pc; | |
38 | gdb_regs[GDB_FR_MDR] = regs->mdr; | |
39 | gdb_regs[GDB_FR_EPSW] = regs->epsw; | |
40 | gdb_regs[GDB_FR_LIR] = regs->lir; | |
41 | gdb_regs[GDB_FR_LAR] = regs->lar; | |
42 | gdb_regs[GDB_FR_MDRQ] = regs->mdrq; | |
43 | gdb_regs[GDB_FR_E0] = regs->e0; | |
44 | gdb_regs[GDB_FR_E1] = regs->e1; | |
45 | gdb_regs[GDB_FR_E2] = regs->e2; | |
46 | gdb_regs[GDB_FR_E3] = regs->e3; | |
47 | gdb_regs[GDB_FR_E4] = regs->e4; | |
48 | gdb_regs[GDB_FR_E5] = regs->e5; | |
49 | gdb_regs[GDB_FR_E6] = regs->e6; | |
50 | gdb_regs[GDB_FR_E7] = regs->e7; | |
51 | gdb_regs[GDB_FR_SSP] = ssp; | |
52 | gdb_regs[GDB_FR_MSP] = 0; | |
53 | gdb_regs[GDB_FR_USP] = regs->sp; | |
54 | gdb_regs[GDB_FR_MCRH] = regs->mcrh; | |
55 | gdb_regs[GDB_FR_MCRL] = regs->mcrl; | |
56 | gdb_regs[GDB_FR_MCVF] = regs->mcvf; | |
57 | gdb_regs[GDB_FR_DUMMY0] = 0; | |
58 | gdb_regs[GDB_FR_DUMMY1] = 0; | |
59 | gdb_regs[GDB_FR_FS0] = 0; | |
60 | } | |
61 | ||
62 | /* | |
63 | * Extracts kernel SP/PC values understandable by gdb from the values | |
64 | * saved by switch_to(). | |
65 | */ | |
66 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | |
67 | { | |
68 | gdb_regs[GDB_FR_SSP] = p->thread.sp; | |
69 | gdb_regs[GDB_FR_PC] = p->thread.pc; | |
70 | gdb_regs[GDB_FR_A3] = p->thread.a3; | |
71 | gdb_regs[GDB_FR_USP] = p->thread.usp; | |
72 | gdb_regs[GDB_FR_FPCR] = p->thread.fpu_state.fpcr; | |
73 | } | |
74 | ||
75 | /* | |
76 | * Fill kernel exception frame registers from the GDB register file | |
77 | */ | |
78 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |
79 | { | |
80 | regs->d0 = gdb_regs[GDB_FR_D0]; | |
81 | regs->d1 = gdb_regs[GDB_FR_D1]; | |
82 | regs->d2 = gdb_regs[GDB_FR_D2]; | |
83 | regs->d3 = gdb_regs[GDB_FR_D3]; | |
84 | regs->a0 = gdb_regs[GDB_FR_A0]; | |
85 | regs->a1 = gdb_regs[GDB_FR_A1]; | |
86 | regs->a2 = gdb_regs[GDB_FR_A2]; | |
87 | regs->a3 = gdb_regs[GDB_FR_A3]; | |
88 | regs->sp = gdb_regs[GDB_FR_SP]; | |
89 | regs->pc = gdb_regs[GDB_FR_PC]; | |
90 | regs->mdr = gdb_regs[GDB_FR_MDR]; | |
91 | regs->epsw = gdb_regs[GDB_FR_EPSW]; | |
92 | regs->lir = gdb_regs[GDB_FR_LIR]; | |
93 | regs->lar = gdb_regs[GDB_FR_LAR]; | |
94 | regs->mdrq = gdb_regs[GDB_FR_MDRQ]; | |
95 | regs->e0 = gdb_regs[GDB_FR_E0]; | |
96 | regs->e1 = gdb_regs[GDB_FR_E1]; | |
97 | regs->e2 = gdb_regs[GDB_FR_E2]; | |
98 | regs->e3 = gdb_regs[GDB_FR_E3]; | |
99 | regs->e4 = gdb_regs[GDB_FR_E4]; | |
100 | regs->e5 = gdb_regs[GDB_FR_E5]; | |
101 | regs->e6 = gdb_regs[GDB_FR_E6]; | |
102 | regs->e7 = gdb_regs[GDB_FR_E7]; | |
103 | regs->sp = gdb_regs[GDB_FR_SSP]; | |
104 | /* gdb_regs[GDB_FR_MSP]; */ | |
105 | // regs->usp = gdb_regs[GDB_FR_USP]; | |
106 | regs->mcrh = gdb_regs[GDB_FR_MCRH]; | |
107 | regs->mcrl = gdb_regs[GDB_FR_MCRL]; | |
108 | regs->mcvf = gdb_regs[GDB_FR_MCVF]; | |
109 | /* gdb_regs[GDB_FR_DUMMY0]; */ | |
110 | /* gdb_regs[GDB_FR_DUMMY1]; */ | |
111 | ||
112 | // regs->fpcr = gdb_regs[GDB_FR_FPCR]; | |
113 | // regs->fs0 = gdb_regs[GDB_FR_FS0]; | |
114 | } | |
115 | ||
116 | struct kgdb_arch arch_kgdb_ops = { | |
117 | .gdb_bpt_instr = { 0xff }, | |
118 | .flags = KGDB_HW_BREAKPOINT, | |
119 | }; | |
120 | ||
121 | /* | |
122 | * Handle unknown packets and [Ccs] packets | |
123 | */ | |
124 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, | |
125 | char *remcom_in_buffer, char *remcom_out_buffer, | |
126 | struct pt_regs *regs) | |
127 | { | |
128 | long addr; | |
129 | char *ptr; | |
130 | ||
131 | switch (remcom_in_buffer[0]) { | |
132 | case 'c': | |
133 | if (kgdb_contthread && kgdb_contthread != current) { | |
134 | strcpy(remcom_out_buffer, "E00"); | |
135 | break; | |
136 | } | |
137 | ||
138 | kgdb_contthread = NULL; | |
139 | ||
140 | /* try to read optional parameter, pc unchanged if no parm */ | |
141 | ptr = &remcom_in_buffer[1]; | |
142 | if (kgdb_hex2long(&ptr, &addr)) | |
143 | regs->pc = addr; | |
144 | return 0; | |
145 | ||
146 | case 's': | |
147 | break; /* we don't do hardware single stepping */ | |
148 | } | |
149 | return -1; /* this means that we do not want to exit from the handler */ | |
150 | } | |
151 | ||
152 | /* | |
153 | * Handle event interception | |
154 | * - returns 0 if the exception should be skipped, -ERROR otherwise. | |
155 | */ | |
156 | int debugger_intercept(enum exception_code excep, int signo, int si_code, | |
157 | struct pt_regs *regs) | |
158 | { | |
159 | int ret; | |
160 | ||
161 | ret = kgdb_handle_exception(excep, signo, si_code, regs); | |
162 | ||
163 | debugger_local_cache_flushinv(); | |
164 | ||
165 | return ret; | |
166 | } | |
167 | ||
168 | /* | |
169 | * Determine if we've hit a debugger special breakpoint | |
170 | */ | |
171 | int at_debugger_breakpoint(struct pt_regs *regs) | |
172 | { | |
173 | return regs->pc == (unsigned long)&__arch_kgdb_breakpoint; | |
174 | } | |
175 | ||
176 | /* | |
177 | * Initialise kgdb | |
178 | */ | |
179 | int kgdb_arch_init(void) | |
180 | { | |
181 | return 0; | |
182 | } | |
183 | ||
184 | /* | |
185 | * Do something, perhaps, but don't know what. | |
186 | */ | |
187 | void kgdb_arch_exit(void) | |
188 | { | |
189 | } | |
190 | ||
191 | #ifdef CONFIG_SMP | |
192 | void debugger_nmi_interrupt(struct pt_regs *regs, enum exception_code code) | |
193 | { | |
194 | kgdb_nmicallback(arch_smp_processor_id(), regs); | |
195 | debugger_local_cache_flushinv(); | |
196 | } | |
197 | ||
198 | void kgdb_roundup_cpus(unsigned long flags) | |
199 | { | |
200 | smp_jump_to_debugger(); | |
201 | } | |
202 | #endif |