code:
/*	$OpenBSD: disksubr.c,v 1.60 2014/12/24 22:48:27 miod Exp $	*/

/*
 * Copyright (c) 2013 Miodrag Vallat.
 *
 * 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.
 */
/*
 * Copyright (c) 1996 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. 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/disklabel.h>
#include <sys/disk.h>
#include <sys/malloc.h>

char	*extract_vdit_portion(char *, const char *, unsigned int, unsigned int,
	    int);
int	 readvditlabel(struct buf *, void (*)(struct buf *), struct disklabel *,
	    daddr_t *, int, struct vdm_boot_info *);
int	 readvdmlabel(struct buf *, void (*)(struct buf *), struct disklabel *,
	    daddr_t *, int);

/*
 * 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 buf *bp = NULL;
	int error;

	if ((error = initdisklabel(lp)))
		goto done;

	bp = geteblk((int)lp->d_secsize);
	bp->b_dev = dev;

	/*
	 * Check for a VDIT or native-in-VDM label first.
	 * If a valid VDM signature is found, but neither a VDIT nor a
	 * native label are found, do not attempt to check for any other
	 * label scheme.
	 */
	error = readvdmlabel(bp, strat, lp, NULL, spoofonly);
	if (error == 0)
		goto done;
	if (error == ENOENT) {
		error = EINVAL;
		goto done;
	}

	error = readdoslabel(bp, strat, lp, NULL, spoofonly);
	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)
{
	daddr_t partoff = -1;
	int error = EIO;
	int offset;
	struct disklabel *dlp;
	struct buf *bp = NULL;

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

	error = readvdmlabel(bp, strat, lp, &partoff, 1);
	if (error == 0 || error == ENOENT) {
		bp->b_blkno = partoff + LABELSECTOR;
		offset = LABELOFFSET;
	} else if (readdoslabel(bp, strat, lp, &partoff, 1) == 0) {
		bp->b_blkno = DL_BLKTOSEC(lp, partoff + DOS_LABELSECTOR) *
		    DL_BLKSPERSEC(lp);
		offset = DL_BLKOFFSET(lp, partoff + DOS_LABELSECTOR);
	} else {
		error = EIO;
		goto done;
	}

	/* Read it in, slap the new label in, and write it back out */
	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 ((error = biowait(bp)) != 0)
		goto done;

	dlp = (struct disklabel *)(bp->b_data + offset);
	*dlp = *lp;
	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);
}

/*
 * Search for a VDM "label" (which does not describe any partition).
 * If one is found, search for either a VDIT label, or a native OpenBSD
 * label in the first sector.
 */
int
readvdmlabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp,
    daddr_t *partoffp, int spoofonly)
{
	struct vdm_label *vdl;
	struct vdm_boot_info *vbi;
	int error = 0;

	/*
	 * Read first sector and check for a VDM label.
	 * Note that a VDM label is only required for bootable disks, and
	 * may not be followed by a VDIT.
	 */

	bp->b_blkno = VDM_LABEL_SECTOR;
	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 ((error = biowait(bp)) != 0)
		return error;

	vdl = (struct vdm_label *)(bp->b_data + VDM_LABEL_OFFSET);
	if (vdl->signature != VDM_LABEL_SIGNATURE)
		vdl = (struct vdm_label *)(bp->b_data + VDM_LABEL_OFFSET_ALT);
	if (vdl->signature != VDM_LABEL_SIGNATURE)
		return EINVAL;

	/*
	 * If the disk is a bootable disk, remember the boot block area, to
	 * be able to check that the VDIT does not overwrite it.
	 */

	vbi = (struct vdm_boot_info *)(bp->b_data + dbtob(1) - sizeof *vbi);
	if (vbi->signature != VDM_LABEL_SIGNATURE || vbi->boot_start == 0)
		vbi = NULL;

	if (vbi != NULL && vbi->boot_start == VDIT_SECTOR)
		return EINVAL;

	if (vbi != NULL && vbi->boot_start + vbi->boot_size > DL_GETBSTART(lp))
		DL_SETBSTART(lp, vbi->boot_start + vbi->boot_size);

	error = readvditlabel(bp, strat, lp, partoffp, spoofonly, vbi);
	if (error == 0)
		return 0;

	/*
	 * Valid VDIT information, but no OpenBSD vdmpart found.
	 * Do not try to read a native label.
	 */
	if (error == ENOENT)
		return error;

	if (partoffp != NULL)
		*partoffp = 0;

	/* don't read the on-disk label if we are in spoofed-only mode */
	if (spoofonly != 0)
		return 0;

	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 ((error = biowait(bp)) != 0)
		return error;

	return checkdisklabel(bp->b_data + LABELOFFSET, lp,
	    DL_GETBSTART(lp), DL_GETBEND(lp));
}

/*
 * Search for a VDIT volume information. If one is found, search for a
 * vdmpart instance of name "OpenBSD". If one is found, set the disklabel
 * bounds to the area it spans, and attempt to read a native label within
 * it.
 */
int
readvditlabel(struct buf *bp, void (*strat)(struct buf *), struct disklabel *lp,
    daddr_t *partoffp, int spoofonly, struct vdm_boot_info *vbi)
{
	struct buf *sbp = NULL;
	struct vdit_block_header *vbh;
	struct vdit_entry_header *veh;
	char *vdit_storage = NULL, *vdit_end;
	size_t vdit_size;
	unsigned int largest_chunk, vdit_blkno;
	int expected_kind;
	daddr_t blkno;
	int error = 0;
	vdit_id_t *vdmpart_id;
	struct vdit_vdmpart_instance *bsd_vdmpart;

	/*
	 * Figure out the size of the first VDIT.
	 */

	vdit_size = largest_chunk = 0;
	expected_kind = VDIT_BLOCK_HEAD_BE;
	blkno = VDIT_SECTOR;
	for (;;) {
		bp->b_blkno = blkno;
		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 ((error = biowait(bp)) != 0)
			return error;

		vbh = (struct vdit_block_header *)bp->b_data;
		if (VDM_ID_KIND(&vbh->id) != expected_kind ||
		    VDM_ID_BLKNO(&vbh->id) != vdit_size ||
		    vbh->id.node_number != VDM_NO_NODE_NUMBER)
			return EINVAL;

		if (vbi != NULL) {
			if ((blkno >= vbi->boot_start &&
			     blkno < vbi->boot_start + vbi->boot_size) ||
			    (blkno + vbh->chunksz - 1 >= vbi->boot_start &&
			     blkno + vbh->chunksz - 1 <
			     vbi->boot_start + vbi->boot_size))
			return EINVAL;
		}

		if (vbh->chunksz > largest_chunk)
			largest_chunk = vbh->chunksz;
		vdit_size += vbh->chunksz;
		if (vbh->nextblk == VDM_NO_BLK_NUMBER)
			break;
		blkno = vbh->nextblk;
		if (blkno >= DL_GETDSIZE(lp))
			return EINVAL;
		expected_kind = VDIT_PORTION_HEADER_BLOCK;
	}

	/*
	 * Now read the first VDIT.
	 */

	vdit_size *= dbtob(1) - sizeof(struct vdit_block_header);
	vdit_storage = malloc(vdit_size, M_DEVBUF, M_WAITOK);
	largest_chunk = dbtob(largest_chunk);
	sbp = geteblk(largest_chunk);
	sbp->b_dev = bp->b_dev;

	vdit_end = vdit_storage;
	expected_kind = VDIT_BLOCK_HEAD_BE;
	blkno = VDIT_SECTOR;
	vdit_blkno = 0;
	for (;;) {
		sbp->b_blkno = blkno;
		sbp->b_bcount = largest_chunk;
		CLR(sbp->b_flags, B_READ | B_WRITE | B_DONE);
		SET(sbp->b_flags, B_BUSY | B_READ | B_RAW);
		(*strat)(sbp);
		if ((error = biowait(sbp)) != 0)
			goto done;

		vbh = (struct vdit_block_header *)sbp->b_data;
		if (VDM_ID_KIND(&vbh->id) != expected_kind) {
			error = EINVAL;
			goto done;
		}

		vdit_end = extract_vdit_portion(vdit_end, sbp->b_data,
		    vbh->chunksz, vdit_blkno, expected_kind);
		if (vdit_end == NULL) {
			error = EINVAL;
			goto done;
		}
		if (vbh->nextblk == VDM_NO_BLK_NUMBER)
			break;
		vdit_blkno += vbh->chunksz;
		blkno = vbh->nextblk;
		expected_kind = VDIT_PORTION_HEADER_BLOCK;
	}

	/*
	 * Walk the VDIT entries.
	 *
	 * If we find an OpenBSD vdmpart, we'll set our disk area bounds to
	 * its area, and will read a label from there.
	 */

	vdmpart_id = NULL;
	bsd_vdmpart = NULL;

	veh = (struct vdit_entry_header *)vdit_storage;
	while ((caddr_t)veh < vdit_end) {
		switch (veh->type) {
		case VDIT_ENTRY_SUBDRIVER_INFO:
		    {
			struct vdit_subdriver_entry *vse;

			vse = (struct vdit_subdriver_entry *)(veh + 1);
			if (strcmp(vse->name, VDM_SUBDRIVER_VDMPART) == 0)
				vdmpart_id = &vse->subdriver_id;
		    }
			break;
		case VDIT_ENTRY_INSTANCE:
		    {
			struct vdit_instance_entry *vie;

			vie = (struct vdit_instance_entry *)(veh + 1);
			if (strcmp(vie->name, VDM_INSTANCE_OPENBSD) == 0) {
				if (vdmpart_id != NULL &&
				    memcmp(vdmpart_id, &vie->subdriver_id,
				      sizeof(vdit_id_t)) == 0) {
					/* found it! */
					if (bsd_vdmpart != NULL) {
						bsd_vdmpart = NULL;
						veh->type = VDIT_ENTRY_SENTINEL;
					} else
						bsd_vdmpart = (struct
						    vdit_vdmpart_instance *)vie;
				}
			}
		    }
			break;
		}
		if (veh->type == VDIT_ENTRY_SENTINEL)
			break;
		veh = (struct vdit_entry_header *)((char *)veh + veh->size);
	}

	if (bsd_vdmpart != NULL) {
		uint32_t start, size;

		memcpy(&start, &bsd_vdmpart->start_blkno, sizeof(uint32_t));
		memcpy(&size, &bsd_vdmpart->size, sizeof(uint32_t));

		if (start >= DL_GETDSIZE(lp) ||
		    start + size > DL_GETDSIZE(lp)) {
			error = EINVAL;
			goto done;
		}

		if (partoffp != NULL) {
			*partoffp = start;
			goto done;
		} else {
			DL_SETBSTART(lp, start);
			DL_SETBEND(lp, start + size);
		}

		/*
		 * Now read the native label.
		 */

		if (spoofonly == 0) {
			bp->b_blkno = start + 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 ((error = biowait(bp)) != 0)
				goto done;

			error = checkdisklabel(bp->b_data + LABELOFFSET, lp,
			    start, start + size);
		}
	} else {
		/*
		 * VDM label, but no OpenBSD vdmpart partition found.
		 * XXX is it worth registering the whole disk as a
		 * XXX `don't touch' vendor partition in that case?
		 */
		error = ENOENT;
		goto done;
	}

done:
	free(vdit_storage, M_DEVBUF, vdit_size);
	if (sbp != NULL) {
		sbp->b_flags |= B_INVAL;
		brelse(sbp);
	}

	return error;
}

/*
 * Process a contiguous chunk of VDIT, verifying and removing each block header
 * as we go.
 */
char *
extract_vdit_portion(char *dst, const char *src, unsigned int nsec,
    unsigned int vdit_blkno, int kind)
{
	struct vdit_block_header *vbh;

	for (; nsec != 0; nsec--) {
		vbh = (struct vdit_block_header *)src;
		if (VDM_ID_KIND(&vbh->id) != kind ||
		    VDM_ID_BLKNO(&vbh->id) != vdit_blkno ||
		    vbh->id.node_number != VDM_NO_NODE_NUMBER)
			return NULL;
		kind = VDIT_BLOCK;

		memcpy(dst, src + sizeof *vbh, dbtob(1) - sizeof *vbh);
		dst += dbtob(1) - sizeof *vbh;
		src += dbtob(1);
		vdit_blkno++;
	}

	return dst;
}


code:
/*	$OpenBSD: eh.S,v 1.9 2014/09/21 16:20:16 miod Exp $	*/
/*
 * Copyright (c) 2006, 2010 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/m8820x.h>

/*
 * Save Pbus fault status register from data and inst CMMU.
 */

#define	PFSR_SAVE \
	NOP;	/* will be changed to	br.n pfsr_handler + 4 */ \
	NOP	/* will be changed to	 first instruction of pfsr_handler */

#include <m88k/m88k/eh_common.S>

ENTRY(pfsr_double)
	/*
	 * 4 CMMUs per CPU. Almost as simple as the 2 CMMUs per CPU
	 * situation...
	 *
	 * However, to be sure we don't get fooled with already-processed
	 * exceptions, we have to reset the fault status registers
	 * after reading them.
	 */
	ld	TMP2, TMP,  CI_PFSR_I0
	ld	TMP3, TMP2, %r0
	extu	TMP3, TMP3, 3<16>
	bcnd	ne0,  TMP3, 1f
	st	%r0,  TMP2, %r0
	ld	TMP2, TMP,  CI_PFSR_I1
1:
	ld	TMP3, TMP2, %r0
	st	%r0,  TMP2, %r0
	st	TMP3, %r31, EF_IPFSR

	ld	TMP2, TMP,  CI_PFSR_D0
	ld	TMP3, TMP2, %r0
	extu	TMP3, TMP3, 3<16>
	bcnd	ne0,  TMP3, 2f
	st	%r0,  TMP2, %r0
	ld	TMP2, TMP,  CI_PFSR_D1
2:
	ld	TMP3, TMP2, %r0
	st	%r0,  TMP2, %r0
	br.n	_ASM_LABEL(pfsr_done)
	 st	TMP3, %r31, EF_DPFSR

ENTRY(pfsr_straight)
	/*
	 * We have the simple 2 CMMUs per CPU mapping. Pick our couple;
	 * note that, at least on AV530 family systems, unlike other
	 * MVME188-derived designs, we *do* need to reset fault status
	 * registers after reading them.
	 */
	ld	TMP2, TMP,  CI_PFSR_I0
	ld	TMP3, TMP2, %r0
	st	%r0,  TMP2, %r0
	st	TMP3, %r31, EF_IPFSR

	ld	TMP2, TMP,  CI_PFSR_D0
	ld	TMP3, TMP2, %r0
	st	%r0,  TMP2, %r0
	br.n	_ASM_LABEL(pfsr_done)
	 st	TMP3, %r31, EF_DPFSR

ENTRY(pfsr_six)
	/*
	 * 6 CMMU (2D4I) per CPU - this is the worst situation.
	 * We handle the instruction CMMU relying upon them being set up
	 * every 0x1000 bytes in the address space. Data CMMU can use
	 * the per-cpu_info pfsr pointers as usual.
	 */
	ld	TMP2, TMP,  CI_PFSR_I0
	ld	TMP3, TMP2, %r0
	extu	TMP3, TMP3, 3<16>
	bcnd	ne0,  TMP3, 1f

	addu	TMP2, TMP2, 0x1000	/* I1 */
	ld	TMP3, TMP2, %r0
	extu	TMP3, TMP3, 3<16>
	bcnd	ne0,  TMP3, 1f

	addu	TMP2, TMP2, 0x1000	/* I2 */
	ld	TMP3, TMP2, %r0
	extu	TMP3, TMP3, 3<16>
	bcnd	ne0,  TMP3, 1f

	addu	TMP2, TMP2, 0x1000	/* I3 */
1:
	ld	TMP3, TMP2, %r0
	st	%r0,  TMP2, %r0
	st	TMP3, %r31, EF_IPFSR

	ld	TMP2, TMP,  CI_PFSR_D0
	ld	TMP3, TMP2, %r0
	extu	TMP3, TMP3, 3<16>
	bcnd	ne0,  TMP3, 2f
	addu	TMP2, TMP2, 0x1000	/* D1 */
2:
	ld	TMP3, TMP2, %r0
	st	%r0,  TMP2, %r0
	br.n	_ASM_LABEL(pfsr_done)
	 st	TMP3, %r31, EF_DPFSR

license: unknown


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


code:
/*	$OpenBSD: locore.S,v 1.21 2015/02/25 17:41:22 miod Exp $	*/
/*
 * Copyright (c) 2005, Miodrag Vallat.
 * 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	0x6274ef2e

	.text

GLOBAL(kernelstart)
GLOBAL(kernel_text)
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)

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

#ifdef M88100
	/*
	 * 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
#endif

	/*
	 * Startup code for main processor.
	 */
ASLOCAL(main_start)
	/*
	 * Save the arguments passed by the PROM
	 * 	%r2 boot string
	 *	%r3 boot device
	 *	%r4 boot unit number
	 *	%r5 boot partition number
	 *	%r6 magic number if not loaded by the PROM
	 *	%r7 end of loaded binary if not loaded by the PROM
	 */
	or.u	%r13, %r0,  %hi16(_C_LABEL(prom_bootargs))
	st	%r2,  %r13, %lo16(_C_LABEL(prom_bootargs))
	or.u	%r13, %r0,  %hi16(_C_LABEL(bootdev))
	st	%r3,  %r13, %lo16(_C_LABEL(bootdev))
	or.u	%r13, %r0,  %hi16(_C_LABEL(bootunit))
	st	%r4,  %r13, %lo16(_C_LABEL(bootunit))
	or.u	%r13, %r0,  %hi16(_C_LABEL(bootlun))
	st	%r5,  %r13, %lo16(_C_LABEL(bootlun))

	or.u	%r12, %r0,  %hi16(BOOT_MAGIC)
	or	%r12, %r12, %lo16(BOOT_MAGIC)
	cmp	%r2,  %r6,  %r12
	bb1	eq,   %r2,  1f
	addu	%r12, %r12, 1		/* BOOT_MAGIC + 1 */
	cmp	%r2,  %r6,  %r12
	bb1	ne,   %r2,  2f

	/* BOOT_MAGIC + 1 */
	or.u	%r13, %r0,  %hi16(_C_LABEL(bootpart))
	st	%r7,  %r13, %lo16(_C_LABEL(bootpart))
#if defined(DDB) || NKSYMS > 0
	or.u	%r13, %r0,  %hi16(_C_LABEL(esym))
	st	%r8,  %r13, %lo16(_C_LABEL(esym))
#endif
	br	2f

	/* BOOT_MAGIC */
1:
#if defined(DDB) || NKSYMS > 0
	or.u	%r13, %r0,  %hi16(_C_LABEL(esym))
	st	%r7,  %r13, %lo16(_C_LABEL(esym))
#endif

2:
	/* set cputyp */
	ldcr	%r1,  PID
	extu	%r8,  %r1,  8<8>

	or.u	%r13, %r0,  %hi16(_C_LABEL(cputyp))
	bsr.n	_ASM_LABEL(setup_psr)
	 st	%r8,  %r13, %lo16(_C_LABEL(cputyp))

	/* save PROM vbr */
	ldcr	%r12, VBR
	or.u	%r13, %r0,  %hi16(_C_LABEL(prom_vbr))
	st	%r12, %r13, %lo16(_C_LABEL(prom_vbr))

	/*
	 * Have curcpu() point at 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

#ifdef MULTIPROCESSOR
	/*
	 * SCM PROM idles all secondary MPUs upon startup, so at this point
	 * we do not have to compete with them.
	 */
#endif	/* MULTIPROCESSOR */

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

#ifdef M88110
#ifdef M88100
	cmp	%r2, %r8, CPU_88110
	bb1	ne,  %r2, 1f	/* if it's a 'mc88110, use different vectors */
#endif
	or.u	%r3, %r0, %hi16(_C_LABEL(m88110_vector_list))
	br.n	2f
	 or	%r3, %r3, %lo16(_C_LABEL(m88110_vector_list))
1:
#endif /* M88110 */
#ifdef M88100
	or.u	%r3, %r0, %hi16(_C_LABEL(vector_list))
	or	%r3, %r3, %lo16(_C_LABEL(vector_list))
#endif /* M88100 */
2:
	or	%r4, %r0, 1
	or.u	%r2, %r0, %hi16(_ASM_LABEL(__start))
	bsr.n	_C_LABEL(vector_init)
	 or	%r2, %r2, %lo16(_ASM_LABEL(__start))
	stcr	%r2, VBR
	FLUSH_PIPELINE

	or.u	%r3, %r0, %hi16(_C_LABEL(kernel_vbr))
	st	%r2, %r3, %lo16(_C_LABEL(kernel_vbr))

#ifdef MULTIPROCESSOR
	bsr	_C_LABEL(atomic_init)
#endif

	/*
	 * aviion_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(aviion_bootstrap)

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

	/* call main() - no arguments although main() still defines one */
	bsr.n	_C_LABEL(main)
	 addu	%r31, %r31, USPACE

#ifdef MULTIPROCESSOR

	/*
	 * Startup code for secondary processors.
	 * Some of these initializations are very close to main_start; refer
	 * to the comments there for details.
	 */
GLOBAL(secondary_start)
	/*
	 * We have been started early, but there is nothing we can do yet.
	 * We'll just spin until we can get the hatching mutex.
	 */
	or.u	%r11, %r0,  %hi16(_C_LABEL(cpu_hatch_mutex))
	or	%r11, %r11, %lo16(_C_LABEL(cpu_hatch_mutex))
1:
	or	%r22, %r0,  1
	xmem	%r22, %r11, %r0	/* if %r22 becomes zero, we own the lock... */
	bcnd	eq0,  %r22, 4f	/* ... but if not, we must wait */
2:
	/* just watch the lock until it clears */
	ld	%r22, %r11, %r0
	bcnd	eq0,  %r22, 1b
	/* wait a bit to avoid overloading the bus */
	or.u	%r2,  %r0,  100
3:
	subu	%r2,  %r2,  1
	bcnd	ne0,  %r2,  3b
	br	2b
4:

	/*
	 * We are now running free with cpu_hatch_mutex held; other
	 * secondary processors (if any) are waiting for the lock,
	 * and the main processor is waiting for us to decrease the
	 * hatch counter, which we'll do later in secondary_main().
	 */

	or.u	%r31, %r0,  %hi16(_ASM_LABEL(slavestack_end))
	bsr.n	_ASM_LABEL(setup_psr)
	 or	%r31, %r31, %lo16(_ASM_LABEL(slavestack_end))

	or.u	%r3,  %r0,  %hi16(_C_LABEL(kernel_vbr))
	ld	%r2,  %r3,  %lo16(_C_LABEL(kernel_vbr))
	stcr	%r2,  VBR
	FLUSH_PIPELINE

	/*
	 * Have curcpu() point at 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_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.
	 */

	bsr	_C_LABEL(secondary_pre_main)	/* set cpu number */

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

	/*
	 * 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 us)
 *
 * 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(aviion_delay_const))
	ld	%r3, %r3, %lo16(_C_LABEL(aviion_delay_const))
	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

/*
 * Switch to a 1:1 mapped stack at shutdown/reboot time.
 */
GLOBAL(bootstack)
	or.u	%r31, %r0,  %hi16(_ASM_LABEL(initstack_end))
	jmp.n	%r1
	 or	%r31, %r31, %lo16(_ASM_LABEL(initstack_end))

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

	.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 */

/* Dummy cpuinfo structure, for cpu_number() to work early. */
ASLOCAL(dummy_cpu)
	.word	3 /* CIF_PRIMARY | CIF_ALIVE */	/* ci_alive */
	.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.12 2013/09/29 14:08:53 miod Exp $	*/
/*
 * Copyright (c) 2004, 2006, 2010 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 <sys/param.h>
#include <sys/systm.h>

#include <uvm/uvm_extern.h>

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

extern	u_int32_t pfsr_straight[];
extern	u_int32_t pfsr_double[];
extern	u_int32_t pfsr_six[];

volatile u_int32_t *whoamiptr;

/*
 * This routine sets up the CPU/CMMU configuration.
 */
void
m8820x_setup_board_config()
{
	extern u_int32_t pfsr_save[];
	struct m8820x_cmmu *cmmu;
	struct scm_cpuconfig scc;
	int type, cpu_num, cpu_cmmu_num, cmmu_num, cmmu_per_cpu;
	volatile u_int *cr;
	u_int32_t whoami;
	u_int32_t *m8820x_pfsr;

	/*
	 * Check whether the WHOAMI register exists.
	 * According to documentation, that register is not available
	 * on 100, 200 and 300 models.
	 *
	 * Since it is unknown whether models 100 and 200 share the
	 * 300/310 cpuid, we'd better check whether the register can
	 * be read.
	 */

	switch (cpuid) {
	case AVIION_300_310:
	/* the following for consistency and safety */
	case AVIION_300C_310C:
	case AVIION_300CD_310CD:
	case AVIION_300D_310D:
		break;
	default:
		if (badaddr((vaddr_t)AV_WHOAMI, 4) == 0)
			whoamiptr = (volatile u_int32_t *)AV_WHOAMI;
		break;
	}

	/*
	 * First, find if any CPU0 CMMU is a 88204. If so, we can
	 * issue the CPUCONFIG system call to get the configuration
	 * details.
	 * NOTE that this relies upon [0] and [1] to always have
	 * valid CMMU addresses - thankfully this is always the case
	 * on model 530 regardless of the CMMU configuration.
	 */
	if (badaddr((vaddr_t)m8820x_cmmu[0].cmmu_regs, 4) != 0 ||
	    badaddr((vaddr_t)m8820x_cmmu[1].cmmu_regs, 4) != 0) {
		printf("CPU0: missing CMMUs ???\n");
		scm_halt();
		/* NOTREACHED */
	}

	cr = (void *)m8820x_cmmu[0].cmmu_regs;
	type = CMMU_TYPE(cr[CMMU_IDR]);

	if (type != M88204_ID && type != M88200_ID) {
		printf("CPU0: unrecognized CMMU type %d\n", type);
		scm_halt();
		/* NOTREACHED */
	}

	/*
	 * Try and use the CPUCONFIG system call to get all the information
	 * we need. This is theoretically only available on 88204-based
	 * machines, but it can't hurt to give it a try.
	 */
	if (scm_cpuconfig(&scc) == 0 && scc.version == SCM_CPUCONFIG_VERSION)
		goto knowledge;

	/*
	 * XXX Instead of deciding on the CMMU type, we should decide on
	 * XXX the board type instead. But then, I am not sure not all
	 * XXX 88204-based designs have the WHOAMI register... -- miod
	 */
	switch (type) {
	case M88204_ID:
		/*
		 * Probe CMMU addresses to discover which CPU slots are
		 * populated. Actually, we'll simply check how many upper
		 * slots we can ignore, and keep using badaddr() to cope
		 * with unpopulated slots.
		 */
hardprobe:
		/*
		 * First, we'll assume we are in a 2:1 configuration, thus no
		 * CMMU split scheme in use.
		 */
		scc.igang = scc.dgang = 1;
		scc.isplit = scc.dsplit = 0;

		/*
		 * Probe CMMU addresses to discover which CPU slots are
		 * populated. Actually, we'll simply check how many upper
		 * slots we can ignore, and keep using badaddr() to cope
		 * with unpopulated slots.
		 */
		cmmu = m8820x_cmmu + MAX_CMMUS - 1;
		for (max_cmmus = MAX_CMMUS - 1; max_cmmus != 0;
		    max_cmmus--, cmmu--) {
			if (cmmu->cmmu_regs == NULL)
				continue;
			if (badaddr((vaddr_t)cmmu->cmmu_regs, 4) == 0)
				break;
		}
		scc.cpucount = (1 + max_cmmus) >> 1;
		break;

	case M88200_ID:
		/*
		 * Deduce our configuration from the WHOAMI register.
		 */

		if (whoamiptr == NULL)
			whoami = 0x0a;	/* 1 CPU, 2 CMMUs */
		else
			whoami = (*whoamiptr & 0xf0) >> 4;

		switch (whoami) {
		case 0:		/* 4 CPUs, 8 CMMUs */
			scc.cpucount = 4;
			break;
		case 5:		/* 2 CPUs, 4 CMMUs */
			scc.cpucount = 2;
			break;
		case 0x0a:	/* 1 CPU, 2 CMMUs */
			scc.cpucount = 1;
			break;
		case 3:		/* 2 CPUs, 12 CMMUs */
		case 7:		/* 1 CPU, 6 CMMUs */
			/*
			 * Regular logic can't cope with asymmetrical
			 * designs. Report a 4:1 ratio with two missing
			 * data CMMUs.
			 */
			ncpusfound = whoami == 7 ? 1 : 2;
			cmmu_per_cpu = 6;
			cmmu_shift = 3;
			max_cmmus = ncpusfound << cmmu_shift;
#if 0
			scc.igang = 4;
			scc.isplit = (1U << 12) | (1U << 13);
			scc.dgang = 2;
			scc.dsplit = (1U << 12);
#endif
			m8820x_pfsr = pfsr_six;
			goto done;
			break;
		default:
			printf("unrecognized CMMU configuration, whoami %x\n",
			    whoami);
#if 0
			scm_halt();
#else
			goto hardprobe;
#endif
		}
		/*
		 * Oh, and we are in a 2:1 configuration, thus no
		 * CMMU split scheme in use.
		 */
		scc.igang = scc.dgang = 1;
		scc.isplit = scc.dsplit = 0;

		break;
	}

knowledge:
	if (scc.igang != scc.dgang ||
	    scc.igang == 0 || scc.igang > 2) {
		printf("Unsupported CMMU to CPU ratio (%dI/%dD)\n",
		    scc.igang, scc.dgang);
		scm_halt();
		/* NOTREACHED */
	}

	ncpusfound = scc.cpucount;
	if (scc.igang == 1) {
		cmmu_shift = 1;
		m8820x_pfsr = pfsr_straight;
	} else {
		cmmu_shift = 2;
		m8820x_pfsr = pfsr_double;
	}
	max_cmmus = ncpusfound << cmmu_shift;
	cmmu_per_cpu = 1 << cmmu_shift;

done:
	/*
	 * Now that we know which CMMUs are there, report every association
	 */
	for (cpu_num = 0; cpu_num < ncpusfound; cpu_num++) {
		cmmu_num = cpu_num << cmmu_shift;
		cr = m8820x_cmmu[cmmu_num].cmmu_regs;
		if (badaddr((vaddr_t)cr, 4) == 0) {
			type = CMMU_TYPE(m8820x_cmmu[cmmu_num].
			    cmmu_regs[CMMU_IDR]);

			printf("CPU%d is associated to %d MC8820%c CMMUs\n",
			    cpu_num, cmmu_per_cpu,
			    type == M88204_ID ? '4' : '0');
		}
	}

	/*
	 * Now set up addressing limits
	 */
	switch (cmmu_shift) {
	case 3:	/* 6:1 schemes */
		for (cmmu_num = 0, cmmu = m8820x_cmmu; cmmu_num < max_cmmus;
		    cmmu_num++, cmmu++) {
			if (cmmu->cmmu_regs == NULL)
				continue;

			cpu_cmmu_num = cmmu_num >> 1; /* CPU view of the CMMU */

			if (CMMU_MODE(cmmu_num) == INST_CMMU) {
				/* I0, I1, I2, I3: A13:A12 split */
				cmmu->cmmu_addr = (cpu_cmmu_num & 0x03) << 12;
				cmmu->cmmu_addr_mask = (1U << 13) | (1U << 12);
			} else {
				/* D0, D1: A12 split */
				cmmu->cmmu_addr = (cpu_cmmu_num & 0x01) << 12;
				cmmu->cmmu_addr_mask = 1U << 12;
			}
		}
		break;
	case 2:	/* 4:1 schemes */
		for (cmmu_num = 0, cmmu = m8820x_cmmu; cmmu_num < max_cmmus;
		    cmmu_num++, cmmu++) {
			cpu_cmmu_num = cmmu_num >> 1; /* CPU view of the CMMU */

			if (CMMU_MODE(cmmu_num) == INST_CMMU) {
				/* I0, I1 */
				cmmu->cmmu_addr =
				    cpu_cmmu_num < 2 ? 0 : scc.isplit;
				cmmu->cmmu_addr_mask = scc.isplit;
			} else {
				/* D0, D1 */
				cmmu->cmmu_addr =
				    cpu_cmmu_num < 2 ? 0 : scc.dsplit;
				cmmu->cmmu_addr_mask = scc.dsplit;
			}
		}
		break;
	}

	/*
	 * Patch the exception handling code to invoke the correct pfsr
	 * analysis chunk.
	 */
	pfsr_save[0] = 0xc4000000 |
	    (((vaddr_t)m8820x_pfsr + 4 - (vaddr_t)pfsr_save) >> 2);
	pfsr_save[1] = m8820x_pfsr[0];
}

/*
 * Find out the CPU number from accessing CMMU.
 * We access the WHOAMI register, which is in data space;
 * its value will let us know which CPU has been used to perform the read.
 */
cpuid_t
m8820x_cpu_number()
{
	u_int32_t whoami;
	cpuid_t cpu;

	if (whoamiptr == NULL)
		return 0;

	whoami = *whoamiptr;
	switch ((whoami & 0xf0) >> 4) {
	case 0:
	case 3:
	case 5:
		for (cpu = 0; cpu < 4; cpu++)
			if (whoami & (1 << cpu))
				return (cpu);
		break;
	case 7:
	case 0x0a:
		/* for single processors, this field of whoami is undefined */
		return (0);
	}

	panic("m8820x_cpu_number: could not determine my cpu number, whoami %x",
	    whoami);
}


code:
/*	$OpenBSD: machdep.c,v 1.74 2015/02/25 17:41:22 miod Exp $	*/
/*
 * Copyright (c) 2007 Miodrag Vallat.
 *
 * 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, this permission notice, and the disclaimer below
 * 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.
 */
/*
 * 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.
 *
 */

#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/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 <sys/device.h>
#include <dev/rndvar.h>

#include <machine/asm.h>
#include <machine/asm_macro.h>
#include <machine/autoconf.h>
#include <machine/avcommon.h>
#include <machine/board.h>
#include <machine/bus.h>
#include <machine/cmmu.h>
#include <machine/cpu.h>
#include <machine/kcore.h>
#include <machine/prom.h>
#include <machine/reg.h>
#include <machine/trap.h>
#ifdef M88100
#include <machine/m88100.h>
#endif

#include <aviion/dev/vmevar.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_var.h>
#endif /* DDB */

void	aviion_bootstrap(void);
void	aviion_identify(void);
void	consinit(void);
void	cpu_hatch_secondary_processors(void);
void	cpu_setup_secondary_processors(void);
__dead void doboot(void);
void	dumpconf(void);
void	dumpsys(void);
void	savectx(struct pcb *);
void	secondary_main(void);
void   *secondary_pre_main(void);

extern void bootstack(void);

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

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

#ifdef MULTIPROCESSOR
__cpu_simple_lock_t cpu_hatch_mutex = __SIMPLELOCK_LOCKED;
__cpu_simple_lock_t cpu_boot_mutex = __SIMPLELOCK_LOCKED;
unsigned int hatch_pending_count;
unsigned int hatch_mask;
#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 vaddr_t esym;
#endif

const char *prom_bootargs;			/* set in locore.S */
char bootargs[256];				/* local copy */

int32_t cpuid;

int cputyp;					/* set in locore.S */
register_t kernel_vbr;				/* set in locore.S */
const struct board *platform;

/* multiplication factor for delay() */
u_int	aviion_delay_const = 33;

vaddr_t first_addr;
vaddr_t last_addr;

extern struct user *proc0paddr;

/*
 * Interrupt masks, one per IPL level.
 */
u_int32_t int_mask_val[NIPLS];
u_int32_t ext_int_mask_val[NIPLS];

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

struct consdev bootcons = {
	NULL,
	NULL,
	bootcngetc,
	bootcnputc,
	nullcnpollc,
	NULL,
	makedev(14, 0),
	CN_LOWPRI
};

/*
 * Early console initialization: called early on from main, before vm init.
 * We want to stick to the BUG routines for now, and we'll switch to the
 * real console in cpu_startup().
 */
void
consinit()
{
	cn_tab = NULL;
	cninit();

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

/*
 * Set up real-time clocks.
 * These function pointers are set in dev/clock.c.
 */
void
cpu_initclocks()
{
	platform->init_clocks();
}

void
setstatclockrate(int newhz)
{
	/* function stub */
}

void
cpu_startup()
{
	vaddr_t minaddr, maxaddr;

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

	/*
	 * Grab machine dependent memory spaces
	 */
	platform->startup();

	/*
	 * 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();

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

__dead void
doboot()
{

	printf("Rebooting system...\n\n");
	bootstack();
	cmmu_shutdown();
	scm_reboot(NULL);
	/*NOTREACHED*/
	for (;;);		/* appease gcc */
}

__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);

	if ((howto & RB_HALT) != 0) {
		printf("System halted.\n\n");
		bootstack();
		cmmu_shutdown();
		scm_halt();
	}

	doboot();

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

unsigned 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;

	/* aviion 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;
	}
}

#ifdef MULTIPROCESSOR

/*
 * 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;
	platform->smp_setup(ci);

	splhigh();

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

	if (ci->ci_curpcb == NULL) {
		printf("cpu%d: unable to get startup stack\n", ci->ci_cpuid);
		/*
		 * Release cpu_hatch_mutex to let other secondary processors
		 * have a chance to run.
		 */
		__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);

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

	SET(ci->ci_flags, CIF_ALIVE);

	cpu_switchto(NULL, sched_chooseproc());
}

#endif	/* MULTIPROCESSOR */

void
nmihand(void *frame)
{
#ifdef DDB
	printf("Abort switch pressed\n");
	if (db_console) {
		/*
		 * We can't use Debugger() here, as we are coming from an
		 * exception, and can't assume anything on the state we are
		 * in. Invoke the post-trap ddb entry directly.
		 */
		extern void m88k_db_trap(int, struct trapframe *);
		m88k_db_trap(T_KDB_ENTRY, (struct trapframe *)frame);
	}
#endif
}

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*/
}

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

	/* Save a copy of our commandline before it gets overwritten. */
	strlcpy(bootargs, prom_bootargs, sizeof bootargs);

	aviion_identify();

	cn_tab = &bootcons;
	aviion_delay_const = platform->bootstrap();
	/* we can use printf() from here. */

	/* Parse the commandline */
	cmdline_parse();

	uvmexp.pagesize = PAGE_SIZE;
	uvm_setpagesize();

#if defined(DDB) || NKSYMS > 0
	if (esym != 0)
		first_addr = esym;
	else
#endif
		first_addr = (vaddr_t)&end;
	first_addr = round_page(first_addr);

	last_addr = platform->memsize();

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

#ifdef M88100
	if (CPU_IS88100) {
		m88100_apply_patches();
	}
#endif

#ifdef MULTIPROCESSOR
	/*
	 * We need to start secondary processors while it is still
	 * possible to invoke SCM functions.
	 */
	cpu_hatch_secondary_processors();
#endif

	/*
	 * 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 = round_page(first_addr);
	avail_end = last_addr;

	/*
	 * Tell the VM system about available physical memory.
	 * The aviion systems only have one contiguous area.
	 *
	 * XXX However, on series 5000, SRAM overlaps a low memory range,
	 * XXX so we will need to upload two ranges of pages on them.
	 */
	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);

	/* ROM work area is on top of physical memory */
	pmap_bootstrap(0, 0);

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

#ifdef MULTIPROCESSOR
/*
 * Spin processors while we can use the PROM, and have them wait for
 * cpu_hatch_mutex.
 */
void
cpu_hatch_secondary_processors()
{
	struct cpu_info *ci = curcpu();
	cpuid_t cpu;
	int rc;
	extern void secondary_start(void);

	/* we might not have a working SMP implementation on this system. */
	if (platform->send_ipi == NULL)
		return;

	for (cpu = 0; cpu < MAX_CPUS; cpu++) {
		if (cpu != ci->ci_cpuid) {
			hatch_pending_count++;
			rc = scm_jpstart(cpu, (vaddr_t)secondary_start);
			switch (rc) {
			case JPSTART_OK:
				hatch_mask |= 1U << cpu;
				break;
			case JPSTART_SINGLE_JP:
				/* this should never happen, but just in case */
				hatch_pending_count = 0;
				ncpusfound = 1;
				return;
			default:
				printf("CPU%ld failed to start, error %d\n",
				    cpu, rc);
				/* FALLTHROUGH */
			case JPSTART_NO_JP:
				hatch_pending_count--;
				break;
			}
		}
	}
}

/*
 * Release cpu_hatch_mutex to let secondary processors initialize.
 */
void
cpu_setup_secondary_processors()
{
	cpuid_t cpu;

	/*
	 * Allocate UPAGES contiguous pages for the idle stack of every
	 * running secondary processor.
	 */
	for (cpu = 0; cpu < MAX_CPUS; cpu++) {
		if ((hatch_mask & (1U << cpu)) == 0)
			continue;

		m88k_cpus[cpu].ci_curpcb =
		    (void *)uvm_km_zalloc(kernel_map, USPACE);
	}

	__cpu_simple_unlock(&cpu_hatch_mutex);
	while (hatch_pending_count != 0)
		delay(10000);	/* 10ms */
}

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

/*
 * Boot console routines:
 * Enables printing of boot messages before consinit().
 */
void
bootcnprobe(cp)
	struct consdev *cp;
{
	cp->cn_dev = makedev(0, 0);
	cp->cn_pri = CN_LOWPRI;
}

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

int
bootcngetc(dev)
	dev_t dev;
{
	return (scm_getc());
}

void
bootcnputc(dev, c)
	dev_t dev;
	int c;
{
	if (c == '\n')
		scm_putcrlf();
	else
		scm_putc(c);
}

int
getipl(void)
{
	return (int)platform->getipl();
}

int
setipl(int level)
{
	return (int)platform->setipl((u_int)level);
}

int
raiseipl(int level)
{
	return (int)platform->raiseipl((u_int)level);
}

#ifdef MULTIPROCESSOR
void
m88k_send_ipi(int ipi, cpuid_t cpu)
{
	struct cpu_info *ci;

	ci = &m88k_cpus[cpu];
	if (ISSET(ci->ci_flags, CIF_ALIVE))
		platform->send_ipi(ipi, cpu);
}

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))
			platform->send_ipi(ipi, ci->ci_cpuid);
	}
}
#endif

void
intsrc_enable(u_int intsrc, int ipl)
{
	u_int32_t psr;
	u_int32_t intmask = platform->intsrc(intsrc);
	u_int32_t exintmask = platform->exintsrc(intsrc);
	int i;

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

	for (i = IPL_NONE; i < ipl; i++) {
		int_mask_val[i] |= intmask;
		ext_int_mask_val[i] |= exintmask;
	}
	setipl(getipl());

	set_psr(psr);
}

void
intsrc_disable(u_int intsrc)
{
	u_int32_t psr;
	u_int32_t intmask = platform->intsrc(intsrc);
	u_int32_t exintmask = platform->exintsrc(intsrc);
	int i;

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

	for (i = 0; i < NIPLS; i++) {
		int_mask_val[i] &= ~intmask;
		ext_int_mask_val[i] &= ~exintmask;
	}
	setipl(getipl());

	set_psr(psr);
}

u_char hostaddr[6];

void
myetheraddr(u_char *cp)
{
	bcopy(hostaddr, cp, 6);
}

/*
 * Attempt to identify which AViiON flavour we are running on.
 */

struct aviion_system {
	int32_t			 cpuid;
	const char		*model;
	const struct board	*platform;
	const char		*kernel_option;
};
static const struct aviion_system aviion_systems[] = {
#define	BOARD_UNSUPPORTED	NULL, NULL
#ifdef AV400
#define	BOARD_AV400		&board_av400, NULL
#else
#define	BOARD_AV400		NULL, "AV400"
#endif
#ifdef AV530
#define	BOARD_AV530		&board_av530, NULL
#else
#define	BOARD_AV530		NULL, "AV530"
#endif
#ifdef AV5000
#define	BOARD_AV5000		&board_av5000, NULL
#else
#define	BOARD_AV5000		BOARD_UNSUPPORTED /* NULL, "AV5000" */
#endif
#ifdef AV6280
#define	BOARD_AV6280		&board_av6280, NULL
#else
#define	BOARD_AV6280		BOARD_UNSUPPORTED /* NULL, "AV6280" */
#endif
	{ AVIION_300_310,		"300/310",	BOARD_AV400 },
	{ AVIION_5100_6100,		"5100/6100",	BOARD_UNSUPPORTED },
	{ AVIION_400_4000,		"400/4000",	BOARD_AV400 },
	{ AVIION_410_4100,		"410/4100",	BOARD_AV400 },
	{ AVIION_300C_310C,		"300C/310C",	BOARD_AV400 },
	{ AVIION_5200_6200,		"5200/6200",	BOARD_AV5000 },
	{ AVIION_5240_6240,		"5240/6240",	BOARD_AV5000 },
	{ AVIION_300CD_310CD,		"300CD/310CD",	BOARD_AV400 },
	{ AVIION_300D_310D,		"300D/310D",	BOARD_AV400 },
	{ AVIION_4600_530,		"4600/530",	BOARD_AV530 },
	{ AVIION_4300_25,		"4300-25",	BOARD_AV400 },
	{ AVIION_4300_20,		"4300-20",	BOARD_AV400 },
	{ AVIION_4300_16,		"4300-16",	BOARD_AV400 },
	{ AVIION_5255_6255,		"5255/6255",	BOARD_AV5000 },
	{ AVIION_350,			"350",		BOARD_UNSUPPORTED },
	{ AVIION_6280,			"6280",		BOARD_AV6280 },
	{ AVIION_8500_9500,		"8500/9500",	BOARD_UNSUPPORTED },
	{ AVIION_9500_HA,		"9500HA",	BOARD_UNSUPPORTED },
	{ AVIION_500,			"500",		BOARD_UNSUPPORTED },
	{ AVIION_5500,			"5500",		BOARD_UNSUPPORTED },
	{ AVIION_450,			"450",		BOARD_UNSUPPORTED },
	{ AVIION_8500_9500_45_1MB,	"8500/9500-45",	BOARD_UNSUPPORTED },
	{ AVIION_10000,			"10000",	BOARD_UNSUPPORTED },
	{ AVIION_10000_QT,		"10000QT",	BOARD_UNSUPPORTED },
	{ AVIION_5500PLUS,		"5500+",	BOARD_UNSUPPORTED },
	{ AVIION_450PLUS,		"450+",		BOARD_UNSUPPORTED },
	{ AVIION_8500_9500_50_1MB,	"8500/9500-50",	BOARD_UNSUPPORTED },
	{ AVIION_8500_9500_50_2MB,	"8500/9500-50d", BOARD_UNSUPPORTED },

	{ AVIION_UNKNOWN1,		"\"Montezuma\"", BOARD_UNSUPPORTED },
	{ AVIION_UNKNOWN2,		"\"Montezuma\"", BOARD_UNSUPPORTED },
	{ AVIION_UNKNOWN3,		"\"Flintstone\"", BOARD_UNSUPPORTED },
	{ AVIION_UNKNOWN1_DIS,		"\"Montezuma-\"", BOARD_UNSUPPORTED },
	{ AVIION_UNKNOWN2_DIS,		"\"Montezuma-\"", BOARD_UNSUPPORTED },

	{ 0 }
#undef	BOARD_AV6280
#undef	BOARD_AV5000
#undef	BOARD_AV530
#undef	BOARD_AV400
};

void
aviion_identify()
{
	const struct aviion_system *system;
	char excuse[512];
	extern char *hw_vendor, *hw_prod;

	cpuid = scm_cpuid();
	hostid = scm_sysid();

	for (system = aviion_systems; ; system++) {
		if (system->cpuid != 0 && system->cpuid != cpuid)
			continue;

		if (system->platform != NULL) {
			hw_vendor = "Data General";
			hw_prod = "AViiON";
			strlcpy(cpu_model, system->model, sizeof cpu_model);
			platform = system->platform;
			return;
		}

		if (system->kernel_option != NULL) {
			/* unconfigured system */
			snprintf(excuse, sizeof excuse, "\n"
			    "Sorry, support for the %s system is not present\n"
			    "in this OpenBSD/" MACHINE " kernel.\n"
			    "Please recompile your kernel with\n"
			    "\toption\t%s\n"
			    "in the kernel configuration file.\n",
			    system->model, system->kernel_option);
		} else if (system->cpuid != 0) {
			/* unsupported system */
			snprintf(excuse, sizeof excuse, "\n"
			    "Sorry, OpenBSD/" MACHINE
			    " does not support the %s system"
			    " (cpuid %04x) yet.\n\n"
			    "Please contact <m88k@openbsd.org>\n",
			    system->model, cpuid);
		} else {
			/* unrecgonized system */
			snprintf(excuse, sizeof excuse, "\n"
			    "Sorry, OpenBSD/" MACHINE
			    " does not recognize this system (cpuid %04x).\n\n"
			    "Please contact <m88k@openbsd.org>\n",
			    cpuid);
		}

		scm_printf(excuse);
		scm_halt();
	}
	/* NOTREACHED */
}


code:
/*	$OpenBSD: pmap_table.c,v 1.3 2011/01/02 13:40:05 miod Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993-1992 Carnegie Mellon University
 * 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 ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS 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 Mellon
 * the rights to redistribute these changes.
 */

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

#include <uvm/uvm_extern.h>

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

const struct pmap_table *
pmap_table_build(void)
{
	return (platform->ptable);
}


code:
/*	$OpenBSD: prom.c,v 1.8 2014/03/29 18:09:29 guenther 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 <sys/param.h>
#include <sys/systm.h>

#include <machine/asm_macro.h>
#include <machine/prom.h>

register_t prom_vbr;					/* set in locore.S */

/*
 * No locking is necessary, since we will only use the SCM routines
 * during startup, before any secondary CPU is started.
 */

#define	SCM_DECL \
	register_t psr; \
	register_t ossr0, ossr1, ossr2, ossr3

#define	SCM_CALL(x) \
	__asm__ volatile ("or %r9, %r0, " __STRING(x));			\
	__asm__ volatile ("tb0 0, %%r0, 496" :::			\
	    "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",		\
	    "r9", "r10", "r11", "r12", "r13")

#define	SCM_VBR() \
	__asm__ volatile ("stcr %0, %%cr7" : : "r" (prom_vbr))

#define	SCM_CONTEXT() \
	__asm__ volatile ("ldcr %0, %%cr17" : "=r" (ossr0)); \
	__asm__ volatile ("ldcr %0, %%cr18" : "=r" (ossr1)); \
	__asm__ volatile ("ldcr %0, %%cr19" : "=r" (ossr2)); \
	__asm__ volatile ("ldcr %0, %%cr20" : "=r" (ossr3))

#define	OS_VBR() \
	__asm__ volatile ("stcr %0, %%cr7" : : "r" (kernel_vbr))

#define	OS_CONTEXT() \
	__asm__ volatile ("stcr %0, %%cr17" : : "r" (ossr0)); \
	__asm__ volatile ("stcr %0, %%cr18" : : "r" (ossr1)); \
	__asm__ volatile ("stcr %0, %%cr19" : : "r" (ossr2)); \
	__asm__ volatile ("stcr %0, %%cr20" : : "r" (ossr3))

/* ==== */

int
scm_cpuconfig(struct scm_cpuconfig *scc)
{
	SCM_DECL;
	int ret;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	__asm__ volatile ("or %%r2, %%r0, %0" : : "r" (scc));
	SCM_CALL(SCM_CPUCONFIG);
	__asm__ volatile ("or %0, %%r0, %%r2" : "=r" (ret));
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);

	return (ret);
}

u_int
scm_cpuid()
{
	SCM_DECL;
	u_int ret;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	SCM_CALL(SCM_CPUID);
	__asm__ volatile ("or %0, %%r0, %%r2" : "=r" (ret));
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);

	return (ret);
}

int
scm_getc(void)
{
	SCM_DECL;
	u_int ret;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	SCM_CALL(SCM_CHAR);
	__asm__ volatile ("or %0, %%r0, %%r2" : "=r" (ret));
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);

	return (ret & 0xff);
}

void
scm_getenaddr(u_char *ea)
{
	SCM_DECL;
	char *addr;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	SCM_CALL(SCM_COMMID);
	__asm__ volatile ("or %0, %%r0, %%r2" : "=r" (addr));
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);

	bcopy(addr, ea, 6);
}

__dead void
scm_halt()
{
	SCM_DECL;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	SCM_CALL(SCM_HALT);
#if 0
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);
#endif
	for (;;) ;
}

u_int
scm_memsize(int which)
{
	SCM_DECL;
	u_int msize;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	__asm__ volatile ("or %%r2, %%r0, %0" : : "r" (which));
	SCM_CALL(SCM_MSIZE);
	__asm__ volatile ("or %0, %%r0, %%r2" : "=r" (msize));
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);

	return (msize);
}

/*
 * Does not accept parameters beyond a string because this would need extra
 * register constraints.
 */
void
scm_printf(const char *msg)
{
	SCM_DECL;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	__asm__ volatile ("or %%r2, %%r0, %0" : : "r" (msg));
	SCM_CALL(SCM_PTLINE);
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);
}

u_int
scm_promver()
{
	SCM_DECL;
	u_int ret;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	SCM_CALL(SCM_REVNUM);
	__asm__ volatile ("or %0, %%r0, %%r2" : "=r" (ret));
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);

	return (ret);
}

void
scm_putc(int c)
{
	SCM_DECL;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	__asm__ volatile ("or %%r2, %%r0, %0" : : "r" (c));
	SCM_CALL(SCM_OCHAR);
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);
}

void
scm_putcrlf()
{
	SCM_DECL;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	SCM_CALL(SCM_OCRLF);
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);
}

__dead void
scm_reboot(const char *cmdline)
{
	SCM_DECL;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	__asm__ volatile ("or %%r2, %%r0, %0" : : "r" (cmdline));
	SCM_CALL(SCM_REBOOT);
#if 0
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);
#endif
	for (;;) ;
}

u_int
scm_sysid()
{
	SCM_DECL;
	u_int ret;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	SCM_CALL(SCM_SYSID);
	__asm__ volatile ("or %0, %%r0, %%r2" : "=r" (ret));
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);

	return (ret);
}

#ifdef MULTIPROCESSOR
u_int
scm_jpstart(cpuid_t cpu, vaddr_t addr)
{
	SCM_DECL;
	u_int ret;

	psr = get_psr();
	set_psr(psr | PSR_IND);
	SCM_CONTEXT();
	SCM_VBR();
	__asm__ volatile ("or %%r2, %%r0, %0; or %%r3, %%r0, %1" : :
	    "r" (cpu), "r" (addr));
	SCM_CALL(SCM_JPSTART);
	__asm__ volatile ("or %0, %%r0, %%r2" : "=r" (ret));
	OS_CONTEXT();
	OS_VBR();
	set_psr(psr);

	return (ret);
}
#endif


code:
/*	$OpenBSD: rtc_clock.c,v 1.3 2013/10/07 19:11:39 miod Exp $	*/

/*
 * Copyright (c) 2010 Miodrag Vallat.
 *
 * 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.
 */

/*
 * Clock routines using a freerunning RTC counter (models 530/4600)
 */

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

#include <machine/board.h>
#include <machine/avcommon.h>
#include <machine/av530.h>

#include <aviion/dev/sysconvar.h>

struct intrhand rtc_clock_ih;

int	rtc_clockintr(void *);
u_int	rtc_get_timecount(struct timecounter *);

struct timecounter rtc_timecounter = {
	.tc_get_timecount = rtc_get_timecount,
	.tc_counter_mask = 0xffffffff,
	.tc_name = "rtc",
	.tc_quality = 0
};

uint32_t pit_step;

void
rtc_init_clocks()
{
	uint rtc_speed, pit_interval;

#ifdef DIAGNOSTIC
	if (1000000 % hz) {
		printf("cannot get %d Hz clock; using 100 Hz\n", hz);
		hz = 100;
	}
#endif
	tick = 1000000 / hz;

	profhz = stathz = 0;

	/*
	 * According to the documentation, all systems of this family run
	 * at 33MHz.
	 */
	rtc_speed = 33333333 / 2;	/* apparently RTC runs at half CPUCLK */

	/*
	 * RTC is free running; we can get a periodic interrupt at any
	 * multiple of 0x100 RTC ticks. We use PIT0 for this purpose.
	 * Therefore to get a proper system clock, we need an interrupt
	 * every (rtc_speed / hz) ticks, rounded down.
	 * With hz being 100, this won't be an exact 100Hz clock, but the
	 * timecounter code will make sure time is kept accurately.
	 */

	/* disable and reset all counters */
	*(volatile uint32_t *)AV530_PIT_CMD_ALL = AV530_PIT_RESET;
	/* setup countdown interrupt threshold */
	pit_interval = rtc_speed / hz;
	pit_step = 0xffffff00 & (-pit_interval);
	*(volatile uint32_t *)AV530_PIT0_CNT = pit_step;
	/* start timer */
	*(volatile uint32_t *)AV530_PIT0_CS = AV530_PIT_CTEN;

	rtc_clock_ih.ih_fn = rtc_clockintr;
	rtc_clock_ih.ih_arg = 0;
	rtc_clock_ih.ih_flags = INTR_WANTFRAME;
	rtc_clock_ih.ih_ipl = IPL_CLOCK;
	sysconintr_establish(INTSRC_CLOCK, &rtc_clock_ih, "clock");

	rtc_timecounter.tc_frequency = rtc_speed;
	tc_init(&rtc_timecounter);
}

int
rtc_clockintr(void *frame)
{
	/*
	 * Not only does the PIT stop upon overflow (requiring us to
	 * rearm it after acknowledging the interrupt), but also the
	 * comparison value is lost and needs to be setup again.
	 */
	*(volatile uint32_t *)AV530_PIT0_CS = AV530_PIT_IACK | AV530_PIT_RESET;
	*(volatile uint32_t *)AV530_PIT0_CNT = pit_step;
	*(volatile uint32_t *)AV530_PIT0_CS = AV530_PIT_CTEN;
	hardclock(frame);

#ifdef MULTIPROCESSOR
	/*
	 * Send an IPI to all other processors, so they can get their
	 * own ticks.
	 */
	m88k_broadcast_ipi(CI_IPI_HARDCLOCK);
#endif

	return 1;
}

u_int
rtc_get_timecount(struct timecounter *tc)
{
	return *(volatile uint32_t *)AV530_RTC_CNT;
}


code:
/.cvsignore/1.2/Wed Jun  2 14:40:41 2010//TOPENBSD_5_8_BASE
D

path: sys/arch/aviion/compile/CVS/Entries


code: src/sys/arch/aviion/compile

path: sys/arch/aviion/compile/CVS/Repository


code: src/sys/arch/aviion/conf

path: sys/arch/aviion/conf/CVS/Repository


code:
#	$OpenBSD: GENERIC,v 1.10 2013/10/15 01:41:46 miod Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
#
# For further information on hardware support for this architecture, see
# the intro(4) man page.  For further information about kernel options
# for this architecture, see the options(4) man page.  For an explanation
# of each device driver in this file see the section 4 man page for the
# device.

machine		aviion m88k
include		"../../../conf/GENERIC"
maxusers	32			# estimated number of users

# Processor type
option		M88100
#option		M88110

# Supported models
option		AV400		# 100, 200, 300, 400, 3000, 4000, 4300
option		AV530		# 4600, 530
#option		AV5000		# 5000, 6000
#option		AV6280		# 6280, 8000-8

# Define this if your 88100 processor has the xxx.usr bug (mask C82N)
option		ERRATA__XXX_USR

config		bsd		swap generic

#
# devices
#

mainbus0 at root

#
# Onboard devices for all 88100-based machines
#

syscon0 at mainbus0 addr 0xfff00000
nvram0	at syscon? offset 0x80000
dart0	at syscon? offset 0x82000		# serial ports
#avkbc0	at syscon? offset 0x82800
#pckbd*	at avkbc?
#wskbd*	at avkbd?
vme0	at syscon? offset 0x85000		# VME bridge
#avfb0	at syscon? offset 0x89000
#wsdisplay* at avfb?

#
# AV400 onboard devices
#

dart1	at syscon? offset 0x82c00
oaic0	at syscon? offset 0x8a000
le0	at syscon? offset 0x8c000		# on-board ethernet

#
# AV530 onboard devices
#

dart1	at syscon? offset 0x82040
#ssi0	at syscon? offset 0x8d000
oosiop0	at syscon? offset 0xb0000
oosiop1	at syscon? offset 0xb0080
le0	at syscon? offset 0xb0100
le1	at syscon? offset 0xb0140

#
# VME devices
#

# Interphase Hawk Ethernet
le*	at vme? a32 0x00900000 a16 0x4000 ipl 3	# artwork X0A factory settings
le*	at vme? a32 0x55540000 a16 0x8600 ipl 3	# artwork X0B factory settings
le*	at vme? a32 0x55900000 a16 0x4000 ipl 3
le*	at vme? a32 0x55980000 a16 0x5000 ipl 3

#
# SCSI devices
#

scsibus* at scsi?
sd*	at scsibus?
st*	at scsibus?
cd*	at scsibus?
ch*	at scsibus?
safte*	at scsibus?
ses*	at scsibus?
uk*	at scsibus?

path: sys/arch/aviion/conf/GENERIC


code:
#	$OpenBSD: GENERIC.MP,v 1.1 2010/04/24 18:46:53 miod Exp $
#
# For further information on compiling OpenBSD kernels, see the config(8)
# man page.
#
# For further information on hardware support for this architecture, see
# the intro(4) man page.  For further information about kernel options
# for this architecture, see the options(4) man page.  For an explanation
# of each device driver in this file see the section 4 man page for the
# device.

include	"arch/aviion/conf/GENERIC"

option	MULTIPROCESSOR
#option	MP_LOCKDEBUG


code:
#	$OpenBSD: Makefile.aviion,v 1.51 2015/01/13 01:12:49 deraadt Exp $

# For instructions on building kernels consult the config(8) and options(4)
# manual pages.
#
# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE
#	IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
# DEBUG is set to -g by config if debugging is requested (config -g).
# PROF is set to -pg by config if profiling is requested (config -p).

.include <bsd.own.mk>

SIZE?=	size
STRIP?=	strip

# source tree is located via $S relative to the compilation directory
.ifndef S
S!=	cd ../../../..; pwd
.endif

_machdir?=	$S/arch/${_mach}
_archdir?=	$S/arch/${_arch}

INCLUDES=	-nostdinc -I$S -I. -I$S/arch
CPPFLAGS=	${INCLUDES} ${IDENT} ${PARAM} -D_KERNEL -D__${_mach}__ -MD -MP
CWARNFLAGS=	-Werror -Wall -Wimplicit-function-declaration \
		-Wno-main -Wno-uninitialized \
		-Wframe-larger-than=2047

CMACHFLAGS=	-mno-check-zero-division -mmemcpy
CMACHFLAGS+=	-fno-builtin-printf -fno-builtin-snprintf \
		-fno-builtin-vsnprintf -fno-builtin-log \
		-fno-builtin-log2 -fno-builtin-malloc ${NOPIE_FLAGS}
.if ${IDENT:M-DNO_PROPOLICE}
CMACHFLAGS+=	-fno-stack-protector
.endif

COPTS?=		-O2
CFLAGS=		${DEBUG} ${CWARNFLAGS} ${CMACHFLAGS} ${COPTS} ${PIPE}
AFLAGS=		-D_LOCORE -x assembler-with-cpp ${CWARNFLAGS} ${CMACHFLAGS}
LDSCRIPT=	${_machdir}/conf/ld.script
LINKFLAGS=	-T ${LDSCRIPT} -Ttext 0x80000 -e __start -X -N --warn-common -nopie

.if ${IDENT:M-DDDB_STRUCT}
DB_STRUCTINFO=	db_structinfo.h
.else
DB_STRUCTINFO=
.endif

HOSTCC?=	${CC}
HOSTED_CPPFLAGS=${CPPFLAGS:S/^-nostdinc$//}
HOSTED_CFLAGS=	${CFLAGS}
HOSTED_C=	${HOSTCC} ${HOSTED_CFLAGS} ${HOSTED_CPPFLAGS} -c $<

NORMAL_C_NOP=	${CC} ${CFLAGS} ${CPPFLAGS} -c $<
NORMAL_C=	${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $<
NORMAL_S=	${CC} ${AFLAGS} ${CPPFLAGS} -c $<
PROFILE_C=	${CC} -S -c ${CFLAGS} ${CPPFLAGS} $<; \
		sed -e s/_mcount/mcount/ -e s/subrmcount/subr_mcount/ <$*.s | \
		${AS} -o $@; \
		rm -f $*.s

%OBJS

%CFILES

%SFILES

# load lines for config "xxx" will be emitted as:
# xxx: ${SYSTEM_DEP} swapxxx.o
#	${SYSTEM_LD_HEAD}
#	${SYSTEM_LD} swapxxx.o
#	${SYSTEM_LD_TAIL}
SYSTEM_HEAD=	locore.o param.o ioconf.o
SYSTEM_OBJ=	${SYSTEM_HEAD} ${OBJS}
SYSTEM_DEP=	Makefile ${SYSTEM_OBJ} ${LDSCRIPT}
SYSTEM_LD_HEAD=	@rm -f $@
SYSTEM_LD=	@echo ${LD} ${LINKFLAGS} -o $@ '$${SYSTEM_HEAD} vers.o $${OBJS}'; \
		${LD} ${LINKFLAGS} -o $@ ${SYSTEM_HEAD} vers.o ${OBJS}
SYSTEM_LD_TAIL=	@${SIZE} $@; chmod 755 $@

DEBUG?=
.if ${DEBUG} == "-g"
LINKFLAGS+=	-X
STRIPFLAGS=	-g -x
SYSTEM_LD_TAIL+=; \
		echo mv $@ $@.gdb; rm -f $@.gdb; mv $@ $@.gdb; \
		echo ${STRIP} ${STRIPFLAGS} -o $@ $@.gdb; \
		${STRIP} ${STRIPFLAGS} -o $@ $@.gdb
.else
LINKFLAGS+=	-S -x
.endif

%LOAD

# cc's -MD puts the source and output paths in the dependency file;
# since those are temp files here we need to fix it up.  It also
# puts the file in /tmp, so we use -MF to put it in the current
# directory as assym.P and then generate assym.d from it with a
# good target name
assym.h: $S/kern/genassym.sh Makefile \
	 ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf
	cat ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf | \
	    sh $S/kern/genassym.sh ${CC} ${CFLAGS} ${CPPFLAGS} -MF assym.P > assym.h.tmp
	sed '1s/.*/assym.h: \\/' assym.P > assym.d
	sort -u assym.h.tmp > assym.h

param.c: $S/conf/param.c
	rm -f param.c
	cp $S/conf/param.c .

param.o: param.c Makefile
	${NORMAL_C}

mcount.o: $S/lib/libkern/mcount.c Makefile
	${NORMAL_C_NOP}

ioconf.o: ioconf.c
	${NORMAL_C}

vers.o: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}
	sh $S/conf/newvers.sh
	${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c

clean::
	rm -f eddep *bsd *bsd.gdb tags *.[dio] [a-z]*.s \
	    [Ee]rrs linterrs assym.h ${DB_STRUCTINFO}

lint:
	@lint -hbxncez -Dvolatile= ${CPPFLAGS} -UKGDB \
	    ${CFILES} ioconf.c param.c | \
	    grep -v 'static function .* unused'

depend:
	@touch $@

tags:
	@echo "see $S/kern/Makefile for tags"

db_structinfo.h: $S/ddb/db_structinfo.c $S/ddb/parse_structinfo.pl
	${CC} ${CFLAGS} ${CPPFLAGS} -MT $@ -gstabs -c $S/ddb/db_structinfo.c
	objdump -g db_structinfo.o | perl $S/ddb/parse_structinfo.pl > $@
	rm -f db_structinfo.o

locore.o: ${_machdir}/${_mach}/locore.S assym.h
eh.o mutex.o process.o subr.o: assym.h

# The install target can be redefined by putting a
# install-kernel-${MACHINE_NAME} target into /etc/mk.conf
MACHINE_NAME!=  uname -n
install: install-kernel-${MACHINE_NAME}
.if !target(install-kernel-${MACHINE_NAME}})
install-kernel-${MACHINE_NAME}:
	cmp -s bsd /bsd || ln -f /bsd /obsd
	cp bsd /nbsd
	mv /nbsd /bsd
.endif

# pull in the dependency information
.if !empty(DB_STRUCTINFO) && !exists(${DB_STRUCTINFO})
 ${SYSTEM_OBJ}: ${DB_STRUCTINFO}
.endif
.ifnmake clean
. for o in ${SYSTEM_OBJ} assym.h ${DB_STRUCTINFO}
.  if exists(${o:R}.d)
.   include "${o:R}.d"
.  elif exists($o)
    .PHONY: $o
.  endif
. endfor
.endif

%RULES


code:
#	$OpenBSD: RAMDISK,v 1.3 2015/07/17 22:52:28 tedu Exp $

machine		aviion m88k
maxusers	4

option		TIMEZONE=0
option		DST=0
option		SMALL_KERNEL
option		NO_PROPOLICE
option		BOOT_CONFIG

option		MINIROOTSIZE=4096
option		RAMDISK_HOOKS

option		FFS
option		NFSCLIENT
option		CD9660
option		INET6

option		M88100
#option		M88110
option		AV400		# 100, 200, 300, 400, 3000, 4000, 4300
option		AV530		# 4600, 530
#option		AV5000		# 5000, 6000
#option		AV6280		# 6280, 8000-8
option		ERRATA__XXX_USR	# processor xxx.usr bug (mask C82N)

config		bsd root on rd0a swap on rd0b

mainbus0	at root
syscon0		at mainbus0 addr 0xfff00000
nvram0		at syscon? offset 0x80000
dart0		at syscon? offset 0x82000		# serial ports
vme0		at syscon? offset 0x85000		# VME bridge

dart1		at syscon? offset 0x82c00
oaic0		at syscon? offset 0x8a000
le0		at syscon? offset 0x8c000		# on-board ethernet

dart1		at syscon? offset 0x82040
oosiop0		at syscon? offset 0xb0000
oosiop1		at syscon? offset 0xb0080
le0		at syscon? offset 0xb0100
le1		at syscon? offset 0xb0140

le*		at vme? a32 0x00900000 a16 0x4000 ipl 3	# artwork X0A factory settings
le*		at vme? a32 0x55540000 a16 0x8600 ipl 3	# artwork X0B factory settings
le*		at vme? a32 0x55900000 a16 0x4000 ipl 3
le*		at vme? a32 0x55980000 a16 0x5000 ipl 3

scsibus*	at scsi?
sd*		at scsibus?
st*		at scsibus?
cd*		at scsibus?

pseudo-device	bpfilter 1
pseudo-device	loop 1
pseudo-device	rd 1

path: sys/arch/aviion/conf/RAMDISK


code:
#	$OpenBSD: files.aviion,v 1.13 2013/10/15 01:41:46 miod Exp $
#
maxpartitions 16

device	mainbus {[addr = -1]}
attach	mainbus at root
file	arch/aviion/dev/mainbus.c

#
# On-board devices
#

device	syscon {[offset = -1]}
attach	syscon at mainbus
file	arch/aviion/dev/syscon.c			syscon needs-flag

device	nvram
attach	nvram at syscon
file	arch/aviion/dev/nvram.c				nvram needs-flag

device	dart: tty
file	dev/ic/mc68681.c
attach	dart at syscon
file	arch/aviion/dev/dart.c				dart needs-count

attach	le at syscon with le_syscon: le24, le32
file	arch/aviion/dev/if_le_syscon.c			le_syscon

attach	oaic at syscon with oaic_syscon
file	arch/aviion/dev/oaic_syscon.c			oaic_syscon

attach	oosiop at syscon with oosiop_syscon
file	arch/aviion/dev/oosiop_syscon.c			oosiop_syscon

include "scsi/files.scsi"

major	{sd = 4}
major	{st = 5}
major	{cd = 6}
major	{rd = 7}
major	{vnd = 8}

#
# VME suppport code and devices
#

device	vme {[a16 = -1], [a24 = -1], [a32 = -1], [ipl = -1]}
attach	vme at syscon
file	arch/aviion/dev/vme.c				vme	needs-flag

attach	le at vme with le_vme: le24 #, le32
file	arch/aviion/dev/if_le_vme.c			le_vme

# list of standard files
file	dev/cninit.c

file	arch/aviion/aviion/autoconf.c
file	arch/aviion/aviion/bus_space.c
file	arch/aviion/aviion/bus_dma.c
file	arch/aviion/aviion/conf.c
file	arch/aviion/aviion/db_machdep.c			ddb
file	arch/aviion/aviion/disksubr.c
file	arch/aviion/aviion/eh.S
file	arch/aviion/aviion/machdep.c
file	arch/aviion/aviion/av400_machdep.c		av400
file	arch/aviion/aviion/av530_machdep.c		av530
file	arch/aviion/aviion/av5000_machdep.c		av5000
file	arch/aviion/aviion/av6280_machdep.c		av6280
file	arch/aviion/aviion/cio_clock.c			av400 |
							av5000 | av6280
file	arch/aviion/aviion/m8820x.c			m88100
file	arch/aviion/aviion/pmap_table.c
file	arch/aviion/aviion/prom.c
file	arch/aviion/aviion/rtc_clock.c			av530


code:
/*	$OpenBSD: ld.script,v 1.2 2013/11/03 09:42:55 miod Exp $	*/

/*
 * Copyright (c) 2012 Miodrag Vallat.
 *
 * 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.
 */

OUTPUT_FORMAT("elf32-m88k")
OUTPUT_ARCH(m88k)
ENTRY(__start)
SECTIONS
{
	.text :
	{
		*(.text)
		PROVIDE(etext = ABSOLUTE(.));
	}
	. = ALIGN(0x80000);
	.rodata :
	{
		*(.rodata*)
		PROVIDE(erodata = ABSOLUTE(.));
	}
	. = ALIGN(0x80000);
	.data :
	{
		*(.data)
		PROVIDE(edata = ABSOLUTE(.));
	}
	.bss :
	{
		*(.bss)
	}
	PROVIDE(end = ABSOLUTE(.));
	/DISCARD/ :
	{
		*(.comment)
	}
}


code: src/sys/arch/aviion/dev

path: sys/arch/aviion/dev/CVS/Repository


code:
/*	$OpenBSD: dart.c,v 1.13 2013/10/17 15:46:18 miod Exp $	*/

/*
 * Copyright (c) 2006, 2013 Miodrag Vallat.
 *
 * 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.
 */
/*
 * Mach Operating System
 * Copyright (c) 1993-1991 Carnegie Mellon University
 * 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/device.h>

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

#include <dev/cons.h>

#include <machine/avcommon.h>
#include <aviion/dev/sysconvar.h>
#include <dev/ic/mc68681reg.h>
#include <dev/ic/mc68681var.h>

struct dartsoftc {
	struct mc68681_softc	sc_base;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	struct intrhand		sc_ih;
};

int	dart_match(struct device *parent, void *self, void *aux);
void	dart_attach(struct device *parent, struct device *self, void *aux);

struct cfattach dart_ca = {
	sizeof(struct dartsoftc), dart_match, dart_attach
};

/* console, if applicable, will always be on the first port */
#define	CONS_PORT	A_PORT

cons_decl(dart);
int	dartintr(void *);
uint8_t	dart_read(void *, uint);
void	dart_write(void *, uint, uint8_t);

/* early console register image */
struct mc68681_sw_reg	dartcn_sw_reg;

/*
 * DUART registers are mapped as the least-significant byte of 32-bit addresses.
 */

uint8_t
dart_read(void *v, uint reg)
{
	struct dartsoftc *sc = v;

	return (uint8_t)bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg << 2);
}

void
dart_write(void *v, uint reg, uint8_t val)
{
	struct dartsoftc *sc = v;

	bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg << 2, val);
	/*
	 * Multiple accesses to the same command register must be delayed,
	 * to prevent the chip from misbehaving.
	 */
	if (reg == DART_CRA || reg == DART_CRB)
		DELAY(2);
}

int
dart_match(struct device *parent, void *cf, void *aux)
{
	struct confargs *ca = aux;
	bus_space_handle_t ioh;
	int rc;

	/*
	 * We do not accept empty locators here...
	 */
	if (ca->ca_paddr == (paddr_t)-1)
		return (0);

	if (bus_space_map(ca->ca_iot, ca->ca_paddr, DART_SIZE << 2, 0, &ioh) !=
	    0)
		return (0);
	rc = badaddr((vaddr_t)bus_space_vaddr(ca->ca_iot, ioh), 4);
	bus_space_unmap(ca->ca_iot, ca->ca_paddr, DART_SIZE << 2);

	return (rc == 0);
}

void
dart_attach(struct device *parent, struct device *self, void *aux)
{
	struct dartsoftc *sc = (struct dartsoftc *)self;
	struct mc68681_softc *msc = &sc->sc_base;
	struct confargs *ca = aux;
	bus_space_handle_t ioh;
	u_int intsrc;

	sc->sc_iot = ca->ca_iot;
	if (bus_space_map(sc->sc_iot, ca->ca_paddr, DART_SIZE << 2, 0, &ioh) !=
	    0) {
		printf(": can't map registers!\n");
		return;
	}
	sc->sc_ioh = ioh;

	if (ca->ca_paddr == CONSOLE_DART_BASE) {
		intsrc = INTSRC_DUART1;
		msc->sc_consport = CONS_PORT;	/* XXX always for now */
		msc->sc_sw_reg = &dartcn_sw_reg;
	} else {
		intsrc = INTSRC_DUART2;
		msc->sc_sw_reg = &msc->sc_sw_reg_store;
		msc->sc_consport = -1;
	}

	msc->sc_read = dart_read;
	msc->sc_write = dart_write;

	/*
	 * Interrupt configuration.
	 *
	 * Timer interrupts are not routed anywhere, so we don't need
	 * to enable them.
	 */
	msc->sc_sw_reg->imr = 0;

	/*
	 * Input Port configuration.
	 *
	 * There is no documentation about the serial port usage
	 * of the input port in the 400 and 4600 manuals. However,
	 * the 6280 manual describes canonical assignments, which
	 * are hopefully correct on other systems:
	 *   IP0 = port A CTS
	 *   IP1 = port B CTS
	 *   IP2 = port A DCD (active low)
	 *   IP3 = port B DCD (active low)
	 */
	msc->sc_hw[A_PORT].dcd_ip = 2;
	msc->sc_hw[A_PORT].dcd_active_low = 1;
	msc->sc_hw[B_PORT].dcd_ip = 3;
	msc->sc_hw[B_PORT].dcd_active_low = 1;
	msc->sc_sw_reg->acr |=
	    DART_ACR_ISR_IP3_CHANGE_ENABLE | DART_ACR_ISR_IP2_CHANGE_ENABLE;

	/*
	 * Output Port configuration.
	 *
	 * Again, the serial bits assigments are not documented until the
	 * 6280 manual, except for the speaker connected to OP3.
	 *   OP0 = port A RTS (guessed)
	 *   OP1 = port B RTS (guessed)
	 *   OP2 = port A DTR
	 *   OP3 = speaker input or port B DTR
	 *   OP4 = speaker enable (active low)
	 *   OP5 = port B DTR if speaker on OP3
	 *   OP6 = parallel port data strobe
	 *   OP7 = parallel port selection
	 */
	msc->sc_sw_reg->opcr = DART_OPCR_OP7 | DART_OPCR_OP6 |
	    DART_OPCR_OP5 | DART_OPCR_OP4 | DART_OPCR_OP3 | DART_OPCR_OP2;
	msc->sc_hw[A_PORT].dtr_op = 2;
	msc->sc_hw[A_PORT].rts_op = 0;
	switch (cpuid) {
	case AVIION_300_310:
	case AVIION_400_4000:
	case AVIION_410_4100:
	case AVIION_300C_310C:
	case AVIION_300CD_310CD:
	case AVIION_300D_310D:
	case AVIION_4300_25:
	case AVIION_4300_20:
	case AVIION_4300_16:
		msc->sc_sw_reg->oprs |= DART_OP_OP4;	/* disable speaker */
		/* FALLTHROUGH */
	case AVIION_4600_530:
		msc->sc_hw[B_PORT].dtr_op = 5;
		msc->sc_sw_reg->oprs |= DART_OP_OP5;
		break;
	default:
		msc->sc_hw[B_PORT].dtr_op = 3;
		msc->sc_sw_reg->oprs |= DART_OP_OP3;
		break;
	}
	msc->sc_hw[B_PORT].rts_op = 1;
	msc->sc_sw_reg->oprs |= DART_OP_OP2 | DART_OP_OP1 | DART_OP_OP0;

	/*
	 * Clock configuration.
	 *
	 * We don't use any clock; the MI driver expects a counter mode
	 * to be set in this case.
	 */
	msc->sc_sw_reg->acr = DART_ACR_CT_COUNTER_CLK_16;

	mc68681_common_attach(msc);

	/* enable interrupts */
	sc->sc_ih.ih_fn = dartintr;
	sc->sc_ih.ih_arg = sc;
	sc->sc_ih.ih_flags = 0;
	sc->sc_ih.ih_ipl = IPL_TTY;

	sysconintr_establish(intsrc, &sc->sc_ih, self->dv_xname);
}

int
dartintr(void *arg)
{
	struct mc68681_softc *sc = arg;
	uint8_t isr, imr;

	isr = (*sc->sc_read)(sc, DART_ISR);
	imr = sc->sc_sw_reg->imr;

	isr &= imr;
	if (isr == 0)
		return 0;

	mc68681_intr(sc, isr);
	return 1;
}

/*
 * Console interface routines.
 */

#define	dart_cnread(reg) \
	*(volatile u_int32_t *)(CONSOLE_DART_BASE + ((reg) << 2))
#define	dart_cnwrite(reg, val) \
	*(volatile u_int32_t *)(CONSOLE_DART_BASE + ((reg) << 2)) = (val)

void
dartcnprobe(struct consdev *cp)
{
	int maj;

	if (badaddr(CONSOLE_DART_BASE, 4) != 0)
		return;

	/* locate the major number */
	for (maj = 0; maj < nchrdev; maj++)
		if (cdevsw[maj].d_open == dartopen)
			break;
	if (maj == nchrdev)
		return;

	cp->cn_dev = makedev(maj, CONS_PORT);
	cp->cn_pri = CN_LOWPRI;
}

void
dartcninit(cp)
	struct consdev *cp;
{
	dartcn_sw_reg.mr1[CONS_PORT] =
	    DART_MR1_RX_IRQ_RXRDY | DART_MR1_ERROR_CHAR |
	    DART_MR1_PARITY_NONE | DART_MR1_RX_RTR | DART_MR1_BPC_8;
	dartcn_sw_reg.mr2[CONS_PORT] =
	    DART_MR2_MODE_NORMAL | /* DART_MR2_TX_CTS | */ DART_MR2_STOP_1;
	dartcn_sw_reg.cr[CONS_PORT]  =
	    DART_CR_TX_ENABLE | DART_CR_RX_ENABLE;

	dartcn_sw_reg.acr = DART_ACR_BRG_SET_2 | DART_ACR_CT_COUNTER_CLK_16;
	dartcn_sw_reg.oprs = CONS_PORT == A_PORT ? DART_OP_OP2 | DART_OP_OP0 :
	    DART_OP_OP5 | DART_OP_OP3 | DART_OP_OP1;
	dartcn_sw_reg.opcr = DART_OPCR_RX_A;	/* XXX unconditional */
	dartcn_sw_reg.imr = DART_ISR_IP_CHANGE;

	dart_cnwrite(DART_CRA,
	    DART_CR_RESET_RX | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE);
	DELAY(2);
	dart_cnwrite(DART_CRA,
	    DART_CR_RESET_TX /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */);
	DELAY(2);
	dart_cnwrite(DART_CRA,
	    DART_CR_RESET_ERROR /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */);
	DELAY(2);
	dart_cnwrite(DART_CRA,
	    DART_CR_RESET_BREAK /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */);
	DELAY(2);
	dart_cnwrite(DART_CRA,
	    DART_CR_RESET_MR1 /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */);
	DELAY(2);

	dart_cnwrite(DART_OPRS, dartcn_sw_reg.oprs);
	dart_cnwrite(DART_OPCR, dartcn_sw_reg.opcr);

	dart_cnwrite(DART_ACR, dartcn_sw_reg.acr);

	dart_cnwrite(DART_MRA, dartcn_sw_reg.mr1[CONS_PORT]);
	dart_cnwrite(DART_MRA, dartcn_sw_reg.mr2[CONS_PORT]);
	dart_cnwrite(DART_CSRA,
	    (DART_CSR_9600 << DART_CSR_RXCLOCK_SHIFT) |
	    (DART_CSR_9600 << DART_CSR_TXCLOCK_SHIFT));
	dart_cnwrite(DART_CRA, dartcn_sw_reg.cr[CONS_PORT]);
	DELAY(2);

	dart_cnwrite(DART_IMR, dartcn_sw_reg.imr);
}

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

	s = spltty();

	/* inhibit interrupts on the chip */
	dart_cnwrite(DART_IMR, dartcn_sw_reg.imr & ~DART_ISR_TXA);
	/* make sure transmitter is enabled */
	dart_cnwrite(DART_CRA, DART_CR_TX_ENABLE);
	DELAY(2);

	while ((dart_cnread(DART_SRA) & DART_SR_TX_READY) == 0)
		;
	dart_cnwrite(DART_TBA, c);

	/* wait for transmitter to empty */
	while ((dart_cnread(DART_SRA) & DART_SR_TX_EMPTY) == 0)
		;

	/* restore the previous state */
	dart_cnwrite(DART_IMR, dartcn_sw_reg.imr);
	dart_cnwrite(DART_CRA, dartcn_sw_reg.cr[0]);
	DELAY(2);

	splx(s);
}

int
dartcngetc(dev_t dev)
{
	uint8_t sr;		/* status reg of port a/b */
	u_char c;		/* received character */
	int s;

	s = spltty();

	/* enable receiver */
	dart_cnwrite(DART_CRA, DART_CR_RX_ENABLE);
	DELAY(2);

	for (;;) {
		/* read status reg */
		sr = dart_cnread(DART_SRA);

		/* receiver interrupt handler*/
		if (sr & DART_SR_RX_READY) {
			/* read character from port */
			c = dart_cnread(DART_RBA);

			/* check break and error conditions */
			if (sr & DART_SR_BREAK) {
				dart_cnwrite(DART_CRA, DART_CR_RESET_BREAK);
				DELAY(2);
				dart_cnwrite(DART_CRA, DART_CR_RESET_ERROR);
				DELAY(2);
			} else if (sr & (DART_SR_FRAME | DART_SR_PARITY |
			    DART_SR_OVERRUN)) {
				dart_cnwrite(DART_CRA, DART_CR_RESET_ERROR);
				DELAY(2);
			} else
				break;
		}
	}
	splx(s);

	return (int)c;
}


code:
/*	$OpenBSD: dartvar.h,v 1.1.1.1 2006/05/08 18:44:10 miod Exp $	*/

/*
 * Mach Operating System
 * Copyright (c) 1993-1991 Carnegie Mellon University
 * 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.
 */

#define	NDARTPORTS	2	/* Number of ports */

struct dart_info {
	struct tty		*tty;
	u_char			dart_swflags;
};

/* saved registers */
struct dart_sv_reg {
	u_int8_t	sv_mr1[NDARTPORTS];
	u_int8_t	sv_mr2[NDARTPORTS];
	u_int8_t	sv_csr[NDARTPORTS];
	u_int8_t	sv_cr[NDARTPORTS];
	u_int8_t	sv_opr;
	u_int8_t	sv_imr;
};

struct dartsoftc {
	struct device		sc_dev;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
	struct intrhand		sc_ih;

	int			sc_console;

	struct dart_sv_reg	*sc_sv_reg;
	struct dart_sv_reg	sc_sv_reg_storage;
	struct dart_info	sc_dart[NDARTPORTS];
};

void	dart_common_attach(struct dartsoftc *);
int	dartintr(void *);

#define	DART_SIZE	0x40