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