xref: /openbmc/linux/arch/arm/kernel/kgdb.c (revision ecba1060)
1 /*
2  * arch/arm/kernel/kgdb.c
3  *
4  * ARM KGDB support
5  *
6  * Copyright (c) 2002-2004 MontaVista Software, Inc
7  * Copyright (c) 2008 Wind River Systems, Inc.
8  *
9  * Authors:  George Davis <davis_g@mvista.com>
10  *           Deepak Saxena <dsaxena@plexity.net>
11  */
12 #include <linux/kgdb.h>
13 #include <asm/traps.h>
14 
15 /* Make a local copy of the registers passed into the handler (bletch) */
16 void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
17 {
18 	int regno;
19 
20 	/* Initialize all to zero. */
21 	for (regno = 0; regno < GDB_MAX_REGS; regno++)
22 		gdb_regs[regno] = 0;
23 
24 	gdb_regs[_R0]		= kernel_regs->ARM_r0;
25 	gdb_regs[_R1]		= kernel_regs->ARM_r1;
26 	gdb_regs[_R2]		= kernel_regs->ARM_r2;
27 	gdb_regs[_R3]		= kernel_regs->ARM_r3;
28 	gdb_regs[_R4]		= kernel_regs->ARM_r4;
29 	gdb_regs[_R5]		= kernel_regs->ARM_r5;
30 	gdb_regs[_R6]		= kernel_regs->ARM_r6;
31 	gdb_regs[_R7]		= kernel_regs->ARM_r7;
32 	gdb_regs[_R8]		= kernel_regs->ARM_r8;
33 	gdb_regs[_R9]		= kernel_regs->ARM_r9;
34 	gdb_regs[_R10]		= kernel_regs->ARM_r10;
35 	gdb_regs[_FP]		= kernel_regs->ARM_fp;
36 	gdb_regs[_IP]		= kernel_regs->ARM_ip;
37 	gdb_regs[_SPT]		= kernel_regs->ARM_sp;
38 	gdb_regs[_LR]		= kernel_regs->ARM_lr;
39 	gdb_regs[_PC]		= kernel_regs->ARM_pc;
40 	gdb_regs[_CPSR]		= kernel_regs->ARM_cpsr;
41 }
42 
43 /* Copy local gdb registers back to kgdb regs, for later copy to kernel */
44 void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
45 {
46 	kernel_regs->ARM_r0	= gdb_regs[_R0];
47 	kernel_regs->ARM_r1	= gdb_regs[_R1];
48 	kernel_regs->ARM_r2	= gdb_regs[_R2];
49 	kernel_regs->ARM_r3	= gdb_regs[_R3];
50 	kernel_regs->ARM_r4	= gdb_regs[_R4];
51 	kernel_regs->ARM_r5	= gdb_regs[_R5];
52 	kernel_regs->ARM_r6	= gdb_regs[_R6];
53 	kernel_regs->ARM_r7	= gdb_regs[_R7];
54 	kernel_regs->ARM_r8	= gdb_regs[_R8];
55 	kernel_regs->ARM_r9	= gdb_regs[_R9];
56 	kernel_regs->ARM_r10	= gdb_regs[_R10];
57 	kernel_regs->ARM_fp	= gdb_regs[_FP];
58 	kernel_regs->ARM_ip	= gdb_regs[_IP];
59 	kernel_regs->ARM_sp	= gdb_regs[_SPT];
60 	kernel_regs->ARM_lr	= gdb_regs[_LR];
61 	kernel_regs->ARM_pc	= gdb_regs[_PC];
62 	kernel_regs->ARM_cpsr	= gdb_regs[_CPSR];
63 }
64 
65 void
66 sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
67 {
68 	struct pt_regs *thread_regs;
69 	int regno;
70 
71 	/* Just making sure... */
72 	if (task == NULL)
73 		return;
74 
75 	/* Initialize to zero */
76 	for (regno = 0; regno < GDB_MAX_REGS; regno++)
77 		gdb_regs[regno] = 0;
78 
79 	/* Otherwise, we have only some registers from switch_to() */
80 	thread_regs		= task_pt_regs(task);
81 	gdb_regs[_R0]		= thread_regs->ARM_r0;
82 	gdb_regs[_R1]		= thread_regs->ARM_r1;
83 	gdb_regs[_R2]		= thread_regs->ARM_r2;
84 	gdb_regs[_R3]		= thread_regs->ARM_r3;
85 	gdb_regs[_R4]		= thread_regs->ARM_r4;
86 	gdb_regs[_R5]		= thread_regs->ARM_r5;
87 	gdb_regs[_R6]		= thread_regs->ARM_r6;
88 	gdb_regs[_R7]		= thread_regs->ARM_r7;
89 	gdb_regs[_R8]		= thread_regs->ARM_r8;
90 	gdb_regs[_R9]		= thread_regs->ARM_r9;
91 	gdb_regs[_R10]		= thread_regs->ARM_r10;
92 	gdb_regs[_FP]		= thread_regs->ARM_fp;
93 	gdb_regs[_IP]		= thread_regs->ARM_ip;
94 	gdb_regs[_SPT]		= thread_regs->ARM_sp;
95 	gdb_regs[_LR]		= thread_regs->ARM_lr;
96 	gdb_regs[_PC]		= thread_regs->ARM_pc;
97 	gdb_regs[_CPSR]		= thread_regs->ARM_cpsr;
98 }
99 
100 static int compiled_break;
101 
102 int kgdb_arch_handle_exception(int exception_vector, int signo,
103 			       int err_code, char *remcom_in_buffer,
104 			       char *remcom_out_buffer,
105 			       struct pt_regs *linux_regs)
106 {
107 	unsigned long addr;
108 	char *ptr;
109 
110 	switch (remcom_in_buffer[0]) {
111 	case 'D':
112 	case 'k':
113 	case 'c':
114 		/*
115 		 * Try to read optional parameter, pc unchanged if no parm.
116 		 * If this was a compiled breakpoint, we need to move
117 		 * to the next instruction or we will just breakpoint
118 		 * over and over again.
119 		 */
120 		ptr = &remcom_in_buffer[1];
121 		if (kgdb_hex2long(&ptr, &addr))
122 			linux_regs->ARM_pc = addr;
123 		else if (compiled_break == 1)
124 			linux_regs->ARM_pc += 4;
125 
126 		compiled_break = 0;
127 
128 		return 0;
129 	}
130 
131 	return -1;
132 }
133 
134 static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr)
135 {
136 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
137 
138 	return 0;
139 }
140 
141 static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr)
142 {
143 	compiled_break = 1;
144 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
145 
146 	return 0;
147 }
148 
149 static struct undef_hook kgdb_brkpt_hook = {
150 	.instr_mask		= 0xffffffff,
151 	.instr_val		= KGDB_BREAKINST,
152 	.fn			= kgdb_brk_fn
153 };
154 
155 static struct undef_hook kgdb_compiled_brkpt_hook = {
156 	.instr_mask		= 0xffffffff,
157 	.instr_val		= KGDB_COMPILED_BREAK,
158 	.fn			= kgdb_compiled_brk_fn
159 };
160 
161 /**
162  *	kgdb_arch_init - Perform any architecture specific initalization.
163  *
164  *	This function will handle the initalization of any architecture
165  *	specific callbacks.
166  */
167 int kgdb_arch_init(void)
168 {
169 	register_undef_hook(&kgdb_brkpt_hook);
170 	register_undef_hook(&kgdb_compiled_brkpt_hook);
171 
172 	return 0;
173 }
174 
175 /**
176  *	kgdb_arch_exit - Perform any architecture specific uninitalization.
177  *
178  *	This function will handle the uninitalization of any architecture
179  *	specific callbacks, for dynamic registration and unregistration.
180  */
181 void kgdb_arch_exit(void)
182 {
183 	unregister_undef_hook(&kgdb_brkpt_hook);
184 	unregister_undef_hook(&kgdb_compiled_brkpt_hook);
185 }
186 
187 /*
188  * Register our undef instruction hooks with ARM undef core.
189  * We regsiter a hook specifically looking for the KGB break inst
190  * and we handle the normal undef case within the do_undefinstr
191  * handler.
192  */
193 struct kgdb_arch arch_kgdb_ops = {
194 #ifndef __ARMEB__
195 	.gdb_bpt_instr		= {0xfe, 0xde, 0xff, 0xe7}
196 #else /* ! __ARMEB__ */
197 	.gdb_bpt_instr		= {0xe7, 0xff, 0xde, 0xfe}
198 #endif
199 };
200