]>
Commit | Line | Data |
---|---|---|
0d71e879 LV |
1 | /* |
2 | * arch/hexagon/kernel/kgdb.c - Hexagon KGDB Support | |
3 | * | |
e1858b2a | 4 | * Copyright (c) 2011, The Linux Foundation. All rights reserved. |
0d71e879 LV |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 and | |
8 | * only version 2 as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
18 | * 02110-1301, USA. | |
19 | */ | |
20 | ||
21 | #include <linux/kdebug.h> | |
22 | #include <linux/kgdb.h> | |
23 | ||
24 | /* All registers are 4 bytes, for now */ | |
25 | #define GDB_SIZEOF_REG 4 | |
26 | ||
27 | /* The register names are used during printing of the regs; | |
28 | * Keep these at three letters to pretty-print. */ | |
29 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { | |
30 | { " r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, r00)}, | |
31 | { " r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, r01)}, | |
32 | { " r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, r02)}, | |
33 | { " r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, r03)}, | |
34 | { " r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, r04)}, | |
35 | { " r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, r05)}, | |
36 | { " r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, r06)}, | |
37 | { " r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, r07)}, | |
38 | { " r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, r08)}, | |
39 | { " r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, r09)}, | |
40 | { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, r10)}, | |
41 | { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, r11)}, | |
42 | { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, r12)}, | |
43 | { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, r13)}, | |
44 | { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, r14)}, | |
45 | { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, r15)}, | |
46 | { "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, r16)}, | |
47 | { "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, r17)}, | |
48 | { "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, r18)}, | |
49 | { "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, r19)}, | |
50 | { "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, r20)}, | |
51 | { "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, r21)}, | |
52 | { "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, r22)}, | |
53 | { "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, r23)}, | |
54 | { "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, r24)}, | |
55 | { "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, r25)}, | |
56 | { "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, r26)}, | |
57 | { "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, r27)}, | |
58 | { "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, r28)}, | |
59 | { "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, r29)}, | |
60 | { "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, r30)}, | |
61 | { "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, r31)}, | |
62 | ||
63 | { "usr", GDB_SIZEOF_REG, offsetof(struct pt_regs, usr)}, | |
64 | { "preds", GDB_SIZEOF_REG, offsetof(struct pt_regs, preds)}, | |
65 | { " m0", GDB_SIZEOF_REG, offsetof(struct pt_regs, m0)}, | |
66 | { " m1", GDB_SIZEOF_REG, offsetof(struct pt_regs, m1)}, | |
67 | { "sa0", GDB_SIZEOF_REG, offsetof(struct pt_regs, sa0)}, | |
68 | { "sa1", GDB_SIZEOF_REG, offsetof(struct pt_regs, sa1)}, | |
69 | { "lc0", GDB_SIZEOF_REG, offsetof(struct pt_regs, lc0)}, | |
70 | { "lc1", GDB_SIZEOF_REG, offsetof(struct pt_regs, lc1)}, | |
71 | { " gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, gp)}, | |
72 | { "ugp", GDB_SIZEOF_REG, offsetof(struct pt_regs, ugp)}, | |
60c4ba99 RK |
73 | { "cs0", GDB_SIZEOF_REG, offsetof(struct pt_regs, cs0)}, |
74 | { "cs1", GDB_SIZEOF_REG, offsetof(struct pt_regs, cs1)}, | |
0d71e879 LV |
75 | { "psp", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmpsp)}, |
76 | { "elr", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmel)}, | |
77 | { "est", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmest)}, | |
78 | { "badva", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmbadva)}, | |
79 | { "restart_r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, restart_r0)}, | |
80 | { "syscall_nr", GDB_SIZEOF_REG, offsetof(struct pt_regs, syscall_nr)}, | |
81 | }; | |
82 | ||
83 | struct kgdb_arch arch_kgdb_ops = { | |
84 | /* trap0(#0xDB) 0x0cdb0054 */ | |
85 | .gdb_bpt_instr = {0x54, 0x00, 0xdb, 0x0c}, | |
86 | }; | |
87 | ||
88 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) | |
89 | { | |
90 | if (regno >= DBG_MAX_REG_NUM || regno < 0) | |
91 | return NULL; | |
92 | ||
93 | *((unsigned long *) mem) = *((unsigned long *) ((void *)regs + | |
94 | dbg_reg_def[regno].offset)); | |
95 | ||
96 | return dbg_reg_def[regno].name; | |
97 | } | |
98 | ||
99 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) | |
100 | { | |
101 | if (regno >= DBG_MAX_REG_NUM || regno < 0) | |
102 | return -EINVAL; | |
103 | ||
104 | *((unsigned long *) ((void *)regs + dbg_reg_def[regno].offset)) = | |
105 | *((unsigned long *) mem); | |
106 | ||
107 | return 0; | |
108 | } | |
109 | ||
110 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) | |
111 | { | |
112 | instruction_pointer(regs) = pc; | |
113 | } | |
114 | ||
115 | #ifdef CONFIG_SMP | |
116 | ||
117 | /** | |
118 | * kgdb_roundup_cpus - Get other CPUs into a holding pattern | |
119 | * @flags: Current IRQ state | |
120 | * | |
121 | * On SMP systems, we need to get the attention of the other CPUs | |
122 | * and get them be in a known state. This should do what is needed | |
123 | * to get the other CPUs to call kgdb_wait(). Note that on some arches, | |
124 | * the NMI approach is not used for rounding up all the CPUs. For example, | |
125 | * in case of MIPS, smp_call_function() is used to roundup CPUs. In | |
126 | * this case, we have to make sure that interrupts are enabled before | |
127 | * calling smp_call_function(). The argument to this function is | |
128 | * the flags that will be used when restoring the interrupts. There is | |
129 | * local_irq_save() call before kgdb_roundup_cpus(). | |
130 | * | |
131 | * On non-SMP systems, this is not called. | |
132 | */ | |
133 | ||
134 | static void hexagon_kgdb_nmi_hook(void *ignored) | |
135 | { | |
136 | kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs()); | |
137 | } | |
138 | ||
139 | void kgdb_roundup_cpus(unsigned long flags) | |
140 | { | |
141 | local_irq_enable(); | |
142 | smp_call_function(hexagon_kgdb_nmi_hook, NULL, 0); | |
143 | local_irq_disable(); | |
144 | } | |
145 | #endif | |
146 | ||
147 | ||
148 | /* Not yet working */ | |
149 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, | |
150 | struct task_struct *task) | |
151 | { | |
152 | struct pt_regs *thread_regs; | |
153 | ||
154 | if (task == NULL) | |
155 | return; | |
156 | ||
157 | /* Initialize to zero */ | |
158 | memset(gdb_regs, 0, NUMREGBYTES); | |
159 | ||
160 | /* Otherwise, we have only some registers from switch_to() */ | |
161 | thread_regs = task_pt_regs(task); | |
162 | gdb_regs[0] = thread_regs->r00; | |
163 | } | |
164 | ||
165 | /** | |
166 | * kgdb_arch_handle_exception - Handle architecture specific GDB packets. | |
167 | * @vector: The error vector of the exception that happened. | |
168 | * @signo: The signal number of the exception that happened. | |
169 | * @err_code: The error code of the exception that happened. | |
170 | * @remcom_in_buffer: The buffer of the packet we have read. | |
171 | * @remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into. | |
172 | * @regs: The &struct pt_regs of the current process. | |
173 | * | |
174 | * This function MUST handle the 'c' and 's' command packets, | |
175 | * as well packets to set / remove a hardware breakpoint, if used. | |
176 | * If there are additional packets which the hardware needs to handle, | |
177 | * they are handled here. The code should return -1 if it wants to | |
178 | * process more packets, and a %0 or %1 if it wants to exit from the | |
179 | * kgdb callback. | |
180 | * | |
181 | * Not yet working. | |
182 | */ | |
183 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, | |
184 | char *remcom_in_buffer, char *remcom_out_buffer, | |
185 | struct pt_regs *linux_regs) | |
186 | { | |
187 | switch (remcom_in_buffer[0]) { | |
188 | case 's': | |
189 | case 'c': | |
190 | return 0; | |
191 | } | |
192 | /* Stay in the debugger. */ | |
193 | return -1; | |
194 | } | |
195 | ||
196 | static int __kgdb_notify(struct die_args *args, unsigned long cmd) | |
197 | { | |
198 | /* cpu roundup */ | |
199 | if (atomic_read(&kgdb_active) != -1) { | |
200 | kgdb_nmicallback(smp_processor_id(), args->regs); | |
201 | return NOTIFY_STOP; | |
202 | } | |
203 | ||
204 | if (user_mode(args->regs)) | |
205 | return NOTIFY_DONE; | |
206 | ||
207 | if (kgdb_handle_exception(args->trapnr & 0xff, args->signr, args->err, | |
208 | args->regs)) | |
209 | return NOTIFY_DONE; | |
210 | ||
211 | return NOTIFY_STOP; | |
212 | } | |
213 | ||
214 | static int | |
215 | kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) | |
216 | { | |
217 | unsigned long flags; | |
218 | int ret; | |
219 | ||
220 | local_irq_save(flags); | |
221 | ret = __kgdb_notify(ptr, cmd); | |
222 | local_irq_restore(flags); | |
223 | ||
224 | return ret; | |
225 | } | |
226 | ||
227 | static struct notifier_block kgdb_notifier = { | |
228 | .notifier_call = kgdb_notify, | |
229 | ||
230 | /* | |
231 | * Lowest-prio notifier priority, we want to be notified last: | |
232 | */ | |
233 | .priority = -INT_MAX, | |
234 | }; | |
235 | ||
236 | /** | |
237 | * kgdb_arch_init - Perform any architecture specific initalization. | |
238 | * | |
239 | * This function will handle the initalization of any architecture | |
240 | * specific callbacks. | |
241 | */ | |
242 | int kgdb_arch_init(void) | |
243 | { | |
244 | return register_die_notifier(&kgdb_notifier); | |
245 | } | |
246 | ||
247 | /** | |
248 | * kgdb_arch_exit - Perform any architecture specific uninitalization. | |
249 | * | |
250 | * This function will handle the uninitalization of any architecture | |
251 | * specific callbacks, for dynamic registration and unregistration. | |
252 | */ | |
253 | void kgdb_arch_exit(void) | |
254 | { | |
255 | unregister_die_notifier(&kgdb_notifier); | |
256 | } |