xref: /openbmc/linux/arch/sparc/kernel/kgdb_64.c (revision 17ec0a17)
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*17ec0a17SGustavo 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