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