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