1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * AArch64 KGDB support |
4 | * |
5 | * Based on arch/arm/kernel/kgdb.c |
6 | * |
7 | * Copyright (C) 2013 Cavium Inc. |
8 | * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.com> |
9 | */ |
10 | |
11 | #include <linux/bug.h> |
12 | #include <linux/irq.h> |
13 | #include <linux/kdebug.h> |
14 | #include <linux/kgdb.h> |
15 | #include <linux/kprobes.h> |
16 | #include <linux/sched/task_stack.h> |
17 | |
18 | #include <asm/debug-monitors.h> |
19 | #include <asm/insn.h> |
20 | #include <asm/patching.h> |
21 | #include <asm/traps.h> |
22 | |
23 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { |
24 | { "x0" , 8, offsetof(struct pt_regs, regs[0])}, |
25 | { "x1" , 8, offsetof(struct pt_regs, regs[1])}, |
26 | { "x2" , 8, offsetof(struct pt_regs, regs[2])}, |
27 | { "x3" , 8, offsetof(struct pt_regs, regs[3])}, |
28 | { "x4" , 8, offsetof(struct pt_regs, regs[4])}, |
29 | { "x5" , 8, offsetof(struct pt_regs, regs[5])}, |
30 | { "x6" , 8, offsetof(struct pt_regs, regs[6])}, |
31 | { "x7" , 8, offsetof(struct pt_regs, regs[7])}, |
32 | { "x8" , 8, offsetof(struct pt_regs, regs[8])}, |
33 | { "x9" , 8, offsetof(struct pt_regs, regs[9])}, |
34 | { "x10" , 8, offsetof(struct pt_regs, regs[10])}, |
35 | { "x11" , 8, offsetof(struct pt_regs, regs[11])}, |
36 | { "x12" , 8, offsetof(struct pt_regs, regs[12])}, |
37 | { "x13" , 8, offsetof(struct pt_regs, regs[13])}, |
38 | { "x14" , 8, offsetof(struct pt_regs, regs[14])}, |
39 | { "x15" , 8, offsetof(struct pt_regs, regs[15])}, |
40 | { "x16" , 8, offsetof(struct pt_regs, regs[16])}, |
41 | { "x17" , 8, offsetof(struct pt_regs, regs[17])}, |
42 | { "x18" , 8, offsetof(struct pt_regs, regs[18])}, |
43 | { "x19" , 8, offsetof(struct pt_regs, regs[19])}, |
44 | { "x20" , 8, offsetof(struct pt_regs, regs[20])}, |
45 | { "x21" , 8, offsetof(struct pt_regs, regs[21])}, |
46 | { "x22" , 8, offsetof(struct pt_regs, regs[22])}, |
47 | { "x23" , 8, offsetof(struct pt_regs, regs[23])}, |
48 | { "x24" , 8, offsetof(struct pt_regs, regs[24])}, |
49 | { "x25" , 8, offsetof(struct pt_regs, regs[25])}, |
50 | { "x26" , 8, offsetof(struct pt_regs, regs[26])}, |
51 | { "x27" , 8, offsetof(struct pt_regs, regs[27])}, |
52 | { "x28" , 8, offsetof(struct pt_regs, regs[28])}, |
53 | { "x29" , 8, offsetof(struct pt_regs, regs[29])}, |
54 | { "x30" , 8, offsetof(struct pt_regs, regs[30])}, |
55 | { "sp" , 8, offsetof(struct pt_regs, sp)}, |
56 | { "pc" , 8, offsetof(struct pt_regs, pc)}, |
57 | /* |
58 | * struct pt_regs thinks PSTATE is 64-bits wide but gdb remote |
59 | * protocol disagrees. Therefore we must extract only the lower |
60 | * 32-bits. Look for the big comment in asm/kgdb.h for more |
61 | * detail. |
62 | */ |
63 | { "pstate" , 4, offsetof(struct pt_regs, pstate) |
64 | #ifdef CONFIG_CPU_BIG_ENDIAN |
65 | + 4 |
66 | #endif |
67 | }, |
68 | { "v0" , 16, -1 }, |
69 | { "v1" , 16, -1 }, |
70 | { "v2" , 16, -1 }, |
71 | { "v3" , 16, -1 }, |
72 | { "v4" , 16, -1 }, |
73 | { "v5" , 16, -1 }, |
74 | { "v6" , 16, -1 }, |
75 | { "v7" , 16, -1 }, |
76 | { "v8" , 16, -1 }, |
77 | { "v9" , 16, -1 }, |
78 | { "v10" , 16, -1 }, |
79 | { "v11" , 16, -1 }, |
80 | { "v12" , 16, -1 }, |
81 | { "v13" , 16, -1 }, |
82 | { "v14" , 16, -1 }, |
83 | { "v15" , 16, -1 }, |
84 | { "v16" , 16, -1 }, |
85 | { "v17" , 16, -1 }, |
86 | { "v18" , 16, -1 }, |
87 | { "v19" , 16, -1 }, |
88 | { "v20" , 16, -1 }, |
89 | { "v21" , 16, -1 }, |
90 | { "v22" , 16, -1 }, |
91 | { "v23" , 16, -1 }, |
92 | { "v24" , 16, -1 }, |
93 | { "v25" , 16, -1 }, |
94 | { "v26" , 16, -1 }, |
95 | { "v27" , 16, -1 }, |
96 | { "v28" , 16, -1 }, |
97 | { "v29" , 16, -1 }, |
98 | { "v30" , 16, -1 }, |
99 | { "v31" , 16, -1 }, |
100 | { "fpsr" , 4, -1 }, |
101 | { "fpcr" , 4, -1 }, |
102 | }; |
103 | |
104 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
105 | { |
106 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
107 | return NULL; |
108 | |
109 | if (dbg_reg_def[regno].offset != -1) |
110 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, |
111 | dbg_reg_def[regno].size); |
112 | else |
113 | memset(mem, 0, dbg_reg_def[regno].size); |
114 | return dbg_reg_def[regno].name; |
115 | } |
116 | |
117 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) |
118 | { |
119 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
120 | return -EINVAL; |
121 | |
122 | if (dbg_reg_def[regno].offset != -1) |
123 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, |
124 | dbg_reg_def[regno].size); |
125 | return 0; |
126 | } |
127 | |
128 | void |
129 | sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) |
130 | { |
131 | struct cpu_context *cpu_context = &task->thread.cpu_context; |
132 | |
133 | /* Initialize to zero */ |
134 | memset((char *)gdb_regs, 0, NUMREGBYTES); |
135 | |
136 | gdb_regs[19] = cpu_context->x19; |
137 | gdb_regs[20] = cpu_context->x20; |
138 | gdb_regs[21] = cpu_context->x21; |
139 | gdb_regs[22] = cpu_context->x22; |
140 | gdb_regs[23] = cpu_context->x23; |
141 | gdb_regs[24] = cpu_context->x24; |
142 | gdb_regs[25] = cpu_context->x25; |
143 | gdb_regs[26] = cpu_context->x26; |
144 | gdb_regs[27] = cpu_context->x27; |
145 | gdb_regs[28] = cpu_context->x28; |
146 | gdb_regs[29] = cpu_context->fp; |
147 | |
148 | gdb_regs[31] = cpu_context->sp; |
149 | gdb_regs[32] = cpu_context->pc; |
150 | } |
151 | |
152 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) |
153 | { |
154 | regs->pc = pc; |
155 | } |
156 | |
157 | static int compiled_break; |
158 | |
159 | static void kgdb_arch_update_addr(struct pt_regs *regs, |
160 | char *remcom_in_buffer) |
161 | { |
162 | unsigned long addr; |
163 | char *ptr; |
164 | |
165 | ptr = &remcom_in_buffer[1]; |
166 | if (kgdb_hex2long(ptr: &ptr, long_val: &addr)) |
167 | kgdb_arch_set_pc(regs, pc: addr); |
168 | else if (compiled_break == 1) |
169 | kgdb_arch_set_pc(regs, pc: regs->pc + 4); |
170 | |
171 | compiled_break = 0; |
172 | } |
173 | |
174 | int kgdb_arch_handle_exception(int exception_vector, int signo, |
175 | int err_code, char *remcom_in_buffer, |
176 | char *remcom_out_buffer, |
177 | struct pt_regs *linux_regs) |
178 | { |
179 | int err; |
180 | |
181 | switch (remcom_in_buffer[0]) { |
182 | case 'D': |
183 | case 'k': |
184 | /* |
185 | * Packet D (Detach), k (kill). No special handling |
186 | * is required here. Handle same as c packet. |
187 | */ |
188 | case 'c': |
189 | /* |
190 | * Packet c (Continue) to continue executing. |
191 | * Set pc to required address. |
192 | * Try to read optional parameter and set pc. |
193 | * If this was a compiled breakpoint, we need to move |
194 | * to the next instruction else we will just breakpoint |
195 | * over and over again. |
196 | */ |
197 | kgdb_arch_update_addr(regs: linux_regs, remcom_in_buffer); |
198 | atomic_set(v: &kgdb_cpu_doing_single_step, i: -1); |
199 | kgdb_single_step = 0; |
200 | |
201 | /* |
202 | * Received continue command, disable single step |
203 | */ |
204 | if (kernel_active_single_step()) |
205 | kernel_disable_single_step(); |
206 | |
207 | err = 0; |
208 | break; |
209 | case 's': |
210 | /* |
211 | * Update step address value with address passed |
212 | * with step packet. |
213 | * On debug exception return PC is copied to ELR |
214 | * So just update PC. |
215 | * If no step address is passed, resume from the address |
216 | * pointed by PC. Do not update PC |
217 | */ |
218 | kgdb_arch_update_addr(regs: linux_regs, remcom_in_buffer); |
219 | atomic_set(v: &kgdb_cpu_doing_single_step, raw_smp_processor_id()); |
220 | kgdb_single_step = 1; |
221 | |
222 | /* |
223 | * Enable single step handling |
224 | */ |
225 | if (!kernel_active_single_step()) |
226 | kernel_enable_single_step(linux_regs); |
227 | else |
228 | kernel_rewind_single_step(linux_regs); |
229 | err = 0; |
230 | break; |
231 | default: |
232 | err = -1; |
233 | } |
234 | return err; |
235 | } |
236 | |
237 | static int kgdb_brk_fn(struct pt_regs *regs, unsigned long esr) |
238 | { |
239 | kgdb_handle_exception(ex_vector: 1, SIGTRAP, err_code: 0, regs); |
240 | return DBG_HOOK_HANDLED; |
241 | } |
242 | NOKPROBE_SYMBOL(kgdb_brk_fn) |
243 | |
244 | static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned long esr) |
245 | { |
246 | compiled_break = 1; |
247 | kgdb_handle_exception(ex_vector: 1, SIGTRAP, err_code: 0, regs); |
248 | |
249 | return DBG_HOOK_HANDLED; |
250 | } |
251 | NOKPROBE_SYMBOL(kgdb_compiled_brk_fn); |
252 | |
253 | static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned long esr) |
254 | { |
255 | if (!kgdb_single_step) |
256 | return DBG_HOOK_ERROR; |
257 | |
258 | kgdb_handle_exception(ex_vector: 0, SIGTRAP, err_code: 0, regs); |
259 | return DBG_HOOK_HANDLED; |
260 | } |
261 | NOKPROBE_SYMBOL(kgdb_step_brk_fn); |
262 | |
263 | static struct break_hook kgdb_brkpt_hook = { |
264 | .fn = kgdb_brk_fn, |
265 | .imm = KGDB_DYN_DBG_BRK_IMM, |
266 | }; |
267 | |
268 | static struct break_hook kgdb_compiled_brkpt_hook = { |
269 | .fn = kgdb_compiled_brk_fn, |
270 | .imm = KGDB_COMPILED_DBG_BRK_IMM, |
271 | }; |
272 | |
273 | static struct step_hook kgdb_step_hook = { |
274 | .fn = kgdb_step_brk_fn |
275 | }; |
276 | |
277 | static int __kgdb_notify(struct die_args *args, unsigned long cmd) |
278 | { |
279 | struct pt_regs *regs = args->regs; |
280 | |
281 | if (kgdb_handle_exception(ex_vector: 1, signo: args->signr, err_code: cmd, regs)) |
282 | return NOTIFY_DONE; |
283 | return NOTIFY_STOP; |
284 | } |
285 | |
286 | static int |
287 | kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) |
288 | { |
289 | unsigned long flags; |
290 | int ret; |
291 | |
292 | local_irq_save(flags); |
293 | ret = __kgdb_notify(args: ptr, cmd); |
294 | local_irq_restore(flags); |
295 | |
296 | return ret; |
297 | } |
298 | |
299 | static struct notifier_block kgdb_notifier = { |
300 | .notifier_call = kgdb_notify, |
301 | /* |
302 | * Want to be lowest priority |
303 | */ |
304 | .priority = -INT_MAX, |
305 | }; |
306 | |
307 | /* |
308 | * kgdb_arch_init - Perform any architecture specific initialization. |
309 | * This function will handle the initialization of any architecture |
310 | * specific callbacks. |
311 | */ |
312 | int kgdb_arch_init(void) |
313 | { |
314 | int ret = register_die_notifier(nb: &kgdb_notifier); |
315 | |
316 | if (ret != 0) |
317 | return ret; |
318 | |
319 | register_kernel_break_hook(&kgdb_brkpt_hook); |
320 | register_kernel_break_hook(&kgdb_compiled_brkpt_hook); |
321 | register_kernel_step_hook(&kgdb_step_hook); |
322 | return 0; |
323 | } |
324 | |
325 | /* |
326 | * kgdb_arch_exit - Perform any architecture specific uninitalization. |
327 | * This function will handle the uninitalization of any architecture |
328 | * specific callbacks, for dynamic registration and unregistration. |
329 | */ |
330 | void kgdb_arch_exit(void) |
331 | { |
332 | unregister_kernel_break_hook(&kgdb_brkpt_hook); |
333 | unregister_kernel_break_hook(&kgdb_compiled_brkpt_hook); |
334 | unregister_kernel_step_hook(&kgdb_step_hook); |
335 | unregister_die_notifier(nb: &kgdb_notifier); |
336 | } |
337 | |
338 | const struct kgdb_arch arch_kgdb_ops; |
339 | |
340 | int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) |
341 | { |
342 | int err; |
343 | |
344 | BUILD_BUG_ON(AARCH64_INSN_SIZE != BREAK_INSTR_SIZE); |
345 | |
346 | err = aarch64_insn_read((void *)bpt->bpt_addr, (u32 *)bpt->saved_instr); |
347 | if (err) |
348 | return err; |
349 | |
350 | return aarch64_insn_write((void *)bpt->bpt_addr, |
351 | (u32)AARCH64_BREAK_KGDB_DYN_DBG); |
352 | } |
353 | |
354 | int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) |
355 | { |
356 | return aarch64_insn_write((void *)bpt->bpt_addr, |
357 | *(u32 *)bpt->saved_instr); |
358 | } |
359 | |