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