1 /* $NetBSD: machdep.c,v 1.75 2002/05/13 07:12:21 matt Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "opt_compat_netbsd.h" 35 #include "opt_ddb.h" 36 37 #include <sys/param.h> 38 #include <sys/buf.h> 39 #include <sys/exec.h> 40 #include <sys/malloc.h> 41 #include <sys/map.h> 42 #include <sys/mbuf.h> 43 #include <sys/mount.h> 44 #include <sys/msgbuf.h> 45 #include <sys/proc.h> 46 #include <sys/reboot.h> 47 #include <sys/syscallargs.h> 48 #include <sys/syslog.h> 49 #include <sys/systm.h> 50 #include <sys/kernel.h> 51 #include <sys/user.h> 52 #include <sys/boot_flag.h> 53 54 #include <uvm/uvm_extern.h> 55 56 #include <net/netisr.h> 57 58 #include <machine/db_machdep.h> 59 #include <ddb/db_extern.h> 60 61 #include <dev/ofw/openfirm.h> 62 63 #include <machine/autoconf.h> 64 #include <machine/bat.h> 65 #include <machine/pmap.h> 66 #include <machine/powerpc.h> 67 #include <machine/trap.h> 68 69 #include <machine/platform.h> 70 71 #include <dev/cons.h> 72 73 /* 74 * Global variables used here and there 75 */ 76 struct vm_map *exec_map = NULL; 77 struct vm_map *mb_map = NULL; 78 struct vm_map *phys_map = NULL; 79 80 struct pcb *curpcb; 81 struct pmap *curpm; 82 struct proc *fpuproc; 83 84 extern struct user *proc0paddr; 85 86 struct bat battable[16]; 87 88 char *bootpath; 89 90 paddr_t msgbuf_paddr; 91 vaddr_t msgbuf_vaddr; 92 93 int lcsplx(int); /* called from locore.S */ 94 95 static int fake_spl __P((int)); 96 static void fake_splx __P((int)); 97 static void fake_setsoft __P((int)); 98 static void fake_clock_return __P((struct clockframe *, int)); 99 static void *fake_intr_establish __P((int, int, int, int (*)(void *), void *)); 100 static void fake_intr_disestablish __P((void *)); 101 102 struct machvec machine_interface = { 103 fake_spl, 104 fake_spl, 105 fake_splx, 106 fake_setsoft, 107 fake_clock_return, 108 fake_intr_establish, 109 fake_intr_disestablish, 110 }; 111 112 void ofppc_bootstrap_console(void); 113 114 void 115 initppc(startkernel, endkernel, args) 116 u_int startkernel, endkernel; 117 char *args; 118 { 119 extern int trapcode, trapsize; 120 extern int alitrap, alisize; 121 extern int dsitrap, dsisize; 122 extern int isitrap, isisize; 123 extern int decrint, decrsize; 124 extern int tlbimiss, tlbimsize; 125 extern int tlbdlmiss, tlbdlmsize; 126 extern int tlbdsmiss, tlbdsmsize; 127 #ifdef DDB 128 extern int ddblow, ddbsize; 129 extern void *startsym, *endsym; 130 #endif 131 #ifdef IPKDB 132 extern int ipkdblow, ipkdbsize; 133 #endif 134 int exc, scratch; 135 136 /* Initialize the bootstrap console. */ 137 ofppc_bootstrap_console(); 138 139 /* 140 * Initialize BAT registers to unmapped to not generate 141 * overlapping mappings below. 142 */ 143 asm volatile ("mtibatu 0,%0" :: "r"(0)); 144 asm volatile ("mtibatu 1,%0" :: "r"(0)); 145 asm volatile ("mtibatu 2,%0" :: "r"(0)); 146 asm volatile ("mtibatu 3,%0" :: "r"(0)); 147 asm volatile ("mtdbatu 0,%0" :: "r"(0)); 148 asm volatile ("mtdbatu 1,%0" :: "r"(0)); 149 asm volatile ("mtdbatu 2,%0" :: "r"(0)); 150 asm volatile ("mtdbatu 3,%0" :: "r"(0)); 151 152 /* 153 * Set up initial BAT table to only map the lowest 256 MB area 154 */ 155 battable[0].batl = BATL(0x00000000, BAT_M, BAT_PP_RW); 156 battable[0].batu = BATU(0x00000000, BAT_BL_256M, BAT_Vs); 157 158 /* 159 * Now setup fixed bat registers 160 * 161 * Note that we still run in real mode, and the BAT 162 * registers were cleared above. 163 */ 164 /* IBAT0 used for initial 256 MB segment */ 165 asm volatile ("mtibatl 0,%0; mtibatu 0,%1" 166 :: "r"(battable[0].batl), "r"(battable[0].batu)); 167 /* DBAT0 used similar */ 168 asm volatile ("mtdbatl 0,%0; mtdbatu 0,%1" 169 :: "r"(battable[0].batl), "r"(battable[0].batu)); 170 171 /* 172 * Initialize the platform structure. This may add entries 173 * to the BAT table. 174 */ 175 platform_init(); 176 177 proc0.p_addr = proc0paddr; 178 memset(proc0.p_addr, 0, sizeof *proc0.p_addr); 179 180 curpcb = &proc0paddr->u_pcb; 181 182 curpm = curpcb->pcb_pmreal = curpcb->pcb_pm = pmap_kernel(); 183 184 #ifdef __notyet__ /* Needs some rethinking regarding real/virtual OFW */ 185 OF_set_callback(callback); 186 #endif 187 188 /* 189 * Set up trap vectors 190 */ 191 for (exc = EXC_RSVD; exc <= EXC_LAST; exc += 0x100) 192 switch (exc) { 193 default: 194 memcpy((void *)exc, &trapcode, (size_t)&trapsize); 195 break; 196 case EXC_EXI: 197 /* 198 * This one is (potentially) installed during autoconf 199 */ 200 break; 201 case EXC_ALI: 202 memcpy((void *)EXC_ALI, &alitrap, (size_t)&alisize); 203 break; 204 case EXC_DSI: 205 memcpy((void *)EXC_DSI, &dsitrap, (size_t)&dsisize); 206 break; 207 case EXC_ISI: 208 memcpy((void *)EXC_ISI, &isitrap, (size_t)&isisize); 209 break; 210 case EXC_DECR: 211 memcpy((void *)EXC_DECR, &decrint, (size_t)&decrsize); 212 break; 213 case EXC_IMISS: 214 memcpy((void *)EXC_IMISS, &tlbimiss, (size_t)&tlbimsize); 215 break; 216 case EXC_DLMISS: 217 memcpy((void *)EXC_DLMISS, &tlbdlmiss, (size_t)&tlbdlmsize); 218 break; 219 case EXC_DSMISS: 220 memcpy((void *)EXC_DSMISS, &tlbdsmiss, (size_t)&tlbdsmsize); 221 break; 222 #if defined(DDB) || defined(IPKDB) 223 case EXC_PGM: 224 case EXC_TRC: 225 case EXC_BPT: 226 #if defined(DDB) 227 memcpy((void *)exc, &ddblow, (size_t)&ddbsize); 228 #else 229 memcpy((void *)exc, &ipkdblow, (size_t)&ipkdbsize); 230 #endif 231 break; 232 #endif /* DDB || IPKDB */ 233 } 234 235 __syncicache((void *)EXC_RST, EXC_LAST - EXC_RST + 0x100); 236 237 /* 238 * Now enable translation (and machine checks/recoverable interrupts). 239 */ 240 asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0; isync" 241 : "=r"(scratch) : "K"(PSL_IR|PSL_DR|PSL_ME|PSL_RI)); 242 243 /* 244 * Now that translation is enabled (and we can access bus space), 245 * initialize the console. 246 */ 247 (*platform.cons_init)(); 248 249 /* 250 * Parse arg string. 251 */ 252 bootpath = args; 253 while (*++args && *args != ' '); 254 if (*args) { 255 for(*args++ = 0; *args; args++) 256 BOOT_FLAG(*args, boothowto); 257 } 258 259 /* 260 * Set the page size. 261 */ 262 uvm_setpagesize(); 263 264 /* 265 * Initialize pmap module. 266 */ 267 pmap_bootstrap(startkernel, endkernel, NULL); 268 269 #ifdef DDB 270 ddb_init((int)((u_int)endsym - (u_int)startsym), startsym, endsym); 271 if (boothowto & RB_KDB) 272 Debugger(); 273 #endif 274 #ifdef IPKDB 275 /* 276 * Now trap to IPKDB 277 */ 278 ipkdb_init(); 279 if (boothowto & RB_KDB) 280 ipkdb_connect(0); 281 #endif 282 } 283 284 /* 285 * This should probably be in autoconf! XXX 286 */ 287 char machine[] = MACHINE; /* from <machine/param.h> */ 288 char machine_arch[] = MACHINE_ARCH; /* from <machine/param.h> */ 289 290 void 291 install_extint(handler) 292 void (*handler) __P((void)); 293 { 294 extern int extint, extsize; 295 extern u_long extint_call; 296 u_long offset = (u_long)handler - (u_long)&extint_call; 297 int omsr, msr; 298 299 #ifdef DIAGNOSTIC 300 if (offset > 0x1ffffff) 301 panic("install_extint: too far away"); 302 #endif 303 asm volatile ("mfmsr %0; andi. %1,%0,%2; mtmsr %1" 304 : "=r"(omsr), "=r"(msr) : "K"((u_short)~PSL_EE)); 305 extint_call = (extint_call & 0xfc000003) | offset; 306 memcpy((void *)EXC_EXI, &extint, (size_t)&extsize); 307 __syncicache((void *)&extint_call, sizeof extint_call); 308 __syncicache((void *)EXC_EXI, (int)&extsize); 309 asm volatile ("mtmsr %0" :: "r"(omsr)); 310 } 311 312 /* 313 * Machine dependent startup code. 314 */ 315 void 316 cpu_startup() 317 { 318 int sz, i; 319 caddr_t v; 320 paddr_t minaddr, maxaddr; 321 int base, residual; 322 char pbuf[9]; 323 324 proc0.p_addr = proc0paddr; 325 v = (caddr_t)proc0paddr + USPACE; 326 327 /* 328 * Initialize error message buffer (at end of core). 329 */ 330 if (!(msgbuf_vaddr = uvm_km_alloc(kernel_map, round_page(MSGBUFSIZE)))) 331 panic("startup: no room for message buffer"); 332 for (i = 0; i < btoc(MSGBUFSIZE); i++) 333 pmap_enter(pmap_kernel(), msgbuf_vaddr + i * NBPG, 334 msgbuf_paddr + i * NBPG, VM_PROT_READ|VM_PROT_WRITE, 335 VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED); 336 pmap_update(pmap_kernel()); 337 initmsgbuf((caddr_t)msgbuf_vaddr, round_page(MSGBUFSIZE)); 338 339 printf("%s", version); 340 cpu_identify(NULL, 0); 341 342 format_bytes(pbuf, sizeof(pbuf), ctob(physmem)); 343 printf("total memory = %s\n", pbuf); 344 345 /* 346 * Find out how much space we need, allocate it, 347 * and then give everything true virtual addresses. 348 */ 349 sz = (int)allocsys(NULL, NULL); 350 if ((v = (caddr_t)uvm_km_zalloc(kernel_map, round_page(sz))) == 0) 351 panic("startup: no room for tables"); 352 if (allocsys(v, NULL) - v != sz) 353 panic("startup: table size inconsistency"); 354 355 /* 356 * Now allocate buffers proper. They are different than the above 357 * in that they usually occupy more virtual memory than physical. 358 */ 359 sz = MAXBSIZE * nbuf; 360 if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(sz), 361 NULL, UVM_UNKNOWN_OFFSET, 0, 362 UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, 363 UVM_ADV_NORMAL, 0)) != 0) 364 panic("startup: cannot allocate VM for buffers"); 365 minaddr = (vaddr_t)buffers; 366 base = bufpages / nbuf; 367 residual = bufpages % nbuf; 368 if (base >= MAXBSIZE) { 369 /* Don't want to alloc more physical mem than ever needed */ 370 base = MAXBSIZE; 371 residual = 0; 372 } 373 for (i = 0; i < nbuf; i++) { 374 vsize_t curbufsize; 375 vaddr_t curbuf; 376 struct vm_page *pg; 377 378 /* 379 * Each buffer has MAXBSIZE bytes of VM space allocated. Of 380 * that MAXBSIZE space, we allocate and map (base+1) pages 381 * for the first "residual" buffers, and then we allocate 382 * "base" pages for the rest. 383 */ 384 curbuf = (vaddr_t) buffers + (i * MAXBSIZE); 385 curbufsize = NBPG * ((i < residual) ? (base+1) : base); 386 387 while (curbufsize) { 388 pg = uvm_pagealloc(NULL, 0, NULL, 0); 389 if (pg == NULL) 390 panic("startup: not enough memory for " 391 "buffer cache"); 392 pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg), 393 VM_PROT_READ | VM_PROT_WRITE); 394 curbuf += PAGE_SIZE; 395 curbufsize -= PAGE_SIZE; 396 } 397 } 398 pmap_update(kernel_map->pmap); 399 400 /* 401 * Allocate a submap for exec arguments. This map effectively 402 * limits the number of processes exec'ing at any time. 403 */ 404 exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 405 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); 406 407 /* 408 * Allocate a submap for physio 409 */ 410 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 411 VM_PHYS_SIZE, 0, FALSE, NULL); 412 413 /* 414 * No need to allocate an mbuf cluster submap. Mbuf clusters 415 * are allocated via the pool allocator, and we use direct-mapped 416 * pool pages. 417 */ 418 419 format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); 420 printf("avail memory = %s\n", pbuf); 421 format_bytes(pbuf, sizeof(pbuf), bufpages * NBPG); 422 printf("using %d buffers containing %s of memory\n", nbuf, pbuf); 423 424 /* 425 * Set up the buffers. 426 */ 427 bufinit(); 428 429 /* 430 * Now allow hardware interrupts. 431 */ 432 { 433 int msr; 434 435 splhigh(); 436 asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0" 437 : "=r"(msr) : "K"((u_short)(PSL_EE|PSL_RI))); 438 } 439 } 440 441 void 442 consinit() 443 { 444 445 /* Nothing to do; console is already initialized. */ 446 } 447 448 int ofppc_cngetc(dev_t); 449 void ofppc_cnputc(dev_t, int); 450 451 struct consdev ofppc_bootcons = { 452 NULL, NULL, ofppc_cngetc, ofppc_cnputc, nullcnpollc, NULL, 453 makedev(0,0), 1, 454 }; 455 456 int ofppc_stdin_ihandle, ofppc_stdout_ihandle; 457 int ofppc_stdin_phandle, ofppc_stdout_phandle; 458 459 void 460 ofppc_bootstrap_console(void) 461 { 462 int chosen; 463 char data[4]; 464 465 chosen = OF_finddevice("/chosen"); 466 467 if (OF_getprop(chosen, "stdin", data, sizeof(data)) != sizeof(int)) 468 goto nocons; 469 ofppc_stdin_ihandle = of_decode_int(data); 470 ofppc_stdin_phandle = OF_instance_to_package(ofppc_stdin_ihandle); 471 472 if (OF_getprop(chosen, "stdout", data, sizeof(data)) != sizeof(int)) 473 goto nocons; 474 ofppc_stdout_ihandle = of_decode_int(data); 475 ofppc_stdout_phandle = OF_instance_to_package(ofppc_stdout_ihandle); 476 477 cn_tab = &ofppc_bootcons; 478 479 nocons: 480 return; 481 } 482 483 int 484 ofppc_cngetc(dev_t dev) 485 { 486 u_char ch = '\0'; 487 int l; 488 489 while ((l = OF_read(ofppc_stdin_ihandle, &ch, 1)) != 1) 490 if (l != -2 && l != 0) 491 return (-1); 492 493 return (ch); 494 } 495 496 void 497 ofppc_cnputc(dev_t dev, int c) 498 { 499 char ch = c; 500 501 OF_write(ofppc_stdout_ihandle, &ch, 1); 502 } 503 504 /* 505 * Crash dump handling. 506 */ 507 508 void 509 dumpsys() 510 { 511 printf("dumpsys: TBD\n"); 512 } 513 514 /* 515 * Soft networking interrupts. 516 */ 517 void 518 softnet() 519 { 520 int isr = netisr; 521 522 netisr = 0; 523 524 #define DONETISR(bit, fn) do { \ 525 if (isr & (1 << bit)) \ 526 fn(); \ 527 } while (0) 528 529 #include <net/netisr_dispatch.h> 530 531 #undef DONETISR 532 } 533 534 /* 535 * Stray interrupts. 536 */ 537 void 538 strayintr(irq) 539 int irq; 540 { 541 log(LOG_ERR, "stray interrupt %d\n", irq); 542 } 543 544 /* 545 * Halt or reboot the machine after syncing/dumping according to howto. 546 */ 547 void 548 cpu_reboot(howto, what) 549 int howto; 550 char *what; 551 { 552 static int syncing; 553 static char str[256]; 554 char *ap = str, *ap1 = ap; 555 556 boothowto = howto; 557 if (!cold && !(howto & RB_NOSYNC) && !syncing) { 558 syncing = 1; 559 vfs_shutdown(); /* sync */ 560 resettodr(); /* set wall clock */ 561 } 562 splhigh(); 563 if (howto & RB_HALT) { 564 doshutdownhooks(); 565 printf("halted\n\n"); 566 ppc_exit(); 567 } 568 if (!cold && (howto & RB_DUMP)) 569 dumpsys(); 570 doshutdownhooks(); 571 printf("rebooting\n\n"); 572 if (what && *what) { 573 if (strlen(what) > sizeof str - 5) 574 printf("boot string too large, ignored\n"); 575 else { 576 strcpy(str, what); 577 ap1 = ap = str + strlen(str); 578 *ap++ = ' '; 579 } 580 } 581 *ap++ = '-'; 582 if (howto & RB_SINGLE) 583 *ap++ = 's'; 584 if (howto & RB_KDB) 585 *ap++ = 'd'; 586 *ap++ = 0; 587 if (ap[-2] == '-') 588 *ap1 = 0; 589 ppc_boot(str); 590 } 591 592 #ifdef notyet 593 /* 594 * OpenFirmware callback routine 595 */ 596 void 597 callback(p) 598 void *p; 599 { 600 panic("callback"); /* for now XXX */ 601 } 602 #endif 603 604 /* 605 * Perform an `splx()' for locore. 606 */ 607 int 608 lcsplx(int ipl) 609 { 610 611 return (_spllower(ipl)); 612 } 613 614 /* 615 * Initial Machine Interface. 616 */ 617 static int 618 fake_spl(int new) 619 { 620 int scratch; 621 622 asm volatile ("mfmsr %0; andi. %0,%0,%1; mtmsr %0; isync" 623 : "=r"(scratch) : "K"((u_short)~(PSL_EE|PSL_ME))); 624 return (-1); 625 } 626 627 static void 628 fake_setsoft(int ipl) 629 { 630 /* Do nothing */ 631 } 632 633 static void 634 fake_splx(new) 635 int new; 636 { 637 638 (void) fake_spl(0); 639 } 640 641 static void 642 fake_clock_return(frame, nticks) 643 struct clockframe *frame; 644 int nticks; 645 { 646 /* Do nothing */ 647 } 648 649 static void * 650 fake_intr_establish(irq, level, ist, handler, arg) 651 int irq, level, ist; 652 int (*handler) __P((void *)); 653 void *arg; 654 { 655 656 panic("fake_intr_establish"); 657 } 658 659 static void 660 fake_intr_disestablish(cookie) 661 void *cookie; 662 { 663 664 panic("fake_intr_disestablish"); 665 } 666