1/*	$NetBSD: sunmon.c,v 1.24 2024/01/13 18:51:38 thorpej Exp $	*/
2
3/*-
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Adam Glass and Gordon W. Ross.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: sunmon.c,v 1.24 2024/01/13 18:51:38 thorpej Exp $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/reboot.h>
38#include <sys/boot_flag.h>
39
40#include <machine/mon.h>
41#include <machine/mc68851.h>
42#include <machine/vectors.h>
43
44#include <m68k/frame.h>
45
46#include <sun3/sun3/machdep.h>
47#include <sun3/sun3/interreg.h>
48
49static void **sunmon_vbr;
50static void *sunmon_vcmd;	/* XXX: always 0? */
51
52static void tracedump(int);
53static void v_handler(int, char *);
54
55/*
56 * Prepare for running the PROM monitor
57 */
58static void
59_mode_monitor(void)
60{
61	/* Disable our level-5 clock. */
62	set_clk_mode(0, IREG_CLOCK_ENAB_5, 0);
63	/* Restore the PROM vector table */
64	setvbr(sunmon_vbr);
65	/* Enable the PROM NMI clock. */
66	set_clk_mode(IREG_CLOCK_ENAB_7, 0, 1);
67	/* XXX - Disable watchdog action? */
68}
69
70/*
71 * Prepare for running the kernel
72 */
73static void
74_mode_kernel(void)
75{
76	/* Disable the PROM NMI clock. */
77	set_clk_mode(0, IREG_CLOCK_ENAB_7, 0);
78	/* Restore our own vector table */
79	setvbr(vectab);
80	/* Enable our level-5 clock. */
81	set_clk_mode(IREG_CLOCK_ENAB_5, 0, 1);
82}
83
84/*
85 * This function takes care of restoring enough of the
86 * hardware state to allow the PROM to run normally.
87 * The PROM needs: NMI enabled, its own vector table.
88 * In case of a temporary "drop into PROM", this will
89 * also put our hardware state back into place after
90 * the PROM "c" (continue) command is given.
91 */
92void
93sunmon_abort(void)
94{
95	int s = splhigh();
96#ifdef	_SUN3X_
97	struct mmu_rootptr crp;
98#endif
99
100	_mode_monitor();
101	delay(100000);
102
103#ifdef	_SUN3X_
104	getcrp(&crp);
105	loadcrp(&mon_crp);
106#endif
107
108	/*
109	 * Drop into the PROM in a way that allows a continue.
110	 * Already setup "trap #14" in sunmon_init().
111	 */
112
113	__asm(" trap #14 ; _sunmon_continued: nop");
114
115	/* We have continued from a PROM abort! */
116#ifdef	_SUN3X_
117	loadcrp(&crp);
118#endif
119	_mode_kernel();
120	splx(s);
121}
122
123void
124sunmon_halt(void)
125{
126	(void) splhigh();
127	_mode_monitor();
128	*romVectorPtr->vector_cmd = sunmon_vcmd;
129#ifdef	_SUN3X_
130	loadcrp(&mon_crp);
131	/*
132	 * The PROM monitor "exit_to_mon" function appears to have problems...
133	 * SunOS uses the "abort" function when you halt (bug work-around?)
134	 * so we might as well do the same.
135	 */
136	__asm(" trap #14"); /* mon_exit_to_mon() provokes PROM monitor bug */
137#endif
138	mon_exit_to_mon();
139	/*NOTREACHED*/
140}
141
142/*
143 * Caller must pass a string that is in our data segment.
144 */
145void
146sunmon_reboot(const char *bs)
147{
148
149	(void) splhigh();
150	_mode_monitor();
151	*romVectorPtr->vector_cmd = sunmon_vcmd;
152#ifdef	_SUN3X_
153	loadcrp(&mon_crp);
154#endif
155	mon_reboot(bs);
156	mon_exit_to_mon();
157	/*NOTREACHED*/
158}
159
160
161/*
162 * Print out a traceback for the caller - can be called anywhere
163 * within the kernel or from the monitor by typing "g4" (for sun-2
164 * compatibility) or "w trace".  This causes the monitor to call
165 * the v_handler() routine which will call tracedump() for these cases.
166 */
167struct funcall_frame {
168	struct funcall_frame *fr_savfp;
169	int fr_savpc;
170	int fr_arg[1];
171};
172/*VARARGS0*/
173static void __noinline
174tracedump(int x1)
175{
176	struct funcall_frame *fp = (struct funcall_frame *)(&x1 - 2);
177	u_int stackpage = ((u_int)fp) & ~PGOFSET;
178
179	mon_printf("Begin traceback...fp = 0x%x\n", fp);
180	do {
181		if (fp == fp->fr_savfp) {
182			mon_printf("FP loop at 0x%x", fp);
183			break;
184		}
185		mon_printf("Called from 0x%x, fp=0x%x, args=0x%x 0x%x 0x%x 0x%x\n",
186				   fp->fr_savpc, fp->fr_savfp,
187				   fp->fr_arg[0], fp->fr_arg[1], fp->fr_arg[2], fp->fr_arg[3]);
188		fp = fp->fr_savfp;
189	} while ( (((u_int)fp) & ~PGOFSET) == stackpage);
190	mon_printf("End traceback...\n");
191}
192
193/*
194 * Handler for monitor vector cmd -
195 * For now we just implement the old "g0" and "g4"
196 * commands and a printf hack.
197 * [lifted from freed cmu mach3 sun3 port]
198 */
199static void
200v_handler(int addr, char *str)
201{
202
203	switch (*str) {
204	case '\0':
205		/*
206		 * No (non-hex) letter was specified on
207		 * command line, use only the number given
208		 */
209		switch (addr) {
210		case 0:			/* old g0 */
211		case 0xd:		/* 'd'ump short hand */
212			_mode_kernel();
213			panic("zero");
214			/*NOTREACHED*/
215
216		case 4:			/* old g4 */
217			goto do_trace;
218
219		default:
220			goto err;
221		}
222		break;
223
224	case 'p':			/* 'p'rint string command */
225	case 'P':
226		mon_printf("%s\n", (char *)addr);
227		break;
228
229	case '%':			/* p'%'int anything a la printf */
230		mon_printf(str, addr);
231		mon_printf("\n");
232		break;
233
234	do_trace:
235	case 't':			/* 't'race kernel stack */
236	case 'T':
237		tracedump(addr);
238		break;
239
240	case 'u':			/* d'u'mp hack ('d' look like hex) */
241	case 'U':
242		goto err;
243		break;
244
245	default:
246	err:
247		mon_printf("Don't understand 0x%x '%s'\n", addr, str);
248	}
249}
250
251/*
252 * Set the PROM vector handler (for g0, g4, etc.)
253 * and set boothowto from the PROM arg strings.
254 *
255 * Note, args are always:
256 * argv[0] = boot_device	(i.e. "sd(0,0,0)")
257 * argv[1] = options	(i.e. "-ds" or NULL)
258 * argv[2] = NULL
259 */
260void
261sunmon_init(void)
262{
263	struct sunromvec *rvec;
264	struct bootparam *bp;
265	char **argp;
266	char *p;
267
268	rvec = romVectorPtr;
269	bp = *rvec->bootParam;
270
271	/* Save the PROM monitor Vector Base Register (VBR). */
272	sunmon_vbr = getvbr();
273
274	/* Arrange for "trap #14" to cause a PROM abort. */
275	sunmon_vbr[32+14] = romVectorPtr->abortEntry;
276
277	/* Save and replace the "v command" handler. */
278	sunmon_vcmd = *rvec->vector_cmd;
279	if (rvec->romvecVersion >= 2)
280		*rvec->vector_cmd = v_handler;
281
282	/* Set boothowto flags from PROM args. */
283	argp = bp->argPtr;
284
285	/* Skip argp[0] (the device string) */
286	argp++;
287
288	/* Have options? */
289	if (*argp == NULL)
290		return;
291	p = *argp;
292	if (*p == '-') {
293		/* yes, parse options */
294#ifdef	DEBUG
295		mon_printf("boot option: %s\n", p);
296#endif
297		for (++p; *p; p++)
298			BOOT_FLAG(*p, boothowto);
299		argp++;
300	}
301
302#ifdef	DEBUG
303	/* Have init name? */
304	if (*argp == NULL)
305		return;
306	p = *argp;
307	mon_printf("boot initpath: %s\n", p);
308#endif
309}
310