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