1 /* $NetBSD: machdep.c,v 1.141 2025/06/11 21:20:37 andvar 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 * from: @(#)machdep.c 8.10 (Berkeley) 4/20/94 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.141 2025/06/11 21:20:37 andvar Exp $"); 42 43 #include "opt_ddb.h" 44 #include "opt_kgdb.h" 45 #include "opt_modular.h" 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <sys/proc.h> 51 #include <sys/buf.h> 52 #include <sys/reboot.h> 53 #include <sys/conf.h> 54 #include <sys/file.h> 55 #include <sys/device.h> 56 #include <sys/mbuf.h> 57 #include <sys/msgbuf.h> 58 #include <sys/ioctl.h> 59 #include <sys/tty.h> 60 #include <sys/mount.h> 61 #include <sys/exec.h> 62 #include <sys/exec_aout.h> /* for MID_* */ 63 #include <sys/core.h> 64 #include <sys/kcore.h> 65 #include <sys/vnode.h> 66 #include <sys/syscallargs.h> 67 #include <sys/ksyms.h> 68 #include <sys/module.h> 69 #include <sys/cpu.h> 70 #ifdef KGDB 71 #include <sys/kgdb.h> 72 #endif 73 74 #include <uvm/uvm_extern.h> 75 76 #include <sys/sysctl.h> 77 78 #include <dev/cons.h> 79 #include <dev/mm.h> 80 81 #include <machine/cpu.h> 82 #include <machine/dvma.h> 83 #include <machine/idprom.h> 84 #include <machine/kcore.h> 85 #include <machine/reg.h> 86 #include <machine/pcb.h> 87 #include <machine/psl.h> 88 #include <machine/pte.h> 89 #include <machine/mon.h> 90 91 #if defined(DDB) 92 #include <machine/db_machdep.h> 93 #include <ddb/db_sym.h> 94 #include <ddb/db_extern.h> 95 #endif 96 97 #include <sun3/sun3/machdep.h> 98 99 #include "ksyms.h" 100 101 /* Defined in locore.s */ 102 extern char kernel_text[]; 103 /* Defined by the linker */ 104 extern char etext[]; 105 106 /* kernel_arch specific values required by module(9) */ 107 const vaddr_t kernbase = KERNBASE3X; 108 const vaddr_t kern_end = KERN_END3X; 109 110 /* Our exported CPU info; we can have only one. */ 111 struct cpu_info cpu_info_store; 112 113 struct vm_map *phys_map = NULL; 114 115 int fputype; 116 void * msgbufaddr; 117 118 /* Virtual page frame for /dev/mem (see mem.c) */ 119 vaddr_t vmmap; 120 121 u_char cpu_machine_id = 0; 122 const char *cpu_string = NULL; 123 int cpu_has_vme = 0; 124 int has_iocache = 0; 125 126 vaddr_t dumppage; 127 128 static void identifycpu(void); 129 static void initcpu(void); 130 131 /* 132 * Console initialization: called early on from main, 133 * before vm init or cpu_startup. This system is able 134 * to use the console for output immediately (via PROM) 135 * but can not use it for input until after this point. 136 */ 137 void 138 consinit(void) 139 { 140 141 /* 142 * Switch from the PROM console (output only) 143 * to our own console driver. 144 */ 145 cninit(); 146 147 #if NKSYMS || defined(DDB) || defined(MODULAR) 148 { 149 extern int nsym; 150 extern char *ssym, *esym; 151 152 ksyms_addsyms_elf(nsym, ssym, esym); 153 } 154 #endif /* DDB */ 155 156 /* 157 * Now that the console can do input as well as 158 * output, consider stopping for a debugger. 159 */ 160 if (boothowto & RB_KDB) { 161 #ifdef KGDB 162 /* XXX - Ask on console for kgdb_dev? */ 163 /* Note: this will just return if kgdb_dev==NODEV */ 164 kgdb_connect(1); 165 #else /* KGDB */ 166 /* Either DDB or no debugger (just PROM). */ 167 Debugger(); 168 #endif /* KGDB */ 169 } 170 } 171 172 /* 173 * cpu_startup: allocate memory for variable-sized tables, 174 * initialize CPU, and do autoconfiguration. 175 * 176 * This is called early in init_main.c:main(), after the 177 * kernel memory allocator is ready for use, but before 178 * the creation of processes 1,2, and mountroot, etc. 179 */ 180 void 181 cpu_startup(void) 182 { 183 char *v; 184 vaddr_t minaddr, maxaddr; 185 char pbuf[9]; 186 187 /* 188 * Initialize message buffer (for kernel printf). 189 * This is put in physical page zero so it will 190 * always be in the same place after a reboot. 191 * Its mapping was prepared in pmap_bootstrap(). 192 * Also, offset some to avoid PROM scribbles. 193 */ 194 v = (char *)KERNBASE3X; 195 msgbufaddr = v + MSGBUFOFF; 196 initmsgbuf(msgbufaddr, MSGBUFSIZE); 197 198 /* 199 * Good {morning,afternoon,evening,night}. 200 */ 201 printf("%s%s", copyright, version); 202 identifycpu(); 203 initfpu(); /* also prints FPU type */ 204 205 format_bytes(pbuf, sizeof(pbuf), ctob(physmem)); 206 printf("total memory = %s\n", pbuf); 207 208 /* 209 * Get scratch page for dumpsys(). 210 */ 211 dumppage = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_WIRED); 212 if (dumppage == 0) 213 panic("startup: alloc dumppage"); 214 215 minaddr = 0; 216 217 /* 218 * Allocate a submap for physio 219 */ 220 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 221 VM_PHYS_SIZE, 0, false, NULL); 222 223 format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false))); 224 printf("avail memory = %s\n", pbuf); 225 226 /* 227 * Allocate a virtual page (for use by /dev/mem) 228 * This page is handed to pmap_enter() therefore 229 * it has to be in the normal kernel VA range. 230 */ 231 vmmap = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, 232 UVM_KMF_VAONLY | UVM_KMF_WAITVA); 233 234 /* 235 * Create the DVMA maps. 236 */ 237 dvma_init(); 238 239 /* 240 * Set up CPU-specific registers, cache, etc. 241 */ 242 initcpu(); 243 } 244 245 /* 246 * Info for CTL_HW 247 */ 248 char machine[16] = MACHINE; /* from <machine/param.h> */ 249 char kernel_arch[16] = "sun3x"; /* XXX needs a sysctl node */ 250 251 /* 252 * XXX - Should empirically estimate the divisor... 253 * Note that the value of delay_divisor is roughly 254 * 2048 / cpuclock (where cpuclock is in MHz). 255 */ 256 int delay_divisor = 62; /* assume the fastest (33 MHz) */ 257 258 void 259 identifycpu(void) 260 { 261 u_char machtype; 262 263 machtype = identity_prom.idp_machtype; 264 if ((machtype & IDM_ARCH_MASK) != IDM_ARCH_SUN3X) { 265 printf("Bad IDPROM arch!\n"); 266 sunmon_abort(); 267 } 268 269 cpu_machine_id = machtype; 270 switch (cpu_machine_id) { 271 272 case ID_SUN3X_80: 273 cpu_string = "80"; /* Hydra */ 274 delay_divisor = 102; /* 20 MHz */ 275 cpu_has_vme = false; 276 break; 277 278 case ID_SUN3X_470: 279 cpu_string = "470"; /* Pegasus */ 280 delay_divisor = 62; /* 33 MHz */ 281 cpu_has_vme = true; 282 break; 283 284 default: 285 printf("unknown sun3x model\n"); 286 sunmon_abort(); 287 } 288 289 /* Other stuff? (VAC, mc6888x version, etc.) */ 290 /* Note: miniroot cares about the kernel_arch part. */ 291 cpu_setmodel("%s %s", kernel_arch, cpu_string); 292 293 printf("Model: %s\n", cpu_getmodel()); 294 } 295 296 /* 297 * machine dependent system variables. 298 */ 299 #if 0 /* XXX - Not yet... */ 300 static int 301 sysctl_machdep_root_device(SYSCTLFN_ARGS) 302 { 303 struct sysctlnode node = *rnode; 304 305 node.sysctl_data = some permutation on root_device; 306 node.sysctl_size = strlen(root_device) + 1; 307 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 308 } 309 310 static int 311 sysctl_machdep_booted_kernel(SYSCTLFN_ARGS) 312 { 313 struct sysctlnode node = *rnode; 314 315 node.sysctl_data = some permutation on booted_kernel; 316 node.sysctl_size = strlen(booted_kernel) + 1; 317 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 318 } 319 #endif 320 321 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup") 322 { 323 324 sysctl_createv(clog, 0, NULL, NULL, 325 CTLFLAG_PERMANENT, 326 CTLTYPE_NODE, "machdep", NULL, 327 NULL, 0, NULL, 0, 328 CTL_MACHDEP, CTL_EOL); 329 330 sysctl_createv(clog, 0, NULL, NULL, 331 CTLFLAG_PERMANENT, 332 CTLTYPE_STRUCT, "console_device", NULL, 333 sysctl_consdev, 0, NULL, sizeof(dev_t), 334 CTL_MACHDEP, CPU_CONSDEV, CTL_EOL); 335 #if 0 /* XXX - Not yet... */ 336 sysctl_createv(clog, 0, NULL, NULL, 337 CTLFLAG_PERMANENT, 338 CTLTYPE_STRING, "root_device", NULL, 339 sysctl_machdep_root_device, 0, NULL, 0, 340 CTL_MACHDEP, CPU_ROOT_DEVICE, CTL_EOL); 341 sysctl_createv(clog, 0, NULL, NULL, 342 CTLFLAG_PERMANENT, 343 CTLTYPE_STRING, "booted_kernel", NULL, 344 sysctl_machdep_booted_kernel, 0, NULL, 0, 345 CTL_MACHDEP, CPU_BOOTED_KERNEL, CTL_EOL); 346 #endif 347 } 348 349 /* See: sig_machdep.c */ 350 351 /* 352 * Do a sync in preparation for a reboot. 353 * XXX - This could probably be common code. 354 * XXX - And now, most of it is in vfs_shutdown() 355 * XXX - Put waittime checks in there too? 356 */ 357 int waittime = -1; /* XXX - Who else looks at this? -gwr */ 358 static void 359 reboot_sync(void) 360 { 361 362 /* Check waittime here to localize its use to this function. */ 363 if (waittime >= 0) 364 return; 365 waittime = 0; 366 vfs_shutdown(); 367 } 368 369 /* 370 * Common part of the BSD and SunOS reboot system calls. 371 */ 372 __dead void 373 cpu_reboot(int howto, char *user_boot_string) 374 { 375 /* Note: this string MUST be static! */ 376 static char bootstr[128]; 377 char *p; 378 379 /* If system is cold, just halt. (early panic?) */ 380 if (cold) 381 goto haltsys; 382 383 /* Un-blank the screen if appropriate. */ 384 cnpollc(1); 385 386 if ((howto & RB_NOSYNC) == 0) { 387 reboot_sync(); 388 /* 389 * If we've been adjusting the clock, the todr 390 * will be out of synch; adjust it now. 391 * 392 * XXX - However, if the kernel has been sitting in ddb, 393 * the time will be way off, so don't set the HW clock! 394 * XXX - Should do sanity check against HW clock. -gwr 395 */ 396 /* resettodr(); */ 397 } 398 399 /* Disable interrupts. */ 400 splhigh(); 401 402 /* Write out a crash dump if asked. */ 403 if (howto & RB_DUMP) 404 dumpsys(); 405 406 /* run any shutdown hooks */ 407 doshutdownhooks(); 408 409 pmf_system_shutdown(boothowto); 410 411 if (howto & RB_HALT) { 412 haltsys: 413 printf("halted.\n"); 414 sunmon_halt(); 415 } 416 417 /* 418 * Automatic reboot. 419 */ 420 if (user_boot_string) 421 strncpy(bootstr, user_boot_string, sizeof(bootstr)); 422 else { 423 /* 424 * Build our own boot string with an empty 425 * boot device/file and (maybe) some flags. 426 * The PROM will supply the device/file name. 427 */ 428 p = bootstr; 429 *p = '\0'; 430 if (howto & (RB_KDB|RB_ASKNAME|RB_SINGLE)) { 431 /* Append the boot flags. */ 432 *p++ = ' '; 433 *p++ = '-'; 434 if (howto & RB_KDB) 435 *p++ = 'd'; 436 if (howto & RB_ASKNAME) 437 *p++ = 'a'; 438 if (howto & RB_SINGLE) 439 *p++ = 's'; 440 *p = '\0'; 441 } 442 } 443 printf("rebooting...\n"); 444 sunmon_reboot(bootstr); 445 for (;;) ; 446 /*NOTREACHED*/ 447 } 448 449 /* 450 * These variables are needed by /sbin/savecore 451 */ 452 uint32_t dumpmag = 0x8fca0101; /* magic number */ 453 int dumpsize = 0; /* pages */ 454 long dumplo = 0; /* blocks */ 455 456 #define DUMP_EXTRA 1 /* CPU-dependent extra pages */ 457 458 /* 459 * This is called by main to set dumplo, dumpsize. 460 * Dumps always skip the first PAGE_SIZE of disk space 461 * in case there might be a disk label stored there. 462 * If there is extra space, put dump at the end to 463 * reduce the chance that swapping trashes it. 464 */ 465 void 466 cpu_dumpconf(void) 467 { 468 int devblks; /* size of dump device in blocks */ 469 int dumpblks; /* size of dump image in blocks */ 470 471 if (dumpdev == NODEV) 472 return; 473 474 devblks = bdev_size(dumpdev); 475 if (devblks <= ctod(1)) 476 return; 477 devblks &= ~(ctod(1) - 1); 478 479 /* 480 * Note: savecore expects dumpsize to be the 481 * number of pages AFTER the dump header. 482 */ 483 dumpsize = physmem; /* pages */ 484 485 /* Position dump image near end of space, page aligned. */ 486 dumpblks = ctod(physmem + DUMP_EXTRA); 487 dumplo = devblks - dumpblks; 488 489 /* If it does not fit, truncate it by moving dumplo. */ 490 /* Note: Must force signed comparison. */ 491 if (dumplo < ((long)ctod(1))) { 492 dumplo = ctod(1); 493 dumpsize = dtoc(devblks - dumplo) - DUMP_EXTRA; 494 } 495 } 496 497 /* Note: gdb looks for "dumppcb" in a kernel crash dump. */ 498 struct pcb dumppcb; 499 500 /* 501 * Write a crash dump. The format while in swap is: 502 * kcore_seg_t cpu_hdr; 503 * cpu_kcore_hdr_t cpu_data; 504 * padding (PAGE_SIZE-sizeof(kcore_seg_t)) 505 * pagemap (2*PAGE_SIZE) 506 * physical memory... 507 */ 508 void 509 dumpsys(void) 510 { 511 const struct bdevsw *dsw; 512 kcore_seg_t *kseg_p; 513 cpu_kcore_hdr_t *chdr_p; 514 struct sun3x_kcore_hdr *sh; 515 phys_ram_seg_t *crs_p; 516 char *vaddr; 517 paddr_t paddr; 518 int psize, todo, seg, segsz; 519 daddr_t blkno; 520 int error = 0; 521 522 if (dumpdev == NODEV) 523 return; 524 dsw = bdevsw_lookup(dumpdev); 525 if (dsw == NULL || dsw->d_psize == NULL) 526 return; 527 528 /* 529 * For dumps during autoconfiguration, 530 * if dump device has already configured... 531 */ 532 if (dumpsize == 0) 533 cpu_dumpconf(); 534 if (dumplo <= 0) { 535 printf("\ndump to dev %u,%u not possible\n", 536 major(dumpdev), minor(dumpdev)); 537 return; 538 } 539 savectx(&dumppcb); 540 541 psize = bdev_size(dumpdev); 542 if (psize == -1) { 543 printf("dump area unavailable\n"); 544 return; 545 } 546 547 printf("\ndumping to dev %u,%u offset %ld\n", 548 major(dumpdev), minor(dumpdev), dumplo); 549 550 /* 551 * Prepare the dump header 552 */ 553 blkno = dumplo; 554 todo = dumpsize; /* pages */ 555 vaddr = (char *)dumppage; 556 memset(vaddr, 0, PAGE_SIZE); 557 558 /* Set pointers to all three parts. */ 559 kseg_p = (kcore_seg_t *)vaddr; 560 chdr_p = (cpu_kcore_hdr_t *)(kseg_p + 1); 561 sh = &chdr_p->un._sun3x; 562 563 /* Fill in kcore_seg_t part. */ 564 CORE_SETMAGIC(*kseg_p, KCORE_MAGIC, MID_MACHINE, CORE_CPU); 565 kseg_p->c_size = (ctob(DUMP_EXTRA) - sizeof(*kseg_p)); 566 567 /* Fill in cpu_kcore_hdr_t part. */ 568 strncpy(chdr_p->name, kernel_arch, sizeof(chdr_p->name)); 569 chdr_p->page_size = PAGE_SIZE; 570 chdr_p->kernbase = KERNBASE3X; 571 572 /* Fill in the sun3x_kcore_hdr part. */ 573 pmap_kcore_hdr(sh); 574 575 /* Write out the dump header. */ 576 error = (*dsw->d_dump)(dumpdev, blkno, vaddr, PAGE_SIZE); 577 if (error) 578 goto fail; 579 blkno += btodb(PAGE_SIZE); 580 581 /* 582 * Now dump physical memory. Note that physical memory 583 * might NOT be contiguous, so do it by segments. 584 */ 585 586 vaddr = (char *)vmmap; /* Borrow /dev/mem VA */ 587 588 for (seg = 0; seg < SUN3X_NPHYS_RAM_SEGS; seg++) { 589 crs_p = &sh->ram_segs[seg]; 590 paddr = crs_p->start; 591 segsz = crs_p->size; 592 593 while (todo && (segsz > 0)) { 594 595 /* Print pages left after every 16. */ 596 if ((todo & 0xf) == 0) 597 printf_nolog("\r%4d", todo); 598 599 /* Make a temporary mapping for the page. */ 600 pmap_kenter_pa(vmmap, paddr | PMAP_NC, VM_PROT_READ, 0); 601 pmap_update(pmap_kernel()); 602 error = (*dsw->d_dump)(dumpdev, blkno, vaddr, 603 PAGE_SIZE); 604 pmap_kremove(vmmap, PAGE_SIZE); 605 pmap_update(pmap_kernel()); 606 if (error) 607 goto fail; 608 paddr += PAGE_SIZE; 609 segsz -= PAGE_SIZE; 610 blkno += btodb(PAGE_SIZE); 611 todo--; 612 } 613 } 614 printf("\rdump succeeded\n"); 615 return; 616 fail: 617 printf(" dump error=%d\n", error); 618 } 619 620 static void 621 initcpu(void) 622 { 623 /* XXX: Enable RAM parity/ECC checking? */ 624 /* XXX: parityenable(); */ 625 626 #ifdef HAVECACHE 627 cache_enable(); 628 #endif 629 } 630 631 /* straptrap() in trap.c */ 632 633 /* from hp300: badaddr() */ 634 /* peek_byte(), peek_word() moved to bus_subr.c */ 635 636 /* XXX: parityenable() ? */ 637 /* regdump() moved to regdump.c */ 638 639 /* 640 * cpu_exec_aout_makecmds(): 641 * CPU-dependent a.out format hook for execve(). 642 * 643 * Determine if the given exec package refers to something which we 644 * understand and, if so, set up the vmcmds for it. 645 */ 646 int 647 cpu_exec_aout_makecmds(struct lwp *l, struct exec_package *epp) 648 { 649 return ENOEXEC; 650 } 651 652 int 653 mm_md_physacc(paddr_t pa, vm_prot_t prot) 654 { 655 656 return pmap_pa_exists(pa) ? 0 : EFAULT; 657 } 658 659 bool 660 mm_md_direct_mapped_phys(paddr_t paddr, vaddr_t *vaddr) 661 { 662 extern paddr_t avail_start; 663 664 if (paddr >= avail_start) 665 return false; 666 *vaddr = KERNBASE3X + paddr; 667 return true; 668 } 669 670 /* 671 * Allow access to the PROM mapping similar to uvm_kernacc(). 672 */ 673 int 674 mm_md_kernacc(void *ptr, vm_prot_t prot, bool *handled) 675 { 676 677 if ((vaddr_t)ptr < SUN3X_PROM_BASE || (vaddr_t)ptr > SUN3X_MONEND) { 678 *handled = false; 679 return 0; 680 } 681 682 *handled = true; 683 /* Read in the PROM itself is OK. */ 684 if ((prot & VM_PROT_WRITE) == 0) 685 return 0; 686 687 /* PROM data page is OK for read/write. */ 688 if ((vaddr_t)ptr >= SUN3X_MONDATA && 689 (vaddr_t)ptr < SUN3X_MONDATA + PAGE_SIZE) 690 return 0; 691 return EFAULT; 692 } 693 694 #ifdef MODULAR 695 /* 696 * Push any modules loaded by the bootloader etc. 697 */ 698 void 699 module_init_md(void) 700 { 701 } 702 #endif 703