1 /* $NetBSD: machdep.c,v 1.226 2026/04/28 03:29:10 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the Systems Programming Group of the University of Utah Computer 9 * Science Department. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * from: Utah Hdr: machdep.c 1.74 92/12/20 36 * from: @(#)machdep.c 8.10 (Berkeley) 4/20/94 37 */ 38 39 /* 40 * Copyright (c) 1994, 1995 Gordon W. Ross 41 * Copyright (c) 1993 Adam Glass 42 * Copyright (c) 1988 University of Utah. 43 * 44 * This code is derived from software contributed to Berkeley by 45 * the Systems Programming Group of the University of Utah Computer 46 * Science Department. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions 50 * are met: 51 * 1. Redistributions of source code must retain the above copyright 52 * notice, this list of conditions and the following disclaimer. 53 * 2. Redistributions in binary form must reproduce the above copyright 54 * notice, this list of conditions and the following disclaimer in the 55 * documentation and/or other materials provided with the distribution. 56 * 3. All advertising materials mentioning features or use of this software 57 * must display the following acknowledgement: 58 * This product includes software developed by the University of 59 * California, Berkeley and its contributors. 60 * 4. Neither the name of the University nor the names of its contributors 61 * may be used to endorse or promote products derived from this software 62 * without specific prior written permission. 63 * 64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 74 * SUCH DAMAGE. 75 * 76 * from: Utah Hdr: machdep.c 1.74 92/12/20 77 * from: @(#)machdep.c 8.10 (Berkeley) 4/20/94 78 */ 79 80 #include <sys/cdefs.h> 81 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.226 2026/04/28 03:29:10 thorpej Exp $"); 82 83 #include "opt_ddb.h" 84 #include "opt_kgdb.h" 85 #include "opt_modular.h" 86 87 #include <sys/param.h> 88 #include <sys/systm.h> 89 #include <sys/kernel.h> 90 #include <sys/proc.h> 91 #include <sys/buf.h> 92 #include <sys/reboot.h> 93 #include <sys/conf.h> 94 #include <sys/file.h> 95 #include <sys/device.h> 96 #include <sys/mbuf.h> 97 #include <sys/msgbuf.h> 98 #include <sys/ioctl.h> 99 #include <sys/tty.h> 100 #include <sys/mount.h> 101 #include <sys/exec.h> 102 #include <sys/core.h> 103 #include <sys/kcore.h> 104 #include <sys/vnode.h> 105 #include <sys/syscallargs.h> 106 #include <sys/ksyms.h> 107 #include <sys/module.h> 108 #include <sys/cpu.h> 109 #ifdef KGDB 110 #include <sys/kgdb.h> 111 #endif 112 113 #include <uvm/uvm.h> /* XXX: not _extern ... need vm_map_create */ 114 115 #include <sys/sysctl.h> 116 117 #include <dev/cons.h> 118 #include <dev/mm.h> 119 120 #include <machine/cpu.h> 121 #include <machine/dvma.h> 122 #include <machine/idprom.h> 123 #include <machine/kcore.h> 124 #include <machine/mon.h> 125 #include <machine/reg.h> 126 #include <machine/pcb.h> 127 #include <machine/psl.h> 128 #include <machine/pte.h> 129 130 #if defined(DDB) 131 #include <machine/db_machdep.h> 132 #include <ddb/db_sym.h> 133 #include <ddb/db_extern.h> 134 #endif 135 136 #include <sun3/sun3/machdep.h> 137 138 CTASSERT(sizeof(struct frame) == 76 /* F_t */ + 84 /* F_u */); 139 140 #include "ksyms.h" 141 142 /* Defined in locore.s */ 143 extern char kernel_text[]; 144 /* Defined by the linker */ 145 extern char etext[]; 146 147 /* kernel_arch specific values required by module(9) */ 148 const vaddr_t kernbase = KERNBASE3; 149 const vaddr_t kern_end = KERN_END3; 150 151 extern void *msgbufaddr; 152 153 /* Virtual page frame for /dev/mem (see mem.c) */ 154 vaddr_t vmmap; 155 156 /* Our private scratch page for dumping the MMU. */ 157 static vaddr_t dumppage; 158 159 char kernel_arch[16] = "sun3"; /* XXX needs a sysctl node */ 160 161 static void initcpu(void); 162 163 /* 164 * Console initialization: called early on from main, 165 * before vm init or cpu_startup. This system is able 166 * to use the console for output immediately (via PROM) 167 * but can not use it for input until after this point. 168 */ 169 void 170 consinit(void) 171 { 172 173 /* 174 * Switch from the PROM console (output only) 175 * to our own console driver. 176 */ 177 cninit(); 178 179 #if NKSYMS || defined(DDB) || defined(MODULAR) 180 { 181 extern int nsym; 182 extern char *ssym, *esym; 183 184 ksyms_addsyms_elf(nsym, ssym, esym); 185 } 186 #endif /* DDB */ 187 188 /* 189 * Now that the console can do input as well as 190 * output, consider stopping for a debugger. 191 */ 192 if (boothowto & RB_KDB) { 193 #ifdef KGDB 194 /* XXX - Ask on console for kgdb_dev? */ 195 /* Note: this will just return if kgdb_dev==NODEV */ 196 kgdb_connect(1); 197 #else /* KGDB */ 198 /* Either DDB or no debugger (just PROM). */ 199 Debugger(); 200 #endif /* KGDB */ 201 } 202 } 203 204 /* 205 * cpu_startup: allocate memory for variable-sized tables, 206 * initialize CPU, and do autoconfiguration. 207 * 208 * This is called early in init_main.c:main(), after the 209 * kernel memory allocator is ready for use, but before 210 * the creation of processes 1,2, and mountroot, etc. 211 */ 212 void 213 cpu_startup(void) 214 { 215 /* Set the FPU bit in the "system enable register" */ 216 enable_fpu(1); 217 218 /* 219 * Get scratch page for dumpsys(). 220 */ 221 dumppage = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_WIRED); 222 if (dumppage == 0) 223 panic("startup: alloc dumppage"); 224 225 cpu_startup_common(); 226 227 /* 228 * Allocate a virtual page (for use by /dev/mem) 229 * This page is handed to pmap_enter() therefore 230 * it has to be in the normal kernel VA range. 231 */ 232 vmmap = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, 233 UVM_KMF_VAONLY | UVM_KMF_WAITVA); 234 235 /* 236 * Create the DVMA maps. 237 */ 238 dvma_init(); 239 240 /* 241 * Set up CPU-specific registers, cache, etc. 242 */ 243 initcpu(); 244 245 if (fputype == FPU_NONE) { 246 /* Might as well turn the enable bit back off. */ 247 enable_fpu(0); 248 } 249 } 250 251 /* 252 * machine dependent system variables. 253 */ 254 #if 0 /* XXX - Not yet... */ 255 static int 256 sysctl_machdep_root_device(SYSCTLFN_ARGS) 257 { 258 struct sysctlnode node = *rnode; 259 260 node.sysctl_data = some permutation on root_device; 261 node.sysctl_size = strlen(root_device) + 1; 262 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 263 } 264 265 static int 266 sysctl_machdep_booted_kernel(SYSCTLFN_ARGS) 267 { 268 struct sysctlnode node = *rnode; 269 270 node.sysctl_data = some permutation on booted_kernel; 271 node.sysctl_size = strlen(booted_kernel) + 1; 272 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 273 } 274 #endif 275 276 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup") 277 { 278 279 sysctl_createv(clog, 0, NULL, NULL, 280 CTLFLAG_PERMANENT, 281 CTLTYPE_NODE, "machdep", NULL, 282 NULL, 0, NULL, 0, 283 CTL_MACHDEP, CTL_EOL); 284 285 sysctl_createv(clog, 0, NULL, NULL, 286 CTLFLAG_PERMANENT, 287 CTLTYPE_STRUCT, "console_device", NULL, 288 sysctl_consdev, 0, NULL, sizeof(dev_t), 289 CTL_MACHDEP, CPU_CONSDEV, CTL_EOL); 290 #if 0 /* XXX - Not yet... */ 291 sysctl_createv(clog, 0, NULL, NULL, 292 CTLFLAG_PERMANENT, 293 CTLTYPE_STRING, "root_device", NULL, 294 sysctl_machdep_root_device, 0, NULL, 0, 295 CTL_MACHDEP, CPU_ROOT_DEVICE, CTL_EOL); 296 sysctl_createv(clog, 0, NULL, NULL, 297 CTLFLAG_PERMANENT, 298 CTLTYPE_STRING, "booted_kernel", NULL, 299 sysctl_machdep_booted_kernel, 0, NULL, 0, 300 CTL_MACHDEP, CPU_BOOTED_KERNEL, CTL_EOL); 301 #endif 302 } 303 304 void 305 machine_halt(void) 306 { 307 sunmon_halt(); 308 } 309 310 void 311 machine_reboot(int howto, char *bootstr) 312 { 313 char *p; 314 char default_boot_string[8]; 315 316 if (bootstr == NULL) { 317 /* 318 * Build our own boot string with an empty 319 * boot device/file and (maybe) some flags. 320 * The PROM will supply the device/file name. 321 */ 322 p = default_boot_string; 323 *p = '\0'; 324 325 if (howto & (RB_KDB|RB_ASKNAME|RB_SINGLE)) { 326 /* Append the boot flags. */ 327 *p++ = ' '; 328 *p++ = '-'; 329 if (howto & RB_KDB) 330 *p++ = 'd'; 331 if (howto & RB_ASKNAME) 332 *p++ = 'a'; 333 if (howto & RB_SINGLE) 334 *p++ = 's'; 335 *p = '\0'; 336 } 337 bootstr = default_boot_string; 338 } 339 sunmon_reboot(bootstr); 340 } 341 342 /* 343 * These variables are needed by /sbin/savecore 344 */ 345 uint32_t dumpmag = 0x8fca0101; /* magic number */ 346 int dumpsize = 0; /* pages */ 347 long dumplo = 0; /* blocks */ 348 349 #define DUMP_EXTRA 3 /* CPU-dependent extra pages */ 350 351 /* 352 * This is called by main to set dumplo, dumpsize. 353 * Dumps always skip the first PAGE_SIZE of disk space 354 * in case there might be a disk label stored there. 355 * If there is extra space, put dump at the end to 356 * reduce the chance that swapping trashes it. 357 */ 358 void 359 cpu_dumpconf(void) 360 { 361 int devblks; /* size of dump device in blocks */ 362 int dumpblks; /* size of dump image in blocks */ 363 364 if (dumpdev == NODEV) 365 return; 366 367 devblks = bdev_size(dumpdev); 368 if (devblks <= ctod(1)) 369 return; 370 devblks &= ~(ctod(1)-1); 371 372 /* 373 * Note: savecore expects dumpsize to be the 374 * number of pages AFTER the dump header. 375 */ 376 dumpsize = physmem; 377 378 /* Position dump image near end of space, page aligned. */ 379 dumpblks = ctod(physmem + DUMP_EXTRA); 380 dumplo = devblks - dumpblks; 381 382 /* If it does not fit, truncate it by moving dumplo. */ 383 /* Note: Must force signed comparison. */ 384 if (dumplo < ((long)ctod(1))) { 385 dumplo = ctod(1); 386 dumpsize = dtoc(devblks - dumplo) - DUMP_EXTRA; 387 } 388 } 389 390 /* Note: gdb looks for "dumppcb" in a kernel crash dump. */ 391 struct pcb dumppcb; 392 extern paddr_t avail_start; 393 394 /* 395 * Write a crash dump. The format while in swap is: 396 * kcore_seg_t cpu_hdr; 397 * cpu_kcore_hdr_t cpu_data; 398 * padding (PAGE_SIZE-sizeof(kcore_seg_t)) 399 * pagemap (2*PAGE_SIZE) 400 * physical memory... 401 */ 402 void 403 dumpsys(void) 404 { 405 const struct bdevsw *dsw; 406 kcore_seg_t *kseg_p; 407 cpu_kcore_hdr_t *chdr_p; 408 struct sun3_kcore_hdr *sh; 409 char *vaddr; 410 paddr_t paddr; 411 int psize, todo, chunk; 412 daddr_t blkno; 413 int error = 0; 414 415 if (dumpdev == NODEV) 416 return; 417 if (dumppage == 0) 418 return; 419 dsw = bdevsw_lookup(dumpdev); 420 if (dsw == NULL || dsw->d_psize == NULL) 421 return; 422 423 /* 424 * For dumps during autoconfiguration, 425 * if dump device has already configured... 426 */ 427 if (dumpsize == 0) 428 cpu_dumpconf(); 429 if (dumplo <= 0) { 430 printf("\ndump to dev %u,%u not possible\n", 431 major(dumpdev), minor(dumpdev)); 432 return; 433 } 434 savectx(&dumppcb); 435 436 psize = bdev_size(dumpdev); 437 if (psize == -1) { 438 printf("dump area unavailable\n"); 439 return; 440 } 441 442 printf("\ndumping to dev %u,%u offset %ld\n", 443 major(dumpdev), minor(dumpdev), dumplo); 444 445 /* 446 * Prepare the dump header, including MMU state. 447 */ 448 blkno = dumplo; 449 todo = dumpsize; /* pages */ 450 vaddr = (char*)dumppage; 451 memset(vaddr, 0, PAGE_SIZE); 452 453 /* Set pointers to all three parts. */ 454 kseg_p = (kcore_seg_t *)vaddr; 455 chdr_p = (cpu_kcore_hdr_t *) (kseg_p + 1); 456 sh = &chdr_p->un._sun3; 457 458 /* Fill in kcore_seg_t part. */ 459 CORE_SETMAGIC(*kseg_p, KCORE_MAGIC, MID_MACHINE, CORE_CPU); 460 kseg_p->c_size = (ctob(DUMP_EXTRA) - sizeof(*kseg_p)); 461 462 /* Fill in cpu_kcore_hdr_t part. */ 463 strncpy(chdr_p->name, kernel_arch, sizeof(chdr_p->name)); 464 chdr_p->page_size = PAGE_SIZE; 465 chdr_p->kernbase = KERNBASE3; 466 467 /* Fill in the sun3_kcore_hdr part (MMU state). */ 468 pmap_kcore_hdr(sh); 469 470 /* Write out the dump header. */ 471 error = (*dsw->d_dump)(dumpdev, blkno, vaddr, PAGE_SIZE); 472 if (error) 473 goto fail; 474 blkno += btodb(PAGE_SIZE); 475 476 /* translation RAM (page zero) */ 477 pmap_get_pagemap((int*)vaddr, 0); 478 error = (*dsw->d_dump)(dumpdev, blkno, vaddr, PAGE_SIZE); 479 if (error) 480 goto fail; 481 blkno += btodb(PAGE_SIZE); 482 483 /* translation RAM (page one) */ 484 pmap_get_pagemap((int*)vaddr, PAGE_SIZE); 485 error = (*dsw->d_dump)(dumpdev, blkno, vaddr, PAGE_SIZE); 486 if (error) 487 goto fail; 488 blkno += btodb(PAGE_SIZE); 489 490 /* 491 * Now dump physical memory. Have to do it in two chunks. 492 * The first chunk is "unmanaged" (by the VM code) and its 493 * range of physical addresses is not allow in pmap_enter. 494 * However, that segment is mapped linearly, so we can just 495 * use the virtual mappings already in place. The second 496 * chunk is done the normal way, using pmap_enter. 497 * 498 * Note that vaddr==(paddr+KERNBASE) for paddr=0 through etext. 499 */ 500 501 /* Do the first chunk (0 <= PA < avail_start) */ 502 paddr = 0; 503 chunk = btoc(avail_start); 504 if (chunk > todo) 505 chunk = todo; 506 do { 507 if ((todo & 0xf) == 0) 508 printf_nolog("\r%4d", todo); 509 vaddr = (char*)(paddr + KERNBASE3); 510 error = (*dsw->d_dump)(dumpdev, blkno, vaddr, PAGE_SIZE); 511 if (error) 512 goto fail; 513 paddr += PAGE_SIZE; 514 blkno += btodb(PAGE_SIZE); 515 --todo; 516 } while (--chunk > 0); 517 518 /* Do the second chunk (avail_start <= PA < dumpsize) */ 519 vaddr = (char*)vmmap; /* Borrow /dev/mem VA */ 520 do { 521 if ((todo & 0xf) == 0) 522 printf_nolog("\r%4d", todo); 523 pmap_kenter_pa(vmmap, paddr | PMAP_NC, VM_PROT_READ, 0); 524 pmap_update(pmap_kernel()); 525 error = (*dsw->d_dump)(dumpdev, blkno, vaddr, PAGE_SIZE); 526 pmap_kremove(vmmap, PAGE_SIZE); 527 pmap_update(pmap_kernel()); 528 if (error) 529 goto fail; 530 paddr += PAGE_SIZE; 531 blkno += btodb(PAGE_SIZE); 532 } while (--todo > 0); 533 534 printf("\rdump succeeded\n"); 535 return; 536 fail: 537 printf(" dump error=%d\n", error); 538 } 539 540 static void 541 initcpu(void) 542 { 543 /* XXX: Enable RAM parity/ECC checking? */ 544 /* XXX: parityenable(); */ 545 546 #ifdef HAVECACHE 547 cache_enable(); 548 #endif 549 } 550 551 /* straptrap() in trap.c */ 552 553 /* from hp300: badaddr() */ 554 /* peek_byte(), peek_word() moved to bus_subr.c */ 555 556 /* XXX: parityenable() ? */ 557 /* regdump() moved to regdump.c */ 558 559 bool 560 mm_md_direct_mapped_phys(paddr_t paddr, vaddr_t *vaddr) 561 { 562 563 if (paddr >= avail_start) 564 return false; 565 *vaddr = KERNBASE3 + paddr; 566 return true; 567 } 568 569 /* 570 * Allow access to the PROM mapping similar to uvm_kernacc(). 571 */ 572 int 573 mm_md_kernacc(void *ptr, vm_prot_t prot, bool *handled) 574 { 575 576 if ((vaddr_t)ptr < SUN3_PROM_BASE || (vaddr_t)ptr > SUN3_MONEND) { 577 *handled = false; 578 return 0; 579 } 580 581 *handled = true; 582 /* Read in the PROM itself is OK. */ 583 if ((prot & VM_PROT_WRITE) == 0) 584 return 0; 585 586 /* PROM data page is OK for read/write. */ 587 if ((vaddr_t)ptr >= SUN3_MONSHORTPAGE && 588 (vaddr_t)ptr < SUN3_MONSHORTPAGE + PAGE_SIZE) 589 return 0; 590 return EFAULT; 591 } 592