code:
/*	$OpenBSD: param.h,v 1.5 2013/11/02 23:06:18 miod Exp $ */

/*
 * Copyright (c) 1999 Steve Murphree, Jr.
 * Copyright (c) 1988 University of Utah.
 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef	_MACHINE_PARAM_H_
#define	_MACHINE_PARAM_H_

#define	_MACHINE	luna88k
#define	MACHINE		"luna88k"

#include <m88k/param.h>

/*
 * The ROM monitor uses the bottom 128KB. The kernel will allocate PTEs to map
 * this space, but the kernel must be linked with a start address past
 * these 128KB.
 */
#define	KERNBASE	0x00000000	/* start of kernel virtual */
#define	KERNTEXTOFF	0x00080000	/* start of kernel text */

#endif /* _MACHINE_PARAM_H_ */


code:
/* $OpenBSD: pcb.h,v 1.3 2004/04/26 14:31:08 miod Exp $ */
/* public domain */
#include <m88k/pcb.h>

license: unknown


code:
/*	$OpenBSD: pcex.h,v 1.2 2014/06/18 12:26:11 aoyama Exp $	*/

/*
 * Copyright (c) 2014 Kenji Aoyama.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _MACHINE_PCEX_H_
#define _MACHINE_PCEX_H_

/*
 * PC-9801 extension board slot support for LUNA-88K2
 */

/* The ioctl defines */

#define	PCEXSETLEVEL	_IOW('P', 1, int)	/* Set INT level */
#define	PCEXRESETLEVEL	_IOW('P', 2, int)	/* Reset INT level */
#define	PCEXWAITINT	_IOW('P', 3, int)	/* Wait for INT  */

#endif /* _MACHINE_PCEX_H_ */


code:
/* $OpenBSD: pmap.h,v 1.5 2010/12/31 21:38:08 miod Exp $ */
/* public domain */
#include <m88k/pmap.h>


code:
/* $OpenBSD: pmap_table.h,v 1.2 2004/07/25 11:06:41 miod Exp $ */
/* public domain */
#include <m88k/pmap_table.h>


code:
/* $OpenBSD: proc.h,v 1.3 2004/04/26 14:31:08 miod Exp $ */
/* public domain */
#include <m88k/proc.h>


code:
/* $OpenBSD: profile.h,v 1.1 2004/04/29 06:25:33 miod Exp $ */
/* public domain */
#include <m88k/profile.h>


code:
/* $OpenBSD: psl.h,v 1.3 2004/04/26 14:31:08 miod Exp $ */
/* public domain */
#include <m88k/psl.h>


code:
/* $OpenBSD: ptrace.h,v 1.3 2004/04/26 14:31:08 miod Exp $ */
/* public domain */
#include <m88k/ptrace.h>


code:
/* $OpenBSD: reg.h,v 1.3 2004/04/26 14:31:08 miod Exp $ */
/* public domain */
#include <m88k/reg.h>


code:
/* $OpenBSD: reloc.h,v 1.1 2013/01/05 11:20:55 miod Exp $ */
/* public domain */
#include <m88k/reloc.h>


code:
/* $OpenBSD: setjmp.h,v 1.3 2004/04/26 14:31:08 miod Exp $ */
/* public domain */
#include <m88k/setjmp.h>


code:
/* $OpenBSD: signal.h,v 1.3 2004/04/26 14:31:08 miod Exp $ */
/* public domain */
#include <m88k/signal.h>


code:
/* $OpenBSD: spinlock.h,v 1.3 2004/04/26 14:31:08 miod Exp $ */
/* public domain */
#include <m88k/spinlock.h>


code:
/* $OpenBSD: stdarg.h,v 1.3 2004/04/26 14:31:08 miod Exp $ */
/* public domain */
#include <m88k/stdarg.h>


code:
/*	$OpenBSD: tcb.h,v 1.2 2013/06/01 21:20:54 jasper Exp $	*/
/* public domain */
#include <m88k/tcb.h>


code:
/* $OpenBSD: trap.h,v 1.3 2004/04/26 14:31:08 miod Exp $ */
/* public domain */
#include <m88k/trap.h>


code:
/* $OpenBSD: varargs.h,v 1.3 2004/04/26 14:31:08 miod Exp $ */
/* public domain */
#include <m88k/varargs.h>


code:
/* $OpenBSD: vmparam.h,v 1.4 2010/12/31 21:38:08 miod Exp $ */
/* public domain */
/*
 * Physical memory is mapped 1:1 at the bottom of the supervisor address
 * space. Kernel virtual memory space starts from the end of physical memory,
 * up to the on-board devices appearing all over the last 3GB of address space.
 */
#define VM_MIN_KERNEL_ADDRESS	((vaddr_t)0x00000000)
#define VM_MAX_KERNEL_ADDRESS	((vaddr_t)0x40000000)

#include <m88k/vmparam.h>


code:
/*	$OpenBSD: autoconf.c,v 1.21 2014/04/22 22:58:02 aoyama Exp $	*/
/*
 * Copyright (c) 1998 Steve Murphree, Jr.
 * Copyright (c) 1996 Nivas Madhur
 * Copyright (c) 1994 Christian E. Hopps
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Christian E. Hopps.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/kernel.h>

#include <uvm/uvm.h>

#include <machine/asm_macro.h>   /* enable/disable interrupts */
#include <machine/autoconf.h>
#include <machine/cpu.h>
#include <machine/vmparam.h>

#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>

#include <dev/cons.h>

/*
 * The following several variables are related to
 * the configuration process, and are used in initializing
 * the machine.
 */

void	dumpconf(void);
void	get_autoboot_device(void);

int cold = 1;   /* 1 if still booting */

void *bootaddr;
int bootpart;
struct device *bootdv;	/* set by device drivers (if found) */

/*
 * called at boot time, configure all devices on the system.
 */
void
cpu_configure()
{
	softintr_init();

	if (config_rootfound("mainbus", "mainbus") == 0)
		panic("no mainbus found");

	/*
	 * Switch to our final trap vectors, and unmap the PROM data area.
	 */
	set_vbr(kernel_vbr);
	pmap_unmap_firmware();

	cold = 0;

	/*
	 * Turn external interrupts on.
	 */
	set_psr(get_psr() & ~PSR_IND);
	spl0();
}

void
diskconf(void)
{
	printf("boot device: %s\n",
	    (bootdv) ? bootdv->dv_xname : "<unknown>");
	setroot(bootdv, 0, RB_USERREQ);
	dumpconf();
}

/*
 * Get 'auto-boot' information from NVRAM
 *
 * XXX Right now we can not handle network boot.
 */
struct autoboot_t
{
	char	cont[16];
	int	targ;
	int	part;
} autoboot;

void
get_autoboot_device(void)
{
	char *value, c;
	int i, len, part;
	extern char *nvram_by_symbol(char *);		/* machdep.c */

	/* Assume default controller is internal spc (spc0) */
	strlcpy(autoboot.cont, "spc0", sizeof(autoboot.cont));

	/* Get boot controler and SCSI target from NVRAM */
	value = nvram_by_symbol("boot_unit");
	if (value != NULL) {
		len = strlen(value);
		if (len == 1) {
			c = value[0];
		} else if (len == 2) {
			if (value[0] == '1') {
				/* External spc (spc1) */
				strlcpy(autoboot.cont, "spc1", sizeof(autoboot.cont));
				c = value[1];
			}
		} else
			c = -1;

		if ((c >= '0') && (c <= '6'))
			autoboot.targ = 6 - (c - '0');
	}

	/* Get partition number from NVRAM */
	value = nvram_by_symbol("boot_partition");
	if (value != NULL) {
		len = strlen(value);
		part = 0;
		for (i = 0; i < len; i++)
			part = part * 10 + (value[i] - '0');
		autoboot.part = part;
	}
}

void
device_register(struct device *dev, void *aux)
{
        /*
         * scsi: sd,cd  XXX: Can LUNA-88K boot from CD-ROM?
         */
        if (strcmp("sd", dev->dv_cfdata->cf_driver->cd_name) == 0 ||
            strcmp("cd", dev->dv_cfdata->cf_driver->cd_name) == 0) {
		struct scsi_attach_args *sa = aux;
		struct device *spcsc;

		spcsc = dev->dv_parent->dv_parent;

                if (strcmp(spcsc->dv_xname, autoboot.cont) == 0 &&
		    sa->sa_sc_link->target == autoboot.targ &&
		    sa->sa_sc_link->lun == 0) {
                        bootdv = dev;
			bootpart = autoboot.part;
                        return;
                }
        }
}

struct nam2blk nam2blk[] = {
	{ "sd",		4 },
	{ "st",		5 },
	{ "rd",		7 },
	{ "vnd",	8 },
	{ NULL,		-1 }
};


code:
/* $OpenBSD: clock.c,v 1.10 2014/09/27 19:50:10 aoyama Exp $ */
/* $NetBSD: clock.c,v 1.2 2000/01/11 10:29:35 nisimura Exp $ */

/*
 * Copyright (c) 1988 University of Utah.
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department and Ralph Campbell.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * from: Utah Hdr: clock.c 1.18 91/01/21
 *
 *	@(#)clock.c	8.1 (Berkeley) 6/10/93
 */

/* from NetBSD/luna68k sys/arch/luna68k/luna68k/clock.c */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/evcount.h>
#include <sys/timetc.h>

#include <machine/board.h>
#include <machine/cpu.h>

#include <dev/clock_subr.h>
#include <luna88k/luna88k/clockvar.h>

struct device *clockdev;
const struct clockfns *clockfns;
struct evcount *clockevc;
int clockinitted, todrvalid;

void
clockattach(dev, fns, evc)
	struct device *dev;
	const struct clockfns *fns;
	struct evcount *evc;
{
	/*
	 * Just bookkeeping.
	 */
	if (clockfns != NULL)
		panic("clockattach: multiple clocks");
	clockdev = dev;
	clockfns = fns;
	clockevc = evc;
}

/*
 * Machine-dependent clock routines.
 *
 * Startrtclock restarts the real-time clock, which provides
 * hardclock interrupts to kern_clock.c.
 *
 * Inittodr initializes the time of day hardware which provides
 * date functions.  Its primary function is to use some file
 * system information in case the hardare clock lost state.
 *
 * Resettodr restores the time of day hardware after a time change.
 */

u_int	clock_get_tc(struct timecounter *);

struct timecounter clock_tc = {
	.tc_get_timecount = clock_get_tc,
	.tc_counter_mask = 0xffffffff,
	.tc_frequency = 0, /* will be filled in */
	.tc_name = "clock",
	.tc_quality = 0
};

/*
 * Start the real-time and statistics clocks. Leave stathz 0 since there
 * are no other timers available.
 */
void
cpu_initclocks()
{

#ifdef DIAGNOSTIC
	if (clockfns == NULL)
		panic("cpu_initclocks: no clock attached");
#endif

	tick = 1000000 / hz;	/* number of microseconds between interrupts */
	clock_tc.tc_frequency = hz;
	tc_init(&clock_tc);
	clockinitted = 1;
}

/*
 * We assume newhz is either stathz or profhz, and that neither will
 * change after being set up above.  Could recalculate intervals here
 * but that would be a drag.
 */
void
setstatclockrate(newhz)
	int newhz;
{
	/* nothing we can do */
}

/*
 * Initialze the time of day register, based on the time base which is, e.g.
 * from a filesystem.  Base provides the time to within six months,
 * and the time of year clock (if any) provides the rest.
 */
void
inittodr(base)
	time_t base;
{
	struct clock_ymdhms dt;
	struct timespec ts;
	time_t deltat;
	int badbase;

	ts.tv_sec = ts.tv_nsec = 0;

	if (base < (2012 - 1970) * SECYR) {
		printf("WARNING: preposterous time in file system");
		/* read the system clock anyway */
		base = (2012 - 1970) * SECYR;
		badbase = 1;
	} else
		badbase = 0;

	(*clockfns->cf_get)(clockdev, base, &dt);
	todrvalid = 1;
	/* simple sanity checks */
	if (dt.dt_year < 1970 || dt.dt_mon < 1 || dt.dt_mon > 12
		|| dt.dt_day < 1 || dt.dt_day > 31
		|| dt.dt_hour > 23 || dt.dt_min > 59 || dt.dt_sec > 59) {
		/*
		 * Believe the time in the file system for lack of
		 * anything better, resetting the TODR.
		 */
		ts.tv_sec = base;
		tc_setclock(&ts);
		if (!badbase) {
			printf("WARNING: preposterous clock chip time");
			resettodr();
		}
		goto bad;
	}
	/* now have days since Jan 1, 1970; the rest is easy... */
	ts.tv_sec = clock_ymdhms_to_secs(&dt);
	tc_setclock(&ts);

	if (!badbase) {
		/*
		 * See if we gained/lost two or more days;
		 * if so, assume something is amiss.
		 */
		deltat = ts.tv_sec - base;
		if (deltat < 0)
			deltat = -deltat;
		if (deltat < 2 * SECDAY)
			return;
		printf("WARNING: clock %s %d days",
		    ts.tv_sec < base ? "lost" : "gained",
		       (int) (deltat / SECDAY));
	}
bad:
	printf(" -- CHECK AND RESET THE DATE!\n");
}

/*
 * Reset the TODR based on the time value; used when the TODR
 * has a preposterous value and also when the time is reset
 * by the stime system call.  Also called when the TODR goes past
 * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
 * to wrap the TODR around.
 */
void
resettodr()
{
	struct clock_ymdhms dt;

	if (!todrvalid)
		return;
	clock_secs_to_ymdhms(time_second, &dt);
	(*clockfns->cf_set)(clockdev, &dt);
}

/*
 * *clock_reg[CPU]
 * Points to the clock register for each CPU.
 */
volatile u_int32_t *clock_reg[] = {
	(u_int32_t *)OBIO_CLOCK0,
	(u_int32_t *)OBIO_CLOCK1,
	(u_int32_t *)OBIO_CLOCK2,
	(u_int32_t *)OBIO_CLOCK3
};

/*
 * Clock interrupt routine
 */
int
clockintr(void *eframe)
{
#ifdef MULTIPROCESSOR
	struct cpu_info *ci = curcpu();
	u_int cpu = ci->ci_cpuid;
#else
	u_int cpu = cpu_number();
#endif

#ifdef MULTIPROCESSOR
	if (CPU_IS_PRIMARY(ci))
#endif
		clockevc->ec_count++;

	*clock_reg[cpu] = 0xffffffff;
	if (clockinitted)
		hardclock(eframe);
	return 1;
}

u_int
clock_get_tc(struct timecounter *tc)
{
	return (u_int)clockevc->ec_count;
}


code:
/* $OpenBSD: clockvar.h,v 1.3 2008/06/26 05:42:11 ray Exp $ */
/* $NetBSD: clockvar.h,v 1.1 2000/01/05 08:49:02 nisimura Exp $ */

/*-
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tohru Nishimura.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

struct clock_ymdhms;

/*
 * clockfns structure:
 *
 * function switch used by chip-independent clock code, to access
 * chip-dependent routines.
 */
struct clockfns {
	void	(*cf_init)(struct device *);
	void	(*cf_get)(struct device *, time_t, struct clock_ymdhms *);
	void	(*cf_set)(struct device *, struct clock_ymdhms *);
};

void clockattach(struct device *, const struct clockfns *, struct evcount *);
int clockintr(void *);


code:
/*	$OpenBSD: conf.c,v 1.26 2015/03/03 23:50:37 aoyama Exp $	*/

/*-
 * Copyright (c) 1991 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *      @(#)conf.c	7.9 (Berkeley) 5/28/91
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/ioctl.h>
#include <sys/tty.h>
#include <sys/vnode.h>

#include <machine/conf.h>

#include "bio.h"
#include "pty.h"
#include "bpfilter.h"
#include "tun.h"
#include "vnd.h"
#include "rd.h"
#include "cd.h"
#include "ch.h"
#include "sd.h"
#include "st.h"
#include "uk.h"
#include "wd.h"

#include "ksyms.h"

#include "audio.h"
#include "com.h"
#include "lcd.h"
#include "pcex.h"
#include "siotty.h"

#include "wsdisplay.h"
#include "wskbd.h"
#include "wsmouse.h"
#include "wsmux.h"

#include "pf.h"
#include "systrace.h"
#include "vscsi.h"
#include "pppx.h"
#include "fuse.h"

struct bdevsw	bdevsw[] =
{
	bdev_notdef(),			/* 0 */
	bdev_notdef(),			/* 1 */
	bdev_notdef(),			/* 2 */
	bdev_swap_init(1,sw),		/* 3: swap pseudo-device */
	bdev_disk_init(NSD,sd),		/* 4: SCSI disk */
	bdev_tape_init(NST,st),		/* 5: SCSI tape */
	bdev_disk_init(NCD,cd),		/* 6: SCSI CD-ROM */
	bdev_disk_init(NRD,rd),		/* 7: ramdisk */
	bdev_disk_init(NVND,vnd),	/* 8: vnode disk driver */
	bdev_disk_init(NWD,wd),		/* 9: IDE disk (on PCMCIA) */
	bdev_notdef(),			/* 10 */
	bdev_notdef(),			/* 11 */
	bdev_notdef(),			/* 12 */
	bdev_notdef(),			/* 13 */
	bdev_notdef(),			/* 14 */
	bdev_notdef(),			/* 15 */
	bdev_notdef(),			/* 16 */
	bdev_notdef(),			/* 17 */
	bdev_notdef(),			/* 18 */
};
int	nblkdev = nitems(bdevsw);

struct cdevsw	cdevsw[] =
{
	cdev_cn_init(1,cn),		/* 0: virtual console */
	cdev_ctty_init(1,ctty),		/* 1: controlling terminal */
	cdev_mm_init(1,mm),		/* 2: /dev/{null,mem,kmem,...} */
	cdev_notdef(),			/* 3 was /dev/drum */
	cdev_tty_init(NPTY,pts),	/* 4: pseudo-tty slave */
	cdev_ptc_init(NPTY,ptc),	/* 5: pseudo-tty master */
	cdev_log_init(1,log),		/* 6: /dev/klog */
	cdev_notdef(),			/* 7 */
	cdev_disk_init(NSD,sd),		/* 8: SCSI disk */
	cdev_disk_init(NCD,cd),		/* 9: SCSI CD-ROM */
	cdev_lcd_init(NLCD,lcd),	/* 10: /dev/lcd */
	cdev_notdef(),			/* 11 */
	cdev_tty_init(NSIOTTY,sio),	/* 12: on-board UART (ttya) */
	cdev_wsdisplay_init(NWSDISPLAY,	/* 13: frame buffers, etc. */
		wsdisplay),
	cdev_mouse_init(NWSKBD,wskbd),	/* 14: keyboard */
	cdev_mouse_init(NWSMOUSE,	/* 15: mouse */
		wsmouse),
	cdev_mouse_init(NWSMUX,wsmux),	/* 16: ws multiplexor */
	cdev_notdef(),			/* 17: was: concatenated disk */
	cdev_disk_init(NRD,rd),		/* 18: ramdisk disk */
	cdev_disk_init(NVND,vnd),	/* 19: vnode disk */
	cdev_tape_init(NST,st),		/* 20: SCSI tape */
	cdev_fd_init(1,filedesc),	/* 21: file descriptor pseudo-dev */
	cdev_bpf_init(NBPFILTER,bpf),	/* 22: berkeley packet filter */
	cdev_tun_init(NTUN,tun),	/* 23: network tunnel */
	cdev_notdef(),			/* 24 was LKM */
	cdev_pcex_init(NPCEX, pcex),	/* 25: PC-9801 extension board slot */
	cdev_audio_init(NAUDIO, audio),	/* 26: generic audio I/O */
	cdev_tty_init(NCOM, com),	/* 27: serial port (on PCMCIA) */
	cdev_disk_init(NWD,wd),		/* 28: IDE disk (on PCMCIA) */
	cdev_notdef(),			/* 29 */
	cdev_notdef(),			/* 30 */
	cdev_notdef(),			/* 31 */
	cdev_notdef(),			/* 32 */
	cdev_notdef(),			/* 33 */
	cdev_notdef(),			/* 34 */
	cdev_notdef(),			/* 35 */
	cdev_notdef(),			/* 36 */
	cdev_notdef(),			/* 37 */
	cdev_notdef(),			/* 38 */
	cdev_pf_init(NPF,pf),		/* 39: packet filter */
	cdev_random_init(1,random),	/* 40: random data source */
	cdev_uk_init(NUK,uk),		/* 41 */
	cdev_notdef(),			/* 42 */
	cdev_ksyms_init(NKSYMS,ksyms),	/* 43: Kernel symbols device */
	cdev_ch_init(NCH,ch),		/* 44: SCSI autochanger */
	cdev_fuse_init(NFUSE,fuse),	/* 45: fuse */
	cdev_notdef(),			/* 46 */
	cdev_notdef(),			/* 47 */
	cdev_notdef(),			/* 48 */
	cdev_bio_init(NBIO,bio),	/* 49: ioctl tunnel */
	cdev_systrace_init(NSYSTRACE,systrace),	/* 50 system call tracing */
	cdev_notdef(),			/* 51 */
	cdev_ptm_init(NPTY,ptm),	/* 52: pseudo-tty ptm device */
	cdev_vscsi_init(NVSCSI,vscsi),	/* 53: vscsi */
	cdev_disk_init(1,diskmap),	/* 54: disk mapper */
	cdev_pppx_init(NPPPX,pppx),	/* 55: pppx */
};
int	nchrdev = nitems(cdevsw);

int	mem_no = 2;	/* major device number of memory special file */

/*
 * Swapdev is a fake device implemented
 * in sw.c used only internally to get to swstrategy.
 * It cannot be provided to the users, because the
 * swstrategy routine munches the b_dev and b_blkno entries
 * before calling the appropriate driver.  This would horribly
 * confuse, e.g. the hashing routines. Instead, /dev/drum is
 * provided as a character (raw) device.
 */
dev_t	swapdev = makedev(3, 0);

/*
 * Returns true if dev is /dev/mem or /dev/kmem.
 */
int
iskmemdev(dev)
	dev_t dev;
{

	return (major(dev) == mem_no && minor(dev) < 2);
}

/*
 * Returns true if dev is /dev/zero.
 */
int
iszerodev(dev)
	dev_t dev;
{

	return (major(dev) == mem_no && minor(dev) == 12);
}

dev_t
getnulldev()
{
	return makedev(mem_no, 2);
}

int chrtoblktbl[] = {
	/*VCHR*/	/*VBLK*/
	/*  0 */	NODEV,
	/*  1 */	NODEV,
	/*  2 */	NODEV,
	/*  3 */	NODEV,
	/*  4 */	NODEV,
	/*  5 */	NODEV,
	/*  6 */	NODEV,
	/*  7 */	NODEV,
	/*  8 */	4,	/* sd */
	/*  9 */	6,	/* cd */
	/* 10 */	NODEV,
	/* 11 */	NODEV,
	/* 12 */	NODEV,
	/* 13 */	NODEV,
	/* 14 */	NODEV,
	/* 15 */	NODEV,
	/* 16 */	NODEV,
	/* 17 */	NODEV,
	/* 18 */	7,	/* rd */
	/* 19 */	8,	/* vnd */
	/* 20 */	5,	/* st */
};
int nchrtoblktbl = nitems(chrtoblktbl);


code:
/* $OpenBSD: disksubr.c,v 1.57 2015/01/16 20:17:05 miod Exp $ */
/* $NetBSD: disksubr.c,v 1.12 2002/02/19 17:09:44 wiz Exp $ */

/*
 * Copyright (c) 1994, 1995 Gordon W. Ross
 * Copyright (c) 1994 Theo de Raadt
 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/disk.h>

#include <dev/sun/disklabel.h>

/*
 * UniOS disklabel (== ISI disklabel) is very similar to SunOS.
 *	SunOS				UniOS/ISI
 *	text		128			128
 *	(pad)		292			294
 *	rpm		2		-
 *	pcyl		2		badchk	2
 *	sparecyl	2		maxblk	4
 *	(pad)		4		dtype	2
 *	interleave	2		ndisk	2
 *	ncyl		2			2
 *	acyl		2			2
 *	ntrack		2			2
 *	nsect		2			2
 *	(pad)		4		bhead	2
 *	-				ppart	2
 *	dkpart[8]	64			64
 *	magic		2			2
 *	cksum		2			2
 *
 * Magic number value and checksum calculation are identical.  Subtle
 * difference is partition start address; UniOS/ISI maintains sector
 * numbers while SunOS label has cylinder number.
 *
 * It is found that LUNA Mach2.5 has BSD label embedded at offset 64
 * retaining UniOS/ISI label at the end of label block.  LUNA Mach
 * manipulates BSD disklabel in the same manner as 4.4BSD.  It's
 * uncertain LUNA Mach can create a disklabel on fresh disks since
 * Mach writedisklabel logic seems to fail when no BSD label is found.
 *
 * Kernel handles disklabel in this way;
 *	- searchs BSD label at offset 64
 *	- if not found, searchs UniOS/ISI label at the end of block
 *	- kernel can distinguish whether it was SunOS label or UniOS/ISI
 *	  label and understand both
 *	- kernel writes UniOS/ISI label combined with BSD label to update
 *	  the label block
 */

#if LABELSECTOR != 0
#error	"Default value of LABELSECTOR no longer zero?"
#endif

int disklabel_om_to_bsd(struct sun_disklabel *, struct disklabel *);
int disklabel_bsd_to_om(struct disklabel *, struct sun_disklabel *);
static __inline u_int sun_extended_sum(struct sun_disklabel *, void *);

/*
 * Attempt to read a disk label from a device
 * using the indicated strategy routine.
 * The label must be partly set up before this:
 * secpercyl, secsize and anything required for a block i/o read
 * operation in the driver's strategy/start routines
 * must be filled in before calling us.
 */
int
readdisklabel(dev_t dev, void (*strat)(struct buf *),
    struct disklabel *lp, int spoofonly)
{
	struct sun_disklabel *slp;
	struct buf *bp = NULL;
	int error;

	if ((error = initdisklabel(lp)))
		goto done;
	lp->d_flags |= D_VENDOR;

	/* get a buffer and initialize it */
	bp = geteblk((int)lp->d_secsize);
	bp->b_dev = dev;

	if (spoofonly)
		goto done;

	bp->b_blkno = LABELSECTOR;
	bp->b_bcount = lp->d_secsize;
	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
	SET(bp->b_flags, B_BUSY | B_READ | B_RAW);
	(*strat)(bp);
	if (biowait(bp)) {
		error = bp->b_error;
		goto done;
	}

	slp = (struct sun_disklabel *)bp->b_data;
	if (slp->sl_magic == SUN_DKMAGIC) {
		error = disklabel_om_to_bsd(slp, lp);
		goto done;
	}

	error = checkdisklabel(bp->b_data + LABELOFFSET, lp, 0,
	    DL_GETDSIZE(lp));
	if (error == 0)
		goto done;

#if defined(CD9660)
	error = iso_disklabelspoof(dev, strat, lp);
	if (error == 0)
		goto done;
#endif
#if defined(UDF)
	error = udf_disklabelspoof(dev, strat, lp);
	if (error == 0)
		goto done;
#endif

done:
	if (bp) {
		bp->b_flags |= B_INVAL;
		brelse(bp);
	}
	disk_change = 1;
	return (error);
}

/*
 * Write disk label back to device after modification.
 */
int
writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp)
{
	struct buf *bp = NULL;
	int error;

	/* get a buffer and initialize it */
	bp = geteblk((int)lp->d_secsize);
	bp->b_dev = dev;

	error = disklabel_bsd_to_om(lp, (struct sun_disklabel *)bp->b_data);
	if (error)
		goto done;

	/* Write out the updated label. */
	bp->b_blkno = LABELSECTOR;
	bp->b_bcount = lp->d_secsize;
	CLR(bp->b_flags, B_READ | B_WRITE | B_DONE);
	SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW);
	(*strat)(bp);
	error = biowait(bp);

done:
	if (bp) {
		bp->b_flags |= B_INVAL;
		brelse(bp);
	}
	disk_change = 1;
	return (error);
}

/************************************************************************
 *
 * The rest of this was taken from arch/sparc/scsi/sun_disklabel.c
 * and then substantially rewritten by Gordon W. Ross
 *
 ************************************************************************/

/* What partition types to assume for Sun disklabels: */
static const u_char
sun_fstypes[16] = {
	FS_BSDFFS,	/* a */
	FS_SWAP,	/* b */
	FS_UNUSED,	/* c - whole disk */
	FS_BSDFFS,	/* d */
	FS_BSDFFS,	/* e */
	FS_BSDFFS,	/* f */
	FS_BSDFFS,	/* g */
	FS_BSDFFS,	/* h */
	FS_BSDFFS,	/* i */
	FS_BSDFFS,	/* j */
	FS_BSDFFS,	/* k */
	FS_BSDFFS,	/* l */
	FS_BSDFFS,	/* m */
	FS_BSDFFS,	/* n */
	FS_BSDFFS,	/* o */
	FS_BSDFFS	/* p */
};

/*
 * Given a struct sun_disklabel, assume it has an extended partition
 * table and compute the correct value for sl_xpsum.
 */
static __inline u_int
sun_extended_sum(struct sun_disklabel *sl, void *end)
{
	u_int sum, *xp, *ep;

	xp = (u_int *)&sl->sl_xpmag;
	ep = (u_int *)end;

	sum = 0;
	for (; xp < ep; xp++)
		sum += *xp;
	return (sum);
}

/*
 * Given a UniOS/ISI disk label, set lp to a BSD disk label.
 *
 * The BSD label is cleared out before this is called.
 */
int
disklabel_om_to_bsd(struct sun_disklabel *sl, struct disklabel *lp)
{
	struct partition *npp;
	struct sun_dkpart *spp;
	int i, secpercyl;
	u_short cksum = 0, *sp1, *sp2;

	/* Verify the XOR check. */
	sp1 = (u_short *)sl;
	sp2 = (u_short *)(sl + 1);
	while (sp1 < sp2)
		cksum ^= *sp1++;
	if (cksum != 0)
		return (EINVAL);	/* UniOS disk label, bad checksum */

	/* Format conversion. */
	lp->d_magic = DISKMAGIC;
	lp->d_magic2 = DISKMAGIC;
	lp->d_flags = D_VENDOR;
	memcpy(lp->d_packname, sl->sl_text, sizeof(lp->d_packname));

	lp->d_secsize = DEV_BSIZE;
	lp->d_nsectors = sl->sl_nsectors;
	lp->d_ntracks = sl->sl_ntracks;
	lp->d_ncylinders = sl->sl_ncylinders;

	secpercyl = sl->sl_nsectors * sl->sl_ntracks;
	lp->d_secpercyl = secpercyl;
	/* If unset or initialized as full disk, permit refinement */
	if (DL_GETDSIZE(lp) == 0 || DL_GETDSIZE(lp) == MAXDISKSIZE)
		DL_SETDSIZE(lp, (u_int64_t)secpercyl * sl->sl_ncylinders);
	lp->d_version = 1;

	memcpy(&lp->d_uid, &sl->sl_uid, sizeof(sl->sl_uid));

	lp->d_acylinders = sl->sl_acylinders;

	lp->d_npartitions = MAXPARTITIONS;
	/* These are as defined in <ufs/ffs/fs.h> */
	lp->d_bbsize = 8192;	/* XXX */
	lp->d_sbsize = 8192;	/* XXX */

	for (i = 0; i < 8; i++) {
		spp = &sl->sl_part[i];
		npp = &lp->d_partitions[i];
		/* UniOS label uses blkoffset, not cyloffset */
		DL_SETPOFFSET(npp, spp->sdkp_cyloffset);
		DL_SETPSIZE(npp, spp->sdkp_nsectors);
		if (DL_GETPSIZE(npp) == 0) {
			npp->p_fstype = FS_UNUSED;
		} else {
			npp->p_fstype = sun_fstypes[i];
			if (npp->p_fstype == FS_BSDFFS) {
				/*
				 * The sun label does not store the FFS fields,
				 * so just set them with default values here.
				 */
				npp->p_fragblock =
				    DISKLABELV1_FFS_FRAGBLOCK(2048, 8);
				npp->p_cpg = 16;
			}
		}
	}

	/*
	 * XXX BandAid XXX
	 * UniOS rootfs sits on part c which don't begin at sect 0,
	 * and impossible to mount.  Thus, make it usable as part b.
	 * XXX how to setup a swap partition on disks shared with UniOS???
	 */
	if (sl->sl_rpm == 0 && DL_GETPOFFSET(&lp->d_partitions[2]) != 0) {
		lp->d_partitions[1] = lp->d_partitions[2];
		lp->d_partitions[1].p_fstype = FS_BSDFFS;
	}

	/* Clear "extended" partition info, tentatively */
	for (i = 0; i < SUNXPART; i++) {
		npp = &lp->d_partitions[i+8];
		DL_SETPOFFSET(npp, 0);
		DL_SETPSIZE(npp, 0);
		npp->p_fstype = FS_UNUSED;
	}

	/* Check to see if there's an "extended" partition table
	 * SL_XPMAG partitions had checksums up to just before the
	 * (new) sl_types variable, while SL_XPMAGTYP partitions have
	 * checksums up to the just before the (new) sl_xxx1 variable.
	 */
	if ((sl->sl_xpmag == SL_XPMAG &&
	    sun_extended_sum(sl, &sl->sl_types) == sl->sl_xpsum) ||
	    (sl->sl_xpmag == SL_XPMAGTYP &&
	    sun_extended_sum(sl, &sl->sl_xxx1) == sl->sl_xpsum)) {
		/*
		 * There is.  Copy over the "extended" partitions.
		 * This code parallels the loop for partitions a-h.
		 */
		for (i = 0; i < SUNXPART; i++) {
			spp = &sl->sl_xpart[i];
			npp = &lp->d_partitions[i+8];
			DL_SETPOFFSET(npp, spp->sdkp_cyloffset);
			DL_SETPSIZE(npp, spp->sdkp_nsectors);
			if (DL_GETPSIZE(npp) == 0) {
				npp->p_fstype = FS_UNUSED;
				continue;
			}
			npp->p_fstype = sun_fstypes[i+8];
			if (npp->p_fstype == FS_BSDFFS) {
				npp->p_fragblock =
				    DISKLABELV1_FFS_FRAGBLOCK(2048, 8);
				npp->p_cpg = 16;
			}
		}
		if (sl->sl_xpmag == SL_XPMAGTYP) {
			for (i = 0; i < MAXPARTITIONS; i++) {
				npp = &lp->d_partitions[i];
				npp->p_fstype = sl->sl_types[i];
				npp->p_fragblock = sl->sl_fragblock[i];
				npp->p_cpg = sl->sl_cpg[i];
			}
		}
	}

	lp->d_checksum = 0;
	lp->d_checksum = dkcksum(lp);
	return (checkdisklabel(lp, lp, 0, DL_GETDSIZE(lp)));
}

/*
 * Given a BSD disk label, update the UniOS disklabel
 * pointed to by sl with the new info.  Note that the
 * UniOS disklabel may have other info we need to keep.
 */
int
disklabel_bsd_to_om(struct disklabel *lp, struct sun_disklabel *sl)
{
	struct partition *npp;
	struct sun_dkpart *spp;
	int i, secpercyl;
	u_short cksum, *sp1, *sp2;

	if (lp->d_secsize != DEV_BSIZE || lp->d_nsectors == 0 ||
	    lp->d_ntracks == 0)
		return (EINVAL);

	/* Format conversion. */
	bzero(sl, sizeof(*sl));
	memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname));
	sl->sl_rpm = 0;					/* UniOS compatible */
#if 0 /* leave as was */
	sl->sl_pcylinders = lp->d_ncylinders + lp->d_acylinders; /* XXX */
#endif
	sl->sl_interleave = 1;
	sl->sl_ncylinders = lp->d_ncylinders;
	sl->sl_acylinders = lp->d_acylinders;
	sl->sl_ntracks = lp->d_ntracks;
	sl->sl_nsectors = lp->d_nsectors;

	memcpy(&sl->sl_uid, &lp->d_uid, sizeof(lp->d_uid));

	for (i = 0; i < 8; i++) {
		spp = &sl->sl_part[i];
		npp = &lp->d_partitions[i];
		spp->sdkp_cyloffset = 0;
		spp->sdkp_nsectors = 0;
		if (DL_GETPSIZE(npp)) {
			spp->sdkp_cyloffset = DL_GETPOFFSET(npp); /* UniOS */
			spp->sdkp_nsectors = DL_GETPSIZE(npp);
		}
	}
	sl->sl_magic = SUN_DKMAGIC;

	secpercyl = sl->sl_nsectors * sl->sl_ntracks;
	for (i = 0; i < SUNXPART; i++) {
		spp = &sl->sl_xpart[i];
		npp = &lp->d_partitions[i+8];
		spp->sdkp_cyloffset = 0;
		spp->sdkp_nsectors = 0;
		if (DL_GETPSIZE(npp)) {
			spp->sdkp_cyloffset = DL_GETPOFFSET(npp);
			spp->sdkp_nsectors = DL_GETPSIZE(npp);
		}
	}
	for (i = 0; i < MAXPARTITIONS; i++) {
		npp = &lp->d_partitions[i];
		sl->sl_types[i] = npp->p_fstype;
		sl->sl_fragblock[i] = npp->p_fragblock;
		sl->sl_cpg[i] = npp->p_cpg;
	}
	sl->sl_xpmag = SL_XPMAGTYP;
	sl->sl_xpsum = sun_extended_sum(sl, &sl->sl_xxx1);

	/* Correct the XOR check. */
	sp1 = (u_short *)sl;
	sp2 = (u_short *)(sl + 1);
	sl->sl_cksum = cksum = 0;
	while (sp1 < sp2)
		cksum ^= *sp1++;
	sl->sl_cksum = cksum;

	return (0);
}


code:
/*	$OpenBSD: eh.S,v 1.10 2014/04/22 22:58:02 aoyama Exp $	*/
/*
 * Copyright (c) 2006, Miodrag Vallat
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <machine/board.h>
#include <machine/m8820x.h>

/*
 * Save Pbus fault status register from data and inst CMMU.
 *
 * PFSR_SAVE is invoked with TMP, TMP2 and TMP3 available, and TMP contains
 * curcpu().
 *
 * On the LUNA-88K we just have to peek at the CMMU PFSR our curcpu() points
 * to.
 */

#define	PFSR_SAVE \
	ld	TMP2, TMP,  CI_PFSR_I0; \
	ld	TMP3, TMP2, %r0; \
	st	TMP3, %r31, EF_IPFSR; \
	ld	TMP2, TMP,  CI_PFSR_D0; \
	ld	TMP3, TMP2, %r0; \
	st	TMP3, %r31, EF_DPFSR

#include <m88k/m88k/eh_common.S>


code: #	$OpenBSD: genassym.cf,v 1.3 2010/04/26 22:11:38 deraadt Exp $


code:
/*	$OpenBSD: isr.c,v 1.10 2015/05/18 04:06:37 miod Exp $	*/
/*	$NetBSD: isr.c,v 1.5 2000/07/09 08:08:20 nisimura Exp $	*/

/*-
 * Copyright (c) 1996 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Adam Glass, Gordon W. Ross, and Jason R. Thorpe.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Link and dispatch interrupts.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/vmmeter.h>
#include <sys/evcount.h>

#include <uvm/uvm_extern.h>

#include <machine/cpu.h>

#include <luna88k/luna88k/isr.h>

isr_autovec_list_t isr_autovec[NISRAUTOVEC];

void
isrinit()
{
	int i;

	/* Initialize the autovector lists. */
	for (i = 0; i < NISRAUTOVEC; ++i) {
		LIST_INIT(&isr_autovec[i]);
	}
}

/*
 * Establish an autovectored interrupt handler.
 * Called by driver attach functions.
 */
void
isrlink_autovec(int (*func)(void *), void *arg, int ipl, int priority,
    const char *name)
{
	struct isr_autovec *newisr, *curisr;
	isr_autovec_list_t *list;

#ifdef DIAGNOSTIC
	if (ipl < 0 || ipl >= NISRAUTOVEC)
		panic("isrlink_autovec: bad ipl %d", ipl);
#endif

	newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec),
	    M_DEVBUF, M_NOWAIT);
	if (newisr == NULL)
		panic("isrlink_autovec: can't allocate space for isr");

	/* Fill in the new entry. */
	newisr->isr_func = func;
	newisr->isr_arg = arg;
	newisr->isr_ipl = ipl;
	newisr->isr_priority = priority;
	evcount_attach(&newisr->isr_count, name, &newisr->isr_ipl);

	/*
	 * Some devices are particularly sensitive to interrupt
	 * handling latency.  The SCC, for example, can lose many
	 * characters if its interrupt isn't handled with reasonable
	 * speed.
	 *
	 * To work around this problem, each device can give itself a
	 * "priority".  An unbuffered SCC would give itself a higher
	 * priority than a SCSI device, for example.
	 *
	 * This solution was originally developed for the hp300, which
	 * has a flat spl scheme (by necessity).  Thankfully, the
	 * MVME systems don't have this problem, though this may serve
	 * a useful purpose in any case.
	 */

	/*
	 * Get the appropriate ISR list.  If the list is empty, no
	 * additional work is necessary; we simply insert ourselves
	 * at the head of the list.
	 */
	list = &isr_autovec[ipl];
	if (LIST_EMPTY(list)) {
		LIST_INSERT_HEAD(list, newisr, isr_link);
		return;
	}

	/*
	 * A little extra work is required.  We traverse the list
	 * and place ourselves after any ISRs with our current (or
	 * higher) priority.
	 */
	for (curisr = LIST_FIRST(list); LIST_NEXT(curisr, isr_link) != NULL;
	    curisr = LIST_NEXT(curisr, isr_link)) {
		if (newisr->isr_priority > curisr->isr_priority) {
			LIST_INSERT_BEFORE(curisr, newisr, isr_link);
			return;
		}
	}

	/*
	 * We're the least important entry, it seems.  We just go
	 * on the end.
	 */
	LIST_INSERT_AFTER(curisr, newisr, isr_link);
}

/*
 * This is the dispatcher called by the low-level
 * assembly language autovectored interrupt routine.
 */
void
isrdispatch_autovec(int ipl)
{
	struct isr_autovec *isr;
	isr_autovec_list_t *list;
	int rc, handled = 0;
	static int straycount, unexpected;

#ifdef DIAGNOSTIC
	if (ipl < 0 || ipl >= NISRAUTOVEC)
		panic("isrdispatch_autovec: bad ipl 0x%d", ipl);
#endif

#if 0	/* XXX: already counted in machdep.c */
	uvmexp.intrs++;
#endif

	list = &isr_autovec[ipl];
	if (LIST_EMPTY(list)) {
		printf("isrdispatch_autovec: ipl %d unexpected\n", ipl);
		if (++unexpected > 10)
			panic("too many unexpected interrupts");
		return;
	}

	/* Give all the handlers a chance. */
	LIST_FOREACH(isr, list, isr_link) {
#ifdef MULTIPROCESSOR
		if (isr->isr_ipl < IPL_CLOCK)
			__mp_lock(&kernel_lock);
#endif
		rc = (*isr->isr_func)(isr->isr_arg);
#ifdef MULTIPROCESSOR
		if (isr->isr_ipl < IPL_CLOCK)
			__mp_unlock(&kernel_lock);
#endif
		if (rc != 0)
			isr->isr_count.ec_count++;
		handled |= rc;
	}

	if (handled)
		straycount = 0;
	else if (++straycount > 50)
		panic("isr_dispatch_autovec: too many stray interrupts");
	else
		printf("isrdispatch_autovec: stray level %d interrupt\n", ipl);
}


code:
/*	$OpenBSD: isr.h,v 1.4 2008/06/26 05:42:11 ray Exp $	*/
/*	$NetBSD: isr.h,v 1.1 2000/01/05 08:49:04 nisimura Exp $	*/

/*-
 * Copyright (c) 1996 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/evcount.h>
#include <sys/queue.h>

/*
 * The max size of the autovectored interrupt.
 */
#define NISRAUTOVEC	8

/*
 * Autovectored interrupt handler cookie.
 */
struct isr_autovec {
	LIST_ENTRY(isr_autovec) isr_link;
	int		(*isr_func)(void *);
	void		*isr_arg;
	int		isr_ipl;
	int		isr_priority;
	struct evcount	isr_count;
};

typedef LIST_HEAD(, isr_autovec) isr_autovec_list_t;

/*
 * Autovectored ISR priorities.  These are not the same as interrupt levels.
 */
#define ISRPRI_BIO		0
#define ISRPRI_NET		1
#define ISRPRI_TTY		2
#define ISRPRI_TTYNOBUF		3

void	isrinit(void);
void	isrlink_autovec(int (*)(void *), void *, int, int, const char *);
void	isrdispatch_autovec(int);


code:
/*	$OpenBSD: locore.S,v 1.30 2015/02/25 17:41:22 miod Exp $	*/
/*
 * Copyright (c) 1998 Steve Murphree, Jr.
 * Copyright (c) 1996 Nivas Madhur
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Nivas Madhur.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
/*
 * Mach Operating System
 * Copyright (c) 1993-1991 Carnegie Mellon University
 * Copyright (c) 1991 OMRON Corporation
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include "assym.h"
#include "ksyms.h"

#include <machine/asm.h>
#include <machine/m88100.h>
#include <machine/param.h>
#include <machine/psl.h>
#include <machine/trap.h>
#include <machine/vmparam.h>

#define	BOOT_MAGIC	0xf1abde3f

/*
 * The memory looks like:
 *   0x00000 - 0x01000	trap vectors
 *   0x01000 - 0x20000	ROM monitor work area
 *   0x20000 == start	Boot loader jumps here.
 */
	.text

GLOBAL(kernelstart)
GLOBAL(kernel_text)

	/*
	 * Room for the kernel (post-autoconf) VBR page.
	 * Note this page is in kernel text, in order to be write-protected
	 * by pmap_bootstrap().
	 */

	.balign	PAGE_SIZE
	.space	PAGE_SIZE

	/*
	 * The 88100 may execute the first instruction of the next trap
	 * handler, as documented in its Errata. Processing trap #511
	 * would then fall into the next page, unless the address computation
	 * wraps, or software traps are exempt from the issue - the Errata
	 * does not provide more detail.
	 * Although the MVME BUG does not add an extra NOP after its VBR page,
	 * it is cheap to add an extra NOP for safety.
	 */
	NOP

ASGLOBAL(__start)
	/*
	 * A few identical jump instructions to make sure the pipeline is
	 * in a good state. Probably overkill, but it's cheap.
	 */
 	br	_ASM_LABEL(main_start)
	br	_ASM_LABEL(main_start)
	br	_ASM_LABEL(main_start)
	br	_ASM_LABEL(main_start)

	/*
	 * Startup code common to all processors.
	 */
ASLOCAL(main_start)
#if defined(DDB) || NKSYMS > 0
	or.u	%r10, %r0,  %hi16(BOOT_MAGIC)
	or	%r10, %r10, %lo16(BOOT_MAGIC)
	cmp	%r11, %r2,  %r10
	bb1	ne,   %r11, 1f

	or.u	%r4,  %r0,  %hi16(_C_LABEL(esym))
	st	%r3,  %r4,  %lo16(_C_LABEL(esym))
1:
#endif

	bsr	_ASM_LABEL(setup_psr)

	stcr	%r0,  VBR		/* start with VBR set to zero */
	FLUSH_PIPELINE

	/*
	 * Now we will compete with the other processors to see which one
	 * will be elected as the main one.
	 */
	or.u	%r11, %r0,  %hi16(_C_LABEL(cpu_hatch_mutex))
	or	%r11, %r11, %lo16(_C_LABEL(cpu_hatch_mutex))
1:
	FLUSH_PIPELINE
	or	%r22, %r0,  1
	xmem	%r22, %r11, %r0		/* If %r22 gets 0, we have the lock.. */
	bcnd	eq0,  %r22, 4f		/* ..but if not, we must wait */
2:
	/* just watch the lock until it looks clear */
	ld	%r22, %r11, %r0
	bcnd	ne0,  %r22, 2b
	/* since we can be here with caches off, add a few nops to
	   keep the bus from getting overloaded */
	or	%r2,  %r0, %lo16(1000)
3:
	subu	%r2,  %r2, 1
	bcnd	eq0,  %r2, 3b
	br	1b			/* looks clear -- try to grab */
4:
	/* now try to grab the master_mpu prize */
	FLUSH_PIPELINE
	or.u	%r11, %r0,  %hi16(_ASM_LABEL(master_mpu))
	or	%r11, %r11, %lo16(_ASM_LABEL(master_mpu))
	or	%r22, %r0,  1
	xmem	%r22, %r11, %r0

	/*
	 * If %r22 is not clear we're a secondary,
	 * otherwise we're first and the main.
	 *
	 * Note that we haven't released the interprocessor lock....
	 * We'll do that when we're ready for another CPU to go.
	 */
	bcnd	ne0,  %r22, _ASM_LABEL(secondary_init)

	/*
	 * Main processor specific initialization (with
	 * cpu_hatch_mutex held).
	 */
ASLOCAL(main_init)
	/* clear BSS. PROM might have already done this... */
	or.u	%r2, %r0, %hi16(_C_LABEL(edata))
	or	%r2, %r2, %lo16(_C_LABEL(edata))
	or.u	%r4, %r0, %hi16(_C_LABEL(end))
	or	%r4, %r4, %lo16(_C_LABEL(end))
	bsr.n	_C_LABEL(bzero)		/* bzero(edata, end-edata) */
	 subu	%r3, %r4, %r2

	/* figure out the end of the kernel image. */
#if defined(DDB) || NKSYMS > 0
	or.u	%r4, %r0, %hi16(_C_LABEL(esym))
	ld	%r4, %r4, %lo16(_C_LABEL(esym))
	bcnd	ne0, %r4, 1f
#endif
	or.u	%r4, %r0, %hi16(_C_LABEL(end))
	or	%r4, %r4, %lo16(_C_LABEL(end))		/* if no symbols */
1:
	or.u	%r5, %r0, %hi16(_C_LABEL(first_addr))
	st	%r4, %r5, %lo16(_C_LABEL(first_addr))

	/*
	 * Have curcpu() point to the dummy cpuinfo structure,
	 * and initialize cr17.
	 * This is necessary for early spl*() usage, as well as
	 * mutex diagnostic code.
	 */
	or.u	%r11, %r0,  %hi16(_ASM_LABEL(dummy_cpu))
	or	%r11, %r11, %lo16(_ASM_LABEL(dummy_cpu))
	stcr	%r11, CPU

	/* Switch to startup stack */
	or.u	%r31, %r0,  %hi16(_ASM_LABEL(initstack_end))
	or	%r31, %r31, %lo16(_ASM_LABEL(initstack_end))

	or.u	%r3,  %r0,  %hi16(_C_LABEL(vector_list))
	or	%r3,  %r3,  %lo16(_C_LABEL(vector_list))

	bsr.n	_C_LABEL(luna88k_vector_init)
	 ldcr	%r2, VBR

	/* PIO stuff */
	or	%r10, %r0,  0xb6		/* initialize pio 0 */
	or.u	%r11, %r0,  %hi16(0x4900000c)	/* 0x4900000c: PIO0 ctrl */
	st.b	%r10, %r11, %lo16(0x4900000c)

	/* read dispswitch setting */
	ld.bu	%r10, %r11, %lo16(0x49000000)	/* dipsw-1 (from portA) */
	mak	%r10, %r10, 0<8>			/* shift left 8 bit */
	ld.bu	%r12, %r11, %lo16(0x49000004)	/* dipsw-2 (from portB) */
	or	%r10, %r10, %r12

	or.u	%r11, %r0,  %hi16(_C_LABEL(dipswitch))
	st.h	%r10, %r11, %lo16(_C_LABEL(dipswitch))

	bb1	14,   %r10, 1f			/* XXX: if dipsw-1:2 is on, */
	or	%r10, %r0,  %r0			/* XXX: console is ttya */
	or.u	%r11, %r0,  %hi16(_C_LABEL(sysconsole))
	st	%r10, %r11, %lo16(_C_LABEL(sysconsole))

1:
	/* read frame buffer depth from ROM work area */
	ld	%r10, %r0,  %lo16(0x00001114)	/* frame buffer depth */
	or.u	%r11, %r0,  %hi16(_C_LABEL(hwplanebits))
	st	%r10, %r11, %lo16(_C_LABEL(hwplanebits))

	or	%r10,  %r0,  0x84		/* initialize pio1 */
	or.u	%r11,  %r0,  %hi16(0x4d00000c)
	st.b	%r10,  %r11, %lo16(0x4d00000c)
	or	%r10,  %r0,  0x9		/* port c bit 1 on */
	st.b	%r10,  %r11, %lo16(0x4d00000c)

	or.u	%r10,  %r0,  %hi16(0xe1000010)	/* clear scsi int */
	ld.b	%r11, %r10,  %lo16(0xe1000010)
	st.b	%r11, %r10,  %lo16(0xe1000010)

	/* write 0x41000000 to escape rom */
	or.u	%r2,  %r0,   %hi16(0x41000000)
	st	%r0,  %r2,   %lo16(0x41000000)

	/*
	 * luna88k_bootstrap(), among other things, clears proc0's u area.
	 * We are still using the interrupt stack here, thus we are not
	 * affected...
	 */
	bsr	_C_LABEL(luna88k_bootstrap)

	/*
	 * ...and we can switch to the u area stack now.
	 */
	ldcr	%r10, CPU
	ld	%r31, %r10, CI_CURPCB
	addu	%r31, %r31, USPACE

	/* call main() - no arguments although main() still defines one */
	bsr	_C_LABEL(main)

	or.u	%r2,  %r0,  %hi16(_ASM_LABEL(main_panic))
	bsr.n	_C_LABEL(panic)
	 or	%r2,  %r2,  %lo16(_ASM_LABEL(main_panic))

	.data
	.balign	4
ASLOCAL(main_panic)
	.string	"main() returned\0"
	.text
	.balign	8

	/*
	 * Secondary processor specific initialization (with
	 * cpu_hatch_mutex held).
	 */
ASLOCAL(secondary_init)
#ifdef MULTIPROCESSOR
	/*
	 * Have curcpu() point to the dummy cpuinfo structure,
	 * and initialize cr17.
	 * This is necessary for early spl*() usage, as well as
	 * mutex diagnostic code.
	 */
	or.u	%r11, %r0,  %hi16(_ASM_LABEL(dummy_cpu))
	or	%r11, %r11, %lo16(_ASM_LABEL(dummy_cpu))
	st	%r0,  %r11, CI_FLAGS		/* reset CIF_PRIMARY */
	stcr	%r11, CPU

	/*
	 * While holding the cpu_hatch_mutex, the secondary cpu can use the
	 * slavestack to call secondary_pre_main() to determine its cpu
	 * number. That function will also return the proper stack to
	 * use and we'll switch to it.
	 */

	or.u	%r31, %r0,  %hi16(_ASM_LABEL(slavestack_end))
	bsr.n	_C_LABEL(secondary_pre_main)	/* set cpu number */
	 or	%r31, %r31, %lo16(_ASM_LABEL(slavestack_end))

	bsr.n	_C_LABEL(secondary_main)
	 addu	%r31, %r2, USPACE		/* switch to idle stack */

#else

	/*
	 * Just keep the processor chewing in silence.
	 */
1:	br	1b

#endif	/* MULTIPROCESSOR */

#ifdef MULTIPROCESSOR
	/*
	 * Dummy mp_atomic_begin() and mp_atomic_end() routine, so that
	 * we can interact with ddb if things go wrong very early during
	 * bootstrap. Of course this should never happen (-:
	 */
ASLOCAL(dummy_mplock)
	jmp	%r1
#endif	/* MULTIPROCESSOR */

/*
 * void delay(int count)
 *
 * The processor loops (busy waits) for the given number of microseconds:
 * Thus, delay(1000000) will delay for one second.
 * (originally from Mach 2.5)
 */

GLOBAL(delay)
	bcnd	eq0, %r2, 2f
	or.u	%r3, %r0, %hi16(_C_LABEL(cpuspeed))
	ld	%r3, %r3, %lo16(_C_LABEL(cpuspeed))
	mul	%r4, %r2, %r3
	subu	%r4, %r4, 4	/* overhead of these instructions */

	/* now loop for the given number of cycles */
1:
	bcnd.n	gt0, %r4, 1b
	 subu	%r4, %r4, 2	/* two cycles per iteration */
2:
	jmp	%r1

/*****************************************************************************/

	.data
	.balign	PAGE_SIZE
GLOBAL(kernel_sdt)		/* SDT (segment descriptor table */
	.space	0x2000		/* 8K - 4K phys, 4K virt*/

	.balign	PAGE_SIZE
ASGLOBAL(initstack)
	.space	USPACE
ASGLOBAL(initstack_end)

#ifdef MULTIPROCESSOR
	.space	PAGE_SIZE	/* 4K, small, interim stack */
ASLOCAL(slavestack_end)
#endif

/*
 * Process 0's u.
 * Should be page aligned.
 */
	.balign	PAGE_SIZE
ASLOCAL(u0)
	.space	USPACE
GLOBAL(proc0paddr)
	.word	_ASM_LABEL(u0)	/*  KVA of proc0 uarea */

/* The first processor to XMEM this becomes the master */
ASLOCAL(master_mpu)
	.word 0

/* Dummy cpuinfo structure, for early bootstrap */
ASLOCAL(dummy_cpu)
	.word	3 /* CIF_ALIVE | CIF_PRIMARY */	/* ci_flags */
	.word	0				/* ci_curproc */
	.word	0				/* ci_curpcb */
	.word	0				/* ci_curpmap */
	.word	0				/* ci_cpuid */
#ifdef MULTIPROCESSOR
	.word	_ASM_LABEL(dummy_mplock)	/* ci_mp_atomic_begin */
	.word	_ASM_LABEL(dummy_mplock)	/* ci_mp_atomic_end */
#else
	.word	0
	.word	0
#endif
	.space	CPU_INFO_SIZEOF - 7 * 4

#if defined(DDB) || NKSYMS > 0
GLOBAL(esym)
	.word 	0
#endif /* DDB || NKSYMS > 0 */


code:
/*	$OpenBSD: m8820x.c,v 1.16 2014/06/03 12:11:19 aoyama Exp $	*/
/*
 * Copyright (c) 2004, Miodrag Vallat.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * Copyright (c) 2001 Steve Murphree, Jr.
 * Copyright (c) 1996 Nivas Madhur
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Nivas Madhur.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
/*
 * Mach Operating System
 * Copyright (c) 1993-1991 Carnegie Mellon University
 * Copyright (c) 1991 OMRON Corporation
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <sys/param.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

#include <machine/asm_macro.h>
#include <machine/board.h>
#include <machine/cmmu.h>
#include <machine/cpu.h>
#include <machine/m8820x.h>

/*
 * This routine sets up the CPU/CMMU configuration.
 */
void
m8820x_setup_board_config()
{
	struct m8820x_cmmu *cmmu;
	u_int num;

	m8820x_cmmu[0].cmmu_regs = (void *)CMMU_I0;
	m8820x_cmmu[1].cmmu_regs = (void *)CMMU_D0;
	m8820x_cmmu[2].cmmu_regs = (void *)CMMU_I1;
	m8820x_cmmu[3].cmmu_regs = (void *)CMMU_D1;
	m8820x_cmmu[4].cmmu_regs = (void *)CMMU_I2;
	m8820x_cmmu[5].cmmu_regs = (void *)CMMU_D2;
	m8820x_cmmu[6].cmmu_regs = (void *)CMMU_I3;
	m8820x_cmmu[7].cmmu_regs = (void *)CMMU_D3;

	/*
	 * Probe CMMU address to discover which CPU slots are populated.
	 * On the luna88k, badaddr() returns 'good' on unpopulated slots,
	 * so we check the CMMU type value for each CMMU register address.
	 */
	cmmu = m8820x_cmmu;

	for (num = 0; num < 8; num++) {
		volatile unsigned *cr = m8820x_cmmu[num].cmmu_regs;
		int type;

		type = CMMU_TYPE(cr[CMMU_IDR]);
		if (type != M88200_ID && type != M88204_ID)
			break;
	}

	ncpusfound = num >> 1;
	max_cmmus = ncpusfound << 1;
	cmmu_shift = 1;	/* fixed 2:1 configuration */

	/*
	 * Now that we know which CMMUs are there, report every association
	 */
	for (num = 0; num < ncpusfound; num++) {
		volatile unsigned *cr;
		int type;

 		cr = m8820x_cmmu[num << cmmu_shift].cmmu_regs;

		type = CMMU_TYPE(cr[CMMU_IDR]);
		printf("CPU%d is associated to %d MC8820%c CMMUs\n",
		    num, 1 << cmmu_shift, type == M88204_ID ? '4' : '0');
	}
}

/*
 * Find out the CPU number from accessing CMMU
 * Better be at splhigh, or even better, with interrupts
 * disabled.
 */
#define ILLADDRESS	0x3ffffff0 	/* faulty address for LUNA-88K{,2} */

cpuid_t
m8820x_cpu_number()
{
	u_int cmmu;
	u_int i;

	CMMU_LOCK;

	for (i = 0; i < 10; i++) {
		/* clear CMMU P-bus status registers */
		for (cmmu = 0; cmmu < max_cmmus; cmmu++) {
			if (CMMU_MODE(cmmu) != INST_CMMU)
				m8820x_cmmu[cmmu].cmmu_regs[CMMU_PFSR] = 0;
		}

		/* access faulting address */
		badaddr((vaddr_t)ILLADDRESS, 4);

		/* check which CMMU is reporting the fault  */
		for (cmmu = 0; cmmu < max_cmmus; cmmu++) {
			if (CMMU_MODE(cmmu) != INST_CMMU &&
			    CMMU_PFSR_FAULT(m8820x_cmmu[cmmu].
			      cmmu_regs[CMMU_PFSR]) != CMMU_PFSR_SUCCESS) {
				/* clean register, just in case... */
				m8820x_cmmu[cmmu].cmmu_regs[CMMU_PFSR] = 0;
				CMMU_UNLOCK;
				return cmmu >> 1;
			}
		}
	}
	CMMU_UNLOCK;

	panic("m8820x_cpu_number: could not determine my cpu number");
}


code:
/*	$OpenBSD: machdep.c,v 1.117 2015/05/18 04:06:37 miod Exp $	*/
/*
 * Copyright (c) 1998, 1999, 2000, 2001 Steve Murphree, Jr.
 * Copyright (c) 1996 Nivas Madhur
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Nivas Madhur.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
/*
 * Mach Operating System
 * Copyright (c) 1993-1991 Carnegie Mellon University
 * Copyright (c) 1991 OMRON Corporation
 * All Rights Reserved.
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 *
 * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 *
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/buf.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/msgbuf.h>
#include <sys/syscallargs.h>
#include <sys/exec.h>
#include <sys/sysctl.h>
#include <sys/errno.h>
#include <sys/extent.h>
#include <sys/core.h>
#include <sys/kcore.h>
#include <dev/rndvar.h>

#include <machine/asm.h>
#include <machine/asm_macro.h>
#include <machine/board.h>
#include <machine/cmmu.h>
#include <machine/cpu.h>
#include <machine/kcore.h>
#include <machine/lock.h>
#include <machine/reg.h>
#include <machine/trap.h>
#include <machine/m88100.h>

#include <luna88k/luna88k/isr.h>

#include <dev/cons.h>

#include <net/if.h>
#include <uvm/uvm.h>

#include "ksyms.h"
#if DDB
#include <machine/db_machdep.h>
#include <ddb/db_extern.h>
#include <ddb/db_interface.h>
#include <ddb/db_output.h>		/* db_printf()		*/
#endif /* DDB */

void	consinit(void);
#ifdef MULTIPROCESSOR
void	cpu_boot_secondary_processors(void);
#endif
void	cpu_setup_secondary_processors(void);
void	dumpconf(void);
void	dumpsys(void);
int	getcpuspeed(void);
void	get_fuse_rom_data(void);
void	get_nvram_data(void);
void	identifycpu(void);
void	luna88k_bootstrap(void);
#ifdef MULTIPROCESSOR
void	luna88k_ipi_handler(struct trapframe *);
#endif
void	luna88k_vector_init(uint32_t *, uint32_t *);
char	*nvram_by_symbol(char *);
void	powerdown(void);
void	savectx(struct pcb *);
void	secondary_main(void);
void   *secondary_pre_main(void);
void	setlevel(u_int);
vaddr_t size_memory(void);

extern int	clockintr(void *);		/* in clock.c */
extern void	get_autoboot_device(void);	/* in autoconf.c */

/*
 * *int_mask_reg[CPU]
 * Points to the hardware interrupt status register for each CPU.
 *
 * When write:
 * Bits 31 to 26 are used to enable ('1') or disable ('0') each
 * interrupt level.  Bit 31 is for level 6, bit 26 is for level 1.
 *
 * When read:
 * Bits 31 to 29 shows the highest level of current (or most recent?)
 * interrupt in 3 bits binary value (0 to 7).
 * Bits 23 to 18 shows the current mask, which is the most recent
 * written value in bits 31 to 26 as described above.
 */
volatile u_int32_t *int_mask_reg[] = {
	(u_int32_t *)INT_ST_MASK0,
	(u_int32_t *)INT_ST_MASK1,
	(u_int32_t *)INT_ST_MASK2,
	(u_int32_t *)INT_ST_MASK3
};

u_int luna88k_curspl[] = { IPL_HIGH, IPL_HIGH, IPL_HIGH, IPL_HIGH };

u_int32_t int_set_val[INT_LEVEL] = {
	INT_SET_LV0,
	INT_SET_LV1,
	INT_SET_LV2,
	INT_SET_LV3,
	INT_SET_LV4,
	INT_SET_LV5,
	INT_SET_LV6,
	INT_SET_LV7
};

/*
 * *swi_reg[CPU]
 * Points to the software interrupt register for each CPU.
 */
volatile u_int32_t *swi_reg[] = {
	(u_int32_t *)SOFT_INT0,
	(u_int32_t *)SOFT_INT1,
	(u_int32_t *)SOFT_INT2,
	(u_int32_t *)SOFT_INT3
};

/*
 * FUSE ROM and NVRAM data
 */
struct fuse_rom_byte {
	u_int32_t h;
	u_int32_t l;
};
#define FUSE_ROM_BYTES        (FUSE_ROM_SPACE / sizeof(struct fuse_rom_byte))
char fuse_rom_data[FUSE_ROM_BYTES];

#define NNVSYM		8
#define NVSYMLEN	16
#define NVVALLEN	16
struct nvram_t {
	char symbol[NVSYMLEN];
	char value[NVVALLEN];
} nvram[NNVSYM];

register_t kernel_vbr;
int physmem;	  /* available physical memory, in pages */

struct vm_map *exec_map = NULL;
struct vm_map *phys_map = NULL;

__cpu_simple_lock_t cpu_hatch_mutex = __SIMPLELOCK_UNLOCKED;
#ifdef MULTIPROCESSOR
__cpu_simple_lock_t cpu_boot_mutex = __SIMPLELOCK_LOCKED;
unsigned int hatch_pending_count;
vaddr_t hatch_stacks[MAXCPUS - 1];
#endif

struct uvm_constraint_range  dma_constraint = { 0x0, (paddr_t)-1 };
struct uvm_constraint_range *uvm_md_constraints[] = { NULL };

/*
 * Info for CTL_HW
 */
char  machine[] = MACHINE;	 /* cpu "architecture" */
char  cpu_model[120];

#if defined(DDB) || NKSYMS > 0
extern char *esym;
#endif

int machtype = LUNA_88K;	/* may be overwritten in cpu_startup() */
int cputyp = CPU_88100;
int bootdev;			/* XXX: should be set in boot loader and locore.S */
int cpuspeed = 33;		/* safe guess */
int sysconsole = 1;		/* 0 = ttya, 1 = keyboard/mouse, used in dev/sio.c */
u_int16_t dipswitch = 0;	/* set in locore.S */
int hwplanebits;		/* set in locore.S */

extern struct consdev syscons;	/* in dev/siotty.c */

extern void syscnattach(int);	/* in dev/siotty.c */
extern int omfb_cnattach(void);	/* in dev/lunafb.c */
extern void ws_cnattach(void);	/* in dev/lunaws.c */

vaddr_t first_addr;
vaddr_t last_addr;

extern struct user *proc0paddr;

/*
 * This is to fake out the console routines, while booting.
 * We could use directly the romtty console, but we want to be able to
 * configure a kernel without romtty since we do not necessarily need a
 * full-blown console driver.
 */
cons_decl(romtty);
extern void nullcnpollc(dev_t, int);

struct consdev romttycons = {
	NULL,
	NULL,
	romttycngetc,
	romttycnputc,
	nullcnpollc,
	NULL,
	makedev(14, 0),
	CN_LOWPRI,
};

struct consdev *cn_tab = &romttycons;

/*
 * Early console initialization: called early on from main, before vm init.
 */
void
consinit()
{
	/*
	 * Initialize the console before we print anything out.
	 */
	if (sysconsole == 0) {
                syscnattach(0);
        } else {
                omfb_cnattach();
                ws_cnattach();
        }

#if defined(DDB)
	db_machine_init();
	ddb_init();
	if (boothowto & RB_KDB)
		Debugger();
#endif
}

/*
 * Figure out how much real memory is available.
 * Start looking from the megabyte after the end of the kernel data,
 * until we find non-memory.
 */
vaddr_t
size_memory()
{
	unsigned int *volatile look;
	unsigned int *max;
#define PATTERN   0x5a5a5a5a
#define STRIDE    (4*1024) 	/* 4k at a time */
#define Roundup(value, stride) (((unsigned)(value) + (stride) - 1) & ~((stride)-1))
	/*
	 * count it up.
	 */
	max = (void *)MAXPHYSMEM;
	for (look = (void *)first_addr; look < max;
	    look = (int *)((unsigned)look + STRIDE)) {
		unsigned save;

		/* if can't access, we've reached the end */
		if (badaddr((vaddr_t)look, 4)) {
			look = (int *)((int)look - STRIDE);
			break;
		}

		/*
		 * If we write a value, we expect to read the same value back.
		 * We'll do this twice, the 2nd time with the opposite bit
		 * pattern from the first, to make sure we check all bits.
		 */
		save = *look;
		if (*look = PATTERN, *look != PATTERN)
			break;
		if (*look = ~PATTERN, *look != ~PATTERN)
			break;
		*look = save;
	}

	return (trunc_page((vaddr_t)look));
}

int
getcpuspeed()
{
	switch(machtype) {
	case LUNA_88K:
		return 25;
	case LUNA_88K2:
		return 33;
	default:
		panic("getcpuspeed: can not determine CPU speed");
	}
}

void
identifycpu()
{
	cpuspeed = getcpuspeed();
	snprintf(cpu_model, sizeof cpu_model,
	    "OMRON LUNA-88K%s, %dMHz",
	    machtype == LUNA_88K2 ? "2" : "", cpuspeed);
}

void
cpu_startup()
{
	vaddr_t minaddr, maxaddr;

	/* Determine the machine type from FUSE ROM data.  */
	get_fuse_rom_data();
	if (strncmp(fuse_rom_data, "MNAME=LUNA88K+", 14) == 0) {
		machtype = LUNA_88K2;
	}

        /* Determine the 'auto-boot' device from NVRAM data */
        get_nvram_data();
        get_autoboot_device();

	/*
	 * Good {morning,afternoon,evening,night}.
	 */
	printf(version);
	identifycpu();
	printf("real mem = %lu (%luMB)\n", ptoa(physmem),
	    ptoa(physmem) / 1024 / 1024);

	/*
	 * Check front DIP switch setting
	 */
#ifdef DEBUG
	printf("dipsw = 0x%x\n", dipswitch);
#endif

	/* Check DIP switch 1 - 1 */
	if ((0x8000 & dipswitch) == 0) {
		boothowto |= RB_SINGLE;
	}

	/* Check DIP switch 1 - 3 */
	if ((0x2000 & dipswitch) == 0) {
		boothowto |= RB_ASKNAME;
	}

	/* Check DIP switch 1 - 4 */
	if ((0x1000 & dipswitch) == 0) {
		boothowto |= RB_CONFIG;
	}

	/*
	 * Check frame buffer depth.
	 */
	switch (hwplanebits) {
	case 0:				/* No frame buffer */
	case 1:
	case 4:
	case 8:
		break;
	default:
		printf("unexpected frame buffer depth = %d\n", hwplanebits);
		hwplanebits = 0;
		break;
	}

	/*
	 * Allocate a submap for exec arguments.  This map effectively
	 * limits the number of processes exec'ing at any time.
	 */
	minaddr = vm_map_min(kernel_map);
	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
	    16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);

	/*
	 * Allocate map for physio.
	 */
	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
	    VM_PHYS_SIZE, 0, FALSE, NULL);

	printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
	    ptoa(uvmexp.free) / 1024 / 1024);

	/*
	 * Set up buffers, so they can be used to read disk labels.
	 */
	bufinit();

	/*
	 * Initialize the autovectored interrupt list.
	 */
	isrinit();

	/*
	 * Configure the system.
	 */
	if (boothowto & RB_CONFIG) {
#ifdef BOOT_CONFIG
		user_config();
#else
		printf("kernel does not support -c; continuing..\n");
#endif
	}
}

__dead void
boot(int howto)
{
	if (curproc && curproc->p_addr)
		savectx(curpcb);

	if (cold) {
		if ((howto & RB_USERREQ) == 0)
			howto |= RB_HALT;
		goto haltsys;
	}

	boothowto = howto;
	if ((howto & RB_NOSYNC) == 0) {
		vfs_shutdown();

		if ((howto & RB_TIMEBAD) == 0) {
			resettodr();
		} else {
			printf("WARNING: not updating battery clock\n");
		}
	}
	if_downall();

	uvm_shutdown();
	splhigh();
	cold = 1;

	if ((howto & RB_DUMP) != 0)
		dumpsys();

haltsys:
	config_suspend_all(DVACT_POWERDOWN);

	/* LUNA-88K supports automatic powerdown */
	if ((howto & RB_POWERDOWN) != 0) {
		printf("attempting to power down...\n");
		powerdown();
		/* if failed, fall through. */
	}

	if ((howto & RB_HALT) != 0) {
		printf("halted\n\n");
	} else {
		/* Reset all cpus, which causes reboot */
		*((volatile unsigned *)0x6d000010) = 0;
	}

	for (;;) ;
	/* NOTREACHED */
}

u_long dumpmag = 0x8fca0101;	 /* magic number for savecore */
int   dumpsize = 0;	/* also for savecore */
long  dumplo = 0;
cpu_kcore_hdr_t cpu_kcore_hdr;

/*
 * This is called by configure to set dumplo and dumpsize.
 * Dumps always skip the first PAGE_SIZE of disk space
 * in case there might be a disk label stored there.
 * If there is extra space, put dump at the end to
 * reduce the chance that swapping trashes it.
 */
void
dumpconf(void)
{
	int nblks;	/* size of dump area */

	if (dumpdev == NODEV ||
	    (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
		return;
	if (nblks <= ctod(1))
		return;

	dumpsize = physmem;

	/* luna88k only uses a single segment. */
	cpu_kcore_hdr.ram_segs[0].start = 0;
	cpu_kcore_hdr.ram_segs[0].size = ptoa(physmem);
	cpu_kcore_hdr.cputype = cputyp;

	/*
	 * Don't dump on the first block
	 * in case the dump device includes a disk label.
	 */
	if (dumplo < ctod(1))
		dumplo = ctod(1);

	/* Put dump at end of partition, and make it fit. */
	if (dumpsize + 1 > dtoc(nblks - dumplo))
		dumpsize = dtoc(nblks - dumplo) - 1;
	if (dumplo < nblks - ctod(dumpsize) - 1)
		dumplo = nblks - ctod(dumpsize) - 1;
}

/*
 * Doadump comes here after turning off memory management and
 * getting on the dump stack, either when called above, or by
 * the auto-restart code.
 */
void
dumpsys()
{
	int maj;
	int psize;
	daddr_t blkno;	/* current block to write */
				/* dump routine */
	int (*dump)(dev_t, daddr_t, caddr_t, size_t);
	int pg;			/* page being dumped */
	paddr_t maddr;		/* PA being dumped */
	int error;		/* error code from (*dump)() */
	kcore_seg_t *kseg_p;
	cpu_kcore_hdr_t *chdr_p;
	char dump_hdr[dbtob(1)];	/* XXX assume hdr fits in 1 block */

	extern int msgbufmapped;

	msgbufmapped = 0;

	/* Make sure dump device is valid. */
	if (dumpdev == NODEV)
		return;
	if (dumpsize == 0) {
		dumpconf();
		if (dumpsize == 0)
			return;
	}
	maj = major(dumpdev);
	if (dumplo < 0) {
		printf("\ndump to dev %u,%u not possible\n", maj,
		    minor(dumpdev));
		return;
	}
	dump = bdevsw[maj].d_dump;
	blkno = dumplo;

	printf("\ndumping to dev %u,%u offset %ld\n", maj,
	    minor(dumpdev), dumplo);

#ifdef UVM_SWAP_ENCRYPT
	uvm_swap_finicrypt_all();
#endif

	/* Setup the dump header */
	kseg_p = (kcore_seg_t *)dump_hdr;
	chdr_p = (cpu_kcore_hdr_t *)&dump_hdr[ALIGN(sizeof(*kseg_p))];
	bzero(dump_hdr, sizeof(dump_hdr));

	CORE_SETMAGIC(*kseg_p, KCORE_MAGIC, MID_MACHINE, CORE_CPU);
	kseg_p->c_size = dbtob(1) - ALIGN(sizeof(*kseg_p));
	*chdr_p = cpu_kcore_hdr;

	printf("dump ");
	psize = (*bdevsw[maj].d_psize)(dumpdev);
	if (psize == -1) {
		printf("area unavailable\n");
		return;
	}

	/* Dump the header. */
	error = (*dump)(dumpdev, blkno++, (caddr_t)dump_hdr, dbtob(1));
	if (error != 0)
		goto abort;

	maddr = (paddr_t)0;
	for (pg = 0; pg < dumpsize; pg++) {
#define NPGMB	(1024 * 1024 / PAGE_SIZE)
		/* print out how many MBs we have dumped */
		if (pg != 0 && (pg % NPGMB) == 0)
			printf("%d ", pg / NPGMB);
#undef NPGMB
		error = (*dump)(dumpdev, blkno, (caddr_t)maddr, PAGE_SIZE);
		if (error == 0) {
			maddr += PAGE_SIZE;
			blkno += btodb(PAGE_SIZE);
		} else
			break;
	}
abort:
	switch (error) {
	case 0:
		printf("succeeded\n");
		break;

	case ENXIO:
		printf("device bad\n");
		break;

	case EFAULT:
		printf("device not ready\n");
		break;

	case EINVAL:
		printf("area improper\n");
		break;

	case EIO:
		printf("i/o error\n");
		break;

	case EINTR:
		printf("aborted from console\n");
		break;

	default:
		printf("error %d\n", error);
		break;
	}
}

/*
 * Release cpu_hatch_mutex to let secondary processors initialize.
 */
void
cpu_setup_secondary_processors()
{
#ifdef MULTIPROCESSOR
	unsigned int cpu;

	hatch_pending_count = ncpusfound - 1;

	/*
	 * Allocate idle stack for all the secondary processors here.
	 *
	 * We can't have this done by the secondaries themselves, because
	 * the main processor owns the kernel lock at this point; and we
	 * can't know in advance which cpuid our secondary processors will
	 * have, so we can't fill m88k_cpus[] directly.
	 *
	 * Allocation failure will be checked by the secondary processors
	 * so that we can still run in degraded mode if hell gets loose.
	 */
	for (cpu = 0; cpu < hatch_pending_count; cpu++)
		hatch_stacks[cpu] = uvm_km_zalloc(kernel_map, USPACE);
#endif

	__cpu_simple_unlock(&cpu_hatch_mutex);

#ifdef MULTIPROCESSOR
	while (hatch_pending_count != 0)
		delay(10000);	/* 10ms */
#endif
}

#ifdef MULTIPROCESSOR
/*
 * Release cpu_boot_mutex to let secondary processors start running
 * processes.
 */
void
cpu_boot_secondary_processors()
{
	__cpu_simple_unlock(&cpu_boot_mutex);
}

/*
 * Secondary CPU early initialization routine.
 * Determine CPU number and set it, then return the startup stack.
 *
 * Running on a minimal stack here, with interrupts disabled; do nothing fancy.
 */
void *
secondary_pre_main()
{
	struct cpu_info *ci;

        /*
         * Invoke the CMMU initialization routine as early as possible,
         * so that we do not risk any memory writes to be lost during
         * cache setup.
         */
        cmmu_initialize_cpu(cmmu_cpu_number());

	/*
	 * Now initialize your cpu_info structure.
	 */
	set_cpu_number(cmmu_cpu_number());
	ci = curcpu();
	ci->ci_curproc = &proc0;
	m88100_smp_setup(ci);

	splhigh();

	/*
	 * Enable MMU on this processor.
	 */
	pmap_bootstrap_cpu(ci->ci_cpuid);

	/*
	 * Return our idle stack for the caller to switch to it.
	 */
	ci->ci_curpcb = (void *)hatch_stacks[hatch_pending_count - 1];
	if (ci->ci_curpcb == NULL) {
		printf("cpu%d: unable to get startup stack\n", ci->ci_cpuid);
		hatch_pending_count--;
		__cpu_simple_unlock(&cpu_hatch_mutex);
		for (;;) ;
	}

	return ci->ci_curpcb;
}

/*
 * Further secondary CPU initialization.
 *
 * We are now running on our startup stack, with proper page tables.
 * There is nothing to do but display some details about the CPU and its CMMUs.
 */

void
secondary_main()
{
	struct cpu_info *ci = curcpu();
	int s;

	cpu_configuration_print(0);
	ncpus++;

	sched_init_cpu(ci);
	nanouptime(&ci->ci_schedstate.spc_runtime);
	ci->ci_curproc = NULL;
	ci->ci_randseed = (arc4random() & 0x7fffffff) + 1;

	/*
	 * Release cpu_hatch_mutex to let other secondary processors
	 * have a chance to run.
	 */
	hatch_pending_count--;
	__cpu_simple_unlock(&cpu_hatch_mutex);

	/* wait for cpu_boot_secondary_processors() */
	__cpu_simple_lock(&cpu_boot_mutex);
	__cpu_simple_unlock(&cpu_boot_mutex);

	set_vbr(kernel_vbr);

	spl0();
	SCHED_LOCK(s);
	set_psr(get_psr() & ~PSR_IND);

	SET(ci->ci_flags, CIF_ALIVE);

	cpu_switchto(NULL, sched_chooseproc());
}

#endif	/* MULTIPROCESSOR */

/*
 *	Device interrupt handler for LUNA-88K
 */

void
luna88k_ext_int(struct trapframe *eframe)
{
#ifdef MULTIPROCESSOR
	struct cpu_info *ci = curcpu();
	u_int cpu = ci->ci_cpuid;
#else
	u_int cpu = cpu_number();
#endif
	u_int32_t cur_isr;
	u_int level, cur_int_level, old_spl;
	int unmasked = 0;

	cur_isr = *int_mask_reg[cpu];
	old_spl = eframe->tf_mask;

	cur_int_level = cur_isr >> 29;

	/*
	 * Ignore level 0 interrupt and 'hardware lied' interrupt,
	 * as same as CMU Mach do.  The 'hardware lied' means that
	 * the received interrupt level is what we have masked before.
	 */
	if (cur_int_level == 0 ||
	    !(cur_isr & (1 << (cur_int_level + 17))))
		goto out;

	uvmexp.intrs++;

#ifdef MULTIPROCESSOR
	/*
	 * Handle unmaskable IPIs immediately, so that we can reenable
	 * interrupts before further processing. We rely on the interrupt
	 * mask to make sure that if we get an IPI, it's really for us
	 * and no other processor.
	 *
	 * On luna88k, IPL_SOFTINT (level 1 interrupt) is used as IPI.
	 */
	while (cur_int_level == IPL_SOFTINT) {
		luna88k_ipi_handler(eframe);

		cur_isr = *int_mask_reg[cpu];
		cur_int_level = cur_isr >> 29;
	}
	if (cur_int_level == 0)
		goto out;
#endif

	/*
	 * Service the highest interrupt, in order.
	 */
	do {
		level = (cur_int_level > old_spl ? cur_int_level : old_spl);
		setipl(level);

		if (unmasked == 0) {
			set_psr(get_psr() & ~PSR_IND);
			unmasked = 1;
		}

		switch (cur_int_level) {
		case 6:
			clockintr((void *)eframe);
			break;
		case 5:
		case 4:
		case 3:
			if (CPU_IS_PRIMARY(ci))
				isrdispatch_autovec(cur_int_level);
			break;
		default:
			printf("%s: cpu%d level %d interrupt.\n",
				__func__, cpu, cur_int_level);
			break;
		}

		cur_isr = *int_mask_reg[cpu];
		cur_int_level = cur_isr >> 29;
	} while (cur_int_level != 0);

out:
	/*
	 * process any remaining data access exceptions before
	 * returning to assembler
	 */
	if (eframe->tf_dmt0 & DMT_VALID)
		m88100_trap(T_DATAFLT, eframe);

	/*
	 * Disable interrupts before returning to assembler, the spl will
	 * be restored later.
	 */
	set_psr(get_psr() | PSR_IND);
}

int
sys_sysarch(p, v, retval)
	struct proc *p;
	void *v;
	register_t *retval;
{
#if 0
	struct sys_sysarch_args	/* {
	   syscallarg(int) op;
	   syscallarg(char *) parm;
	} */ *uap = v;
#endif

	return (ENOSYS);
}

/*
 * machine dependent system variables.
 */

int
cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
	int *name;
	u_int namelen;
	void *oldp;
	size_t *oldlenp;
	void *newp;
	size_t newlen;
	struct proc *p;
{
	dev_t consdev;

	/* all sysctl names are this level are terminal */
	if (namelen != 1)
		return (ENOTDIR); /* overloaded */

	switch (name[0]) {
	case CPU_CONSDEV:
		if (cn_tab != NULL)
			consdev = cn_tab->cn_dev;
		else
			consdev = NODEV;
		return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev,
		    sizeof consdev));
	case CPU_CPUTYPE:
		return (sysctl_rdint(oldp, oldlenp, newp, cputyp));
	default:
		return (EOPNOTSUPP);
	}
	/*NOTREACHED*/
}

void
luna88k_vector_init(uint32_t *bootvbr, uint32_t *vectors)
{
	extern vaddr_t vector_init(uint32_t *, uint32_t *, int); /* gross */
	extern int kernelstart;

	/*
	 * Set up bootstrap vectors, overwriting the existing PROM vbr
	 * page.
	 */
	vector_init(bootvbr, vectors, 1);

	/*
	 * Set up final vectors. These will be used by all processors,
	 * once autoconf is over.
	 */
	kernel_vbr = trunc_page((vaddr_t)&kernelstart);
	vector_init((uint32_t *)kernel_vbr, vectors, 0);
}

/*
 * Called from locore.S during boot,
 * this is the first C code that's run.
 */
void
luna88k_bootstrap()
{
	extern const struct cmmu_p cmmu8820x;
	extern vaddr_t avail_start;
	extern vaddr_t avail_end;
#ifndef MULTIPROCESSOR
	cpuid_t master_cpu;
#endif

	cmmu = &cmmu8820x;

	/* clear and disable all interrupts */
	*int_mask_reg[0] = *int_mask_reg[1] =
	*int_mask_reg[2] = *int_mask_reg[3] = 0;

	/* clear software interrupts; just read registers */
	*(volatile uint32_t *)swi_reg[0];
	*(volatile uint32_t *)swi_reg[1];
	*(volatile uint32_t *)swi_reg[2];
	*(volatile uint32_t *)swi_reg[3];

	uvmexp.pagesize = PAGE_SIZE;
	uvm_setpagesize();

	first_addr = round_page(first_addr);
	last_addr = size_memory();
	physmem = atop(last_addr);

	setup_board_config();
	master_cpu = cmmu_init();
	set_cpu_number(master_cpu);
#ifdef MULTIPROCESSOR
	m88100_smp_setup(curcpu());
#endif
	SET(curcpu()->ci_flags, CIF_ALIVE | CIF_PRIMARY);

	m88100_apply_patches();

	/*
	 * Now that set_cpu_number() set us with a valid cpu_info pointer,
	 * we need to initialize p_addr and curpcb before autoconf, for the
	 * fault handler to behave properly [except for badaddr() faults,
	 * which can be taken care of without a valid curcpu()].
	 */
	proc0.p_addr = proc0paddr;
	curproc = &proc0;
	curpcb = &proc0paddr->u_pcb;

	avail_start = first_addr;
	avail_end = last_addr;

#ifdef DEBUG
	printf("LUNA-88K boot: memory from 0x%x to 0x%x\n",
	    avail_start, avail_end);
#endif

	/*
	 * Tell the VM system about available physical memory.
	 * luna88k only has one segment.
	 */
	uvm_page_physload(atop(avail_start), atop(avail_end),
	    atop(avail_start), atop(avail_end), 0);

	/*
	 * Initialize message buffer.
	 */
	initmsgbuf((caddr_t)pmap_steal_memory(MSGBUFSIZE, NULL, NULL),
	    MSGBUFSIZE);

	pmap_bootstrap(0, 0x20000);	/* ROM needs 128KB */

	/* Initialize the "u-area" pages. */
	bzero((caddr_t)curpcb, USPACE);

#ifndef MULTIPROCESSOR
	/* Release the cpu_hatch_mutex */
	cpu_setup_secondary_processors();
#endif

#ifdef DEBUG
	printf("leaving luna88k_bootstrap()\n");
#endif
}

/*
 * Rom console routines:
 * Enables printing of boot messages before consinit().
 */

#define __ROM_FUNC_TABLE	((int **)0x00001100)
#define ROMGETC()	(*(int (*)(void))__ROM_FUNC_TABLE[3])()
#define ROMPUTC(x)	(*(void (*)(int))__ROM_FUNC_TABLE[4])(x)

void
romttycnprobe(cp)
	struct consdev *cp;
{
	cp->cn_dev = makedev(14, 0);
	cp->cn_pri = CN_LOWPRI;
}

void
romttycninit(cp)
	struct consdev *cp;
{
	/* Nothing to do */
}

int
romttycngetc(dev)
	dev_t dev;
{
	int s, c;

	do {
		s = splhigh();
		c = ROMGETC();
		splx(s);
	} while (c == -1);
	return c;
}

void
romttycnputc(dev, c)
	dev_t dev;
	int c;
{
	int s;

	s = splhigh();
	ROMPUTC(c);
	splx(s);
}

/* powerdown */

struct pio {
	volatile u_int8_t portA;
	volatile unsigned : 24;
	volatile u_int8_t portB;
	volatile unsigned : 24;
	volatile u_int8_t portC;
	volatile unsigned : 24;
	volatile u_int8_t cntrl;
	volatile unsigned : 24;
};

#define	PIO1_POWER	0x04

#define	PIO1_ENABLE	0x01
#define	PIO1_DISABLE	0x00

void
powerdown(void)
{
	struct pio *p1 = (struct pio *)OBIO_PIO1_BASE;

	DELAY(100000);
	p1->cntrl = (PIO1_POWER << 1) | PIO1_DISABLE;
	*(volatile u_int8_t *)&p1->portC;
}

/* Get data from FUSE ROM */

void
get_fuse_rom_data(void)
{
	int i;
	struct fuse_rom_byte *p = (struct fuse_rom_byte *)FUSE_ROM_ADDR;

	for (i = 0; i < FUSE_ROM_BYTES; i++) {
		fuse_rom_data[i] =
		    (char)((((p->h) >> 24) & 0x000000f0) |
		           (((p->l) >> 28) & 0x0000000f));
		p++;
	}
}

/* Get data from NVRAM */

void
get_nvram_data(void)
{
	int i, j;
	u_int8_t *page;
	char buf[NVSYMLEN], *data;

	if (machtype == LUNA_88K) {
		data = (char *)(NVRAM_ADDR + 0x80);

		for (i = 0; i < NNVSYM; i++) {
			for (j = 0; j < NVSYMLEN; j++) {
				buf[j] = *data;
				data += 4;
			}
			strlcpy(nvram[i].symbol, buf, sizeof(nvram[i].symbol));

			for (j = 0; j < NVVALLEN; j++) {
				buf[j] = *data;
				data += 4;
			}
			strlcpy(nvram[i].value, buf, sizeof(nvram[i].value));
		}
	} else if (machtype == LUNA_88K2) {
		page = (u_int8_t *)(NVRAM_ADDR_88K2 + 0x20);

		for (i = 0; i < NNVSYM; i++) {
			*page = (u_int8_t)i;

			data = (char *)NVRAM_ADDR_88K2;
			strlcpy(nvram[i].symbol, data, sizeof(nvram[i].symbol));

			data = (char *)(NVRAM_ADDR_88K2 + 0x10);
			strlcpy(nvram[i].value, data, sizeof(nvram[i].value));
		}
	}
}

char *
nvram_by_symbol(symbol)
	char *symbol;
{
	char *value;
	int i;

	value = NULL;

	for (i = 0; i < NNVSYM; i++) {
		if (strncmp(nvram[i].symbol, symbol, NVSYMLEN) == 0) {
			value = nvram[i].value;
			break;
		}
	}

	return value;
}

void
setlevel(u_int level)
{
	u_int32_t set_value;
#ifdef MULTIPROCESSOR
	struct cpu_info *ci = curcpu();
	int cpu = ci->ci_cpuid;
#else
	int cpu = cpu_number();
#endif

	set_value = int_set_val[level];

#ifdef MULTIPROCESSOR
	if (!CPU_IS_PRIMARY(ci))
		set_value &= INT_SLAVE_MASK;
#endif

	luna88k_curspl[cpu] = level;
	*int_mask_reg[cpu] = set_value;
	/*
	 * We do not flush the pipeline here, because we are invoked
	 * with interrupts disabled, and the caller will synchronize
	 * the pipeline when restoring the psr.
	 */
}

int
getipl(void)
{
	return (int)luna88k_curspl[cpu_number()];
}

int
setipl(int level)
{
	u_int curspl, psr;
#ifdef MULTIPROCESSOR
	struct cpu_info *ci = curcpu();
	int cpu = ci->ci_cpuid;
#else
	int cpu = cpu_number();
#endif

	psr = get_psr();
	set_psr(psr | PSR_IND);

	curspl = luna88k_curspl[cpu];
	setlevel((u_int)level);

	set_psr(psr);
	return (int)curspl;
}

int
raiseipl(int level)
{
	u_int curspl, psr;
#ifdef MULTIPROCESSOR
	struct cpu_info *ci = curcpu();
	int cpu = ci->ci_cpuid;
#else
	int cpu = cpu_number();
#endif

	psr = get_psr();
	set_psr(psr | PSR_IND);

	curspl = luna88k_curspl[cpu];
	if (curspl < (u_int)level)
		setlevel((u_int)level);

	set_psr(psr);
	return (int)curspl;
}

#ifdef MULTIPROCESSOR
void
m88k_send_ipi(int ipi, cpuid_t cpu)
{
	struct cpu_info *ci = &m88k_cpus[cpu];

	if (ci->ci_ipi & ipi)
		return;

	atomic_setbits_int(&ci->ci_ipi, ipi);
	*swi_reg[cpu] = 0xffffffff;
}

/*
 * Process inter-processor interrupts.
 */

/*
 * Unmaskable IPIs - those are processed with interrupts disabled,
 * and no lock held.
 */
void
luna88k_ipi_handler(struct trapframe *eframe)
{
	struct cpu_info *ci = curcpu();
	int cpu = ci->ci_cpuid;
	int ipi = ci->ci_ipi & (CI_IPI_DDB | CI_IPI_NOTIFY);

	/* just read; reset software interrupt */
	*swi_reg[cpu];
	atomic_clearbits_int(&ci->ci_ipi, ipi);

	if (ipi & CI_IPI_DDB) {
#ifdef DDB
		/*
		 * Another processor has entered DDB. Spin on the ddb lock
		 * until it is done.
		 */
		extern struct __mp_lock ddb_mp_lock;

		__mp_lock(&ddb_mp_lock);
		__mp_unlock(&ddb_mp_lock);

		/*
		 * If ddb is hoping to us, it's our turn to enter ddb now.
		 */
		if (ci->ci_cpuid == ddb_mp_nextcpu)
			Debugger();
#endif
	}
	if (ipi & CI_IPI_NOTIFY) {
		/* nothing to do */
	}
}

void
m88k_broadcast_ipi(int ipi)
{
	struct cpu_info *us = curcpu();
	struct cpu_info *ci;
	CPU_INFO_ITERATOR cii;

	CPU_INFO_FOREACH(cii, ci) {
		if (ci == us)
			continue;

		if (ISSET(ci->ci_flags, CIF_ALIVE))
			m88k_send_ipi(ipi, ci->ci_cpuid);
	}
}
#endif