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