1 /* $NetBSD: machdep.c,v 1.193 2025/11/06 15:54:48 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.193 2025/11/06 15:54:48 thorpej Exp $"); 43 44 #include "opt_ddb.h" 45 #include "opt_compat_netbsd.h" 46 #include "opt_mbtype.h" 47 #include "opt_modular.h" 48 #include "opt_panicbutton.h" 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/signalvar.h> 53 #include <sys/kernel.h> 54 #include <sys/proc.h> 55 #include <sys/buf.h> 56 #include <sys/reboot.h> 57 #include <sys/conf.h> 58 #include <sys/file.h> 59 #include <sys/device.h> 60 #include <sys/kmem.h> 61 #include <sys/mbuf.h> 62 #include <sys/msgbuf.h> 63 #include <sys/vnode.h> 64 #include <sys/queue.h> 65 #include <sys/mount.h> 66 #include <sys/syscallargs.h> 67 #include <sys/ksyms.h> 68 #include <sys/module.h> 69 #include <sys/intr.h> 70 #include <sys/exec.h> 71 #include <sys/exec_aout.h> 72 #include <sys/cpu.h> 73 #include <sys/exec_elf.h> 74 #include <sys/bus.h> 75 76 #include <uvm/uvm_extern.h> 77 78 #include <sys/sysctl.h> 79 80 #include <machine/db_machdep.h> 81 #include <ddb/db_sym.h> 82 #include <ddb/db_extern.h> 83 84 #include <machine/reg.h> 85 #include <machine/psl.h> 86 #include <machine/pte.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 bootsync(void); 97 static void call_sicallbacks(void); 98 static void identifycpu(void); 99 void straymfpint(int, u_short); 100 void straytrap(int, u_short); 101 102 #ifdef _MILANHW_ 103 void nmihandler(void); 104 #endif 105 106 struct vm_map *phys_map = NULL; 107 108 void * msgbufaddr; 109 vaddr_t msgbufpa; 110 111 extern int freebufspace; 112 extern u_int lowram; 113 114 /* 115 * For the fpu emulation and the fpu driver 116 */ 117 int fputype = 0; 118 119 /* the following is used externally (sysctl_hw) */ 120 char machine[] = MACHINE; /* from <machine/param.h> */ 121 122 /* Our exported CPU info; we can have only one. */ 123 struct cpu_info cpu_info_store; 124 125 /* 126 * Console initialization: called early on from main, 127 * before vm init or startup. Do enough configuration 128 * to choose and initialize a console. 129 */ 130 void 131 consinit(void) 132 { 133 int i; 134 135 /* 136 * Initialize error message buffer. pmap_bootstrap() has 137 * positioned this at the end of kernel memory segment - map 138 * and initialize it now. 139 */ 140 for (i = 0; i < btoc(MSGBUFSIZE); i++) 141 pmap_kenter_pa((vaddr_t)msgbufaddr + i * PAGE_SIZE, 142 msgbufpa + i * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, 0); 143 pmap_update(pmap_kernel()); 144 initmsgbuf(msgbufaddr, m68k_round_page(MSGBUFSIZE)); 145 146 /* 147 * Initialize hardware that support various console types like 148 * the grf and PCI busses. 149 */ 150 config_console(); 151 152 /* 153 * Now pick the best console candidate. 154 */ 155 cninit(); 156 157 #if NKSYMS || defined(DDB) || defined(MODULAR) 158 { 159 extern int end; 160 extern int *esym; 161 162 ksyms_addsyms_elf((int)esym - (int)&end - sizeof(Elf32_Ehdr), 163 (void *)&end, esym); 164 } 165 #endif 166 #if defined (DDB) 167 if (boothowto & RB_KDB) 168 Debugger(); 169 #endif 170 } 171 172 vsize_t mem_size; 173 174 /* 175 * cpu_startup: allocate memory for variable-sized tables, 176 * initialize CPU, and do autoconfiguration. 177 */ 178 void 179 cpu_startup(void) 180 { 181 char pbuf[9]; 182 #ifdef DEBUG 183 extern int pmapdebug; 184 int opmapdebug = pmapdebug; 185 #endif 186 vaddr_t minaddr, maxaddr; 187 188 #ifdef DEBUG 189 pmapdebug = 0; 190 #endif 191 192 if (fputype != FPU_NONE) 193 m68k_make_fpu_idle_frame(); 194 195 /* 196 * Good {morning,afternoon,evening,night}. 197 */ 198 printf("%s%s", copyright, version); 199 identifycpu(); 200 201 format_bytes(pbuf, sizeof(pbuf), mem_size); 202 printf("total memory = %s\n", pbuf); 203 204 minaddr = 0; 205 206 /* 207 * Allocate a submap for physio 208 */ 209 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 210 VM_PHYS_SIZE, 0, false, NULL); 211 212 #ifdef DEBUG 213 pmapdebug = opmapdebug; 214 #endif 215 format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false))); 216 printf("avail memory = %s\n", pbuf); 217 } 218 219 /* 220 * Info for CTL_HW 221 */ 222 static void 223 identifycpu(void) 224 { 225 const char *mach, *mmu, *fpu, *cpu; 226 uint32_t pcr; 227 char cputxt[30]; 228 229 switch (machineid & ATARI_ANYMACH) { 230 case ATARI_TT: 231 mach = "Atari TT"; 232 break; 233 case ATARI_FALCON: 234 mach = "Atari Falcon"; 235 break; 236 case ATARI_HADES: 237 mach = "Atari Hades"; 238 break; 239 case ATARI_MILAN: 240 mach = "Atari Milan"; 241 break; 242 default: 243 mach = "Atari UNKNOWN"; 244 break; 245 } 246 247 cpu = "m68k"; 248 fputype = fpu_probe(); 249 fpu = fpu_describe(fputype); 250 251 switch (cputype) { 252 case CPU_68060: 253 __asm(".word 0x4e7a,0x0808;" 254 "movl %%d0,%0" : "=d"(pcr) : : "d0"); 255 snprintf(cputxt, sizeof(cputxt), "MC68%s060 rev.%d", 256 pcr & 0x10000 ? "LC/EC" : "", (pcr >> 8) & 0xff); 257 cpu = cputxt; 258 mmu = "/MMU"; 259 break; 260 case CPU_68040: 261 cpu = "MC68040"; 262 mmu = "/MMU"; 263 break; 264 case CPU_68030: 265 cpu = "MC68030"; 266 mmu = "/MMU"; 267 break; 268 default: /* XXX */ 269 cpu = "MC68020"; 270 mmu = " MC68851 MMU"; 271 } 272 cpu_setmodel("%s (%s CPU%s%sFPU)", mach, cpu, mmu, fpu); 273 printf("%s\n", cpu_getmodel()); 274 } 275 276 /* 277 * machine dependent system variables. 278 */ 279 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup") 280 { 281 282 sysctl_createv(clog, 0, NULL, NULL, 283 CTLFLAG_PERMANENT, 284 CTLTYPE_NODE, "machdep", NULL, 285 NULL, 0, NULL, 0, 286 CTL_MACHDEP, CTL_EOL); 287 288 sysctl_createv(clog, 0, NULL, NULL, 289 CTLFLAG_PERMANENT, 290 CTLTYPE_STRUCT, "console_device", NULL, 291 sysctl_consdev, 0, NULL, sizeof(dev_t), 292 CTL_MACHDEP, CPU_CONSDEV, CTL_EOL); 293 } 294 295 static int waittime = -1; 296 297 static void 298 bootsync(void) 299 { 300 if (waittime < 0) { 301 waittime = 0; 302 vfs_shutdown(); 303 } 304 } 305 306 void 307 cpu_reboot(int howto, char *bootstr) 308 { 309 struct pcb *pcb = lwp_getpcb(curlwp); 310 311 /* take a snap shot before clobbering any registers */ 312 if (pcb != NULL) 313 savectx(pcb); 314 315 boothowto = howto; 316 if ((howto & RB_NOSYNC) == 0) 317 bootsync(); 318 319 /* 320 * Call shutdown hooks. Do this _before_ anything might be 321 * asked to the user in case nobody is there.... 322 */ 323 doshutdownhooks(); 324 325 pmf_system_shutdown(boothowto); 326 327 splhigh(); /* extreme priority */ 328 if (howto & RB_HALT) { 329 printf("halted\n\n"); 330 __asm(" stop #0x2700"); 331 } else { 332 if (howto & RB_DUMP) 333 dumpsys(); 334 335 doboot(); 336 /*NOTREACHED*/ 337 } 338 panic("Boot() should never come here"); 339 /*NOTREACHED*/ 340 } 341 342 static vaddr_t dumpspace; /* Virt. space to map dumppages */ 343 344 /* 345 * Reserve _virtual_ memory to map in the page to be dumped 346 */ 347 vaddr_t 348 reserve_dumppages(vaddr_t p) 349 { 350 351 dumpspace = p; 352 return p + PAGE_SIZE; 353 } 354 355 uint32_t dumpmag = 0x8fca0101; /* magic number for savecore */ 356 int dumpsize = 0; /* also for savecore (pages) */ 357 long dumplo = 0; /* (disk blocks) */ 358 359 void 360 cpu_dumpconf(void) 361 { 362 int nblks, i; 363 364 for (i = dumpsize = 0; i < NMEM_SEGS; i++) { 365 if (boot_segs[i].start == boot_segs[i].end) 366 break; 367 dumpsize += boot_segs[i].end - boot_segs[i].start; 368 } 369 dumpsize = btoc(dumpsize); 370 371 if (dumpdev != NODEV) { 372 nblks = bdev_size(dumpdev); 373 if (nblks > 0) { 374 if (dumpsize > btoc(dbtob(nblks - dumplo))) 375 dumpsize = btoc(dbtob(nblks - dumplo)); 376 else if (dumplo == 0) 377 dumplo = nblks - btodb(ctob(dumpsize)); 378 } 379 } 380 dumplo -= cpu_dumpsize(); 381 382 /* 383 * Don't dump on the first PAGE_SIZE (why PAGE_SIZE?) 384 * in case the dump device includes a disk label. 385 */ 386 if (dumplo < btodb(PAGE_SIZE)) 387 dumplo = btodb(PAGE_SIZE); 388 } 389 390 /* 391 * Doadump comes here after turning off memory management and 392 * getting on the dump stack, either when called above, or by 393 * the auto-restart code. 394 */ 395 void 396 dumpsys(void) 397 { 398 const struct bdevsw *bdev; 399 daddr_t blkno; /* Current block to write */ 400 int (*dump)(dev_t, daddr_t, void *, size_t); 401 /* Dumping function */ 402 u_long maddr; /* PA being dumped */ 403 int segbytes; /* Number of bytes in this seg. */ 404 int segnum; /* Segment we are dumping */ 405 int nbytes; /* Bytes left to dump */ 406 int i, n, error; 407 408 error = segnum = 0; 409 if (dumpdev == NODEV) 410 return; 411 bdev = bdevsw_lookup(dumpdev); 412 if (bdev == NULL) 413 return; 414 /* 415 * For dumps during autoconfiguration, 416 * if dump device has already configured... 417 */ 418 if (dumpsize == 0) 419 cpu_dumpconf(); 420 if (dumplo <= 0) { 421 printf("\ndump to dev %u,%u not possible\n", 422 major(dumpdev), minor(dumpdev)); 423 return; 424 } 425 printf("\ndumping to dev %u,%u offset %ld\n", 426 major(dumpdev), minor(dumpdev), dumplo); 427 428 #if defined(DDB) || defined(PANICWAIT) 429 printf("Do you want to dump memory? [y]"); 430 cnpollc(1); 431 i = cngetc(); 432 cnpollc(0); 433 cnputc(i); 434 switch (i) { 435 case 'n': 436 case 'N': 437 return; 438 case '\n': 439 break; 440 default : 441 cnputc('\n'); 442 } 443 #endif /* defined(DDB) || defined(PANICWAIT) */ 444 445 maddr = 0; 446 segbytes = boot_segs[0].end; 447 blkno = dumplo; 448 dump = bdev->d_dump; 449 nbytes = dumpsize * PAGE_SIZE; 450 451 printf("dump "); 452 453 error = cpu_dump(dump, &blkno); 454 if (!error) { 455 for (i = 0; i < nbytes; i += n, segbytes -= n) { 456 /* 457 * Skip the hole 458 */ 459 if (segbytes == 0) { 460 segnum++; 461 maddr = boot_segs[segnum].start; 462 segbytes = boot_segs[segnum].end - 463 boot_segs[segnum].start; 464 } 465 /* 466 * Print Mb's to go 467 */ 468 n = nbytes - i; 469 if (n && (n % (1024 * 1024)) == 0) 470 printf_nolog("%d ", n / (1024 * 1024)); 471 472 /* 473 * Limit transfer to PAGE_SIZE 474 */ 475 if (n > PAGE_SIZE) 476 n = PAGE_SIZE; 477 478 /* 479 * Map to a VA and write it 480 */ 481 if (maddr != 0) { /* XXX kvtop chokes on this */ 482 pmap_enter(pmap_kernel(), dumpspace, maddr, 483 VM_PROT_READ, VM_PROT_READ|PMAP_WIRED); 484 pmap_update(pmap_kernel()); 485 error = (*dump)(dumpdev, blkno, 486 (void *)dumpspace, n); 487 if (error) 488 break; 489 } 490 491 maddr += n; 492 blkno += btodb(n); 493 } 494 } 495 switch (error) { 496 497 case ENXIO: 498 printf("device bad\n"); 499 break; 500 501 case EFAULT: 502 printf("device not ready\n"); 503 break; 504 505 case EINVAL: 506 printf("area improper\n"); 507 break; 508 509 case EIO: 510 printf("i/o error\n"); 511 break; 512 513 default: 514 printf("succeeded\n"); 515 break; 516 } 517 printf("\n\n"); 518 delay(5000000); /* 5 seconds */ 519 } 520 521 void 522 straytrap(int pc, u_short evec) 523 { 524 static int prev_evec; 525 526 printf("unexpected trap (vector offset 0x%x) from 0x%x\n", 527 evec & 0xFFF, pc); 528 529 if (prev_evec == evec) { 530 delay(1000000); 531 prev_evec = 0; 532 } else 533 prev_evec = evec; 534 } 535 536 void 537 straymfpint(int pc, u_short evec) 538 { 539 540 printf("unexpected mfp-interrupt (vector offset 0x%x) from 0x%x\n", 541 evec & 0xFFF, pc); 542 } 543 544 int *nofault; 545 546 int 547 badbaddr(void *addr, int size) 548 { 549 int i; 550 label_t faultbuf; 551 552 nofault = (int *) &faultbuf; 553 if (setjmp((label_t *)nofault)) { 554 nofault = (int *) 0; 555 return 1; 556 } 557 switch (size) { 558 case 1: 559 i = *(volatile uint8_t *)addr; 560 break; 561 case 2: 562 i = *(volatile uint16_t *)addr; 563 break; 564 case 4: 565 i = *(volatile uint32_t *)addr; 566 break; 567 default: 568 panic("badbaddr: unknown size"); 569 } 570 __USE(i); 571 nofault = (int *)0; 572 return 0; 573 } 574 575 /* 576 * this is a handy package to have asynchronously executed 577 * function calls executed at very low interrupt priority. 578 * Example for use is keyboard repeat, where the repeat 579 * handler running at splclock() triggers such a (hardware 580 * aided) software interrupt. 581 * Note: the installed functions are currently called in a 582 * LIFO fashion, might want to change this to FIFO 583 * later. 584 * 585 * XXX: Some of functions which use this callback should be rewritten 586 * XXX: to use MI softintr(9) directly. 587 */ 588 struct si_callback { 589 struct si_callback *next; 590 void (*function)(void *rock1, void *rock2); 591 void *rock1, *rock2; 592 }; 593 static void *si_callback_cookie; 594 static struct si_callback *si_callbacks; 595 static struct si_callback *si_free; 596 #ifdef DIAGNOSTIC 597 static int ncbd; /* number of callback blocks dynamically allocated */ 598 #endif 599 600 void 601 init_sicallback(void) 602 { 603 604 si_callback_cookie = softint_establish(SOFTINT_NET, 605 (void (*)(void *))call_sicallbacks, NULL); 606 } 607 608 void 609 add_sicallback(void (*function)(void *, void *), void *rock1, void *rock2) 610 { 611 struct si_callback *si; 612 int s; 613 614 /* 615 * this function may be called from high-priority interrupt handlers. 616 * We may NOT block for memory-allocation in here!. 617 */ 618 s = splhigh(); 619 if ((si = si_free) != NULL) 620 si_free = si->next; 621 splx(s); 622 623 if (si == NULL) { 624 si = kmem_intr_alloc(sizeof(*si), KM_NOSLEEP); 625 #ifdef DIAGNOSTIC 626 if (si) 627 ++ncbd; /* count # dynamically allocated */ 628 #endif 629 if (si == NULL) 630 return; 631 } 632 633 si->function = function; 634 si->rock1 = rock1; 635 si->rock2 = rock2; 636 637 s = splhigh(); 638 si->next = si_callbacks; 639 si_callbacks = si; 640 splx(s); 641 642 /* 643 * and cause a software interrupt (spl1). This interrupt might 644 * happen immediately, or after returning to a safe enough level. 645 * 646 * XXX: 647 * According to <machine/scu.h> and lev1intr() handler in locore.s, 648 * at least _ATARIHW_ machines (ATARITT and HADES?) seem to have 649 * some hardware support which can initiate real hardware interrupt 650 * at ipl 1 for software interrupt. But as per <machine/mtpr.h>, 651 * this feature was not used at all on setsoft*() calls and 652 * traditional hp300 derived ssir (simulated software interrupt 653 * request) on VAX REI emulation in locore.s is used. 654 */ 655 softint_schedule(si_callback_cookie); 656 } 657 658 void 659 rem_sicallback(void (*function)(void *rock1, void *rock2)) 660 { 661 struct si_callback *si, *psi, *nsi; 662 int s; 663 664 s = splhigh(); 665 for (psi = 0, si = si_callbacks; si; ) { 666 nsi = si->next; 667 668 if (si->function != function) 669 psi = si; 670 else { 671 si->next = si_free; 672 si_free = si; 673 if (psi != NULL) 674 psi->next = nsi; 675 else 676 si_callbacks = nsi; 677 } 678 si = nsi; 679 } 680 splx(s); 681 } 682 683 /* purge the list */ 684 static void 685 call_sicallbacks(void) 686 { 687 struct si_callback *si; 688 int s; 689 void *rock1, *rock2; 690 void (*function)(void *, void *); 691 692 do { 693 s = splhigh(); 694 if ((si = si_callbacks) != NULL) 695 si_callbacks = si->next; 696 splx(s); 697 698 if (si != NULL) { 699 function = si->function; 700 rock1 = si->rock1; 701 rock2 = si->rock2; 702 s = splhigh(); 703 if (si_callbacks) 704 softint_schedule(si_callback_cookie); 705 si->next = si_free; 706 si_free = si; 707 splx(s); 708 709 /* 710 * Raise spl for BASEPRI() checks to see 711 * nested interrupts in some drivers using callbacks 712 * since modern MI softint(9) doesn't seem to do it 713 * in !__HAVE_FAST_SOFTINTS case. 714 * 715 * XXX: This is just a workaround hack. 716 * Each driver should raise spl in its handler 717 * to avoid nested interrupts if necessary. 718 */ 719 s = splsoftnet(); /* XXX */ 720 function(rock1, rock2); 721 splx(s); 722 } 723 } while (si != NULL); 724 #ifdef DIAGNOSTIC 725 if (ncbd) { 726 #ifdef DEBUG 727 printf("call_sicallback: %d more dynamic structures\n", ncbd); 728 #endif 729 ncbd = 0; 730 } 731 #endif 732 } 733 734 #if defined(DEBUG) && !defined(PANICBUTTON) 735 #define PANICBUTTON 736 #endif 737 738 #ifdef PANICBUTTON 739 int panicbutton = 1; /* non-zero if panic buttons are enabled */ 740 int crashandburn = 0; 741 int candbdelay = 50; /* give em half a second */ 742 743 void candbtimer(void); 744 745 void 746 candbtimer(void) 747 { 748 749 crashandburn = 0; 750 } 751 #endif 752 753 /* 754 * should only get here, if no standard executable. This can currently 755 * only mean, we're reading an old ZMAGIC file without MID, but since Atari 756 * ZMAGIC always worked the `right' way (;-)) just ignore the missing 757 * MID and proceed to new zmagic code ;-) 758 */ 759 int 760 cpu_exec_aout_makecmds(struct lwp *l, struct exec_package *epp) 761 { 762 int error = ENOEXEC; 763 #ifdef COMPAT_NOMID 764 struct exec *execp = epp->ep_hdr; 765 #endif 766 767 #ifdef COMPAT_NOMID 768 if (!((execp->a_midmag >> 16) & 0x0fff) 769 && execp->a_midmag == ZMAGIC) 770 return exec_aout_prep_zmagic(l->l_proc, epp); 771 #endif 772 return error; 773 } 774 775 #ifdef MODULAR 776 /* 777 * Push any modules loaded by the bootloader etc. 778 */ 779 void 780 module_init_md(void) 781 { 782 } 783 #endif 784 785 #ifdef _MILANHW_ 786 787 /* 788 * Currently the only source of NMI interrupts on the Milan is the PLX9080. 789 * On access errors to the PCI bus, an NMI is generated. This NMI is shorted 790 * in locore in case of a PCI config cycle to a non-existing address to allow 791 * for probes. On other occasions, it ShouldNotHappen(TM). 792 * Note: The handler in locore clears the errors, to make further PCI access 793 * possible. 794 */ 795 void 796 nmihandler(void) 797 { 798 extern unsigned long plx_status; 799 800 printf("nmihandler: plx_status = 0x%08lx\n", plx_status); 801 } 802 #endif 803 804 int 805 mm_md_physacc(paddr_t pa, vm_prot_t prot) 806 { 807 struct memseg *ms; 808 809 for (ms = boot_segs; ms->start != ms->end; ms++) { 810 if ((pa >= ms->start) && (pa < ms->end)) 811 return 0; 812 } 813 return EFAULT; 814 } 815 816 int 817 mm_md_readwrite(dev_t dev, struct uio *uio) 818 { 819 switch (minor(dev)) { 820 case DEV_NVRAM: 821 #if NNVR > 0 822 return nvram_uio(uio); 823 #else 824 return ENXIO; 825 #endif 826 default: 827 return ENXIO; 828 } 829 } 830