1 /* $NetBSD: machdep.c,v 1.272 2026/04/28 03:29:09 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1982, 1986, 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: Utah $Hdr: machdep.c 1.74 92/12/20$ 37 * 38 * @(#)machdep.c 8.10 (Berkeley) 4/20/94 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.272 2026/04/28 03:29:09 thorpej Exp $"); 43 44 #include "opt_ddb.h" 45 #include "opt_fpu_emulate.h" 46 #include "opt_modular.h" 47 #include "opt_m68k_arch.h" 48 #include "opt_panicbutton.h" 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/callout.h> 53 #include <sys/buf.h> 54 #include <sys/conf.h> 55 #include <sys/exec.h> 56 #include <sys/file.h> 57 #include <sys/ioctl.h> 58 #include <sys/kernel.h> 59 #include <sys/device.h> 60 #include <sys/malloc.h> 61 #include <sys/mbuf.h> 62 #include <sys/mount.h> 63 #include <sys/msgbuf.h> 64 #include <sys/proc.h> 65 #include <sys/reboot.h> 66 #include <sys/signalvar.h> 67 #include <sys/syscallargs.h> 68 #include <sys/tty.h> 69 #include <sys/core.h> 70 #include <sys/kcore.h> 71 #include <sys/vnode.h> 72 #include <sys/ksyms.h> 73 #include <sys/module.h> 74 #include <sys/cpu.h> 75 76 #ifdef DDB 77 #include <machine/db_machdep.h> 78 #include <ddb/db_sym.h> 79 #include <ddb/db_extern.h> 80 #endif /* DDB */ 81 #include <sys/exec_elf.h> 82 83 #include <machine/autoconf.h> 84 #include <machine/bootinfo.h> 85 #include <machine/bus.h> 86 #include <machine/cpu.h> 87 #include <machine/hp300spu.h> 88 #include <machine/reg.h> 89 #include <machine/pcb.h> 90 #include <machine/psl.h> 91 #include <machine/pte.h> 92 93 #include <m68k/seglist.h> 94 95 #include <machine/kcore.h> /* XXX should be pulled in by sys/kcore.h */ 96 97 #include <dev/cons.h> 98 #include <dev/mm.h> 99 100 #define MAXMEM 64*1024 /* XXX - from cmap.h */ 101 #include <uvm/uvm_extern.h> 102 103 #include <sys/sysctl.h> 104 105 #include "opt_useleds.h" 106 107 #ifdef USELEDS 108 #include <hp300/hp300/leds.h> 109 #endif 110 111 #include "ksyms.h" 112 113 /* 114 * bootinfo base (physical and virtual). The bootinfo is placed, by 115 * the boot loader, into the first page of kernel text, which is zero 116 * filled (see locore.s) and not mapped at 0. It is remapped to a 117 * different address in pmap_bootstrap(). 118 */ 119 paddr_t bootinfo_pa; 120 vaddr_t bootinfo_va; 121 122 int maxmem; /* max memory per process */ 123 124 extern u_int lowram; 125 126 /* prototypes for local functions */ 127 static void parityenable(void); 128 static int parityerror(struct frame *); 129 static int parityerrorfind(void); 130 131 /* functions called from locore.s */ 132 void machine_init(paddr_t); 133 void nmihand(struct frame); 134 135 int delay_divisor; /* delay constant */ 136 137 /* 138 * machine_bootmap[] is checked in pmap_bootstrap1() of the new m68k pmap 139 * and it allocates kernel address space for intio devices. 140 */ 141 #define PMBM_INTIO 0 142 #define PMBM_EXTIO 1 143 #define PMBM_BOOTINFO 2 144 #define PMBM_MAXADDR 3 145 struct pmap_bootmap machine_bootmap[] = { 146 { .pmbm_vaddr_ptr = (vaddr_t *)&intiobase, 147 .pmbm_paddr = INTIOBASE, 148 .pmbm_size = INTIOSIZE, 149 .pmbm_flags = PMBM_F_CI }, 150 151 { .pmbm_vaddr_ptr = (vaddr_t *)&extiobase, 152 .pmbm_paddr = 0, /* VAONLY, so no PA mappings */ 153 .pmbm_size = ctob(EIOMAPSIZE), 154 .pmbm_flags = PMBM_F_VAONLY | PMBM_F_CI }, 155 156 { .pmbm_vaddr_ptr = &bootinfo_va, 157 .pmbm_paddr = 0, /* VAONLY, so no PA mappings */ 158 .pmbm_size = ctob(1), 159 .pmbm_flags = PMBM_F_VAONLY }, 160 161 /* Last page of RAM is mapped VA==PA for the MMU trampoline. */ 162 { .pmbm_vaddr = MAXADDR, 163 .pmbm_paddr = MAXADDR, 164 .pmbm_size = PAGE_SIZE, 165 .pmbm_flags = PMBM_F_FIXEDVA | PMBM_F_CI }, 166 167 { .pmbm_vaddr = -1 }, 168 }; 169 170 #ifdef __HAVE_NEW_PMAP_68K 171 /* 172 * The new 68k pmap utilizes the MAXADDR page as the NULL segment table 173 * to save a page, so we have to preserve PROM workarea for the next reboot. 174 * This preservation area is much less than a page size, so the trade-off 175 * seems worth it. 176 */ 177 #define BOOTWORKSTART 0xfffffdc0U /* from hp300/stand/common/srt0.S */ 178 #define BOOTWORKSIZE (0U - BOOTWORKSTART) 179 static char bootwork_savearea[BOOTWORKSIZE]; 180 #endif /* __HAVE_NEW_PMAP_68K */ 181 182 /* 183 * Early initialization, before main() is called. 184 */ 185 void 186 machine_init(paddr_t nextpa) 187 { 188 struct btinfo_magic *bt_mag; 189 190 #ifdef M68K_EC_VAC 191 /* 192 * Determine VA aliasing distance if any 193 */ 194 switch (machineid) { 195 case HP_320: 196 pmap_init_vac(16 * 1024); 197 break; 198 case HP_350: 199 pmap_init_vac(32 * 1024); 200 break; 201 default: 202 break; 203 } 204 #endif 205 206 /* Enable the external cache, if any. */ 207 ecacheon(); 208 209 #ifdef __HAVE_NEW_PMAP_68K 210 /* 211 * We've used NULL_SEGTAB_PA in <machine/pmap.h> to use the 212 * reserved last-page-of-RAM as the NULL segment table. But, 213 * we copied code into that page (the MMU trampoline) and it 214 * also contains the PROM's work area. Preserve the PROM work 215 * area and zero it out now. 216 */ 217 memcpy(bootwork_savearea, (void *)BOOTWORKSTART, BOOTWORKSIZE); 218 memset((void *)MAXADDR, 0, PAGE_SIZE); 219 #endif 220 221 /* 222 * N.B. we exclude the last page of memory from the physical 223 * address range; if we didn't, ps_end would be 0. 224 */ 225 phys_seg_list[0].ps_start = lowram; 226 phys_seg_list[0].ps_end = MAXADDR; 227 228 machine_init_common(nextpa); 229 230 /* Calibrate the delay loop. */ 231 hp300_calibrate_delay(); 232 233 /* 234 * Map in the bootinfo page, and make sure the bootinfo 235 * exists by searching for the MAGIC record. If it's not 236 * there, disable bootinfo. 237 */ 238 #ifndef __HAVE_NEW_PMAP_68K 239 bootinfo_va = virtual_avail; 240 virtual_avail += PAGE_SIZE; 241 #endif 242 pmap_kenter_pa(bootinfo_va, bootinfo_pa, 243 VM_PROT_READ|VM_PROT_WRITE, 0); 244 pmap_update(pmap_kernel()); 245 bt_mag = lookup_bootinfo(BTINFO_MAGIC); 246 if (bt_mag == NULL || 247 bt_mag->magic1 != BOOTINFO_MAGIC1 || 248 bt_mag->magic2 != BOOTINFO_MAGIC2) { 249 pmap_kremove(bootinfo_va, PAGE_SIZE); 250 pmap_update(pmap_kernel()); 251 #ifndef __HAVE_NEW_PMAP_68K 252 virtual_avail -= PAGE_SIZE; 253 #endif 254 bootinfo_va = 0; 255 } 256 } 257 258 /* 259 * Console initialization: called early on from main, 260 * before vm init or startup. Do enough configuration 261 * to choose and initialize a console. 262 */ 263 void 264 consinit(void) 265 { 266 267 /* 268 * Initialize the external I/O extent map. 269 */ 270 iomap_init(); 271 272 /* 273 * Initialize the console before we print anything out. 274 */ 275 276 hp300_cninit(); 277 278 /* 279 * Issue a warning if the boot loader didn't provide bootinfo. 280 */ 281 if (bootinfo_va != 0) 282 printf("bootinfo found at 0x%08lx\n", bootinfo_pa); 283 else 284 printf("WARNING: boot loader did not provide bootinfo\n"); 285 286 #if NKSYMS || defined(DDB) || defined(MODULAR) 287 { 288 extern int end; 289 extern int *esym; 290 291 ksyms_addsyms_elf((int)esym - (int)&end - sizeof(Elf32_Ehdr), 292 (void *)&end, esym); 293 } 294 #endif 295 #ifdef DDB 296 if (boothowto & RB_KDB) 297 Debugger(); 298 #endif 299 } 300 301 /* 302 * cpu_startup: allocate memory for variable-sized tables, 303 * initialize CPU 304 */ 305 void 306 cpu_startup(void) 307 { 308 hp300_cninit_deferred(); 309 310 cpu_startup_common(); 311 312 printf("cpu: delay divisor %d", delay_divisor); 313 if (mmuid) 314 printf(", mmuid %d", mmuid); 315 printf("\n"); 316 317 /* 318 * Now that we have told the user what they have, 319 * let them know if that machine type isn't configured. 320 */ 321 switch (machineid) { 322 case -1: /* keep compilers happy */ 323 #if !defined(HP320) 324 case HP_320: 325 #endif 326 #if !defined(HP330) 327 case HP_330: 328 #endif 329 #if !defined(HP340) 330 case HP_340: 331 #endif 332 #if !defined(HP345) 333 case HP_345: 334 #endif 335 #if !defined(HP350) 336 case HP_350: 337 #endif 338 #if !defined(HP360) 339 case HP_360: 340 #endif 341 #if !defined(HP362) 342 case HP_362: 343 #endif 344 #if !defined(HP370) 345 case HP_370: 346 #endif 347 #if !defined(HP375) 348 case HP_375: 349 #endif 350 #if !defined(HP380) 351 case HP_380: 352 #endif 353 #if !defined(HP382) 354 case HP_382: 355 #endif 356 #if !defined(HP385) 357 case HP_385: 358 #endif 359 #if !defined(HP400) 360 case HP_400: 361 #endif 362 #if !defined(HP425) 363 case HP_425: 364 #endif 365 #if !defined(HP433) 366 case HP_433: 367 #endif 368 panic("SPU type not configured"); 369 default: 370 break; 371 } 372 373 parityenable(); 374 #ifdef USELEDS 375 ledinit(); 376 #endif 377 } 378 379 struct hp300_model { 380 int id; 381 int mmuid; 382 const char *name; 383 int speed_khz; 384 }; 385 386 static const struct hp300_model hp300_models[] = { 387 { HP_320, -1, "320", 16670 }, 388 { HP_330, -1, "318/319/330", 16670 }, 389 { HP_340, -1, "340", 16670 }, 390 { HP_345, -1, "345", 50000 }, 391 { HP_350, -1, "350", 25000 }, 392 { HP_360, -1, "360", 25000 }, 393 { HP_362, -1, "362", 25000 }, 394 { HP_370, -1, "370", 33330 }, 395 { HP_375, -1, "375", 50000 }, 396 { HP_380, -1, "380", 25000 }, 397 { HP_382, -1, "382", 25000 }, 398 { HP_385, -1, "385", 33000 }, 399 { HP_400, -1, "400", 50000 }, 400 { HP_425, MMUID_425_T, "425t", 25000 }, 401 { HP_425, MMUID_425_S, "425s", 25000 }, 402 { HP_425, MMUID_425_E, "425e", 25000 }, 403 { HP_425, -1, "425", 25000 }, 404 { HP_433, MMUID_433_T, "433t", 33000 }, 405 { HP_433, MMUID_433_S, "433s", 33000 }, 406 { HP_433, -1, "433", 33000 }, 407 { 0, -1, NULL, 0 }, 408 }; 409 410 void 411 machine_set_model(void) 412 { 413 int i; 414 415 for (i = 0; hp300_models[i].name != NULL; i++) { 416 if (hp300_models[i].id == machineid) { 417 if (hp300_models[i].mmuid != -1 && 418 hp300_models[i].mmuid != mmuid) 419 continue; 420 break; 421 } 422 } 423 if (hp300_models[i].name == NULL) { 424 printf("\nunknown machineid %d\n", machineid); 425 panic("startup"); 426 } 427 cpu_setmodel("HP 9000/%s", hp300_models[i].name); 428 cpuspeed_khz = hp300_models[i].speed_khz; 429 430 if (fputype == FPU_68881) { 431 fpuspeed_khz = machineid == HP_350 ? 20000 : 16670; 432 } 433 434 #ifdef M68K_EC 435 if (ectype != EC_NONE) { 436 switch (machineid) { 437 case HP_320: 438 ecsize = 16*1024; 439 break; 440 case HP_370: 441 ecsize = 64*1024; 442 break; 443 default: 444 ecsize = 32*1024; 445 break; 446 } 447 } 448 #endif /* M68K_EC */ 449 } 450 451 /* 452 * machine dependent system variables. 453 */ 454 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup") 455 { 456 static bool broken_rmc; 457 458 broken_rmc = (cputype == M68020); 459 460 sysctl_createv(clog, 0, NULL, NULL, 461 CTLFLAG_PERMANENT, 462 CTLTYPE_NODE, "machdep", NULL, 463 NULL, 0, NULL, 0, 464 CTL_MACHDEP, CTL_EOL); 465 466 sysctl_createv(clog, 0, NULL, NULL, 467 CTLFLAG_PERMANENT, 468 CTLTYPE_STRUCT, "console_device", NULL, 469 sysctl_consdev, 0, NULL, sizeof(dev_t), 470 CTL_MACHDEP, CPU_CONSDEV, CTL_EOL); 471 472 sysctl_createv(clog, 0, NULL, NULL, 473 CTLFLAG_PERMANENT, 474 CTLTYPE_BOOL, "broken_rmc", NULL, 475 NULL, 0, &broken_rmc, 0, 476 CTL_MACHDEP, CPU_BROKEN_RMC, CTL_EOL); 477 } 478 479 void 480 machine_reboot(int howto, char *bootstr) 481 { 482 #ifdef __HAVE_NEW_PMAP_68K 483 /* Restore the PROM work area first. */ 484 memcpy((void *)BOOTWORKSTART, bootwork_savearea, BOOTWORKSIZE); 485 #endif 486 doboot(); 487 } 488 489 /* 490 * lookup_bootinfo: 491 * 492 * Look up information in bootinfo from boot loader. 493 */ 494 void * 495 lookup_bootinfo(int type) 496 { 497 struct btinfo_common *bt; 498 char *help = (char *)bootinfo_va; 499 500 /* Check for a bootinfo record first. */ 501 if (help == NULL) 502 return NULL; 503 504 do { 505 bt = (struct btinfo_common *)help; 506 if (bt->type == type) 507 return help; 508 help += bt->next; 509 } while (bt->next != 0 && 510 (size_t)help < (size_t)bootinfo_va + BOOTINFO_SIZE); 511 512 return NULL; 513 } 514 515 #if defined(PANICBUTTON) && !defined(DDB) 516 /* 517 * Declare these so they can be patched. 518 */ 519 int panicbutton = 1; /* non-zero if panic buttons are enabled */ 520 int candbdiv = 2; /* give em half a second (hz / candbdiv) */ 521 522 static void candbtimer(void *); 523 524 int crashandburn; 525 526 callout_t candbtimer_ch; 527 528 void 529 candbtimer(void *arg) 530 { 531 532 crashandburn = 0; 533 } 534 #endif /* PANICBUTTON & !DDB */ 535 536 static int innmihand; /* simple mutex */ 537 538 /* 539 * Level 7 interrupts can be caused by HIL keyboards (in cooked mode only, 540 * but we run them in raw mode) or parity errors. 541 */ 542 void 543 nmihand(struct frame frame) 544 { 545 546 /* Prevent unwanted recursion. */ 547 if (innmihand) 548 return; 549 innmihand = 1; 550 551 if (parityerror(&frame)) 552 return; 553 /* panic?? */ 554 printf("unexpected level 7 interrupt ignored\n"); 555 556 innmihand = 0; 557 } 558 559 /* 560 * Parity error section. Contains magic. 561 */ 562 #define PARREG ((volatile short *)IIOV(0x5B0000)) 563 static int gotparmem = 0; 564 #ifdef DEBUG 565 int ignorekperr = 0; /* ignore kernel parity errors */ 566 #endif 567 568 /* 569 * Enable parity detection 570 */ 571 static void 572 parityenable(void) 573 { 574 label_t faultbuf; 575 576 nofault = &faultbuf; 577 if (setjmp(nofault)) { 578 nofault = NULL; 579 printf("Parity detection disabled\n"); 580 return; 581 } 582 *PARREG = 1; 583 nofault = NULL; 584 gotparmem = 1; 585 } 586 587 /* 588 * Determine if level 7 interrupt was caused by a parity error 589 * and deal with it if it was. Returns 1 if it was a parity error. 590 */ 591 static int 592 parityerror(struct frame *fp) 593 { 594 if (!gotparmem) 595 return 0; 596 *PARREG = 0; 597 DELAY(10); 598 *PARREG = 1; 599 if (panicstr) { 600 printf("parity error after panic ignored\n"); 601 return 1; 602 } 603 if (!parityerrorfind()) 604 printf("WARNING: transient parity error ignored\n"); 605 else if (USERMODE(fp->f_sr)) { 606 printf("pid %d: parity error\n", curproc->p_pid); 607 uprintf("sorry, pid %d killed due to memory parity error\n", 608 curproc->p_pid); 609 psignal(curproc, SIGKILL); 610 #ifdef DEBUG 611 } else if (ignorekperr) { 612 printf("WARNING: kernel parity error ignored\n"); 613 #endif 614 } else { 615 regdump((struct trapframe *)fp, 128); 616 panic("kernel parity error"); 617 } 618 return 1; 619 } 620 621 /* 622 * Yuk! There has got to be a better way to do this! 623 * Searching all of memory with interrupts blocked can lead to disaster. 624 */ 625 static int 626 parityerrorfind(void) 627 { 628 static label_t parcatch; 629 static int looking = 0; 630 volatile int pg, o, s; 631 volatile int *ip; 632 int i; 633 int found; 634 635 /* 636 * If looking is true we are searching for a known parity error 637 * and it has just occurred. All we do is return to the higher 638 * level invocation. 639 */ 640 if (looking) 641 longjmp(&parcatch); 642 s = splhigh(); 643 /* 644 * If setjmp returns true, the parity error we were searching 645 * for has just occurred (longjmp above) at the current pg+o 646 */ 647 if (setjmp(&parcatch)) { 648 printf("Parity error at 0x%x\n", ctob(pg)|o); 649 found = 1; 650 goto done; 651 } 652 /* 653 * If we get here, a parity error has occurred for the first time 654 * and we need to find it. We turn off any external caches and 655 * loop thru memory, testing every longword til a fault occurs and 656 * we regain control at setjmp above. Note that because of the 657 * setjmp, pg and o need to be volatile or their values will be lost. 658 */ 659 looking = 1; 660 ecacheoff(); 661 for (pg = btoc(lowram); pg < btoc(lowram)+physmem; pg++) { 662 pmap_enter(pmap_kernel(), (vaddr_t)vmmap, ctob(pg), 663 VM_PROT_READ, VM_PROT_READ|PMAP_WIRED); 664 pmap_update(pmap_kernel()); 665 ip = (int *)vmmap; 666 for (o = 0; o < PAGE_SIZE; o += sizeof(int)) 667 i = *ip++; 668 } 669 __USE(i); 670 /* 671 * Getting here implies no fault was found. Should never happen. 672 */ 673 printf("Couldn't locate parity error\n"); 674 found = 0; 675 done: 676 looking = 0; 677 pmap_remove(pmap_kernel(), (vaddr_t)vmmap, (vaddr_t)&vmmap[PAGE_SIZE]); 678 pmap_update(pmap_kernel()); 679 ecacheon(); 680 splx(s); 681 return found; 682 } 683 684 int 685 mm_md_physacc(paddr_t pa, vm_prot_t prot) 686 { 687 int rv = mm_md_physacc_regular(pa, prot); 688 689 if (rv != 0) { 690 /* phys_seg_list[] doesn't include the last page of RAM. */ 691 if (pa >= MAXADDR) { 692 rv = 0; 693 } 694 } 695 return rv; 696 } 697 698 int 699 mm_md_kernacc(void *ptr, vm_prot_t prot, bool *handled) 700 { 701 702 /* 703 * Do not allow reading intio or dio device space. This could lead 704 * to corruption of device registers. 705 */ 706 *handled = false; 707 return (ISIIOVA(ptr) || ((uint8_t *)ptr >= extiobase && 708 (uint8_t *)ptr < extiobase + (EIOMAPSIZE * PAGE_SIZE))) 709 ? EFAULT : 0; 710 } 711