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