1 /* $NetBSD: promlib.c,v 1.9 2002/05/30 22:43:07 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, Gordon W. Ross, and Matthew Fredette. 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/reboot.h> 42 #include <sys/boot_flag.h> 43 44 #include <machine/stdarg.h> 45 #define _SUN2_PROMLIB_PRIVATE 46 #include <machine/promlib.h> 47 48 #include <sun2/sun2/machdep.h> 49 #include <sun2/sun2/control.h> 50 #include <sun68k/sun68k/vector.h> 51 #include <machine/pte.h> 52 53 /* 54 * The state we save when we get ready to disappear into the PROM. 55 */ 56 struct kernel_state { 57 int saved_spl; 58 int saved_ctx; 59 u_int saved_ptes[4]; 60 }; 61 62 static void **sunmon_vbr; 63 static struct kernel_state sunmon_kernel_state; 64 static struct bootparam sunmon_bootparam; 65 static u_int sunmon_ptes[4]; 66 67 static void tracedump __P((int)); 68 69 /* 70 * The PROM keeps its data is in the first four physical pages, and 71 * assumes that they're mapped to the first four virtual pages. 72 * Normally we keep the first four virtual pages unmapped, so before 73 * we can dereference pointers in romVectorPtr or call the PROM, we 74 * have to restore its mappings. 75 */ 76 77 /* 78 * This swaps out one set of PTEs for the first 79 * four virtual pages, and swaps another set in. 80 */ 81 static inline void _prom_swap_ptes __P((u_int *, u_int *)); 82 static inline void 83 _prom_swap_ptes(swapout, swapin) 84 u_int *swapout, *swapin; 85 { 86 int pte_number; 87 vaddr_t va; 88 89 for(pte_number = 0, va = 0; pte_number < 4; pte_number++, va += NBPG) { 90 swapout[pte_number] = get_pte(va); 91 set_pte(va, swapin[pte_number]); 92 } 93 } 94 95 /* 96 * Prepare for running the PROM monitor. 97 */ 98 static inline void _mode_monitor __P((struct kernel_state *, int)); 99 static inline void 100 _mode_monitor(state, full) 101 struct kernel_state *state; 102 int full; 103 { 104 /* 105 * Save the current context, and the PTEs for pages 106 * zero through three, and reset them to what the PROM 107 * expects. 108 */ 109 state->saved_ctx = get_context(); 110 set_context(0); 111 _prom_swap_ptes(state->saved_ptes, sunmon_ptes); 112 113 /* 114 * If we're going to enter the PROM fully, raise the interrupt 115 * level, disable our level 5 clock, restore the PROM vector 116 * table, and enable the PROM NMI clock. 117 */ 118 if (full) { 119 state->saved_spl = splhigh(); 120 set_clk_mode(0, 0); 121 setvbr(sunmon_vbr); 122 set_clk_mode(1, 1); 123 } 124 } 125 126 /* 127 * Prepare for running the kernel. 128 */ 129 static inline void _mode_kernel __P((struct kernel_state *, int)); 130 static inline void 131 _mode_kernel(state, full) 132 struct kernel_state *state; 133 int full; 134 { 135 /* 136 * If we were in the PROM fully, disable the PROM NMI clock, 137 * restore our own vector table, and enable our level 5 clock. 138 */ 139 if (full) { 140 set_clk_mode(1, 0); 141 setvbr(vector_table); 142 set_clk_mode(0, 1); 143 splx(state->saved_spl); 144 } 145 146 /* 147 * Restore our PTEs for pages zero through three, 148 * and restore the current context. 149 */ 150 _prom_swap_ptes(sunmon_ptes, state->saved_ptes); 151 set_context(state->saved_ctx); 152 } 153 154 /* We define many prom_ functions using this macro. */ 155 #define PROMLIB_FUNC(type, new, proto, old, args, ret) \ 156 type new proto \ 157 { \ 158 struct kernel_state state; \ 159 int rc; \ 160 _mode_monitor(&state, 0); \ 161 rc = (*(romVectorPtr->old)) args; \ 162 _mode_kernel(&state, 0); \ 163 ret ; \ 164 } 165 PROMLIB_FUNC(int, prom_memsize, (void), memorySize, + 0, return(rc)) 166 PROMLIB_FUNC(int, prom_stdin, (void), inSource, + 0, return(rc)) 167 PROMLIB_FUNC(int, prom_stdout, (void), outSink, + 0, return(rc)) 168 PROMLIB_FUNC(int, prom_kbdid, (void), keyBid, + 0, return(rc)) 169 PROMLIB_FUNC(int, prom_getchar, (void), getChar, (), return(rc)) 170 PROMLIB_FUNC(int, prom_peekchar, (void), mayGet, (), return(rc)) 171 PROMLIB_FUNC(void, prom_putchar, (int c), putChar, (c), return) 172 173 void prom_putstr(buf, len) 174 char *buf; 175 int len; 176 { 177 struct kernel_state state; 178 _mode_monitor(&state, 0); 179 for(; len > 0; buf++, len--) { 180 (*(romVectorPtr->putChar))((int) (*buf)); 181 } 182 _mode_kernel(&state, 0); 183 } 184 185 /* 186 * printf is difficult, because it's a varargs function. 187 * This is very ugly. Please fix me! 188 */ 189 void 190 #ifdef __STDC__ 191 prom_printf(const char *fmt, ...) 192 #else 193 prom_printf(fmt, va_alist) 194 const char *fmt; 195 va_dcl 196 #endif 197 { 198 struct kernel_state state; 199 int rc; 200 va_list ap; 201 const char *p1; 202 char c1; 203 struct printf_args { 204 int arg[15]; 205 } varargs; 206 int i; 207 208 /* 209 * Since the PROM obviously doesn't take a va_list, we conjure 210 * up a structure of ints to hold the arguments, and pass it 211 * the structure (*not* a pointer to the structure!) to get 212 * the same effect. This means there is a limit on the number 213 * of arguments you can use with prom_printf. Ugly indeed. 214 */ 215 va_start(ap, fmt); 216 i = 0; 217 for(p1 = fmt; (c1 = *(p1++)) != '\0'; ) { 218 if (c1 == '%') { 219 if (i == (sizeof(varargs.arg) / sizeof(varargs.arg[0]))) { 220 prom_printf("too many args to prom_printf, format %s", fmt); 221 prom_abort(); 222 } 223 varargs.arg[i++] = va_arg(ap, int); 224 } 225 } 226 va_end(ap); 227 228 /* now call the monitor's printf: */ 229 _mode_monitor(&state, 0); 230 rc = (* 231 /* the ghastly type we cast the PROM printf vector to: */ 232 ( (int (*) __P((const char *, struct printf_args))) 233 /* the PROM printf vector: */ 234 (romVectorPtr->printf)) 235 )(fmt, varargs); 236 _mode_kernel(&state, 0); 237 } 238 239 /* Return the boot path. */ 240 char * 241 prom_getbootpath() 242 { 243 /* 244 * The first bootparam argument is the device string. 245 */ 246 return (sunmon_bootparam.argPtr[0]); 247 } 248 249 /* Return the boot args. */ 250 char * 251 prom_getbootargs() 252 { 253 /* 254 * The second bootparam argument is any options. 255 */ 256 return (sunmon_bootparam.argPtr[1]); 257 } 258 259 /* Return the boot file. */ 260 char * 261 prom_getbootfile() 262 { 263 return (sunmon_bootparam.fileName); 264 } 265 266 /* This maps a PROM `sd' unit number into a SCSI target. */ 267 int 268 prom_sd_target(unit) 269 int unit; 270 { 271 switch(unit) { 272 case 2: return (4); 273 } 274 return (unit); 275 } 276 277 /* 278 * This aborts to the PROM, but should allow the user 279 * to "c" continue back into the kernel. 280 */ 281 void 282 prom_abort() 283 { 284 u_int16_t old_g0_g4_vectors[4], *vec, *store; 285 286 _mode_monitor(&sunmon_kernel_state, 1); 287 288 /* 289 * Set up our g0 and g4 handlers, by writing into 290 * the PROM's vector table directly. Note that 291 * the braw instruction displacement is PC-relative. 292 */ 293 #define BRAW 0x6000 294 vec = (u_int16_t *) sunmon_vbr; 295 store = old_g0_g4_vectors; 296 *(store++) = *vec; 297 *(vec++) = BRAW; 298 *(store++) = *vec; 299 *vec = ((u_long) g0_entry) - ((u_long) vec); 300 vec++; 301 *(store++) = *vec; 302 *(vec++) = BRAW; 303 *(store++) = *vec; 304 *vec = ((u_long) g4_entry) - ((u_long) vec); 305 vec++; 306 #undef BRAW 307 308 delay(100000); 309 310 /* 311 * Drop into the PROM in a way that allows a continue. 312 * Already setup "trap #14" in prom_init(). 313 */ 314 315 asm(" trap #14 ; _sunmon_continued: nop"); 316 317 /* We have continued from a PROM abort! */ 318 319 /* Put back the old g0 and g4 handlers. */ 320 vec = (u_int16_t *) sunmon_vbr; 321 store = old_g0_g4_vectors; 322 *(vec++) = *(store++); 323 *(vec++) = *(store++); 324 *(vec++) = *(store++); 325 *(vec++) = *(store++); 326 327 _mode_kernel(&sunmon_kernel_state, 1); 328 } 329 330 void 331 prom_halt() 332 { 333 _mode_monitor(&sunmon_kernel_state, 1); 334 (*romVectorPtr->exitToMon)(); 335 for(;;); 336 /*NOTREACHED*/ 337 } 338 339 /* 340 * Caller must pass a string that is in our data segment. 341 */ 342 void 343 prom_boot(bs) 344 char *bs; 345 { 346 _mode_monitor(&sunmon_kernel_state, 1); 347 (*romVectorPtr->reBoot)(bs); 348 (*romVectorPtr->exitToMon)(); 349 for(;;); 350 /*NOTREACHED*/ 351 } 352 353 354 /* 355 * Print out a traceback for the caller - can be called anywhere 356 * within the kernel or from the monitor by typing "g4". 357 */ 358 struct funcall_frame { 359 struct funcall_frame *fr_savfp; 360 int fr_savpc; 361 int fr_arg[1]; 362 }; 363 /*VARARGS0*/ 364 static void 365 tracedump(x1) 366 int x1; 367 { 368 struct funcall_frame *fp = (struct funcall_frame *)(&x1 - 2); 369 u_int stackpage = ((u_int)fp) & ~PGOFSET; 370 371 prom_printf("Begin traceback...fp = 0x%x\n", fp); 372 do { 373 if (fp == fp->fr_savfp) { 374 prom_printf("FP loop at 0x%x", fp); 375 break; 376 } 377 prom_printf("Called from 0x%x, fp=0x%x, args=0x%x 0x%x 0x%x 0x%x\n", 378 fp->fr_savpc, fp->fr_savfp, 379 fp->fr_arg[0], fp->fr_arg[1], fp->fr_arg[2], fp->fr_arg[3]); 380 fp = fp->fr_savfp; 381 } while ( (((u_int)fp) & ~PGOFSET) == stackpage); 382 prom_printf("End traceback...\n"); 383 } 384 385 /* Handlers for the old-school "g0" and "g4" */ 386 void g0_handler __P((void)); 387 void 388 g0_handler() 389 { 390 _mode_kernel(&sunmon_kernel_state, 1); 391 panic("zero"); 392 } 393 void g4_handler __P((int)); 394 void 395 g4_handler(addr) 396 int addr; 397 { 398 _mode_kernel(&sunmon_kernel_state, 1); 399 tracedump(addr); 400 } 401 402 /* 403 * Set the PROM vector handler (for g0, g4, etc.) 404 * and set boothowto from the PROM arg strings. 405 * 406 * Note, args are always: 407 * argv[0] = boot_device (i.e. "sd(0,0,0)") 408 * argv[1] = options (i.e. "-ds" or NULL) 409 * argv[2] = NULL 410 */ 411 void 412 prom_init() 413 { 414 struct bootparam *old_bp; 415 struct bootparam *new_bp; 416 int bp_shift; 417 int i; 418 char *p; 419 int fl; 420 421 /* 422 * Any second the pointers in the PROM vector are going to 423 * break (since they point into pages zero through three, 424 * which we like to keep unmapped), so we grab a complete 425 * copy of the bootparams, taking care to adjust the pointers 426 * in the copy to also point to the copy. 427 */ 428 old_bp = *romVectorPtr->bootParam; 429 new_bp = &sunmon_bootparam; 430 *new_bp = *old_bp; 431 bp_shift = ((char *) new_bp) - ((char *) old_bp); 432 for(i = 0; i < 8 && new_bp->argPtr[i] != NULL; i++) { 433 new_bp->argPtr[i] += bp_shift; 434 } 435 new_bp->fileName += bp_shift; 436 437 /* Save the PROM's mappings for pages zero through three. */ 438 _prom_swap_ptes(sunmon_ptes, sunmon_ptes); 439 440 /* Save the PROM monitor Vector Base Register (VBR). */ 441 sunmon_vbr = getvbr(); 442 443 /* Arrange for "trap #14" to cause a PROM abort. */ 444 sunmon_vbr[32+14] = romVectorPtr->abortEntry; 445 446 /* Try to find some options. */ 447 p = prom_getbootargs(); 448 if (p != NULL) { 449 450 /* Skip any whitespace */ 451 for(; *p != '-'; ) 452 if (*(p++) == '\0') { 453 p = NULL; 454 break; 455 } 456 } 457 458 /* If we have options. */ 459 if (p != NULL) { 460 #ifdef DEBUG 461 prom_printf("boot options: %s\n", p); 462 #endif 463 for(; *(++p); ) { 464 fl = 0; 465 BOOT_FLAG(*p, fl); 466 if (fl) 467 boothowto |= fl; 468 else 469 prom_printf("unknown option `%c'\n", *p); 470 } 471 } 472 } 473