1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2a88b5ba8SSam Ravnborg /* kgdb.c: KGDB support for 64-bit sparc.
3a88b5ba8SSam Ravnborg *
4a88b5ba8SSam Ravnborg * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
5a88b5ba8SSam Ravnborg */
6a88b5ba8SSam Ravnborg
7a88b5ba8SSam Ravnborg #include <linux/kgdb.h>
8a88b5ba8SSam Ravnborg #include <linux/kdebug.h>
99960e9e8SDavid S. Miller #include <linux/ftrace.h>
101de425c7SKirill Tkhai #include <linux/context_tracking.h>
11a88b5ba8SSam Ravnborg
128befc9f2SDavid S. Miller #include <asm/cacheflush.h>
13a88b5ba8SSam Ravnborg #include <asm/kdebug.h>
14a88b5ba8SSam Ravnborg #include <asm/ptrace.h>
15a88b5ba8SSam Ravnborg #include <asm/irq.h>
16a88b5ba8SSam Ravnborg
1748c7eca5SSam Ravnborg #include "kernel.h"
1848c7eca5SSam Ravnborg
pt_regs_to_gdb_regs(unsigned long * gdb_regs,struct pt_regs * regs)19a88b5ba8SSam Ravnborg void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
20a88b5ba8SSam Ravnborg {
21a88b5ba8SSam Ravnborg struct reg_window *win;
22a88b5ba8SSam Ravnborg int i;
23a88b5ba8SSam Ravnborg
24a88b5ba8SSam Ravnborg gdb_regs[GDB_G0] = 0;
25a88b5ba8SSam Ravnborg for (i = 0; i < 15; i++)
26a88b5ba8SSam Ravnborg gdb_regs[GDB_G1 + i] = regs->u_regs[UREG_G1 + i];
27a88b5ba8SSam Ravnborg
28a88b5ba8SSam Ravnborg win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
29a88b5ba8SSam Ravnborg for (i = 0; i < 8; i++)
30a88b5ba8SSam Ravnborg gdb_regs[GDB_L0 + i] = win->locals[i];
31a88b5ba8SSam Ravnborg for (i = 0; i < 8; i++)
32a88b5ba8SSam Ravnborg gdb_regs[GDB_I0 + i] = win->ins[i];
33a88b5ba8SSam Ravnborg
34a88b5ba8SSam Ravnborg for (i = GDB_F0; i <= GDB_F62; i++)
35a88b5ba8SSam Ravnborg gdb_regs[i] = 0;
36a88b5ba8SSam Ravnborg
37a88b5ba8SSam Ravnborg gdb_regs[GDB_PC] = regs->tpc;
38a88b5ba8SSam Ravnborg gdb_regs[GDB_NPC] = regs->tnpc;
39a88b5ba8SSam Ravnborg gdb_regs[GDB_STATE] = regs->tstate;
40a88b5ba8SSam Ravnborg gdb_regs[GDB_FSR] = 0;
41a88b5ba8SSam Ravnborg gdb_regs[GDB_FPRS] = 0;
42a88b5ba8SSam Ravnborg gdb_regs[GDB_Y] = regs->y;
43a88b5ba8SSam Ravnborg }
44a88b5ba8SSam Ravnborg
sleeping_thread_to_gdb_regs(unsigned long * gdb_regs,struct task_struct * p)45a88b5ba8SSam Ravnborg void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
46a88b5ba8SSam Ravnborg {
47a88b5ba8SSam Ravnborg struct thread_info *t = task_thread_info(p);
48a88b5ba8SSam Ravnborg extern unsigned int switch_to_pc;
4937d6fa34SKirill Tkhai extern unsigned int ret_from_fork;
50a88b5ba8SSam Ravnborg struct reg_window *win;
51a88b5ba8SSam Ravnborg unsigned long pc, cwp;
52a88b5ba8SSam Ravnborg int i;
53a88b5ba8SSam Ravnborg
54a88b5ba8SSam Ravnborg for (i = GDB_G0; i < GDB_G6; i++)
55a88b5ba8SSam Ravnborg gdb_regs[i] = 0;
56a88b5ba8SSam Ravnborg gdb_regs[GDB_G6] = (unsigned long) t;
57a88b5ba8SSam Ravnborg gdb_regs[GDB_G7] = (unsigned long) p;
58a88b5ba8SSam Ravnborg for (i = GDB_O0; i < GDB_SP; i++)
59a88b5ba8SSam Ravnborg gdb_regs[i] = 0;
60a88b5ba8SSam Ravnborg gdb_regs[GDB_SP] = t->ksp;
61a88b5ba8SSam Ravnborg gdb_regs[GDB_O7] = 0;
62a88b5ba8SSam Ravnborg
63a88b5ba8SSam Ravnborg win = (struct reg_window *) (t->ksp + STACK_BIAS);
64a88b5ba8SSam Ravnborg for (i = 0; i < 8; i++)
65a88b5ba8SSam Ravnborg gdb_regs[GDB_L0 + i] = win->locals[i];
66a88b5ba8SSam Ravnborg for (i = 0; i < 8; i++)
67a88b5ba8SSam Ravnborg gdb_regs[GDB_I0 + i] = win->ins[i];
68a88b5ba8SSam Ravnborg
69a88b5ba8SSam Ravnborg for (i = GDB_F0; i <= GDB_F62; i++)
70a88b5ba8SSam Ravnborg gdb_regs[i] = 0;
71a88b5ba8SSam Ravnborg
72a88b5ba8SSam Ravnborg if (t->new_child)
7337d6fa34SKirill Tkhai pc = (unsigned long) &ret_from_fork;
74a88b5ba8SSam Ravnborg else
75a88b5ba8SSam Ravnborg pc = (unsigned long) &switch_to_pc;
76a88b5ba8SSam Ravnborg
77a88b5ba8SSam Ravnborg gdb_regs[GDB_PC] = pc;
78a88b5ba8SSam Ravnborg gdb_regs[GDB_NPC] = pc + 4;
79a88b5ba8SSam Ravnborg
80a88b5ba8SSam Ravnborg cwp = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP];
81a88b5ba8SSam Ravnborg
82a88b5ba8SSam Ravnborg gdb_regs[GDB_STATE] = (TSTATE_PRIV | TSTATE_IE | cwp);
83a88b5ba8SSam Ravnborg gdb_regs[GDB_FSR] = 0;
84a88b5ba8SSam Ravnborg gdb_regs[GDB_FPRS] = 0;
85a88b5ba8SSam Ravnborg gdb_regs[GDB_Y] = 0;
86a88b5ba8SSam Ravnborg }
87a88b5ba8SSam Ravnborg
gdb_regs_to_pt_regs(unsigned long * gdb_regs,struct pt_regs * regs)88a88b5ba8SSam Ravnborg void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
89a88b5ba8SSam Ravnborg {
90a88b5ba8SSam Ravnborg struct reg_window *win;
91a88b5ba8SSam Ravnborg int i;
92a88b5ba8SSam Ravnborg
93a88b5ba8SSam Ravnborg for (i = 0; i < 15; i++)
94a88b5ba8SSam Ravnborg regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i];
95a88b5ba8SSam Ravnborg
96a88b5ba8SSam Ravnborg /* If the TSTATE register is changing, we have to preserve
97a88b5ba8SSam Ravnborg * the CWP field, otherwise window save/restore explodes.
98a88b5ba8SSam Ravnborg */
99a88b5ba8SSam Ravnborg if (regs->tstate != gdb_regs[GDB_STATE]) {
100a88b5ba8SSam Ravnborg unsigned long cwp = regs->tstate & TSTATE_CWP;
101a88b5ba8SSam Ravnborg
102a88b5ba8SSam Ravnborg regs->tstate = (gdb_regs[GDB_STATE] & ~TSTATE_CWP) | cwp;
103a88b5ba8SSam Ravnborg }
104a88b5ba8SSam Ravnborg
105a88b5ba8SSam Ravnborg regs->tpc = gdb_regs[GDB_PC];
106a88b5ba8SSam Ravnborg regs->tnpc = gdb_regs[GDB_NPC];
107a88b5ba8SSam Ravnborg regs->y = gdb_regs[GDB_Y];
108a88b5ba8SSam Ravnborg
109a88b5ba8SSam Ravnborg win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
110a88b5ba8SSam Ravnborg for (i = 0; i < 8; i++)
111a88b5ba8SSam Ravnborg win->locals[i] = gdb_regs[GDB_L0 + i];
112a88b5ba8SSam Ravnborg for (i = 0; i < 8; i++)
113a88b5ba8SSam Ravnborg win->ins[i] = gdb_regs[GDB_I0 + i];
114a88b5ba8SSam Ravnborg }
115a88b5ba8SSam Ravnborg
116a88b5ba8SSam Ravnborg #ifdef CONFIG_SMP
smp_kgdb_capture_client(int irq,struct pt_regs * regs)1179960e9e8SDavid S. Miller void __irq_entry smp_kgdb_capture_client(int irq, struct pt_regs *regs)
118a88b5ba8SSam Ravnborg {
119a88b5ba8SSam Ravnborg unsigned long flags;
120a88b5ba8SSam Ravnborg
121a88b5ba8SSam Ravnborg __asm__ __volatile__("rdpr %%pstate, %0\n\t"
122a88b5ba8SSam Ravnborg "wrpr %0, %1, %%pstate"
123a88b5ba8SSam Ravnborg : "=r" (flags)
124a88b5ba8SSam Ravnborg : "i" (PSTATE_IE));
125a88b5ba8SSam Ravnborg
126a88b5ba8SSam Ravnborg flushw_all();
127a88b5ba8SSam Ravnborg
128a88b5ba8SSam Ravnborg if (atomic_read(&kgdb_active) != -1)
129a88b5ba8SSam Ravnborg kgdb_nmicallback(raw_smp_processor_id(), regs);
130a88b5ba8SSam Ravnborg
131a88b5ba8SSam Ravnborg __asm__ __volatile__("wrpr %0, 0, %%pstate"
132a88b5ba8SSam Ravnborg : : "r" (flags));
133a88b5ba8SSam Ravnborg }
134a88b5ba8SSam Ravnborg #endif
135a88b5ba8SSam Ravnborg
kgdb_arch_handle_exception(int e_vector,int signo,int err_code,char * remcomInBuffer,char * remcomOutBuffer,struct pt_regs * linux_regs)136a88b5ba8SSam Ravnborg int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
137a88b5ba8SSam Ravnborg char *remcomInBuffer, char *remcomOutBuffer,
138a88b5ba8SSam Ravnborg struct pt_regs *linux_regs)
139a88b5ba8SSam Ravnborg {
140a88b5ba8SSam Ravnborg unsigned long addr;
141a88b5ba8SSam Ravnborg char *ptr;
142a88b5ba8SSam Ravnborg
143a88b5ba8SSam Ravnborg switch (remcomInBuffer[0]) {
144a88b5ba8SSam Ravnborg case 'c':
145a88b5ba8SSam Ravnborg /* try to read optional parameter, pc unchanged if no parm */
146a88b5ba8SSam Ravnborg ptr = &remcomInBuffer[1];
147a88b5ba8SSam Ravnborg if (kgdb_hex2long(&ptr, &addr)) {
148a88b5ba8SSam Ravnborg linux_regs->tpc = addr;
149a88b5ba8SSam Ravnborg linux_regs->tnpc = addr + 4;
150a88b5ba8SSam Ravnborg }
151*df561f66SGustavo A. R. Silva fallthrough;
152a88b5ba8SSam Ravnborg
153a88b5ba8SSam Ravnborg case 'D':
154a88b5ba8SSam Ravnborg case 'k':
155a88b5ba8SSam Ravnborg if (linux_regs->tpc == (unsigned long) arch_kgdb_breakpoint) {
156a88b5ba8SSam Ravnborg linux_regs->tpc = linux_regs->tnpc;
157a88b5ba8SSam Ravnborg linux_regs->tnpc += 4;
158a88b5ba8SSam Ravnborg }
159a88b5ba8SSam Ravnborg return 0;
160a88b5ba8SSam Ravnborg }
161a88b5ba8SSam Ravnborg return -1;
162a88b5ba8SSam Ravnborg }
163a88b5ba8SSam Ravnborg
kgdb_trap(unsigned long trap_level,struct pt_regs * regs)164a88b5ba8SSam Ravnborg asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs)
165a88b5ba8SSam Ravnborg {
166812cb83aSKirill Tkhai enum ctx_state prev_state = exception_enter();
167a88b5ba8SSam Ravnborg unsigned long flags;
168a88b5ba8SSam Ravnborg
169a88b5ba8SSam Ravnborg if (user_mode(regs)) {
170a88b5ba8SSam Ravnborg bad_trap(regs, trap_level);
171812cb83aSKirill Tkhai goto out;
172a88b5ba8SSam Ravnborg }
173a88b5ba8SSam Ravnborg
174a88b5ba8SSam Ravnborg flushw_all();
175a88b5ba8SSam Ravnborg
176a88b5ba8SSam Ravnborg local_irq_save(flags);
177a88b5ba8SSam Ravnborg kgdb_handle_exception(0x172, SIGTRAP, 0, regs);
178a88b5ba8SSam Ravnborg local_irq_restore(flags);
179812cb83aSKirill Tkhai out:
180812cb83aSKirill Tkhai exception_exit(prev_state);
181a88b5ba8SSam Ravnborg }
182a88b5ba8SSam Ravnborg
kgdb_arch_init(void)183a88b5ba8SSam Ravnborg int kgdb_arch_init(void)
184a88b5ba8SSam Ravnborg {
185a88b5ba8SSam Ravnborg return 0;
186a88b5ba8SSam Ravnborg }
187a88b5ba8SSam Ravnborg
kgdb_arch_exit(void)188a88b5ba8SSam Ravnborg void kgdb_arch_exit(void)
189a88b5ba8SSam Ravnborg {
190a88b5ba8SSam Ravnborg }
191a88b5ba8SSam Ravnborg
kgdb_arch_set_pc(struct pt_regs * regs,unsigned long ip)192c75fbb05SJason Wessel void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
193c75fbb05SJason Wessel {
194c75fbb05SJason Wessel regs->tpc = ip;
195c75fbb05SJason Wessel regs->tnpc = regs->tpc + 4;
196c75fbb05SJason Wessel }
197c75fbb05SJason Wessel
198cc028297SChristophe Leroy const struct kgdb_arch arch_kgdb_ops = {
199a88b5ba8SSam Ravnborg /* Breakpoint instruction: ta 0x72 */
200a88b5ba8SSam Ravnborg .gdb_bpt_instr = { 0x91, 0xd0, 0x20, 0x72 },
201a88b5ba8SSam Ravnborg };
202