xref: /netbsd-src/sys/arch/sun2/dev/zs_kgdb.c (revision 5977086ffe47951a09cd4a6fb4835963309624b2)
1*5977086fSandvar /*	$NetBSD: zs_kgdb.c,v 1.11 2023/10/24 19:05:07 andvar Exp $	*/
2453e503bSfredette 
3453e503bSfredette /*-
4453e503bSfredette  * Copyright (c) 1996 The NetBSD Foundation, Inc.
5453e503bSfredette  * All rights reserved.
6453e503bSfredette  *
7453e503bSfredette  * This code is derived from software contributed to The NetBSD Foundation
8453e503bSfredette  * by Gordon W. Ross.
9453e503bSfredette  *
10453e503bSfredette  * Redistribution and use in source and binary forms, with or without
11453e503bSfredette  * modification, are permitted provided that the following conditions
12453e503bSfredette  * are met:
13453e503bSfredette  * 1. Redistributions of source code must retain the above copyright
14453e503bSfredette  *    notice, this list of conditions and the following disclaimer.
15453e503bSfredette  * 2. Redistributions in binary form must reproduce the above copyright
16453e503bSfredette  *    notice, this list of conditions and the following disclaimer in the
17453e503bSfredette  *    documentation and/or other materials provided with the distribution.
18453e503bSfredette  *
19453e503bSfredette  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20453e503bSfredette  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21453e503bSfredette  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22453e503bSfredette  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23453e503bSfredette  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24453e503bSfredette  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25453e503bSfredette  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26453e503bSfredette  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27453e503bSfredette  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28453e503bSfredette  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29453e503bSfredette  * POSSIBILITY OF SUCH DAMAGE.
30453e503bSfredette  */
31453e503bSfredette 
32453e503bSfredette /*
33453e503bSfredette  * Hooks for kgdb when attached via the z8530 driver
34453e503bSfredette  *
35453e503bSfredette  * To use this, build a kernel with: option KGDB, and
36453e503bSfredette  * boot that kernel with "-d".  (The kernel will call
37453e503bSfredette  * zs_kgdb_init, kgdb_connect.)  When the console prints
38453e503bSfredette  * "kgdb waiting..." you run "gdb -k kernel" and do:
39453e503bSfredette  *   (gdb) set remotebaud 19200
40453e503bSfredette  *   (gdb) target remote /dev/ttyb
41453e503bSfredette  */
42453e503bSfredette 
43ed517291Slukem #include <sys/cdefs.h>
44*5977086fSandvar __KERNEL_RCSID(0, "$NetBSD: zs_kgdb.c,v 1.11 2023/10/24 19:05:07 andvar Exp $");
45ed517291Slukem 
46453e503bSfredette #include "opt_kgdb.h"
47453e503bSfredette 
48453e503bSfredette #include <sys/param.h>
49453e503bSfredette #include <sys/systm.h>
50453e503bSfredette #include <sys/proc.h>
51453e503bSfredette #include <sys/device.h>
52453e503bSfredette #include <sys/conf.h>
53453e503bSfredette #include <sys/ioctl.h>
54453e503bSfredette #include <sys/kernel.h>
55453e503bSfredette #include <sys/syslog.h>
56453e503bSfredette #include <sys/kgdb.h>
57453e503bSfredette 
58453e503bSfredette #include <dev/ic/z8530reg.h>
59453e503bSfredette #include <machine/z8530var.h>
60453e503bSfredette #include <machine/promlib.h>
61453e503bSfredette #include <sun2/dev/cons.h>
62453e503bSfredette 
6310b1a7beSchs static void zs_setparam(struct zs_chanstate *, int, int);
64453e503bSfredette struct zsops zsops_kgdb;
65453e503bSfredette 
6610b1a7beSchs extern int  zs_getc(void *arg);
6710b1a7beSchs extern void zs_putc(void *arg, int c);
68453e503bSfredette 
69453e503bSfredette static u_char zs_kgdb_regs[16] = {
70453e503bSfredette 	0,	/* 0: CMD (reset, etc.) */
71453e503bSfredette 	0,	/* 1: No interrupts yet. */
72453e503bSfredette #ifdef	ZS_INIT_IVECT
73453e503bSfredette 	ZS_INIT_IVECT,	/* 2: IVECT */
74453e503bSfredette #else
75453e503bSfredette 	0,	/* 2: IVECT */
76453e503bSfredette #endif
77453e503bSfredette 	ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
78453e503bSfredette 	ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
79453e503bSfredette 	ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
80453e503bSfredette 	0,	/* 6: TXSYNC/SYNCLO */
81453e503bSfredette 	0,	/* 7: RXSYNC/SYNCHI */
82453e503bSfredette 	0,	/* 8: alias for data port */
83453e503bSfredette #ifdef	ZS_INIT_IVECT
84453e503bSfredette 	ZSWR9_MASTER_IE,
85453e503bSfredette #else
86453e503bSfredette 	ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR,
87453e503bSfredette #endif
88453e503bSfredette 	0,	/*10: Misc. TX/RX control bits */
89453e503bSfredette 	ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
90453e503bSfredette 	14,	/*12: BAUDLO (default=9600) */
91453e503bSfredette 	0,	/*13: BAUDHI (default=9600) */
92453e503bSfredette 	ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
93453e503bSfredette 	ZSWR15_BREAK_IE,
94453e503bSfredette };
95453e503bSfredette 
96453e503bSfredette /*
97453e503bSfredette  * This replaces "zs_reset()" in the sparc driver.
98453e503bSfredette  */
99453e503bSfredette static void
zs_setparam(struct zs_chanstate * cs,int iena,int rate)10010b1a7beSchs zs_setparam(struct zs_chanstate *cs, int iena, int rate)
101453e503bSfredette {
102453e503bSfredette 	int s, tconst;
103453e503bSfredette 
104856e98cdSfredette 	memcpy(cs->cs_preg, zs_kgdb_regs, 16);
105453e503bSfredette 
106453e503bSfredette 	if (iena) {
107453e503bSfredette 		cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_SIE;
108453e503bSfredette 	}
109453e503bSfredette 
110453e503bSfredette 	/* Initialize the speed, etc. */
111453e503bSfredette 	tconst = BPS_TO_TCONST(cs->cs_brg_clk, rate);
112453e503bSfredette 	cs->cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS;
113453e503bSfredette 	cs->cs_preg[12] = tconst;
114453e503bSfredette 	cs->cs_preg[13] = tconst >> 8;
115453e503bSfredette 
116453e503bSfredette 	s = splhigh();
117453e503bSfredette 	zs_loadchannelregs(cs);
118453e503bSfredette 	splx(s);
119453e503bSfredette }
120453e503bSfredette 
121453e503bSfredette /*
122453e503bSfredette  * Set up for kgdb; called at boot time before configuration.
123453e503bSfredette  * KGDB interrupts will be enabled later when zs0 is configured.
124453e503bSfredette  * Called after cninit(), so printf() etc. works.
125453e503bSfredette  */
126453e503bSfredette void
zs_kgdb_init(void)12710b1a7beSchs zs_kgdb_init(void)
128453e503bSfredette {
129453e503bSfredette 	struct zs_chanstate cs;
130453e503bSfredette 	struct zsdevice *zsd;
131453e503bSfredette 	volatile struct zschan *zc;
132453e503bSfredette 	int channel, promzs_unit;
13377a6b82bSgehenna 	extern const struct cdevsw zstty_cdevsw;
134453e503bSfredette 
135*5977086fSandvar 	/* printf("zs_kgdb_init: kgdb_dev=0x%llx\n", kgdb_dev); */
13677a6b82bSgehenna 	if (cdevsw_lookup(kgdb_dev) != &zstty_cdevsw)
137453e503bSfredette 		return;
138453e503bSfredette 
139453e503bSfredette 	/* Note: (ttya,ttyb) on zs0, and (ttyc,ttyd) on zs2 */
140453e503bSfredette 	promzs_unit = (kgdb_dev & 2) ? 2 : 0;
141453e503bSfredette 	channel  =  kgdb_dev & 1;
142*5977086fSandvar 	printf("zs_kgdb_init: attaching Serial(%lld) at %d baud\n",
143*5977086fSandvar 		   (kgdb_dev & 3), kgdb_rate);
144453e503bSfredette 
145453e503bSfredette 	/* Setup temporary chanstate. */
14653524e44Schristos 	memset((void *)&cs, 0, sizeof(cs));
147453e503bSfredette 	zsd = zs_find_prom(promzs_unit);
148453e503bSfredette 	if (zsd == NULL) {
149453e503bSfredette 		printf("zs_kgdb_init: zs not mapped.\n");
150453e503bSfredette 		return;
151453e503bSfredette 	}
152453e503bSfredette 	zc = (channel == 0) ? &zsd->zs_chan_a : &zsd->zs_chan_b;
153453e503bSfredette 
154453e503bSfredette 	cs.cs_channel = channel;
155453e503bSfredette 	cs.cs_brg_clk = PCLK / 16;
156453e503bSfredette 	cs.cs_reg_csr  = &zc->zc_csr;
157453e503bSfredette 	cs.cs_reg_data = &zc->zc_data;
158453e503bSfredette 
159453e503bSfredette 	/* Now set parameters. (interrupts disabled) */
160453e503bSfredette 	zs_setparam(&cs, 0, kgdb_rate);
161453e503bSfredette 
162453e503bSfredette 	/* Store the getc/putc functions and arg. */
1633d7f38ecShauke 	kgdb_attach(zs_getc, zs_putc, __UNVOLATILE(zc));
164453e503bSfredette }
165453e503bSfredette 
166453e503bSfredette /*
167453e503bSfredette  * This is a "hook" called by zstty_attach to allow the tty
168453e503bSfredette  * to be "taken over" for exclusive use by kgdb.
169453e503bSfredette  * Return non-zero if this is the kgdb port.
170453e503bSfredette  *
171453e503bSfredette  * Set the speed to kgdb_rate, CS8, etc.
172453e503bSfredette  */
173453e503bSfredette int
zs_check_kgdb(struct zs_chanstate * cs,int dev)17410b1a7beSchs zs_check_kgdb(struct zs_chanstate *cs, int dev)
175453e503bSfredette {
176453e503bSfredette 
177453e503bSfredette 	if (dev != kgdb_dev)
178453e503bSfredette 		return (0);
179453e503bSfredette 
180453e503bSfredette 	/*
181453e503bSfredette 	 * Yes, this is port in use by kgdb.
182453e503bSfredette 	 */
183453e503bSfredette 	cs->cs_private = NULL;
184453e503bSfredette 	cs->cs_ops = &zsops_kgdb;
185453e503bSfredette 
186453e503bSfredette 	/* Now set parameters. (interrupts enabled) */
187453e503bSfredette 	zs_setparam(cs, 1, kgdb_rate);
188453e503bSfredette 
189453e503bSfredette 	return (1);
190453e503bSfredette }
191453e503bSfredette 
192453e503bSfredette /*
193453e503bSfredette  * KGDB framing character received: enter kernel debugger.  This probably
194453e503bSfredette  * should time out after a few seconds to avoid hanging on spurious input.
195453e503bSfredette  */
196453e503bSfredette void
zskgdb(struct zs_chanstate * cs)19710b1a7beSchs zskgdb(struct zs_chanstate *cs)
198453e503bSfredette {
199453e503bSfredette 	int unit = minor(kgdb_dev);
200453e503bSfredette 
201453e503bSfredette 	printf("zstty%d: kgdb interrupt\n", unit);
202453e503bSfredette 	/* This will trap into the debugger. */
203453e503bSfredette 	kgdb_connect(1);
204453e503bSfredette }
205453e503bSfredette 
206453e503bSfredette 
207453e503bSfredette /****************************************************************
208453e503bSfredette  * Interface to the lower layer (zscc)
209453e503bSfredette  ****************************************************************/
210453e503bSfredette 
21110b1a7beSchs static void zs_kgdb_rxint(struct zs_chanstate *);
21210b1a7beSchs static void zs_kgdb_stint(struct zs_chanstate *, int);
21310b1a7beSchs static void zs_kgdb_txint(struct zs_chanstate *);
21410b1a7beSchs static void zs_kgdb_softint(struct zs_chanstate *);
215453e503bSfredette 
216453e503bSfredette int kgdb_input_lost;
217453e503bSfredette 
218453e503bSfredette static void
zs_kgdb_rxint(struct zs_chanstate * cs)21910b1a7beSchs zs_kgdb_rxint(struct zs_chanstate *cs)
220453e503bSfredette {
22110b1a7beSchs 	u_char c, rr1;
222453e503bSfredette 
223453e503bSfredette 	/*
224453e503bSfredette 	 * First read the status, because reading the received char
225453e503bSfredette 	 * destroys the status of this char.
226453e503bSfredette 	 */
227453e503bSfredette 	rr1 = zs_read_reg(cs, 1);
228453e503bSfredette 	c = zs_read_data(cs);
229453e503bSfredette 
230453e503bSfredette 	if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
231453e503bSfredette 		/* Clear the receive error. */
232453e503bSfredette 		zs_write_csr(cs, ZSWR0_RESET_ERRORS);
233453e503bSfredette 	}
234453e503bSfredette 
235453e503bSfredette 	if (c == KGDB_START) {
236453e503bSfredette 		zskgdb(cs);
237453e503bSfredette 	} else {
238453e503bSfredette 		kgdb_input_lost++;
239453e503bSfredette 	}
240453e503bSfredette }
241453e503bSfredette 
242453e503bSfredette static void
zs_kgdb_txint(struct zs_chanstate * cs)24310b1a7beSchs zs_kgdb_txint(struct zs_chanstate *cs)
244453e503bSfredette {
245453e503bSfredette 	zs_write_csr(cs, ZSWR0_RESET_TXINT);
246453e503bSfredette }
247453e503bSfredette 
248453e503bSfredette static void
zs_kgdb_stint(struct zs_chanstate * cs,int force)24910b1a7beSchs zs_kgdb_stint(struct zs_chanstate *cs, int force)
250453e503bSfredette {
25110b1a7beSchs 	int rr0;
252453e503bSfredette 
253453e503bSfredette 	rr0 = zs_read_csr(cs);
254453e503bSfredette 	zs_write_csr(cs, ZSWR0_RESET_STATUS);
255453e503bSfredette 
256453e503bSfredette 	/*
257453e503bSfredette 	 * Check here for console break, so that we can abort
258453e503bSfredette 	 * even when interrupts are locking up the machine.
259453e503bSfredette 	 */
260453e503bSfredette 	if (rr0 & ZSRR0_BREAK) {
261453e503bSfredette 		zskgdb(cs);
262453e503bSfredette 	}
263453e503bSfredette }
264453e503bSfredette 
265453e503bSfredette static void
zs_kgdb_softint(struct zs_chanstate * cs)26610b1a7beSchs zs_kgdb_softint(struct zs_chanstate *cs)
267453e503bSfredette {
268453e503bSfredette 	printf("zs_kgdb_softint?\n");
269453e503bSfredette }
270453e503bSfredette 
271453e503bSfredette struct zsops zsops_kgdb = {
272453e503bSfredette 	zs_kgdb_rxint,	/* receive char available */
273453e503bSfredette 	zs_kgdb_stint,	/* external/status */
274453e503bSfredette 	zs_kgdb_txint,	/* xmit buffer empty */
275453e503bSfredette 	zs_kgdb_softint,	/* process software interrupt */
276453e503bSfredette };
277