Home | History | Annotate | Line # | Download | only in hp300
      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