xref: /netbsd-src/sys/arch/sun3/sun3/sunmon.c (revision 1acb62a3e4408c1dfda13cfda517d781e7c0751e)
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 
49 static void **sunmon_vbr;
50 static void *sunmon_vcmd;	/* XXX: always 0? */
51 
52 static void tracedump(int);
53 static void v_handler(int, char *);
54 
55 /*
56  * Prepare for running the PROM monitor
57  */
58 static void
_mode_monitor(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  */
73 static void
_mode_kernel(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  */
92 void
sunmon_abort(void)93 sunmon_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 
123 void
sunmon_halt(void)124 sunmon_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  */
145 void
sunmon_reboot(const char * bs)146 sunmon_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  */
167 struct funcall_frame {
168 	struct funcall_frame *fr_savfp;
169 	int fr_savpc;
170 	int fr_arg[1];
171 };
172 /*VARARGS0*/
173 static void __noinline
tracedump(int x1)174 tracedump(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  */
199 static void
v_handler(int addr,char * str)200 v_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  */
260 void
sunmon_init(void)261 sunmon_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