1 /* $NetBSD: machdep.c,v 1.209 2026/04/28 03:29:09 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 6 * 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.63 91/04/24$ 37 * 38 * @(#)machdep.c 7.16 (Berkeley) 6/3/91 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.209 2026/04/28 03:29:09 thorpej Exp $"); 43 44 #include "opt_ddb.h" 45 #include "opt_mbtype.h" 46 #include "opt_modular.h" 47 #include "opt_panicbutton.h" 48 49 #include <sys/param.h> 50 #include <sys/systm.h> 51 #include <sys/signalvar.h> 52 #include <sys/kernel.h> 53 #include <sys/proc.h> 54 #include <sys/buf.h> 55 #include <sys/reboot.h> 56 #include <sys/conf.h> 57 #include <sys/file.h> 58 #include <sys/device.h> 59 #include <sys/kmem.h> 60 #include <sys/mbuf.h> 61 #include <sys/msgbuf.h> 62 #include <sys/vnode.h> 63 #include <sys/queue.h> 64 #include <sys/mount.h> 65 #include <sys/syscallargs.h> 66 #include <sys/ksyms.h> 67 #include <sys/module.h> 68 #include <sys/intr.h> 69 #include <sys/exec.h> 70 #include <sys/cpu.h> 71 #include <sys/exec_elf.h> 72 #include <sys/bus.h> 73 74 #include <uvm/uvm_extern.h> 75 76 #include <sys/sysctl.h> 77 78 #include <machine/db_machdep.h> 79 #include <ddb/db_sym.h> 80 #include <ddb/db_extern.h> 81 82 #include <machine/reg.h> 83 #include <machine/psl.h> 84 #include <machine/pte.h> 85 86 #include <m68k/pcr.h> 87 88 #include <dev/cons.h> 89 #include <dev/mm.h> 90 91 #include "ksyms.h" 92 #include "nvr.h" 93 94 #define DEV_NVRAM 11 /* Nvram minor-number */ 95 96 static void call_sicallbacks(void); 97 void straymfpint(int, u_short); 98 99 #ifdef _MILANHW_ 100 void nmihandler(void); 101 #endif 102 103 extern int freebufspace; 104 extern u_int lowram; 105 106 struct pmap_bootmap machine_bootmap[] = { 107 /* XXX */ 108 { .pmbm_vaddr = -1 }, 109 }; 110 111 /* 112 * Console initialization: called early on from main, 113 * before vm init or startup. Do enough configuration 114 * to choose and initialize a console. 115 */ 116 void 117 consinit(void) 118 { 119 int i; 120 121 /* 122 * Initialize error message buffer. pmap_bootstrap() has 123 * positioned this at the end of kernel memory segment - map 124 * and initialize it now. 125 */ 126 extern paddr_t msgbufpa; 127 for (i = 0; i < btoc(MSGBUFSIZE); i++) 128 pmap_kenter_pa((vaddr_t)msgbufaddr + i * PAGE_SIZE, 129 msgbufpa + i * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, 0); 130 pmap_update(pmap_kernel()); 131 initmsgbuf(msgbufaddr, m68k_round_page(MSGBUFSIZE)); 132 133 /* 134 * Initialize hardware that support various console types like 135 * the grf and PCI busses. 136 */ 137 config_console(); 138 139 /* 140 * Now pick the best console candidate. 141 */ 142 cninit(); 143 144 #if NKSYMS || defined(DDB) || defined(MODULAR) 145 { 146 extern int end; 147 extern int *esym; 148 149 ksyms_addsyms_elf((int)esym - (int)&end - sizeof(Elf32_Ehdr), 150 (void *)&end, esym); 151 } 152 #endif 153 #if defined (DDB) 154 if (boothowto & RB_KDB) 155 Debugger(); 156 #endif 157 } 158 159 vsize_t mem_size; 160 161 void 162 machine_set_model(void) 163 { 164 const char *mach; 165 166 switch (machineid & ATARI_ANYMACH) { 167 case ATARI_TT: 168 mach = "Atari TT"; 169 break; 170 case ATARI_FALCON: 171 mach = "Atari Falcon"; 172 break; 173 case ATARI_HADES: 174 mach = "Atari Hades"; 175 break; 176 case ATARI_MILAN: 177 mach = "Atari Milan"; 178 break; 179 default: 180 mach = "Atari UNKNOWN"; 181 break; 182 } 183 184 cpu_setmodel("%s", mach); 185 } 186 187 /* 188 * machine dependent system variables. 189 */ 190 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup") 191 { 192 193 sysctl_createv(clog, 0, NULL, NULL, 194 CTLFLAG_PERMANENT, 195 CTLTYPE_NODE, "machdep", NULL, 196 NULL, 0, NULL, 0, 197 CTL_MACHDEP, CTL_EOL); 198 199 sysctl_createv(clog, 0, NULL, NULL, 200 CTLFLAG_PERMANENT, 201 CTLTYPE_STRUCT, "console_device", NULL, 202 sysctl_consdev, 0, NULL, sizeof(dev_t), 203 CTL_MACHDEP, CPU_CONSDEV, CTL_EOL); 204 } 205 206 static vaddr_t dumpspace; /* Virt. space to map dumppages */ 207 208 /* 209 * Reserve _virtual_ memory to map in the page to be dumped 210 */ 211 vaddr_t 212 reserve_dumppages(vaddr_t p) 213 { 214 215 dumpspace = p; 216 return p + PAGE_SIZE; 217 } 218 219 uint32_t dumpmag = 0x8fca0101; /* magic number for savecore */ 220 int dumpsize = 0; /* also for savecore (pages) */ 221 long dumplo = 0; /* (disk blocks) */ 222 223 void 224 cpu_dumpconf(void) 225 { 226 int nblks, i; 227 228 for (i = dumpsize = 0; i < NMEM_SEGS; i++) { 229 if (boot_segs[i].start == boot_segs[i].end) 230 break; 231 dumpsize += boot_segs[i].end - boot_segs[i].start; 232 } 233 dumpsize = btoc(dumpsize); 234 235 if (dumpdev != NODEV) { 236 nblks = bdev_size(dumpdev); 237 if (nblks > 0) { 238 if (dumpsize > btoc(dbtob(nblks - dumplo))) 239 dumpsize = btoc(dbtob(nblks - dumplo)); 240 else if (dumplo == 0) 241 dumplo = nblks - btodb(ctob(dumpsize)); 242 } 243 } 244 dumplo -= cpu_dumpsize(); 245 246 /* 247 * Don't dump on the first PAGE_SIZE (why PAGE_SIZE?) 248 * in case the dump device includes a disk label. 249 */ 250 if (dumplo < btodb(PAGE_SIZE)) 251 dumplo = btodb(PAGE_SIZE); 252 } 253 254 /* 255 * Doadump comes here after turning off memory management and 256 * getting on the dump stack, either when called above, or by 257 * the auto-restart code. 258 */ 259 void 260 dumpsys(void) 261 { 262 const struct bdevsw *bdev; 263 daddr_t blkno; /* Current block to write */ 264 int (*dump)(dev_t, daddr_t, void *, size_t); 265 /* Dumping function */ 266 u_long maddr; /* PA being dumped */ 267 int segbytes; /* Number of bytes in this seg. */ 268 int segnum; /* Segment we are dumping */ 269 int nbytes; /* Bytes left to dump */ 270 int i, n, error; 271 272 error = segnum = 0; 273 if (dumpdev == NODEV) 274 return; 275 bdev = bdevsw_lookup(dumpdev); 276 if (bdev == NULL) 277 return; 278 /* 279 * For dumps during autoconfiguration, 280 * if dump device has already configured... 281 */ 282 if (dumpsize == 0) 283 cpu_dumpconf(); 284 if (dumplo <= 0) { 285 printf("\ndump to dev %u,%u not possible\n", 286 major(dumpdev), minor(dumpdev)); 287 return; 288 } 289 printf("\ndumping to dev %u,%u offset %ld\n", 290 major(dumpdev), minor(dumpdev), dumplo); 291 292 #if defined(DDB) || defined(PANICWAIT) 293 printf("Do you want to dump memory? [y]"); 294 cnpollc(true); 295 i = cngetc(); 296 cnpollc(false); 297 cnputc(i); 298 switch (i) { 299 case 'n': 300 case 'N': 301 return; 302 case '\n': 303 break; 304 default : 305 cnputc('\n'); 306 } 307 #endif /* defined(DDB) || defined(PANICWAIT) */ 308 309 maddr = 0; 310 segbytes = boot_segs[0].end; 311 blkno = dumplo; 312 dump = bdev->d_dump; 313 nbytes = dumpsize * PAGE_SIZE; 314 315 printf("dump "); 316 317 error = cpu_dump(dump, &blkno); 318 if (!error) { 319 for (i = 0; i < nbytes; i += n, segbytes -= n) { 320 /* 321 * Skip the hole 322 */ 323 if (segbytes == 0) { 324 segnum++; 325 maddr = boot_segs[segnum].start; 326 segbytes = boot_segs[segnum].end - 327 boot_segs[segnum].start; 328 } 329 /* 330 * Print Mb's to go 331 */ 332 n = nbytes - i; 333 if (n && (n % (1024 * 1024)) == 0) 334 printf_nolog("%d ", n / (1024 * 1024)); 335 336 /* 337 * Limit transfer to PAGE_SIZE 338 */ 339 if (n > PAGE_SIZE) 340 n = PAGE_SIZE; 341 342 /* 343 * Map to a VA and write it 344 */ 345 if (maddr != 0) { /* XXX kvtop chokes on this */ 346 pmap_enter(pmap_kernel(), dumpspace, maddr, 347 VM_PROT_READ, VM_PROT_READ|PMAP_WIRED); 348 pmap_update(pmap_kernel()); 349 error = (*dump)(dumpdev, blkno, 350 (void *)dumpspace, n); 351 if (error) 352 break; 353 } 354 355 maddr += n; 356 blkno += btodb(n); 357 } 358 } 359 switch (error) { 360 361 case ENXIO: 362 printf("device bad\n"); 363 break; 364 365 case EFAULT: 366 printf("device not ready\n"); 367 break; 368 369 case EINVAL: 370 printf("area improper\n"); 371 break; 372 373 case EIO: 374 printf("i/o error\n"); 375 break; 376 377 default: 378 printf("succeeded\n"); 379 break; 380 } 381 printf("\n\n"); 382 delay(5000000); /* 5 seconds */ 383 } 384 385 void 386 straymfpint(int pc, u_short evec) 387 { 388 389 printf("unexpected mfp-interrupt (vector offset 0x%x) from 0x%x\n", 390 evec & 0xFFF, pc); 391 } 392 393 /* 394 * this is a handy package to have asynchronously executed 395 * function calls executed at very low interrupt priority. 396 * Example for use is keyboard repeat, where the repeat 397 * handler running at splclock() triggers such a (hardware 398 * aided) software interrupt. 399 * Note: the installed functions are currently called in a 400 * LIFO fashion, might want to change this to FIFO 401 * later. 402 * 403 * XXX: Some of functions which use this callback should be rewritten 404 * XXX: to use MI softintr(9) directly. 405 */ 406 struct si_callback { 407 struct si_callback *next; 408 void (*function)(void *rock1, void *rock2); 409 void *rock1, *rock2; 410 }; 411 static void *si_callback_cookie; 412 static struct si_callback *si_callbacks; 413 static struct si_callback *si_free; 414 #ifdef DIAGNOSTIC 415 static int ncbd; /* number of callback blocks dynamically allocated */ 416 #endif 417 418 void 419 init_sicallback(void) 420 { 421 422 si_callback_cookie = softint_establish(SOFTINT_NET, 423 (void (*)(void *))call_sicallbacks, NULL); 424 } 425 426 void 427 add_sicallback(void (*function)(void *, void *), void *rock1, void *rock2) 428 { 429 struct si_callback *si; 430 int s; 431 432 /* 433 * this function may be called from high-priority interrupt handlers. 434 * We may NOT block for memory-allocation in here!. 435 */ 436 s = splhigh(); 437 if ((si = si_free) != NULL) 438 si_free = si->next; 439 splx(s); 440 441 if (si == NULL) { 442 si = kmem_intr_alloc(sizeof(*si), KM_NOSLEEP); 443 #ifdef DIAGNOSTIC 444 if (si) 445 ++ncbd; /* count # dynamically allocated */ 446 #endif 447 if (si == NULL) 448 return; 449 } 450 451 si->function = function; 452 si->rock1 = rock1; 453 si->rock2 = rock2; 454 455 s = splhigh(); 456 si->next = si_callbacks; 457 si_callbacks = si; 458 splx(s); 459 460 /* 461 * and cause a software interrupt (spl1). This interrupt might 462 * happen immediately, or after returning to a safe enough level. 463 * 464 * XXX: 465 * According to <machine/scu.h> and lev1intr() handler in locore.s, 466 * at least _ATARIHW_ machines (ATARITT and HADES?) seem to have 467 * some hardware support which can initiate real hardware interrupt 468 * at ipl 1 for software interrupt. But as per <machine/mtpr.h>, 469 * this feature was not used at all on setsoft*() calls and 470 * traditional hp300 derived ssir (simulated software interrupt 471 * request) on VAX REI emulation in locore.s is used. 472 */ 473 softint_schedule(si_callback_cookie); 474 } 475 476 void 477 rem_sicallback(void (*function)(void *rock1, void *rock2)) 478 { 479 struct si_callback *si, *psi, *nsi; 480 int s; 481 482 s = splhigh(); 483 for (psi = 0, si = si_callbacks; si; ) { 484 nsi = si->next; 485 486 if (si->function != function) 487 psi = si; 488 else { 489 si->next = si_free; 490 si_free = si; 491 if (psi != NULL) 492 psi->next = nsi; 493 else 494 si_callbacks = nsi; 495 } 496 si = nsi; 497 } 498 splx(s); 499 } 500 501 /* purge the list */ 502 static void 503 call_sicallbacks(void) 504 { 505 struct si_callback *si; 506 int s; 507 void *rock1, *rock2; 508 void (*function)(void *, void *); 509 510 do { 511 s = splhigh(); 512 if ((si = si_callbacks) != NULL) 513 si_callbacks = si->next; 514 splx(s); 515 516 if (si != NULL) { 517 function = si->function; 518 rock1 = si->rock1; 519 rock2 = si->rock2; 520 s = splhigh(); 521 if (si_callbacks) 522 softint_schedule(si_callback_cookie); 523 si->next = si_free; 524 si_free = si; 525 splx(s); 526 527 /* 528 * Raise spl for BASEPRI() checks to see 529 * nested interrupts in some drivers using callbacks 530 * since modern MI softint(9) doesn't seem to do it 531 * in !__HAVE_FAST_SOFTINTS case. 532 * 533 * XXX: This is just a workaround hack. 534 * Each driver should raise spl in its handler 535 * to avoid nested interrupts if necessary. 536 */ 537 s = splsoftnet(); /* XXX */ 538 function(rock1, rock2); 539 splx(s); 540 } 541 } while (si != NULL); 542 #ifdef DIAGNOSTIC 543 if (ncbd) { 544 #ifdef DEBUG 545 printf("call_sicallback: %d more dynamic structures\n", ncbd); 546 #endif 547 ncbd = 0; 548 } 549 #endif 550 } 551 552 #if defined(DEBUG) && !defined(PANICBUTTON) 553 #define PANICBUTTON 554 #endif 555 556 #ifdef PANICBUTTON 557 int panicbutton = 1; /* non-zero if panic buttons are enabled */ 558 int crashandburn = 0; 559 int candbdelay = 50; /* give em half a second */ 560 561 void candbtimer(void); 562 563 void 564 candbtimer(void) 565 { 566 567 crashandburn = 0; 568 } 569 #endif 570 571 #ifdef _MILANHW_ 572 573 /* 574 * Currently the only source of NMI interrupts on the Milan is the PLX9080. 575 * On access errors to the PCI bus, an NMI is generated. This NMI is shorted 576 * in locore in case of a PCI config cycle to a non-existing address to allow 577 * for probes. On other occasions, it ShouldNotHappen(TM). 578 * Note: The handler in locore clears the errors, to make further PCI access 579 * possible. 580 */ 581 void 582 nmihandler(void) 583 { 584 extern unsigned long plx_status; 585 586 printf("nmihandler: plx_status = 0x%08lx\n", plx_status); 587 } 588 #endif 589 590 int 591 mm_md_physacc(paddr_t pa, vm_prot_t prot) 592 { 593 struct memseg *ms; 594 595 for (ms = boot_segs; ms->start != ms->end; ms++) { 596 if ((pa >= ms->start) && (pa < ms->end)) 597 return 0; 598 } 599 return EFAULT; 600 } 601 602 int 603 mm_md_readwrite(dev_t dev, struct uio *uio) 604 { 605 switch (minor(dev)) { 606 case DEV_NVRAM: 607 #if NNVR > 0 608 return nvram_uio(uio); 609 #else 610 return ENXIO; 611 #endif 612 default: 613 return ENXIO; 614 } 615 } 616