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