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