xref: /netbsd-src/sys/arch/powerpc/powerpc/kgdb_machdep.c (revision bf2b4973da895f5cc85bdbf849d0ed13404727bc)
1 /*	$NetBSD: kgdb_machdep.c,v 1.26 2024/09/08 10:02:49 andvar Exp $	*/
2 
3 /*
4  * Copyright 2001 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Allen Briggs for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed for the NetBSD Project by
20  *      Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: kgdb_machdep.c,v 1.26 2024/09/08 10:02:49 andvar Exp $");
40 
41 #ifdef _KERNEL_OPT
42 #include "opt_ppcarch.h"
43 #endif
44 
45 /*
46  * Machine-dependent functions for remote KGDB.
47  */
48 
49 #include <sys/param.h>
50 #include <sys/kgdb.h>
51 #include <sys/systm.h>
52 
53 #include <uvm/uvm_extern.h>
54 
55 #include <machine/reg.h>
56 #include <machine/trap.h>
57 #include <machine/pmap.h>
58 #include <machine/psl.h>
59 
60 #include <powerpc/spr.h>
61 #if defined (PPC_OEA) || defined (PPC_OEA601) || defined (PPC_OEA64_BRIDGE)
62 #include <powerpc/oea/spr.h>
63 #include <powerpc/oea/bat.h>
64 
65 #elif defined (PPC_OEA64)
66 #include <powerpc/oea/spr.h>
67 
68 #elif defined (PPC_IBM4XX)
69 #include <powerpc/booke/spr.h>
70 
71 #elif defined (PPC_BOOKE)
72 #include <powerpc/booke/spr.h>
73 
74 #else
75 #error unknown architecture
76 #endif
77 
78 /*
79  * Determine if the memory at va..(va+len) is valid.
80  */
81 int
82 kgdb_acc(vaddr_t va, size_t len)
83 {
84 	vaddr_t   last_va;
85 	paddr_t   pa;
86 	u_int msr;
87 #if defined (PPC_OEA) || defined (PPC_OEA601) || defined (PPC_OEA64_BRIDGE)
88 	u_int batu;
89 #ifdef PPC_OEA601
90 	u_int batl;
91 #endif
92 #endif
93 
94 	/* If translation is off, everything is fair game */
95 	__asm volatile ("mfmsr %0" : "=r"(msr));
96 	if ((msr & PSL_DR) == 0) {
97 		return 1;
98 	}
99 
100 #if defined (PPC_OEA) || defined (PPC_OEA601) || defined (PPC_OEA64_BRIDGE)
101 	/* Now check battable registers */
102 #ifdef PPC_OEA601
103 	if ((mfpvr() >> 16) == MPC601) {
104 		__asm volatile ("mfibatl %0,0" : "=r"(batl));
105 		__asm volatile ("mfibatu %0,0" : "=r"(batu));
106 		if (BAT601_VALID_P(batl) &&
107 				BAT601_VA_MATCH_P(batu,batl,va))
108 			return 1;
109 		__asm volatile ("mfibatl %0,1" : "=r"(batl));
110 		__asm volatile ("mfibatu %0,1" : "=r"(batu));
111 		if (BAT601_VALID_P(batl) &&
112 				BAT601_VA_MATCH_P(batu,batl,va))
113 			return 1;
114 		__asm volatile ("mfibatl %0,2" : "=r"(batl));
115 		__asm volatile ("mfibatu %0,2" : "=r"(batu));
116 		if (BAT601_VALID_P(batl) &&
117 				BAT601_VA_MATCH_P(batu,batl,va))
118 			return 1;
119 		__asm volatile ("mfibatl %0,3" : "=r"(batl));
120 		__asm volatile ("mfibatu %0,3" : "=r"(batu));
121 		if (BAT601_VALID_P(batl) &&
122 				BAT601_VA_MATCH_P(batu,batl,va))
123 			return 1;
124 	} else {
125 #endif /* PPC_OEA601 */
126 		__asm volatile ("mfdbatu %0,0" : "=r"(batu));
127 		if (BAT_VALID_P(batu,msr) &&
128 				BAT_VA_MATCH_P(batu,va) &&
129 				(batu & BAT_PP) != BAT_PP_NONE) {
130 			return 1;
131 		}
132 		__asm volatile ("mfdbatu %0,1" : "=r"(batu));
133 		if (BAT_VALID_P(batu,msr) &&
134 				BAT_VA_MATCH_P(batu,va) &&
135 				(batu & BAT_PP) != BAT_PP_NONE) {
136 			return 1;
137 		}
138 		__asm volatile ("mfdbatu %0,2" : "=r"(batu));
139 		if (BAT_VALID_P(batu,msr) &&
140 				BAT_VA_MATCH_P(batu,va) &&
141 				(batu & BAT_PP) != BAT_PP_NONE) {
142 			return 1;
143 		}
144 		__asm volatile ("mfdbatu %0,3" : "=r"(batu));
145 		if (BAT_VALID_P(batu,msr) &&
146 				BAT_VA_MATCH_P(batu,va) &&
147 				(batu & BAT_PP) != BAT_PP_NONE) {
148 			return 1;
149 #ifdef PPC_OEA601
150 		}
151 #endif
152 	}
153 #endif /* PPC_OEA || PPC_OEA601 || PPC_OEA64_BRIDGE */
154 
155 #if defined(PPC_IBM4XX)
156 	/* Is it (supposed to be) TLB-reserved mapping? */
157 	if (va < VM_MIN_KERNEL_ADDRESS || va > VM_MAX_KERNEL_ADDRESS)
158 		return (1);
159 #endif
160 
161 	last_va = va + len;
162 	va  &= ~PGOFSET;
163 	last_va &= ~PGOFSET;
164 
165 	do {
166 		/*
167 		 * I think this should be able to handle
168 		 * non-pmap_kernel() va's, too.
169 		 */
170 		if (!pmap_extract(pmap_kernel(), va, &pa))
171 			return 0;
172 		va += PAGE_SIZE;
173 	} while (va <= last_va);
174 
175 	return (1);
176 }
177 
178 /*
179  * Translate a trap number into a unix compatible signal value.
180  * (gdb only understands unix signal numbers).  Some of these are bogus
181  * and should be reviewed.
182  */
183 int
184 kgdb_signal(int type)
185 {
186 	switch (type) {
187 #if defined (PPC_IBM4XX) || defined (PPC_BOOKE)
188 	case EXC_PIT:		/* 40x - Programmable interval timer */
189 	case EXC_FIT:		/* 40x - Fixed interval timer */
190 		return SIGALRM;
191 
192 	case EXC_CII:		/* 40x - Critical input interrupt */
193 	case EXC_WDOG:		/* 40x - Watchdog timer */
194 	case EXC_DEBUG:		/* 40x - Debug trap */
195 		return SIGTRAP;
196 
197 	case EXC_DTMISS:	/* 40x - Instruction TLB miss */
198 	case EXC_ITMISS:	/* 40x - Data TLB miss */
199 		return SIGSEGV;
200 #endif
201 
202 #if defined (PPC_OEA) || defined (PPC_OEA601) || defined (PPC_OEA64_BRIDGE)
203 	case EXC_PERF:		/* 604/750/7400 - Performance monitoring */
204 	case EXC_BPT:		/* 604/750/7400 - Instruction breakpoint */
205 	case EXC_SMI:		/* 604/750/7400 - System management interrupt */
206 	case EXC_THRM:		/* 750/7400 - Thermal management interrupt */
207 		return SIGTRAP;
208 
209 	case EXC_IMISS:		/* 603 - Instruction translation miss */
210 	case EXC_DLMISS:	/* 603 - Data load translation miss */
211 	case EXC_DSMISS:	/* 603 - Data store translation miss */
212 		return SIGSEGV;
213 
214 	case EXC_RST:		/* All but IBM 4xx - Reset */
215 		return SIGURG;
216 
217 	case EXC_VEC:		/* 7400 - Altivec unavailable */
218 	case EXC_VECAST:	/* 7400 - Altivec assist */
219 		return SIGFPE;
220 #endif
221 
222 	case EXC_DECR:		/* Decrementer interrupt */
223 		return SIGALRM;
224 
225 	case EXC_EXI:		/* External interrupt */
226 		return SIGINT;
227 
228 	case EXC_PGM:		/* Program interrupt */
229 	case EXC_ALI:		/* Alignment */
230 		return SIGILL;
231 
232   case T_BREAKPOINT:
233 	case EXC_MCHK:		/* Machine check */
234 	case EXC_TRC:		/* Trace */
235 		return SIGTRAP;
236 
237 	case EXC_ISI:		/* Instruction storage interrupt */
238 	case EXC_DSI:		/* Data storage interrupt */
239 		return SIGSEGV;
240 
241 	case EXC_FPU:		/* Floating point unavailable */
242 	case EXC_FPA:		/* Floating-point assist */
243 		return SIGFPE;
244 
245 	case EXC_SC:		/* System call */
246 		return SIGURG;
247 
248 	case EXC_RSVD:		/* Reserved */
249 	case EXC_AST:		/* Floating point unavailable */
250 	default:
251 		return SIGEMT;
252 	}
253 }
254 
255 /*
256  * Translate the values stored in the kernel regs struct to the format
257  * understood by gdb.
258  */
259 void
260 kgdb_getregs(db_regs_t *regs, kgdb_reg_t *gdb_regs)
261 {
262 	memcpy(gdb_regs, regs, 32 * sizeof(unsigned long));
263 	gdb_regs[KGDB_PPC_PC_REG]  = regs->iar;
264 	gdb_regs[KGDB_PPC_MSR_REG] = regs->msr;
265 	gdb_regs[KGDB_PPC_CR_REG]  = regs->cr;
266 	gdb_regs[KGDB_PPC_LR_REG]  = regs->lr;
267 	gdb_regs[KGDB_PPC_CTR_REG] = regs->ctr;
268 	gdb_regs[KGDB_PPC_XER_REG] = regs->xer;
269 }
270 
271 /*
272  * Reverse the above.
273  */
274 void
275 kgdb_setregs(db_regs_t *regs, kgdb_reg_t *gdb_regs)
276 {
277 	regs->xer = gdb_regs[KGDB_PPC_XER_REG];
278 	regs->ctr = gdb_regs[KGDB_PPC_CTR_REG];
279 	regs->lr  = gdb_regs[KGDB_PPC_LR_REG];
280 	regs->cr  = gdb_regs[KGDB_PPC_CR_REG];
281 	regs->msr = gdb_regs[KGDB_PPC_MSR_REG];
282 	regs->iar = gdb_regs[KGDB_PPC_PC_REG];
283 	memcpy(regs, gdb_regs, 32 * sizeof(unsigned long));
284 }
285 
286 /*
287  * Trap into kgdb to wait for debugger to connect,
288  * noting on the console why nothing else is going on.
289  */
290 void
291 kgdb_connect(int verbose)
292 {
293 	if (kgdb_dev == NODEV)
294 		return;
295 
296 	if (verbose)
297 		printf("kgdb waiting...");
298 
299 	__asm volatile(BKPT_ASM);
300 
301 	if (verbose && kgdb_active) {
302 		printf("kgdb connected.\n");
303 	}
304 
305 	kgdb_debug_panic = 1;
306 }
307 
308 /*
309  * Decide what to do on panic.
310  * (This is called by panic, like Debugger())
311  */
312 void
313 kgdb_panic(void)
314 {
315 	if (kgdb_dev != NODEV && kgdb_debug_panic) {
316 		printf("entering kgdb\n");
317 		kgdb_connect(kgdb_active == 0);
318 	}
319 }
320