1/*	$NetBSD: kgdb_stub.c,v 1.21 2024/01/07 07:58:35 isaki Exp $	*/
2
3/*
4 * Copyright (c) 1990, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 *	This product includes software developed by the University of
14 *	California, Lawrence Berkeley Laboratories.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 *	@(#)kgdb_stub.c	8.4 (Berkeley) 1/12/94
41 */
42
43/*
44 * "Stub" to allow remote CPU to debug over a serial line using gdb.
45 */
46
47#include <sys/cdefs.h>
48__KERNEL_RCSID(0, "$NetBSD: kgdb_stub.c,v 1.21 2024/01/07 07:58:35 isaki Exp $");
49
50#include "opt_kgdb.h"
51
52#ifdef KGDB
53#ifndef lint
54static char rcsid[] = "$NetBSD: kgdb_stub.c,v 1.21 2024/01/07 07:58:35 isaki Exp $";
55#endif
56
57#include <sys/param.h>
58#include <sys/systm.h>
59
60#include <machine/trap.h>
61#include <machine/cpu.h>
62#include <machine/psl.h>
63#include <machine/reg.h>
64#include <machine/frame.h>
65
66#include <sys/buf.h>
67#include <dev/cons.h>
68
69#include <x68k/x68k/kgdb_proto.h>
70#include <machine/remote-sl.h>
71
72extern int kernacc();
73extern void chgkprot();
74
75#ifndef KGDB_DEV
76#define KGDB_DEV NODEV
77#endif
78#ifndef KGDB_DEVRATE
79#define KGDB_DEVRATE 9600
80#endif
81
82dev_t kgdb_dev = KGDB_DEV;	/* remote debugging device (NODEV if none) */
83int kgdb_rate = KGDB_DEVRATE;	/* remote debugging baud rate */
84int kgdb_active = 0;            /* remote debugging active if != 0 */
85int kgdb_debug_init = 0;	/* != 0 waits for remote at system init */
86int kgdb_debug_panic = 1;	/* != 0 waits for remote on panic */
87int kgdb_debug = 0;
88
89#define GETC	((*kgdb_getc)(kgdb_dev))
90#define PUTC(c)	((*kgdb_putc)(kgdb_dev, c))
91#define PUTESC(c) { \
92	if (c == FRAME_END) { \
93		PUTC(FRAME_ESCAPE); \
94		c = TRANS_FRAME_END; \
95	} else if (c == FRAME_ESCAPE) { \
96		PUTC(FRAME_ESCAPE); \
97		c = TRANS_FRAME_ESCAPE; \
98	} else if (c == FRAME_START) { \
99		PUTC(FRAME_ESCAPE); \
100		c = TRANS_FRAME_START; \
101	} \
102	PUTC(c); \
103}
104static int (*kgdb_getc)();
105static int (*kgdb_putc)();
106
107/*
108 * Send a message.  The host gets one chance to read it.
109 */
110static void
111kgdb_send(u_char type, u_char *bp, int len)
112{
113	u_char csum;
114	u_char *ep = bp + len;
115
116	PUTC(FRAME_START);
117	PUTESC(type);
118
119	csum = type;
120	while (bp < ep) {
121		type = *bp++;
122		csum += type;
123		PUTESC(type)
124	}
125	csum = -csum;
126	PUTESC(csum)
127	PUTC(FRAME_END);
128}
129
130static int
131kgdb_recv(u_char *bp, int *lenp)
132{
133	u_char c, csum;
134	int escape, len;
135	int type;
136
137restart:
138	csum = len = escape = 0;
139	type = -1;
140	while (1) {
141		c = GETC;
142		switch (c) {
143
144		case FRAME_ESCAPE:
145			escape = 1;
146			continue;
147
148		case TRANS_FRAME_ESCAPE:
149			if (escape)
150				c = FRAME_ESCAPE;
151			break;
152
153		case TRANS_FRAME_END:
154			if (escape)
155				c = FRAME_END;
156			break;
157
158		case TRANS_FRAME_START:
159			if (escape)
160				c = FRAME_START;
161			break;
162
163		case FRAME_START:
164			goto restart;
165
166		case FRAME_END:
167			if (type < 0 || --len < 0) {
168				csum = len = escape = 0;
169				type = -1;
170				continue;
171			}
172			if (csum != 0) {
173				return (0);
174			}
175			*lenp = len;
176			return type;
177		}
178		csum += c;
179		if (type < 0) {
180			type = c;
181			escape = 0;
182			continue;
183		}
184		if (++len > SL_RPCSIZE) {
185			while (GETC != FRAME_END)
186				;
187			return (0);
188		}
189		*bp++ = c;
190		escape = 0;
191	}
192}
193
194/*
195 * Translate a trap number into a unix compatible signal value.
196 * (gdb only understands unix signal numbers).
197 */
198static int
199computeSignal(int type)
200{
201	int sigval;
202
203	switch (type) {
204	case T_BUSERR:
205	case T_ADDRERR:
206		sigval = SIGBUS;
207		break;
208	case T_ILLINST:
209	case T_PRIVINST:
210		sigval = SIGILL;
211		break;
212	case T_ZERODIV:
213	case T_CHKINST:
214	case T_TRAPVINST:
215		sigval = SIGFPE;
216		break;
217	case T_TRACE:
218		sigval = SIGTRAP;
219		break;
220	case T_MMUFLT:
221		sigval = SIGSEGV;
222		break;
223	case T_SSIR:
224		sigval = SIGSEGV;
225		break;
226	case T_FMTERR:
227		sigval = SIGILL;
228		break;
229	case T_FPERR:
230	case T_COPERR:
231		sigval = SIGFPE;
232		break;
233	case T_ASTFLT:
234		sigval = SIGINT;
235		break;
236	case T_TRAP15:
237		sigval = SIGTRAP;
238		break;
239	default:
240		sigval = SIGEMT;
241		break;
242	}
243	return (sigval);
244}
245
246/*
247 * Trap into kgdb to wait for debugger to connect,
248 * noting on the console why nothing else is going on.
249 */
250void
251kgdb_connect(int verbose)
252{
253
254	if (verbose)
255		printf("kgdb waiting...");
256	/* trap into kgdb */
257	__asm("trap #15;");
258	if (verbose)
259		printf("connected.\n");
260}
261
262/*
263 * Decide what to do on panic.
264 */
265void
266kgdb_panic(void)
267{
268
269	if (kgdb_active == 0 && kgdb_debug_panic && kgdb_dev != NODEV)
270		kgdb_connect(1);
271}
272
273/*
274 * Definitions exported from gdb.
275 */
276#define NUM_REGS 18
277#define REGISTER_BYTES ((16+2)*4)
278#define REGISTER_BYTE(N)  ((N)*4)
279
280#define GDB_SR 16
281#define GDB_PC 17
282
283static inline void
284kgdb_copy(u_char *src, u_char *dst, u_int nbytes)
285{
286	u_char *ep = src + nbytes;
287
288	while (src < ep)
289		*dst++ = *src++;
290}
291
292/*
293 * There is a short pad word between SP (A7) and SR which keeps the
294 * kernel stack long word aligned (note that this is in addition to
295 * the stack adjust short that we treat as the upper half of a longword
296 * SR).  We must skip this when copying into and out of gdb.
297 */
298static inline void
299regs_to_gdb(struct frame *fp, u_long *regs)
300{
301	kgdb_copy((u_char *)fp->f_regs, (u_char *)regs, 16*4);
302	kgdb_copy((u_char *)&fp->f_stackadj, (u_char *)&regs[GDB_SR], 2*4);
303}
304
305static inline void
306gdb_to_regs(struct frame *fp, u_long *regs)
307{
308	kgdb_copy((u_char *)regs, (u_char *)fp->f_regs, 16*4);
309	kgdb_copy((u_char *)&regs[GDB_SR], (u_char *)&fp->f_stackadj, 2*4);
310}
311
312static u_long reg_cache[NUM_REGS];
313static u_char inbuffer[SL_RPCSIZE+1];
314static u_char outbuffer[SL_RPCSIZE];
315
316/*
317 * This function does all command processing for interfacing to
318 * a remote gdb.
319 */
320int
321kgdb_trap(int type, struct frame *frame)
322{
323	u_long len;
324	u_char *addr;
325	u_char *cp;
326	u_char out, in;
327	int outlen;
328	int inlen;
329	u_long gdb_regs[NUM_REGS];
330
331	if ((int)kgdb_dev < 0) {
332		/* not debugging */
333		return (0);
334	}
335	if (kgdb_active == 0) {
336		if (type != T_TRAP15) {
337			/* No debugger active -- let trap handle this. */
338			return (0);
339		}
340		kgdb_getc = 0;
341		for (inlen = 0; constab[inlen].cn_probe; inlen++) {
342			if (major(constab[inlen].cn_dev) == major(kgdb_dev)) {
343				kgdb_getc = constab[inlen].cn_getc;
344				kgdb_putc = constab[inlen].cn_putc;
345				break;
346			}
347		}
348		if (kgdb_getc == 0 || kgdb_putc == 0)
349			return (0);
350		/*
351		 * If the packet that woke us up isn't an exec packet,
352		 * ignore it since there is no active debugger.  Also,
353		 * we check that it's not an ack to be sure that the
354		 * remote side doesn't send back a response after the
355		 * local gdb has exited.  Otherwise, the local host
356		 * could trap into gdb if it's running a gdb kernel too.
357		 */
358		in = GETC;
359		/*
360		 * If we came in asynchronously through the serial line,
361		 * the framing character is eaten by the receive interrupt,
362		 * but if we come in through a synchronous trap (i.e., via
363		 * kgdb_connect()), we will see the extra character.
364		 */
365		if (in == FRAME_START)
366			in = GETC;
367
368		/*
369		 * Check that this is a debugger exec message.  If so,
370		 * slurp up the entire message then ack it, and fall
371		 * through to the recv loop.
372		 */
373		if (KGDB_CMD(in) != KGDB_EXEC || (in & KGDB_ACK) != 0)
374			return (0);
375		while (GETC != FRAME_END)
376			;
377		/*
378		 * Do the printf *before* we ack the message.  This way
379		 * we won't drop any inbound characters while we're
380		 * doing the polling printf.
381		 */
382		printf("kgdb started from device %x\n", kgdb_dev);
383		kgdb_send(in | KGDB_ACK, (u_char *)0, 0);
384		kgdb_active = 1;
385	}
386	/*
387	 * Stick frame regs into our reg cache then tell remote host
388	 * that an exception has occurred.
389	 */
390	regs_to_gdb(frame, gdb_regs);
391	if (type != T_TRAP15) {
392		/*
393		 * Only send an asynchronous SIGNAL message when we hit
394		 * a breakpoint.  Otherwise, we will drop the incoming
395		 * packet while we output this one (and on entry the other
396		 * side isn't interested in the SIGNAL type -- if it is,
397		 * it will have used a signal packet.)
398		 */
399		outbuffer[0] = computeSignal(type);
400		kgdb_send(KGDB_SIGNAL, outbuffer, 1);
401	}
402
403	while (1) {
404		in = kgdb_recv(inbuffer, &inlen);
405		if (in == 0 || (in & KGDB_ACK))
406			/* Ignore inbound acks and error conditions. */
407			continue;
408
409		out = in | KGDB_ACK;
410		switch (KGDB_CMD(in)) {
411
412		case KGDB_SIGNAL:
413			/*
414			 * if this command came from a running gdb,
415			 * answer it -- the other guy has no way of
416			 * knowing if we're in or out of this loop
417			 * when he issues a "remote-signal".  (Note
418			 * that without the length check, we could
419			 * loop here forever if the output line is
420			 * looped back or the remote host is echoing.)
421			 */
422			if (inlen == 0) {
423				outbuffer[0] = computeSignal(type);
424				kgdb_send(KGDB_SIGNAL, outbuffer, 1);
425			}
426			continue;
427
428		case KGDB_REG_R:
429		case KGDB_REG_R | KGDB_DELTA:
430			cp = outbuffer;
431			outlen = 0;
432			for (len = inbuffer[0]; len < NUM_REGS; ++len) {
433				if (reg_cache[len] != gdb_regs[len] ||
434				    (in & KGDB_DELTA) == 0) {
435					if (outlen + 5 > SL_MAXDATA) {
436						out |= KGDB_MORE;
437						break;
438					}
439					cp[outlen] = len;
440					kgdb_copy((u_char *)&gdb_regs[len],
441						  &cp[outlen + 1], 4);
442					reg_cache[len] = gdb_regs[len];
443					outlen += 5;
444				}
445			}
446			break;
447
448		case KGDB_REG_W:
449		case KGDB_REG_W | KGDB_DELTA:
450			cp = inbuffer;
451			for (len = 0; len < inlen; len += 5) {
452				int j = cp[len];
453
454				kgdb_copy(&cp[len + 1],
455					  (u_char *)&gdb_regs[j], 4);
456				reg_cache[j] = gdb_regs[j];
457			}
458			gdb_to_regs(frame, gdb_regs);
459			outlen = 0;
460			break;
461
462		case KGDB_MEM_R:
463			len = inbuffer[0];
464			kgdb_copy(&inbuffer[1], (u_char *)&addr, 4);
465			if (len > SL_MAXDATA) {
466				outlen = 1;
467				outbuffer[0] = E2BIG;
468			} else if (!kgdb_acc(addr, len, B_READ)) {
469				outlen = 1;
470				outbuffer[0] = EFAULT;
471			} else {
472				outlen = len + 1;
473				outbuffer[0] = 0;
474				kgdb_copy(addr, &outbuffer[1], len);
475			}
476			break;
477
478		case KGDB_MEM_W:
479			len = inlen - 4;
480			kgdb_copy(inbuffer, (u_char *)&addr, 4);
481			outlen = 1;
482			if (!kgdb_acc(addr, len, B_READ))
483				outbuffer[0] = EFAULT;
484			else {
485				outbuffer[0] = 0;
486				if (!kgdb_acc(addr, len, B_WRITE))
487					chgkprot(addr, len, B_WRITE);
488				kgdb_copy(&inbuffer[4], addr, len);
489				ICIA();
490			}
491			break;
492
493		case KGDB_KILL:
494			kgdb_active = 0;
495			printf("kgdb detached\n");
496			/* fall through */
497		case KGDB_CONT:
498			kgdb_send(out, 0, 0);
499			frame->f_sr &=~ PSL_T;
500			return (1);
501
502		case KGDB_STEP:
503			kgdb_send(out, 0, 0);
504			frame->f_sr |= PSL_T;
505			return (1);
506
507		case KGDB_EXEC:
508		default:
509			/* Unknown command.  Ack with a null message. */
510			outlen = 0;
511			break;
512		}
513		/* Send the reply */
514		kgdb_send(out, outbuffer, outlen);
515	}
516}
517
518/*
519 * XXX do kernacc call if safe, otherwise attempt
520 * to simulate by simple bounds-checking.
521 */
522int
523kgdb_acc(void *addr, int len, int rw)
524{
525	extern char kstack[];	/* XXX */
526	extern char *kernel_map;		/* XXX! */
527
528	if (kernel_map != NULL)
529		return (kernacc(addr, len, rw));
530	if (addr < uvm_lwp_getuarea(&lwp0) + USPACE  ||
531	    kstack <= addr && addr < kstack + USPACE)
532		return (1);
533	return (0);
534}
535#endif /* KGDB */
536