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