locore2.c revision 1.2
1/*	$NetBSD: locore2.c,v 1.2 1997/01/16 21:53:07 gwr 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 Gordon W. Ross, and Jeremy Cooper.
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/proc.h>
42#include <sys/reboot.h>
43#include <sys/user.h>
44#include <sys/exec_aout.h>
45
46#include <vm/vm.h>
47
48#include <machine/cpu.h>
49#include <machine/db_machdep.h>
50#include <machine/dvma.h>
51#include <machine/mon.h>
52#include <machine/pte.h>
53#include <machine/pmap.h>
54#include <machine/idprom.h>
55#include <machine/obio.h>
56
57#include "vector.h"
58#include "interreg.h"
59#include "machdep.h"
60
61/* This is defined in locore.s */
62extern char kernel_text[];
63
64/* This is set by locore.s with the monitor's root ptr. */
65extern struct mmu_rootptr mon_crp;
66
67/* These are defined by the linker */
68extern char etext[], edata[], end[];
69char *esym;	/* DDB */
70
71/*
72 * Now our own stuff.
73 */
74int boothowto = RB_KDB; 	/* XXX - For now... */
75int cold = 1;
76void **old_vector_table;
77
78unsigned char cpu_machine_id = 0;
79char *cpu_string = NULL;
80int cpu_has_vme = 0;
81int has_iocache = 0;
82
83int msgbufmapped = 0;
84struct msgbuf *msgbufp = NULL;
85
86struct user *proc0paddr;	/* proc[0] pcb address (u-area VA) */
87extern struct pcb *curpcb;
88
89/* First C code called by locore.s */
90void _bootstrap __P((struct exec));
91
92static void _monitor_hooks __P((void));
93static void _verify_hardware __P((void));
94static void _vm_init __P((struct exec *kehp));
95static void tracedump __P((int));
96static void v_handler __P((int addr, char *str));
97
98
99/*
100 * Prepare for running the PROM monitor
101 */
102static void
103sun3x_mode_monitor __P((void))
104{
105	/* Install PROM vector table and enable NMI clock. */
106	/* XXX - Disable watchdog action? */
107	set_clk_mode(0, IREG_CLOCK_ENAB_5, 0);
108	setvbr(old_vector_table);
109	set_clk_mode(IREG_CLOCK_ENAB_7, 0, 1);
110
111	loadcrp((int)&mon_crp);
112}
113
114/*
115 * Prepare for running the kernel
116 */
117static void
118sun3x_mode_normal __P((void))
119{
120	struct pcb *pcb;
121
122	/* Install our vector table and disable the NMI clock. */
123	set_clk_mode(0, IREG_CLOCK_ENAB_7, 0);
124	setvbr((void**)vector_table);
125	set_clk_mode(IREG_CLOCK_ENAB_5, 0, 1);
126
127	pcb = curpcb ? curpcb :
128		pcb = &proc0paddr->u_pcb;
129
130	loadcrp(pcb->pcb_mmuctx);
131}
132
133/*
134 * This function takes care of restoring enough of the
135 * hardware state to allow the PROM to run normally.
136 * The PROM needs: NMI enabled, it's own vector table.
137 * In case of a temporary "drop into PROM", this will
138 * also put our hardware state back into place after
139 * the PROM "c" (continue) command is given.
140 */
141void sun3x_mon_abort()
142{
143	int s = splhigh();
144
145	sun3x_mode_monitor();
146	mon_printf("kernel stop: enter c to continue or g0 to panic\n");
147	delay(100000);
148
149	/*
150	 * Drop into the PROM in a way that allows a continue.
151	 * That's what the PROM function (romp->abortEntry) is for,
152	 * but that wants to be entered as a trap hander, so just
153	 * stuff it into the PROM interrupt vector for trap zero
154	 * and then do a trap.  Needs PROM vector table in RAM.
155	 */
156	old_vector_table[32] = romVectorPtr->abortEntry;
157	asm(" trap #0 ; _sun3x_mon_continued: nop");
158
159	/* We have continued from a PROM abort! */
160
161	sun3x_mode_normal();
162	splx(s);
163}
164
165void sun3x_mon_halt()
166{
167	(void) splhigh();
168	sun3x_mode_monitor();
169	mon_exit_to_mon();
170	/*NOTREACHED*/
171}
172
173/*
174 * Caller must pass a string that is in our data segment.
175 */
176void sun3x_mon_reboot(bootstring)
177	char *bootstring;
178{
179#ifdef	DIAGNOSTIC
180	if (bootstring > end)
181		bootstring = "?";
182#endif
183
184	(void) splhigh();
185	sun3x_mode_monitor();
186	mon_reboot(bootstring);
187	mon_exit_to_mon();
188	/*NOTREACHED*/
189}
190
191
192#if defined(DDB) && !defined(SYMTAB_SPACE)
193static void _save_symtab __P((struct exec *kehp));
194
195/*
196 * Preserve DDB symbols and strings by setting esym.
197 */
198static void
199_save_symtab(kehp)
200	struct exec *kehp;	/* kernel exec header */
201{
202	int x, *symsz, *strsz;
203	char *endp;
204	char *errdesc = "?";
205
206	/*
207	 * First, sanity-check the exec header.
208	 */
209	mon_printf("_save_symtab: ");
210	if ((kehp->a_midmag & 0xFFF0) != 0x0100) {
211		errdesc = "magic";
212		goto err;
213	}
214	/* Boundary between text and data varries a little. */
215	x = kehp->a_text + kehp->a_data;
216	if (x != (edata - kernel_text)) {
217		errdesc = "a_text+a_data";
218		goto err;
219	}
220	if (kehp->a_bss != (end - edata)) {
221		errdesc = "a_bss";
222		goto err;
223	}
224	if (kehp->a_entry != (int)kernel_text) {
225		errdesc = "a_entry";
226		goto err;
227	}
228	if (kehp->a_trsize || kehp->a_drsize) {
229		errdesc = "a_Xrsize";
230		goto err;
231	}
232	/* The exec header looks OK... */
233
234	/* Check the symtab length word. */
235	endp = end;
236	symsz = (int*)endp;
237	if (kehp->a_syms != *symsz) {
238		errdesc = "a_syms";
239		goto err;
240	}
241	endp += sizeof(int);	/* past length word */
242	endp += *symsz;			/* past nlist array */
243
244	/* Check the string table length. */
245	strsz = (int*)endp;
246	if ((*strsz < 4) || (*strsz > 0x80000)) {
247		errdesc = "strsize";
248		goto err;
249	}
250
251	/* Success!  We have a valid symbol table! */
252	endp += *strsz;			/* past strings */
253	esym = endp;
254	mon_printf(" found %d + %d\n", *symsz, *strsz);
255	return;
256
257 err:
258	mon_printf(" no symbols (bad %s)\n", errdesc);
259}
260#endif	/* DDB && !SYMTAB_SPACE */
261
262/*
263 * This function is called from _bootstrap() to initialize
264 * pre-vm-sytem virtual memory.  All this really does is to
265 * set virtual_avail to the first page following preloaded
266 * data (i.e. the kernel and its symbol table) and special
267 * things that may be needed very early (proc0 upages).
268 * Once that is done, pmap_bootstrap() is called to do the
269 * usual preparations for our use of the MMU.
270 */
271static void
272_vm_init(kehp)
273	struct exec *kehp;	/* kernel exec header */
274{
275	vm_offset_t nextva;
276
277	/*
278	 * First, reserve our symbol table which might have been
279	 * loaded after our BSS area by the boot loader.  However,
280	 * if DDB is not part of this kernel, ignore the symbols.
281	 */
282	esym = end;
283#if defined(DDB) && !defined(SYMTAB_SPACE)
284	/* This will advance esym past the symbols. */
285	_save_symtab(kehp);
286#endif
287
288	/*
289	 * Steal some special-purpose, already mapped pages.
290	 * Note: msgbuf is setup in machdep.c:cpu_startup()
291	 */
292	nextva = sun3x_round_page(esym);
293
294	/*
295	 * Setup the u-area pages (stack, etc.) for proc0.
296	 * This is done very early (here) to make sure the
297	 * fault handler works in case we hit an early bug.
298	 * (The fault handler may reference proc0 stuff.)
299	 */
300	proc0paddr = (struct user *) nextva;
301	nextva += USPACE;
302	bzero((caddr_t)proc0paddr, USPACE);
303	proc0.p_addr = proc0paddr;
304
305	/*
306	 * Now that proc0 exists, make it the "current" one.
307	 */
308	curproc = &proc0;
309	curpcb = &proc0paddr->u_pcb;
310
311	/*
312	 * Call pmap_bootstrap() so that we may begin using
313	 * pmap_enter_kernel() and pmap_bootstrap_alloc().
314	 */
315	pmap_bootstrap(nextva);
316}
317
318
319/*
320 * XXX - Should empirically estimate the divisor...
321 * Note that the value of delay_divisor is roughly
322 * 2048 / cpuclock	(where cpuclock is in MHz).
323 */
324int delay_divisor = 82;		/* assume the fastest (3/260) */
325
326static void
327_verify_hardware()
328{
329	unsigned char machtype;
330	int cpu_match = 0;
331
332	machtype = identity_prom.idp_machtype;
333	if ((machtype & CPU_ARCH_MASK) != SUN3X_ARCH)
334		mon_panic("not a sun3x?\n");
335
336	cpu_machine_id = machtype & SUN3X_IMPL_MASK;
337	switch (cpu_machine_id) {
338
339	case SUN3X_MACH_80 :
340		cpu_match++;
341		cpu_string = "80";
342		delay_divisor = 102;	/* 20 MHz ? XXX */
343		cpu_has_vme = FALSE;
344		break;
345
346	case SUN3X_MACH_470:
347		cpu_match++;
348		cpu_string = "470";
349		delay_divisor = 82; 	/* 25 MHz ? XXX */
350		cpu_has_vme = TRUE;
351		break;
352
353	default:
354		mon_panic("unknown sun3x model\n");
355	}
356	if (!cpu_match)
357		mon_panic("kernel not configured for the Sun 3 model\n");
358}
359
360/*
361 * Print out a traceback for the caller - can be called anywhere
362 * within the kernel or from the monitor by typing "g4" (for sun-2
363 * compatibility) or "w trace".  This causes the monitor to call
364 * the v_handler() routine which will call tracedump() for these cases.
365 */
366struct funcall_frame {
367	struct funcall_frame *fr_savfp;
368	int fr_savpc;
369	int fr_arg[1];
370};
371/*VARARGS0*/
372static void
373tracedump(x1)
374	int x1;
375{
376	struct funcall_frame *fp = (struct funcall_frame *)(&x1 - 2);
377	u_int stackpage = ((u_int)fp) & ~PGOFSET;
378
379	mon_printf("Begin traceback...fp = %x\n", fp);
380	do {
381		if (fp == fp->fr_savfp) {
382			mon_printf("FP loop at %x", fp);
383			break;
384		}
385		mon_printf("Called from %x, fp=%x, args=%x %x %x %x\n",
386				   fp->fr_savpc, fp->fr_savfp,
387				   fp->fr_arg[0], fp->fr_arg[1], fp->fr_arg[2], fp->fr_arg[3]);
388		fp = fp->fr_savfp;
389	} while ( (((u_int)fp) & ~PGOFSET) == stackpage);
390	mon_printf("End traceback...\n");
391}
392
393/*
394 * Handler for monitor vector cmd -
395 * For now we just implement the old "g0" and "g4"
396 * commands and a printf hack.  [lifted from freed cmu mach3 sun3 port]
397 */
398static void
399v_handler(addr, str)
400	int addr;
401	char *str;
402{
403
404	switch (*str) {
405	case '\0':
406		/*
407		 * No (non-hex) letter was specified on
408		 * command line, use only the number given
409		 */
410		switch (addr) {
411		case 0:			/* old g0 */
412		case 0xd:		/* 'd'ump short hand */
413			sun3x_mode_normal();
414			panic("zero");
415			/*NOTREACHED*/
416
417		case 4:			/* old g4 */
418			goto do_trace;
419
420		default:
421			goto err;
422		}
423		break;
424
425	case 'p':			/* 'p'rint string command */
426	case 'P':
427		mon_printf("%s\n", (char *)addr);
428		break;
429
430	case '%':			/* p'%'int anything a la printf */
431		mon_printf(str, addr);
432		mon_printf("\n");
433		break;
434
435	do_trace:
436	case 't':			/* 't'race kernel stack */
437	case 'T':
438		tracedump(addr);
439		break;
440
441	case 'u':			/* d'u'mp hack ('d' look like hex) */
442	case 'U':
443		goto err;
444		break;
445
446	default:
447	err:
448		mon_printf("Don't understand 0x%x '%s'\n", addr, str);
449	}
450}
451
452/*
453 * Set the PROM vector handler (for g0, g4, etc.)
454 * and set boothowto from the PROM arg strings.
455 *
456 * Note, args are always:
457 * argv[0] = boot_device	(i.e. "sd(0,0,0)")
458 * argv[1] = options	(i.e. "-ds" or NULL)
459 * argv[2] = NULL
460 */
461static void
462_monitor_hooks()
463{
464	MachMonRomVector *romp;
465	MachMonBootParam *bpp;
466	char **argp;
467	char *p;
468
469	romp = romVectorPtr;
470	if (romp->romvecVersion >= 2)
471		*romp->vector_cmd = v_handler;
472
473	/* Set boothowto flags from PROM args. */
474	bpp = *romp->bootParam;
475	argp = bpp->argPtr;
476
477	/* Skip argp[0] (the device string) */
478	argp++;
479
480	/* Have options? */
481	if (*argp == NULL)
482		return;
483	p = *argp;
484	if (*p == '-') {
485		/* yes, parse options */
486#ifdef	DEBUG
487		mon_printf("boot option: %s\n", p);
488#endif
489		for (++p; *p; p++) {
490			switch (*p) {
491			case 'a':
492				boothowto |= RB_ASKNAME;
493				break;
494			case 's':
495				boothowto |= RB_SINGLE;
496				break;
497			case 'd':
498				boothowto |= RB_KDB;
499				break;
500			}
501		}
502		argp++;
503	}
504
505#ifdef	DEBUG
506	/* Have init name? */
507	if (*argp == NULL)
508		return;
509	p = *argp;
510	mon_printf("boot initpath: %s\n", p);
511#endif
512}
513
514/*
515 * This is called from locore.s just after the kernel is remapped
516 * to its proper address, but before the call to main().  The work
517 * done here corresponds to various things done in locore.s on the
518 * hp300 port (and other m68k) but which we prefer to do in C code.
519 * Also do setup specific to the Sun PROM monitor and IDPROM here.
520 */
521void
522_bootstrap(keh)
523	struct exec keh;	/* kernel exec header */
524{
525
526	/* First, Clear BSS. */
527	bzero(edata, end - edata);
528
529	/* set v_handler, get boothowto */
530	_monitor_hooks();
531
532	/* Find devices we need early (like the IDPROM). */
533	obio_init();
534
535	/* Note: must come after obio_init (for IDPROM). */
536	_verify_hardware();	/* get CPU type, etc. */
537
538	/* handle kernel mapping, pmap_bootstrap(), etc. */
539	_vm_init(&keh);
540
541	/*
542	 * Point interrupts/exceptions to our vector table.
543	 * (Until now, we use the one setup by the PROM.)
544	 *
545	 * This is done after obio_init() / intreg_init() finds
546	 * the interrupt register and disables the NMI clock so
547	 * it will not cause "spurrious level 7" complaints.
548	 */
549	old_vector_table = getvbr();
550	setvbr((void **)vector_table);
551
552	/* Interrupts are enabled later, after autoconfig. */
553}
554