code:
/*	$OpenBSD: disksubr.c,v 1.69 2015/01/16 20:17:06 miod Exp $	*/
/*	$NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk Exp $ */

/*
 * Copyright (c) 1994, 1995 Gordon W. Ross
 * Copyright (c) 1994 Theo de Raadt
 * 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. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

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

#include <dev/sun/disklabel.h>

#include "cd.h"

static	int disklabel_sun_to_bsd(struct sun_disklabel *, struct disklabel *);
static	int disklabel_bsd_to_sun(struct disklabel *, struct sun_disklabel *);
static __inline u_int sun_extended_sum(struct sun_disklabel *, void *);

#if NCD > 0
extern void cdstrategy(struct buf *);
#endif

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

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

	/*
	 * On sparc64 we check for a CD label first, because our
	 * CD install media contains both sparc & sparc64 labels.
	 * We want the sparc64 machine to find the "CD label", not
	 * the SunOS label, for loading its kernel.
	 */
#if NCD > 0
	if (strat == cdstrategy) {
#if defined(CD9660)
		if (iso_disklabelspoof(dev, strat, lp) == 0)
			goto done;
#endif
#if defined(UDF)
		if (udf_disklabelspoof(dev, strat, lp) == 0)
			goto done;
#endif
	}
#endif /* NCD > 0 */

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

	if (spoofonly)
		goto doslabel;

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

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

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

doslabel:
	error = readdoslabel(bp, strat, lp, NULL, spoofonly);
	if (error == 0)
		goto done;

	/* A CD9660/UDF label may be on a non-CD drive, so recheck */
#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);
	}
	return (error);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	lp->d_acylinders = sl->sl_acylinders;

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

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

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

	/* Check to see if there's an "extended" partition table
	 * SL_XPMAG partitions had checksums up to just before the
	 * (new) sl_types variable, while SL_XPMAGTYP partitions have
	 * checksums up to the just before the (new) sl_xxx1 variable.
	 * Also, disklabels created prior to the addition of sl_uid will
	 * have a checksum to just before the sl_uid variable.
	 */
	if ((sl->sl_xpmag == SL_XPMAG &&
	    sun_extended_sum(sl, &sl->sl_types) == sl->sl_xpsum) ||
	    (sl->sl_xpmag == SL_XPMAGTYP &&
	    sun_extended_sum(sl, &sl->sl_uid) == sl->sl_xpsum) ||
	    (sl->sl_xpmag == SL_XPMAGTYP &&
	    sun_extended_sum(sl, &sl->sl_xxx1) == sl->sl_xpsum)) {
		/*
		 * There is.  Copy over the "extended" partitions.
		 * This code parallels the loop for partitions a-h.
		 */
		for (i = 0; i < SUNXPART; i++) {
			spp = &sl->sl_xpart[i];
			npp = &lp->d_partitions[i+8];
			DL_SETPOFFSET(npp, spp->sdkp_cyloffset * secpercyl);
			DL_SETPSIZE(npp, spp->sdkp_nsectors);
			if (DL_GETPSIZE(npp) == 0) {
				npp->p_fstype = FS_UNUSED;
				continue;
			}
			npp->p_fstype = sun_fstypes[i+8];
			if (npp->p_fstype == FS_BSDFFS) {
				npp->p_fragblock =
				    DISKLABELV1_FFS_FRAGBLOCK(2048, 8);
				npp->p_cpg = 16;
			}
		}
		if (sl->sl_xpmag == SL_XPMAGTYP) {
			for (i = 0; i < MAXPARTITIONS; i++) {
				npp = &lp->d_partitions[i];
				npp->p_fstype = sl->sl_types[i];
				npp->p_fragblock = sl->sl_fragblock[i];
				npp->p_cpg = sl->sl_cpg[i];
			}
		}
	} else if (preamble->sl_nparts <= 8) {
		/*
		 * A more traditional Sun label.  Recognise certain filesystem
		 * types from it, if they are available.
		 */
		i = preamble->sl_nparts;
		if (i == 0)
			i = 8;

		npp = &lp->d_partitions[i-1];
		ppp = &preamble->sl_part[i-1];
		for (; i > 0; i--, npp--, ppp--) {
			if (npp->p_size == 0)
				continue;
			if ((ppp->spi_tag == 0) && (ppp->spi_flag == 0))
				continue;

			switch (ppp->spi_tag) {
			case SPTAG_SUNOS_ROOT:
			case SPTAG_SUNOS_USR:
			case SPTAG_SUNOS_VAR:
			case SPTAG_SUNOS_HOME:
				npp->p_fstype = FS_BSDFFS;
				npp->p_fragblock =
				    DISKLABELV1_FFS_FRAGBLOCK(2048, 8);
				npp->p_cpg = 16;
				break;
			case SPTAG_LINUX_EXT2:
				npp->p_fstype = FS_EXT2FS;
				break;
			default:
				/* FS_SWAP for _SUNOS_SWAP and _LINUX_SWAP? */
				npp->p_fstype = FS_UNUSED;
				break;
			}
		}
	}

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

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

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

	/* Format conversion. */
	bzero(sl, sizeof(*sl));
	memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname));
	sl->sl_pcylinders = lp->d_ncylinders + lp->d_acylinders; /* XXX */
	sl->sl_ncylinders = lp->d_ncylinders;
	sl->sl_acylinders = lp->d_acylinders;
	sl->sl_ntracks = lp->d_ntracks;
	sl->sl_nsectors = lp->d_nsectors;

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

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

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

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

	return (0);
}


code:
/*	$OpenBSD: emul.c,v 1.23 2014/11/16 12:30:59 deraadt Exp $	*/
/*	$NetBSD: emul.c,v 1.8 2001/06/29 23:58:40 eeh Exp $	*/

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

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/malloc.h>
#include <machine/reg.h>
#include <machine/instr.h>
#include <machine/cpu.h>
#include <machine/psl.h>
#include <uvm/uvm_extern.h>

#ifdef DEBUG_EMUL
# define DPRINTF(a) printf a
#else
# define DPRINTF(a)
#endif

#define GPR(tf, i)	((int32_t *)(u_long)&tf->tf_global)[i]
#define IPR(tf, i)	((int32_t *)(u_long)tf->tf_out[6])[i - 16]
#define FPR(p, i)	((int32_t) p->p_md.md_fpstate->fs_regs[i])
#define FPRSET(p, i, v)	p->p_md.md_fpstate->fs_regs[i] = (v)

static __inline int readgpreg(struct trapframe64 *, int, void *);
static __inline int readfpreg(struct proc *, int, void *);
static __inline int writegpreg(struct trapframe64 *, int, const void *);
static __inline int writefpreg(struct proc *, int, const void *);
static __inline int decodeaddr(struct trapframe64 *, union instr *, void *);
static int muldiv(struct trapframe64 *, union instr *, int32_t *, int32_t *,
    int32_t *);
void swap_quad(int64_t *);

#define	REGNAME(i)	"goli"[i >> 3], i & 7

static __inline int
readgpreg(tf, i, val)
	struct trapframe64 *tf;
	int i;
	void *val;
{
	int error = 0;
	if (i == 0)
		*(int32_t *) val = 0;
	else if (i < 16)
		*(int32_t *) val = GPR(tf, i);
	else
		error = copyin(&IPR(tf, i), val, sizeof(int32_t));

	return error;
}

static __inline int
writegpreg(tf, i, val)
	struct trapframe64 *tf;
	int i;
	const void *val;
{
	int error = 0;

	if (i == 0)
		return error;
	else if (i < 16)
		GPR(tf, i) = *(int32_t *) val;
	else
		/* XXX: Fix copyout prototype */
		error = copyout((caddr_t) val, &IPR(tf, i), sizeof(int32_t));

	return error;
}

static __inline int
readfpreg(p, i, val)
	struct proc *p;
	int i;
	void *val;
{
	*(int32_t *) val = FPR(p, i);
	return 0;
}

static __inline int
writefpreg(p, i, val)
	struct proc *p;
	int i;
	const void *val;
{
	FPRSET(p, i, *(const int32_t *) val);
	return 0;
}

static __inline int
decodeaddr(tf, code, val)
	struct trapframe64 *tf;
	union instr *code;
	void *val;
{
	if (code->i_simm13.i_i)
		*((int32_t *) val) = code->i_simm13.i_simm13;
	else {
		int error;

		if (code->i_asi.i_asi)
			return EINVAL;
		if ((error = readgpreg(tf, code->i_asi.i_rs2, val)) != 0)
			return error;
	}
	return 0;
}

static int
muldiv(tf, code, rd, rs1, rs2)
	struct trapframe64 *tf;
	union instr *code;
	int32_t *rd, *rs1, *rs2;
{
	/*
	 * We check for {S,U}{MUL,DIV}{,cc}
	 *
	 * [c = condition code, s = sign]
	 * Mul = 0c101s
	 * Div = 0c111s
	 */
	union {
		struct {
			unsigned unused:26;	/* padding */
			unsigned zero:1;	/* zero by opcode */
			unsigned cc:1;		/* one to send condition code */
			unsigned one1:1;	/* one by opcode */
			unsigned div:1;		/* one if divide */
			unsigned one2:1;	/* one by opcode */
			unsigned sgn:1;		/* sign bit */
		} bits;
		int num;
	} op;

	op.num = code->i_op3.i_op3;

#ifdef DEBUG_EMUL
	printf("muldiv 0x%x: %c%s%s %c%d, %c%d, ", code->i_int,
	    "us"[op.bits.sgn], op.bits.div ? "div" : "mul",
	    op.bits.cc ? "cc" : "", REGNAME(code->i_op3.i_rd),
	    REGNAME(code->i_op3.i_rs1));
	if (code->i_loadstore.i_i)
		printf("0x%x\n", *rs2);
	else
		printf("%c%d\n", REGNAME(code->i_asi.i_rs2));
#endif

	if (op.bits.div) {
		if (*rs2 == 0) {
			/*
			 * XXX: to be 100% correct here, on sunos we need to
			 *	ignore the error and return *rd = *rs1.
			 *	It should be easy to fix by passing struct
			 *	proc in here.
			 */
			DPRINTF(("muldiv: avoid zerodivide\n"));
			return EINVAL;
		}
		*rd = *rs1 / *rs2;
		DPRINTF(("muldiv: %d / %d = %d\n", *rs1, *rs2, *rd));
	}
	else {
		*rd = *rs1 * *rs2;
		DPRINTF(("muldiv: %d * %d = %d\n", *rs1, *rs2, *rd));
	}

	if (op.bits.cc) {
		/* Set condition codes */
		tf->tf_tstate &= ~(TSTATE_CCR);

		if (*rd == 0)
			tf->tf_tstate |= (u_int64_t)(ICC_Z|XCC_Z) << TSTATE_CCR_SHIFT;
		else {
			if (op.bits.sgn && *rd < 0)
				tf->tf_tstate |= (u_int64_t)(ICC_N|XCC_N) << TSTATE_CCR_SHIFT;
			if (op.bits.div) {
				if (*rd * *rs2 != *rs1)
					tf->tf_tstate |= (u_int64_t)(ICC_V|XCC_V) << TSTATE_CCR_SHIFT;
			}
			else {
				if (*rd / *rs2 != *rs1)
					tf->tf_tstate |= (u_int64_t)(ICC_V|XCC_V) << TSTATE_CCR_SHIFT;
			}
		}
	}

	return 0;
}

/*
 * Emulate unimplemented instructions on earlier sparc chips.
 */
int
emulinstr(pc, tf)
	vaddr_t pc;
	struct trapframe64 *tf;
{
	union instr code;
	int32_t rs1, rs2, rd;
	int error;

	/* fetch and check the instruction that caused the fault */
	error = copyin((caddr_t) pc, &code.i_int, sizeof(code.i_int));
	if (error != 0) {
		DPRINTF(("emulinstr: Bad instruction fetch\n"));
		return (SIGILL);
	}

	/* Only support format 2 */
	if (code.i_any.i_op != 2) {
		DPRINTF(("emulinstr: Not a format 2 instruction\n"));
		return (SIGILL);
	}

	write_user_windows();

	if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) {
		DPRINTF(("emulinstr: read rs1 %d\n", error));
		return (SIGILL);
	}

	if ((error = decodeaddr(tf, &code, &rs2)) != 0) {
		DPRINTF(("emulinstr: decode addr %d\n", error));
		return (SIGILL);
	}

	switch (code.i_op3.i_op3) {
	case IOP3_FLUSH:
/*		cpuinfo.cache_flush((caddr_t)(rs1 + rs2), 4); XXX */
		return (0);

	default:
		if ((code.i_op3.i_op3 & 0x2a) != 0xa) {
			DPRINTF(("emulinstr: Unsupported op3 0x%x\n",
			    code.i_op3.i_op3));
			return (SIGILL);
		}
		else if ((error = muldiv(tf, &code, &rd, &rs1, &rs2)) != 0)
			return (SIGFPE);
	}

	if ((error = writegpreg(tf, code.i_op3.i_rd, &rd)) != 0) {
		DPRINTF(("muldiv: write rd %d\n", error));
		return (SIGILL);
	}

	return (0);
}

#define	SIGN_EXT13(v)	(((int64_t)(v) << 51) >> 51)

void
swap_quad(int64_t *p)
{
	int64_t t;

	t = htole64(p[0]);
	p[0] = htole64(p[1]);
	p[1] = t;
}

/*
 * emulate STQF, STQFA, LDQF, and LDQFA
 */
int
emul_qf(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf)
{
	extern struct fpstate64 initfpstate;
	struct fpstate64 *fs = p->p_md.md_fpstate;
	int64_t addr, buf[2];
	union instr ins;
	int freg, isload, err;
	u_int8_t asi;

	ins.i_int = insv;
	freg = ins.i_op3.i_rd & ~1;
	freg |= (ins.i_op3.i_rd & 1) << 5;

	if (ins.i_op3.i_op3 == IOP3_LDQF || ins.i_op3.i_op3 == IOP3_LDQFA)
		isload = 1;
	else
		isload = 0;

	if (ins.i_op3.i_op3 == IOP3_STQF || ins.i_op3.i_op3 == IOP3_LDQF)
		asi = ASI_PRIMARY;
	else if (ins.i_loadstore.i_i)
		asi = (tf->tf_tstate & TSTATE_ASI) >> TSTATE_ASI_SHIFT;
	else
		asi = ins.i_asi.i_asi;

	addr = tf->tf_global[ins.i_asi.i_rs1];
	if (ins.i_loadstore.i_i)
		addr += SIGN_EXT13(ins.i_simm13.i_simm13);
	else
		addr += tf->tf_global[ins.i_asi.i_rs2];

	if (asi < ASI_PRIMARY) {
		/* privileged asi */
		KERNEL_LOCK();
		trapsignal(p, SIGILL, 0, ILL_PRVOPC, sv);
		KERNEL_UNLOCK();
		return (0);
	}
	if (asi > ASI_SECONDARY_NOFAULT_LITTLE ||
	    (asi > ASI_SECONDARY_NOFAULT && asi < ASI_PRIMARY_LITTLE)) {
		/* architecturally undefined user ASI's */
		goto segv;
	}

	if ((freg & 3) != 0) {
		/* only valid for %fN where N % 4 = 0 */
		KERNEL_LOCK();
		trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
		KERNEL_UNLOCK();
		return (0);
	}

	if ((addr & 3) != 0) {
		/* request is not aligned */
		KERNEL_LOCK();
		trapsignal(p, SIGBUS, 0, BUS_ADRALN, sv);
		KERNEL_UNLOCK();
		return (0);
	}

	fs = p->p_md.md_fpstate;
	if (fs == NULL) {
		KERNEL_LOCK();
		/* don't currently have an fpu context, get one */
		fs = malloc(sizeof(*fs), M_SUBPROC, M_WAITOK);
		*fs = initfpstate;
		fs->fs_qsize = 0;
		p->p_md.md_fpstate = fs;
		KERNEL_UNLOCK();
	} else
		fpusave_proc(p, 1);

	/* Ok, try to do the actual operation (finally) */
	if (isload) {
		err = copyin((caddr_t)addr, buf, sizeof(buf));
		if (err != 0 && (asi & 2) == 0)
			goto segv;
		if (err == 0) {
			if (asi & 8)
				swap_quad(buf);
			bcopy(buf, &fs->fs_regs[freg], sizeof(buf));
		}
	} else {
		bcopy(&fs->fs_regs[freg], buf, sizeof(buf));
		if (asi & 8)
			swap_quad(buf);
		if (copyout(buf, (caddr_t)addr, sizeof(buf)) && (asi & 2) == 0)
			goto segv;
	}

	return (1);

segv:
	KERNEL_LOCK();
	trapsignal(p, SIGSEGV, isload ? PROT_READ : PROT_WRITE,
	    SEGV_MAPERR, sv);
	KERNEL_UNLOCK();
	return (0);
}

int
emul_popc(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf)
{
	u_int64_t val, ret = 0;
	union instr ins;

	ins.i_int = insv;
	if (ins.i_simm13.i_i == 0)
		val = tf->tf_global[ins.i_asi.i_rs2];
	else
		val = SIGN_EXT13(ins.i_simm13.i_simm13);

	for (; val != 0; val >>= 1)
		ret += val & 1;

	tf->tf_global[ins.i_asi.i_rd] = ret;
	return (1);
}

license: unknown


code:
#	$OpenBSD: genassym.cf,v 1.35 2014/04/03 09:15:06 mpi Exp $
#	$NetBSD: genassym.cf,v 1.23 2001/08/08 00:09:30 eeh Exp $

#
# Copyright (c) 1997 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Christos Zoulas.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# Copyright (c) 1992, 1993
#	The Regents of the University of California.  All rights reserved.
#
# This software was developed by the Computer Systems Engineering group
# at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
# contributed to Berkeley.
#
# All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
#	This product includes software developed by the University of
#	California, Lawrence Berkeley Laboratory.
#
# 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.
#
#	@(#)genassym.c	8.1 (Berkeley) 6/11/93
#

include <sys/param.h>
include <sys/buf.h>
include <sys/proc.h>
include <sys/mbuf.h>
include <sys/msgbuf.h>
include <sys/syscall.h>
include <sys/user.h>
include <sys/device.h>
include <sys/disklabel.h>
include <sys/disk.h>

include <uvm/uvm_extern.h>

ifdef DDB
include <machine/db_machdep.h>
endif
include <machine/pmap.h>
include <machine/cpu.h>
include <machine/mutex.h>

include <machine/reg.h>

ifdef notyet
include <sparc64/dev/zsreg.h>
include <sparc64/dev/zsvar.h>
endif

ifdef notyet
include <dev/ic/am7930reg.h>
include <dev/ic/am7930var.h>
endif

# proc fields and values
struct	proc
member	p_addr
member	p_stat
member	p_wchan
member	p_vmspace
member	p_pid
member	p_cpu
member	P_FPSTATE	p_md.md_fpstate
member	P_MD_ASTPENDING	p_md.md_astpending

export	SRUN
export	SONPROC

# user structure fields
define	USIZ		sizeof(struct user)

# VM structure fields
define	VM_PMAP		offsetof(struct vmspace, vm_map.pmap)

# pmap structure fields
struct	pmap
member	pm_ctx
member	pm_segs
member	PM_PHYS		pm_physaddr

# interrupt/fault metering
struct	uvmexp		V_
member	swtch
member	INTR		intrs
member	faults

# CPU info structure
struct	cpu_info
member	ci_self
member	ci_curproc
member	ci_cpcb
member	ci_next
member	ci_fpproc
member	ci_number
member	ci_upaid
member	ci_want_resched
member	ci_handled_intr_level
member	ci_intrpending
member	ci_tickintr
member	ci_spinup
member	ci_initstack
member	ci_paddr
ifdef SUN4V
member	ci_rw
member	ci_rwsp
member	ci_mmfsa
member	ci_cpumq
member	ci_devmq
endif
ifdef DIAGNOSTIC
member	ci_mutex_level
endif

# FPU state
struct	fpstate64
member	fs_regs
member	fs_fsr
member	fs_gsr
member	fs_qsize
member	fs_queue
define	FS_SIZE		sizeof(struct fpstate64)
export	FSR_QNE
export	FPRS_FEF
export	FPRS_DU
export	FPRS_DL

# system calls
export	SYS_sigreturn
export	SYS_execve
export	SYS_exit

# errno
export	EFAULT
export	ENAMETOOLONG

# PCB fields
struct	pcb
member	pcb_nsaved
member	pcb_onfault
member	pcb_pstate
member	pcb_cwp
member	pcb_pil
member	pcb_rw
member	pcb_rwsp
member	pcb_sp
member	pcb_wcookie
member	pcb_pc
member	PCB_LASTCALL	lastcall
define	PCB_SIZE	sizeof(struct pcb)

# trapframe64 fields
struct	trapframe64
member	tf_tstate
member	tf_pc
member	tf_npc
member	tf_fault
member	tf_kstack
member	tf_y
member	tf_pil
member	tf_oldpil
member	tf_tt
member	tf_global
member	tf_out
member	tf_local
member	tf_in
# shortened versions
member	TF_G		tf_global
member	TF_O		tf_out
member	TF_L		tf_local
member	TF_I		tf_in
define	TF_SIZE		sizeof(struct trapframe64)

ifdef notyet
# clockframe fields
struct	clockframe	CF_
member	tstate
member	pc
member	npc
member	pil
member	oldpil
member	fp
endif

# interrupt handler fields
struct	intrhand
member	ih_fun
member	ih_arg
member	ih_number
member	ih_pil
member	IH_PEND		ih_pending
member	ih_next
member	ih_ack
member	IH_COUNT	ih_count.ec_count

# mbuf fields of import
struct	mbuf
member	m_next
member	m_data
member	m_len

ifdef notyet
# db_regs structure so we can save all registers
struct	db_regs
member	dbr_traps
member	dbr_y
member	dbr_tl
member	dbr_canrestore
member	dbr_cansave
member	dbr_cleanwin
member	dbr_cwp
member	dbr_wstate
member	dbr_g
member	dbr_ag
member	dbr_ig
member	dbr_mg
member	dbr_out
member	dbr_local
member	dbr_in
endif

export	TSB_TAG_LOCKED

export	SUN4U_TLB_ACCESS
export	SUN4U_TLB_MODIFY
export	SUN4U_TLB_REAL_W
export	SUN4U_TLB_EXEC
export	SUN4U_TLB_W

export	SUN4V_TLB_ACCESS
export	SUN4V_TLB_MODIFY
export	SUN4V_TLB_REAL_W
export	SUN4V_TLB_EXEC
export	SUN4V_TLB_W

struct	mutex
member	mtx_wantipl
member	mtx_oldipl
member	mtx_owner

export	CPU_SUN4U
export	CPU_SUN4V


code:
/*	$OpenBSD: hvcall.S,v 1.10 2011/06/25 20:45:00 kettenis Exp $	*/

/*
 * Copyright (c) 2008 Mark Kettenis
 *
 * 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.
 */

#include "assym.h"
#include <machine/asm.h>

#define FAST_TRAP	0x80
#define MMU_MAP_ADDR	0x83
#define MMU_UNMAP_ADDR	0x84
#define CORE_TRAP	0xff

#define MACH_EXIT		0x00
#define MACH_DESC		0x01
#define MACH_SIR		0x02
#define MACH_SET_WATCHDOG	0x05

#define CPU_START		0x10
#define CPU_STOP		0x11
#define CPU_YIELD		0x12
#define CPU_QCONF		0x14
#define CPU_QINFO		0x15
#define CPU_MYID		0x16
#define CPU_STATE		0x17
#define CPU_SET_RTBA		0x18
#define CPU_GET_RTBA		0x19

#define MMU_TSB_CTX0		0x20
#define MMU_TSB_CTXNON0		0x21
#define MMU_DEMAP_PAGE		0x22
#define MMU_DEMAP_CTX		0x23
#define MMU_DEMAP_ALL		0x24
#define MMU_MAP_PERM_ADDR	0x25
#define MMU_FAULT_AREA_CONF	0x26
#define MMU_ENABLE		0x27
#define MMU_UNMAP_PERM_ADDR	0x28
#define MMU_TSB_CTX0_INFO	0x29
#define MMU_TSB_CTXNON0_INFO	0x2a
#define MMU_FAULT_AREA_INFO	0x2b

#define MEM_SCRUB		0x30
#define MEM_SYNC		0x31

#define CPU_MONDO_SEND		0x42

#define TOD_GET			0x50
#define TOD_SET			0x51

#define CONS_GETCHAR		0x60
#define CONS_PUTCHAR		0x61

#define SOFT_STATE_SET		0x70
#define SOFT_STATE_GET		0x71

#define INTR_DEVINO2SYSINO	0xa0
#define INTR_GETENABLED		0xa1
#define INTR_SETENABLED		0xa2
#define INTR_GETSTATE		0xa3
#define INTR_SETSTATE		0xa4
#define INTR_GETTARGET		0xa5
#define INTR_SETTARGET		0xa6

#define VINTR_GETCOOKIE		0xa7
#define VINTR_SETCOOKIE		0xa8
#define VINTR_GETENABLED	0xa9
#define VINTR_SETENABLED	0xaa
#define VINTR_GETSTATE		0xab
#define VINTR_SETSTATE		0xac
#define VINTR_GETTARGET		0xad
#define VINTR_SETTARGET		0xae

#define PCI_IOMMU_MAP		0xb0
#define PCI_IOMMU_DEMAP		0xb1
#define PCI_IOMMU_GETMAP	0xb2
#define PCI_IOMMU_GETBYPASS	0xb3
#define PCI_CONFIG_GET		0xb4
#define PCI_CONFIG_PUT		0xb5

#define PCI_MSIQ_CONF		0xc0
#define PCI_MSIQ_INFO		0xc1
#define PCI_MSIQ_GETVALID	0xc2
#define PCI_MSIQ_SETVALID	0xc3
#define PCI_MSIQ_GETSTATE	0xc4
#define PCI_MSIQ_SETSTATE	0xc5
#define PCI_MSIQ_GETHEAD	0xc6
#define PCI_MSIQ_SETHEAD	0xc7
#define PCI_MSIQ_GETTAIL	0xc8
#define PCI_MSI_GETVALID	0xc9
#define PCI_MSI_SETVALID	0xca
#define PCI_MSI_GETMSIQ		0xcb
#define PCI_MSI_SETMSIQ		0xcc
#define PCI_MSI_GETSTATE	0xcd
#define PCI_MSI_SETSTATE	0xce
#define PCI_MSG_GETMSIQ		0xd0
#define PCI_MSG_SETMSIQ		0xd1
#define PCI_MSG_GETSTATE	0xd2
#define PCI_MSG_SETSTATE	0xd3

#define LDC_TX_QCONF		0xe0
#define LDC_TX_QINFO		0xe1
#define LDC_TX_GET_STATE	0xe2
#define LDC_TX_SET_QTAIL	0xe3
#define LDC_RX_QCONF		0xe4
#define LDC_RX_QINFO		0xe5
#define LDC_RX_GET_STATE	0xe6
#define LDC_RX_SET_QHEAD	0xe7

#define LDC_SET_MAP_TABLE	0xea
#define LDC_GET_MAP_TABLE	0xeb
#define LDC_COPY		0xec

#define LDC_MAPIN		0xed
#define LDC_UNMAP		0xee
#define LDC_REVOKE		0xef

#define RNG_GET_DIAG_CONTROL	0x130
#define RNG_CTL_READ		0x131
#define RNG_CTL_WRITE		0x132
#define RNG_DATA_READ_DIAG	0x133
#define RNG_DATA_READ		0x134

#define API_SET_VERSION		0x00
#define API_PUTCHAR		0x01
#define API_EXIT		0x02
#define API_GET_VERSION		0x03

ENTRY(hv_api_putchar)
	mov	API_PUTCHAR, %o5
	ta	CORE_TRAP
	retl
	 nop

ENTRY(hv_api_get_version)
	mov	%o2, %o4
	mov	%o1, %o3
	mov	API_GET_VERSION, %o5
	ta	CORE_TRAP
	stx	%o1, [%o3]
	retl
	 stx	%o2, [%o4]

ENTRY(hv_mach_desc)
	mov	%o1, %o2
	ldx	[%o2], %o1
	mov	MACH_DESC, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_cpu_yield)
	mov	CPU_YIELD, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_cpu_qconf)
	mov	CPU_QCONF, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_cpu_mondo_send)
	mov	CPU_MONDO_SEND, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_cpu_myid)
	mov	%o0, %o2
	mov	CPU_MYID, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_mmu_tsb_ctx0)
	mov	MMU_TSB_CTX0, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_mmu_tsb_ctxnon0)
	mov	MMU_TSB_CTXNON0, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_mmu_demap_page)
	mov	%o2, %o4
	mov	%o1, %o3
	mov	%o0, %o2
	clr	%o1
	clr	%o0
	mov	MMU_DEMAP_PAGE, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_mmu_demap_ctx)
	mov	%o1, %o3
	mov	%o0, %o2
	clr	%o1
	clr	%o0
	mov	MMU_DEMAP_CTX, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_mmu_demap_all)
	mov	%o1, %o3
	mov	%o0, %o2
	clr	%o1
	clr	%o0
	mov	MMU_DEMAP_CTX, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_mmu_map_perm_addr)
	mov	%o2, %o3
	mov	%o1, %o2
	clr	%o1
	mov	MMU_MAP_PERM_ADDR, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_mmu_unmap_perm_addr)
	mov	%o1, %o2
	clr	%o1
	mov	MMU_UNMAP_PERM_ADDR, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_mmu_map_addr)
	ta	MMU_MAP_ADDR
	retl
	 nop

ENTRY(hv_mmu_unmap_addr)
	ta	MMU_UNMAP_ADDR
	retl
	 nop

ENTRY(hv_mem_scrub)
	mov	MEM_SCRUB, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_mem_sync)
	mov	MEM_SYNC, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_tod_get)
	mov	%o0, %o2
	mov	TOD_GET, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_tod_set)
	mov	TOD_SET, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_cons_getchar)
	mov	%o0, %o2
	mov	CONS_GETCHAR, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_cons_putchar)
	mov	CONS_PUTCHAR, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_soft_state_set)
	mov	SOFT_STATE_SET, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_intr_devino_to_sysino)
	mov	INTR_DEVINO2SYSINO, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_intr_getenabled)
	mov	%o1, %o2
	mov	INTR_GETENABLED, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_intr_setenabled)
	mov	INTR_SETENABLED, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_intr_getstate)
	mov	%o1, %o2
	mov	INTR_GETSTATE, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_intr_setstate)
	mov	INTR_SETSTATE, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_intr_gettarget)
	mov	%o1, %o2
	mov	INTR_GETTARGET, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_intr_settarget)
	mov	INTR_SETTARGET, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_vintr_getcookie)
	mov	VINTR_GETCOOKIE, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_vintr_setcookie)
	mov	VINTR_SETCOOKIE, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_vintr_getenabled)
	mov	VINTR_GETENABLED, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_vintr_setenabled)
	mov	VINTR_SETENABLED, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_vintr_getstate)
	mov	VINTR_GETSTATE, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_vintr_setstate)
	mov	VINTR_SETSTATE, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_vintr_gettarget)
	mov	VINTR_GETTARGET, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_vintr_settarget)
	mov	VINTR_SETTARGET, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_pci_iommu_map)
	mov	%o5, %g5
	mov	PCI_IOMMU_MAP, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%g5]

ENTRY(hv_pci_iommu_demap)
	mov	PCI_IOMMU_DEMAP, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o3]

ENTRY(hv_pci_iommu_getmap)
	mov	%o2, %o4
	mov	PCI_IOMMU_GETMAP, %o5
	ta	FAST_TRAP
	stx	%o1, [%o4]
	retl
	 stx	%o2, [%o3]

ENTRY(hv_pci_iommu_getbypass)
	mov	PCI_IOMMU_GETBYPASS, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o3]

ENTRY(hv_pci_config_get)
	mov	%o5, %g5
	mov	PCI_CONFIG_GET, %o5
	ta	FAST_TRAP
	stx	%o1, [%o4]
	retl
	 stx	%o2, [%g5]

ENTRY(hv_pci_config_put)
	mov	%o5, %g5
	mov	PCI_CONFIG_PUT, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%g5]

ENTRY(hv_pci_msiq_conf)
	mov	PCI_MSIQ_CONF, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_pci_msiq_info)
	mov	%o2, %o4
	mov	PCI_MSIQ_INFO, %o5
	ta	FAST_TRAP
	stx	%o1, [%o4]
	retl
	 stx	%o2, [%o3]

ENTRY(hv_pci_msiq_getvalid)
	mov	PCI_MSIQ_GETVALID, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_pci_msiq_setvalid)
	mov	PCI_MSIQ_SETVALID, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_pci_msiq_getstate)
	mov	PCI_MSIQ_GETSTATE, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_pci_msiq_setstate)
	mov	PCI_MSIQ_SETSTATE, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_pci_msiq_gethead)
	mov	PCI_MSIQ_GETHEAD, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_pci_msiq_sethead)
	mov	PCI_MSIQ_SETHEAD, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_pci_msiq_gettail)
	mov	PCI_MSIQ_GETTAIL, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_pci_msi_getvalid)
	mov	PCI_MSI_GETVALID, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_pci_msi_setvalid)
	mov	PCI_MSI_SETVALID, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_pci_msi_getmsiq)
	mov	PCI_MSI_GETMSIQ, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_pci_msi_setmsiq)
	mov	PCI_MSI_SETMSIQ, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_pci_msi_getstate)
	mov	PCI_MSI_GETSTATE, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_pci_msi_setstate)
	mov	PCI_MSI_SETSTATE, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_pci_msg_getmsiq)
	mov	PCI_MSG_GETMSIQ, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_pci_msg_setmsiq)
	mov	PCI_MSG_SETMSIQ, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_pci_msg_getstate)
	mov	PCI_MSG_GETSTATE, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_pci_msg_setstate)
	mov	PCI_MSG_SETSTATE, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_ldc_tx_qconf)
	mov	LDC_TX_QCONF, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_ldc_tx_qinfo)
	mov	%o2, %o4
	mov	%o1, %o3
	mov	LDC_TX_QINFO, %o5
	ta	FAST_TRAP
	stx	%o1, [%o3]
	retl
	 stx	%o2, [%o4]

ENTRY(hv_ldc_tx_get_state)
	mov	%o3, %g5
	mov	%o2, %g4
	mov	%o1, %o4
	mov	LDC_TX_GET_STATE, %o5
	ta	FAST_TRAP
	stx	%o1, [%o4]
	stx	%o2, [%g4]
	retl
	 stx	%o3, [%g5]

ENTRY(hv_ldc_tx_set_qtail)
	mov	LDC_TX_SET_QTAIL, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_ldc_rx_qconf)
	mov	LDC_RX_QCONF, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_ldc_rx_qinfo)
	mov	%o2, %o4
	mov	%o1, %o3
	mov	LDC_RX_QINFO, %o5
	ta	FAST_TRAP
	stx	%o1, [%o3]
	retl
	 stx	%o2, [%o4]

ENTRY(hv_ldc_rx_get_state)
	mov	%o3, %g5
	mov	%o2, %g4
	mov	%o1, %o4
	mov	LDC_RX_GET_STATE, %o5
	ta	FAST_TRAP
	stx	%o1, [%o4]
	stx	%o2, [%g4]
	retl
	 stx	%o3, [%g5]

ENTRY(hv_ldc_rx_set_qhead)
	mov	LDC_RX_SET_QHEAD, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_ldc_set_map_table)
	mov	LDC_SET_MAP_TABLE, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_ldc_get_map_table)
	mov	%o2, %o4
	mov	%o1, %o3
	mov	LDC_GET_MAP_TABLE, %o5
	ta	FAST_TRAP
	stx	%o1, [%o3]
	retl
	 stx	%o2, [%o4]

ENTRY(hv_ldc_copy)
	mov	%o5, %g5
	mov	LDC_COPY, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%g5]

ENTRY(hv_ldc_mapin)
	mov	%o2, %o4
	mov	LDC_MAPIN, %o5
	ta	FAST_TRAP
	stx	%o1, [%o4]
	retl
	 stx	%o2, [%o3]

ENTRY(hv_ldc_unmap)
	mov	%o1, %o2
	mov	LDC_UNMAP, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_rng_get_diag_control)
	mov	RNG_GET_DIAG_CONTROL, %o5
	ta	FAST_TRAP
	retl
	 nop

ENTRY(hv_rng_ctl_read)
	mov	%o2, %o4
	mov	%o1, %o3
	mov	RNG_CTL_READ, %o5
	ta	FAST_TRAP
	stx	%o1, [%o3]
	retl
	 stx	%o2, [%o4]

ENTRY(hv_rng_ctl_write)
	mov	RNG_CTL_WRITE, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o3]

ENTRY(hv_rng_data_read_diag)
	mov	RNG_DATA_READ_DIAG, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]

ENTRY(hv_rng_data_read)
	mov	%o1, %o2
	mov	RNG_DATA_READ, %o5
	ta	FAST_TRAP
	retl
	 stx	%o1, [%o2]


code:
/*	$OpenBSD: in4_cksum.c,v 1.7 2014/08/24 20:06:57 deraadt Exp $	*/
/*	$NetBSD: in4_cksum.c,v 1.5 2003/10/13 14:22:20 agc Exp $ */

/*
 * Copyright (c) 1995 Matthew R. Green.
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, and its contributors.
 *
 * 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.
 *
 *	@(#)in_cksum.c	8.1 (Berkeley) 6/11/93
 */

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

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

#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>

extern int in_cksum_internal(struct mbuf *, int len, int offset, int sum);

int
in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len)
{
	u_char *w;
	u_int sum = 0;
	struct ipovly ipov;

	/*
	 * Declare three temporary registers for use by the asm code.  We
	 * allow the compiler to pick which specific machine registers to
	 * use, instead of hard-coding this in the asm code.
	 */
	u_int tmp1, tmp2, tmp3;

	if (nxt != 0) {
		/* pseudo header */
		memset(&ipov, 0, sizeof(ipov));
		ipov.ih_len = htons(len);
		ipov.ih_pr = nxt;
		ipov.ih_src = mtod(m, struct ip *)->ip_src;
		ipov.ih_dst = mtod(m, struct ip *)->ip_dst;
		w = (u_char *)&ipov;
		/* assumes sizeof(ipov) == 20 */
		__asm volatile(" lduw [%5 + 0], %1; "
			" lduw [%5 + 4], %2; "
			" lduw [%5 + 8], %3; add %0, %1, %0; "
			" lduw [%5 + 12], %1; add %0, %2, %0; "
			" lduw [%5 + 16], %2; add %0, %3, %0; "
			" mov -1, %3; add %0, %1, %0; "
			" srl %3, 0, %3; add %0, %2, %0; "
			" srlx %0, 32, %2; and %0, %3, %1; "
			" add %0, %2, %0; "
			: "=r" (sum), "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3)
			: "0" (sum), "r" (w));
	}

	/* skip unnecessary part */
	while (m && off > 0) {
		if (m->m_len > off)
			break;
		off -= m->m_len;
		m = m->m_next;
	}
	return (in_cksum_internal(m, len, off, sum));
}


code:
/*	$OpenBSD: in_cksum.S,v 1.2 2005/05/01 05:42:43 brad Exp $	*/
/*	$NetBSD: in_cksum.S,v 1.2 2001/08/10 20:53:11 eeh Exp $ */

/*
 * Copyright (c) 2001 Eduardo Horvath
 *
 * 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 Eduardo Horvath.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "assym.h"
#include <machine/asm.h>

/*
 * int in_cksum(struct mbuf *m, int len)
 * int in_cksum_internal(struct mbuf *m, int len, int offset, int sum)
 *
 * The only fields of the mbuf we really care about
 * is m_next and m_len and m_data.
 *
 *
 * Register usage:
 *
 *	%o0 -	mbuf
 *	%o1 -	len
 *	%o2 -	mlen
 *	%o3 -	sum
 *	%o4 -	temp
 *	%o5 -	mdata
 *	%g1 -	swapped
 *	%g4 -	temp
 *	%g5 -	temp
 */

#define	IALIGN	.align	32

ENTRY(in_cksum)
	clr	%o3		! sum = 0;
	clr	%o2
_ENTRY(_C_LABEL(in_cksum_internal))
	brz	%o0, Lfinish	! for (; m && len > 0; m->m_next) {
	 clr	%g1		! swapped = 0;
	brlez	%o1, Lfinish
	 mov	%o2, %o4	! Stash this elsewhere for a bit

	lduw	[%o0 + M_LEN], %o2	! Code duplicated at Lloop
	srlx	%o3, 32, %g4	! REDUCE bigtime
	sethi	%hi(0xffff), %g5
	ldx	[%o0 + M_DATA], %o5
	srl	%o3, 0, %o3
	or	%g5, %lo(0xffff), %g5

	sub	%o2, %o4, %o2	! Correct for initial offset
	ba,pt	%icc, 0f
	 add	%o5, %o4, %o5

	IALIGN
Lloop:
	lduw	[%o0 + M_LEN], %o2
	srlx	%o3, 32, %g4	! REDUCE bigtime
	sethi	%hi(0xffff), %g5
	ldx	[%o0 + M_DATA], %o5
	srl	%o3, 0, %o3
	or	%g5, %lo(0xffff), %g5
0:
	add	%o3, %g4, %o3
	brz	%o2, Lnext	! if (m->m_len == 0) continue;

	 cmp	%o1, %o2	! if (len < mlen)
	movl	%icc, %o1, %o2	!	mlen = len;

	btst	3, %o5		! if (!(*w & 3)) {
	bz	Lint_aligned
	 sub	%o1, %o2, %o1	! len -= mlen

	srlx	%o3, 16, %o4	! REDUCE {sum = (sum & 0xffff) + (sum >> 16);}
	and	%o3, %g5, %o3

	add	%o3, %o4, %o3
	btst	1, %o5		! if (!(*w & 3) &&
	bz	Lshort_aligned
	 nop

	deccc	%o2
	bl,a,pn	%icc, Lnext	! mlen >= 1) {
	 inc	%o2
	ldub	[%o5], %o4	! ADDBYTE {ROL; sum += *w; byte_swapped ^= 1;}
	sllx	%o3, 8, %o3	! ROL { sum = sum << 8; }
	inc	%o5		! }
	add	%o3, %o4, %o3
	xor	%g1, 1, %g1	! Flip byte_swapped

Lshort_aligned:
	btst	2, %o5		! if (!(*w & 3) &&
	bz	Lint_aligned
	 nop

	deccc	2, %o2		! mlen >= 1) {
	bl,a,pn	%icc, Lfinish_byte
	 inc	2, %o2
	lduh	[%o5], %o4	! ADDSHORT {sum += *(u_short *)w;}
	inc	2, %o5		! }
	add	%o3, %o4, %o3	! }
Lint_aligned:
	deccc	0xc, %o2	! while (mlen >= 12) {
	ble,pn	%icc, Ltoofar
	 clr	%g5
	ba,pt	%icc, 0f
	 clr	%g4
	IALIGN
0:
	lduw	[%o5 + 0x00], %o4
	add	%o3, %g4, %o3
	deccc	0xc, %o2
	lduw	[%o5 + 0x04], %g4
	add	%o3, %g5, %o3
	lduw	[%o5 + 0x08], %g5
	inc	0xc, %o5	! ADVANCE(12) }
	bg,pt	%icc, 0b
	 add	%o3, %o4, %o3
	add	%o3, %g4, %o3
	add	%o3, %g5, %o3
Ltoofar:
	inc	0xc, %o2

Ldo_int:
	deccc	4, %o2
	bl,pn	%icc, Lfinish_short
	 nop
0:
	lduw	[%o5], %o4
	inc	4, %o5
	deccc	4, %o2
	bge,pt	%icc, 0b
	 add	%o3, %o4, %o3

Lfinish_short:
	btst	2, %o2
	bz	Lfinish_byte
	 nop
	lduh	[%o5], %o4
	inc	2, %o5
	add	%o3, %o4, %o3

Lfinish_byte:
	btst	1, %o2
	bz	Lnext
	 nop
	ldub	[%o5], %o4
	sllx	%o3, 8, %o3	! ROL { sum = sum << 8; }
	inc	%o5
	xor	%g1, 1, %g1	! Flip byte_swapped
	add	%o3, %o4, %o3

Lnext:
	ldx	[%o0 + M_NEXT], %o0
Lfinish:
	srlx	%o3, 32, %o4	! Reduce to 32-bits
	srl	%o3, 0, %o3
	brz,pt	%o0, 1f		! In general there is only one mbuf
	 add	%o3, %o4, %o3
	brgz,pt	%o1, Lloop	! But usually all need to be fully checksummed
	 nop
1:
	sethi	%hi(0x0000ffff), %o5	! data ptr not needed any more

	srlx	%o3, 16, %o4
	or	%o5, %lo(0x0000ffff), %o5

	and	%o3, %o5, %o3

	add	%o3, %o4, %o3
	brz,pt	%g1, 0f		! if (byte_swapped) {
	 nop

	sllx	%o3, 8, %o3	! ROL

	srlx	%o3, 16, %o4	! REDUCE
	and	%o3, %o5, %o3

	add	%o3, %o4, %o3
0:
	subcc	%o3, %o5, %o4	! if (sum > 0xffff)
	movg	%icc, %o4, %o3	! sum -= 0xffff;

	clr	%g4		! In case we are using EMBEDANY (ick)
	retl
	 xor	%o3, %o5, %o0	! return (0xffff ^ sum);


code:
/*	$OpenBSD: intr.c,v 1.52 2014/10/05 11:40:37 dlg Exp $	*/
/*	$NetBSD: intr.c,v 1.39 2001/07/19 23:38:11 eeh Exp $ */

/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * 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 OT 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.
 *
 *	@(#)intr.c	8.3 (Berkeley) 11/11/93
 */

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

#include <dev/cons.h>

#include <machine/atomic.h>
#include <machine/cpu.h>
#include <machine/ctlreg.h>
#include <machine/instr.h>
#include <machine/trap.h>

/* Grab interrupt map stuff (what is it doing there???) */
#include <sparc64/dev/iommureg.h>

/*
 * The following array is to used by locore.s to map interrupt packets
 * to the proper IPL to send ourselves a softint.  It should be filled
 * in as the devices are probed.  We should eventually change this to a
 * vector table and call these things directly.
 */
struct intrhand *intrlev[MAXINTNUM];

void	strayintr(const struct trapframe64 *, int);
int	softintr(void *);
int	intr_handler(struct trapframe64 *, struct intrhand *);
int	intr_list_handler(void *);
void	intr_ack(struct intrhand *);

/*
 * Stray interrupt handler.  Clear it if possible.
 * If not, and if we get 10 interrupts in 10 seconds, panic.
 */
int ignore_stray = 1;
int straycnt[16];

void
strayintr(const struct trapframe64 *fp, int vectored)
{
	static int straytime, nstray;
	int timesince;
#if 0
	extern int swallow_zsintrs;
#endif

	if (fp->tf_pil < 16)
		straycnt[(int)fp->tf_pil]++;

	if (ignore_stray)
		return;

	/* If we're in polled mode ignore spurious interrupts */
	if ((fp->tf_pil == PIL_SER) /* && swallow_zsintrs */) return;

	printf("stray interrupt ipl %u pc=%llx npc=%llx pstate=%llb "
	    "vectored=%d\n", fp->tf_pil, fp->tf_pc, fp->tf_npc,
	    fp->tf_tstate >> TSTATE_PSTATE_SHIFT, PSTATE_BITS, vectored);

	timesince = time_second - straytime;
	if (timesince <= 10) {
		if (++nstray > 500)
			panic("crazy interrupts");
	} else {
		straytime = time_second;
		nstray = 1;
	}
#ifdef DDB
	Debugger();
#endif
}

int
intr_handler(struct trapframe64 *tf, struct intrhand *ih)
{
	int rc;
#ifdef MULTIPROCESSOR
	int need_lock;

	if (ih->ih_mpsafe)
		need_lock = 0;
	else
		need_lock = tf->tf_pil < PIL_SCHED && tf->tf_pil != PIL_CLOCK;

	if (need_lock)
		KERNEL_LOCK();
#endif
	rc = (*ih->ih_fun)(ih->ih_arg ? ih->ih_arg : tf);
#ifdef MULTIPROCESSOR
	if (need_lock)
		KERNEL_UNLOCK();
#endif
	return rc;
}

/*
 * Level 1 software interrupt (could also be SBus level 1 interrupt).
 * Three possible reasons:
 *	Network software interrupt
 *	Soft clock interrupt
 */

/*
 * PCI devices can share interrupts so we need to have
 * a handler to hand out interrupts.
 */
int
intr_list_handler(void *arg)
{
	struct cpu_info *ci = curcpu();
	struct intrhand *ih = arg;
	int claimed = 0, rv, ipl = ci->ci_handled_intr_level;

	while (ih) {
		sparc_wrpr(pil, ih->ih_pil, 0);
		ci->ci_handled_intr_level = ih->ih_pil;

		rv = ih->ih_fun(ih->ih_arg);
		if (rv) {
			ih->ih_count.ec_count++;
			claimed = 1;
			if (rv == 1)
				break;
		}

		ih = ih->ih_next;
	}
	sparc_wrpr(pil, ipl, 0);
	ci->ci_handled_intr_level = ipl;

	return (claimed);
}

void
intr_ack(struct intrhand *ih)
{
	*ih->ih_clr = INTCLR_IDLE;
}

/*
 * Attach an interrupt handler to the vector chain for the given level.
 * This is not possible if it has been taken away as a fast vector.
 */
void
intr_establish(int level, struct intrhand *ih)
{
	struct intrhand *q;
	u_int64_t m, id;
	int s;

	s = splhigh();

	/*
	 * This is O(N^2) for long chains, but chains are never long
	 * and we do want to preserve order.
	 */
	ih->ih_pil = level; /* XXXX caller should have done this before */
	ih->ih_pending = 0; /* XXXX caller should have done this before */
	ih->ih_next = NULL;
	if (ih->ih_clr)
		ih->ih_ack = intr_ack;
	else
		ih->ih_ack = NULL;

	/*
	 * Store in fast lookup table
	 */
#ifdef NOT_DEBUG
	if (!ih->ih_number) {
		printf("\nintr_establish: NULL vector fun %p arg %p pil %p",
			  ih->ih_fun, ih->ih_arg, ih->ih_number, ih->ih_pil);
		Debugger();
	}
#endif

	if (ih->ih_number <= 0 || ih->ih_number >= MAXINTNUM)
		panic("intr_establish: bad intr number %x", ih->ih_number);

	if (strlen(ih->ih_name) == 0)
		evcount_attach(&ih->ih_count, "unknown", NULL);
	else
		evcount_attach(&ih->ih_count, ih->ih_name, NULL);

	q = intrlev[ih->ih_number];
	if (q == NULL) {
		/* No interrupt already there, just put handler in place. */
		intrlev[ih->ih_number] = ih;
	} else {
		struct intrhand *nih, *pih;
		int ipl;

		/*
		 * Interrupt is already there.  We need to create a
		 * new interrupt handler and interpose it.
		 */
#ifdef DEBUG
		printf("intr_establish: intr reused %x\n", ih->ih_number);
#endif
		if (q->ih_fun != intr_list_handler) {
			nih = malloc(sizeof(struct intrhand),
			    M_DEVBUF, M_NOWAIT | M_ZERO);
			if (nih == NULL)
				panic("intr_establish");

			nih->ih_fun = intr_list_handler;
			nih->ih_arg = q;
			nih->ih_number = q->ih_number;
			nih->ih_pil = min(q->ih_pil, ih->ih_pil);
			nih->ih_map = q->ih_map;
			nih->ih_clr = q->ih_clr;
			nih->ih_ack = q->ih_ack;
			q->ih_ack = NULL;

			intrlev[ih->ih_number] = q = nih;
		} else
			q->ih_pil = min(q->ih_pil, ih->ih_pil);

		ih->ih_ack = NULL;

		/* Add ih to list in priority order. */
		pih = q;
		nih = pih->ih_arg;
		ipl = nih->ih_pil;
		while (nih && ih->ih_pil <= nih->ih_pil) {
			ipl = nih->ih_pil;
			pih = nih;
			nih = nih->ih_next;
		}
#if DEBUG
		printf("intr_establish: inserting pri %i after %i\n",
		    ih->ih_pil, ipl);
#endif
		if (pih == q) {
			ih->ih_next = pih->ih_arg;
			pih->ih_arg = ih;
		} else {
			ih->ih_next = pih->ih_next;
			pih->ih_next = ih;
		}
	}

	if (ih->ih_clr != NULL)			/* Set interrupt to idle */
		*ih->ih_clr = INTCLR_IDLE;

	if (ih->ih_map) {
		id = CPU_UPAID;
		m = *ih->ih_map;
		if (INTTID(m) != id) {
#ifdef DEBUG
			printf("\nintr_establish: changing map 0x%llx -> ", m);
#endif
			m = (m & ~INTMAP_TID) | (id << INTTID_SHIFT);
#ifdef DEBUG
			printf("0x%llx (id=%llx) ", m, id);
#endif
		}
		m |= INTMAP_V;
		*ih->ih_map = m;
	}

#ifdef DEBUG
	printf("\nintr_establish: vector %x pil %x mapintr %p "
	    "clrintr %p fun %p arg %p target %d",
	    ih->ih_number, ih->ih_pil, (void *)ih->ih_map,
	    (void *)ih->ih_clr, (void *)ih->ih_fun,
	    (void *)ih->ih_arg, (int)(ih->ih_map ? INTTID(*ih->ih_map) : -1));
#endif

	splx(s);
}

void *
softintr_establish(int level, void (*fun)(void *), void *arg)
{
	struct intrhand *ih;

	if (level == IPL_TTY)
		level = IPL_SOFTTTY;

	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK | M_ZERO);
	ih->ih_fun = (int (*)(void *))fun;	/* XXX */
	ih->ih_arg = arg;
	ih->ih_pil = level;
	ih->ih_pending = 0;
	ih->ih_ack = NULL;
	ih->ih_clr = NULL;
	return (ih);
}

void
softintr_disestablish(void *cookie)
{
	struct intrhand *ih = cookie;

	free(ih, M_DEVBUF, sizeof(*ih));
}

void
softintr_schedule(void *cookie)
{
	struct intrhand *ih = cookie;

	send_softint(-1, ih->ih_pil, ih);
}

#ifdef DIAGNOSTIC
void
splassert_check(int wantipl, const char *func)
{
	struct cpu_info *ci = curcpu();
	int oldipl;

	__asm volatile("rdpr %%pil,%0" : "=r" (oldipl));

	if (oldipl < wantipl) {
		splassert_fail(wantipl, oldipl, func);
	}

	if (ci->ci_handled_intr_level > wantipl) {
		/*
		 * XXX - need to show difference between what's blocked and
		 * what's running.
		 */
		splassert_fail(wantipl, ci->ci_handled_intr_level, func);
	}
}
#endif


code:
/*	$OpenBSD: intreg.h,v 1.3 2003/06/02 23:27:56 millert Exp $	*/
/*	$NetBSD: intreg.h,v 1.4 2000/06/24 04:21:05 eeh Exp $ */

/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * 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.
 *
 *	@(#)intreg.h	8.1 (Berkeley) 6/11/93
 */

/*
 * All sun4u interrupts arrive as interrupt packets.  These packets
 * consist of up to six (three on spitfires) quads.  The first one
 * contains the interrupt number.  This is either the device ID
 * or a pointer to the handler routine.
 *
 * Device IDs are split into two parts: a 5-bit interrupt group number
 * and a 5-bit interrupt number.  We ignore this distinction.
 *
 */
#define MAXINTNUM	(1<<11)

#ifndef _LOCORE
struct intrhand;	/* This is in cpu.h if you need it. */
void	send_softint(int cpu, int level, struct intrhand *ih);
#endif


code:
/*	$OpenBSD: ipifuncs.c,v 1.15 2014/05/10 12:29:58 kettenis Exp $	*/
/*	$NetBSD: ipifuncs.c,v 1.8 2006/10/07 18:11:36 rjs Exp $ */

/*-
 * Copyright (c) 2004 The NetBSD Foundation, Inc.
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

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

#include <uvm/uvm_extern.h>

#include <machine/cpu.h>
#include <machine/ctlreg.h>
#include <machine/hypervisor.h>
#include <machine/pmap.h>
#include <machine/sparc64.h>

extern int db_active;

#define SPARC64_IPI_RETRIES	10000

#define	sparc64_ipi_sleep()	delay(1000)

void	sun4u_send_ipi(int, void (*)(void), u_int64_t, u_int64_t);
void	sun4u_broadcast_ipi(void (*)(void), u_int64_t, u_int64_t);
void	sun4v_send_ipi(int, void (*)(void), u_int64_t, u_int64_t);
void	sun4v_broadcast_ipi(void (*)(void), u_int64_t, u_int64_t);

/*
 * These are the "function" entry points in locore.s to handle IPI's.
 */
void	sun4u_ipi_tlb_page_demap(void);
void	sun4u_ipi_tlb_context_demap(void);
void	sun4v_ipi_tlb_page_demap(void);
void	sun4v_ipi_tlb_context_demap(void);
void	ipi_softint(void);

/*
 * Send an interprocessor interrupt.
 */
void
sparc64_send_ipi(int itid, void (*func)(void), u_int64_t arg0, u_int64_t arg1)
{
	if (CPU_ISSUN4V)
		sun4v_send_ipi(itid, func, arg0, arg1);
	else
		sun4u_send_ipi(itid, func, arg0, arg1);
}

void
sun4u_send_ipi(int itid, void (*func)(void), u_int64_t arg0, u_int64_t arg1)
{
	int i, j, shift = 0;

	KASSERT((u_int64_t)func > MAXINTNUM);

	/*
	 * UltraSPARC-IIIi CPUs select the BUSY/NACK pair based on the
	 * lower two bits of the ITID.
	 */
	if (((getver() & VER_IMPL) >> VER_IMPL_SHIFT) == IMPL_JALAPENO)
		shift = (itid & 0x3) * 2;

	if (ldxa(0, ASR_IDSR) & (IDSR_BUSY << shift)) {
		__asm volatile("ta 1; nop");
	}

	/* Schedule an interrupt. */
	for (i = 0; i < SPARC64_IPI_RETRIES; i++) {
		u_int64_t s = intr_disable();

		stxa(IDDR_0H, ASI_INTERRUPT_DISPATCH, (u_int64_t)func);
		stxa(IDDR_1H, ASI_INTERRUPT_DISPATCH, arg0);
		stxa(IDDR_2H, ASI_INTERRUPT_DISPATCH, arg1);
		stxa(IDCR(itid), ASI_INTERRUPT_DISPATCH, 0);
		membar(Sync);

		for (j = 0; j < 1000000; j++) {
			if (ldxa(0, ASR_IDSR) & (IDSR_BUSY << shift))
				continue;
			else
				break;
		}
		intr_restore(s);

		if (j == 1000000)
			break;

		if ((ldxa(0, ASR_IDSR) & (IDSR_NACK << shift)) == 0)
			return;
	}

#if 1
	if (db_active || panicstr != NULL)
		printf("ipi_send: couldn't send ipi to module %u\n", itid);
	else
		panic("ipi_send: couldn't send ipi");
#else
	__asm volatile("ta 1; nop" : :);
#endif
}

void
sun4v_send_ipi(int itid, void (*func)(void), u_int64_t arg0, u_int64_t arg1)
{
	struct cpu_info *ci = curcpu();
	int err, i;

	stha(ci->ci_cpuset, ASI_PHYS_CACHED, itid);
	stxa(ci->ci_mondo, ASI_PHYS_CACHED, (vaddr_t)func);
	stxa(ci->ci_mondo + 8, ASI_PHYS_CACHED, arg0);
	stxa(ci->ci_mondo + 16, ASI_PHYS_CACHED, arg1);

	for (i = 0; i < SPARC64_IPI_RETRIES; i++) {
		err = hv_cpu_mondo_send(1, ci->ci_cpuset, ci->ci_mondo);
		if (err != H_EWOULDBLOCK)
			break;
		delay(10);
	}
	if (err != H_EOK)
		panic("Unable to send mondo %llx to cpu %d: %d",
		    (u_int64_t)func, itid, err);
}

/*
 * Broadcast an IPI to all but ourselves.
 */
void
sparc64_broadcast_ipi(void (*func)(void), u_int64_t arg0, u_int64_t arg1)
{
	if (CPU_ISSUN4V)
		sun4v_broadcast_ipi(func, arg0, arg1);
	else
		sun4u_broadcast_ipi(func, arg0, arg1);
}

void
sun4u_broadcast_ipi(void (*func)(void), u_int64_t arg0, u_int64_t arg1)
{
	struct cpu_info *ci;

	for (ci = cpus; ci != NULL; ci = ci->ci_next) {
		if (ci->ci_number == cpu_number())
			continue;
		if ((ci->ci_flags & CPUF_RUNNING) == 0)
			continue;
		sun4u_send_ipi(ci->ci_itid, func, arg0, arg1);
	}
}

void
sun4v_broadcast_ipi(void (*func)(void), u_int64_t arg0, u_int64_t arg1)
{
	struct cpu_info *ci = curcpu();
	paddr_t cpuset = ci->ci_cpuset;
	int err, i, ncpus = 0;

	for (ci = cpus; ci != NULL; ci = ci->ci_next) {
		if (ci->ci_number == cpu_number())
			continue;
		if ((ci->ci_flags & CPUF_RUNNING) == 0)
			continue;
		stha(cpuset, ASI_PHYS_CACHED, ci->ci_itid);
		cpuset += sizeof(int16_t);
		ncpus++;
	}

	if (ncpus == 0)
		return;

	ci = curcpu();
	stxa(ci->ci_mondo, ASI_PHYS_CACHED, (vaddr_t)func);
	stxa(ci->ci_mondo + 8, ASI_PHYS_CACHED, arg0);
	stxa(ci->ci_mondo + 16, ASI_PHYS_CACHED, arg1);

	for (i = 0; i < SPARC64_IPI_RETRIES; i++) {
		err = hv_cpu_mondo_send(ncpus, ci->ci_cpuset, ci->ci_mondo);
		if (err != H_EWOULDBLOCK)
			break;
		delay(10);
	}
	if (err != H_EOK)
		panic("Unable to broadcast mondo %llx: %d",
		    (u_int64_t)func, err);
}

void
smp_tlb_flush_pte(vaddr_t va, int ctx)
{
	sp_tlb_flush_pte(va, ctx);

	if (db_active)
		return;

	if (CPU_ISSUN4V)
		sun4v_broadcast_ipi(sun4v_ipi_tlb_page_demap, va, ctx);
	else
		sun4u_broadcast_ipi(sun4u_ipi_tlb_page_demap, va, ctx);
}

void
smp_tlb_flush_ctx(int ctx)
{
	sp_tlb_flush_ctx(ctx);

	if (db_active)
		return;

	if (CPU_ISSUN4V)
		sun4v_broadcast_ipi(sun4v_ipi_tlb_context_demap, ctx, 0);
	else
		sun4u_broadcast_ipi(sun4u_ipi_tlb_context_demap, ctx, 0);
}

void
cpu_unidle(struct cpu_info *ci)
{
	if (ci == curcpu() || db_active || ((ci->ci_flags & CPUF_RUNNING) == 0))
		return;

	if (CPU_ISSUN4V)
		sun4v_send_ipi(ci->ci_itid, ipi_softint, 1 << IPL_SOFTINT, 0);
	else
		sun4u_send_ipi(ci->ci_itid, ipi_softint, 1 << IPL_SOFTINT, 0);
}


code:
/*	$OpenBSD: lock_machdep.c,v 1.10 2015/06/25 00:53:19 dlg Exp $	*/

/*
 * Copyright (c) 2007 Artur Grabowski <art@openbsd.org>
 *
 * 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.
 */

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

#include <machine/lock.h>
#include <machine/psl.h>

#include <ddb/db_output.h>

void
__mp_lock_init(struct __mp_lock *mpl)
{
	memset(mpl->mpl_cpus, 0, sizeof(mpl->mpl_cpus));
	mpl->mpl_users = 0;
	mpl->mpl_ticket = 1;
}

#if defined(MP_LOCKDEBUG)
#ifndef DDB
#error "MP_LOCKDEBUG requires DDB"
#endif

/* CPU-dependent timing, needs this to be settable from ddb. */
extern int __mp_lock_spinout;
#endif

/*
 * On processors with multiple threads we force a thread switch.
 *
 * On UltraSPARC T2 and its successors, the optimal way to do this
 * seems to be to do three nop reads of %ccr.  This works on
 * UltraSPARC T1 as well, even though three nop casx operations seem
 * to be slightly more optimal.  Since these instructions are
 * effectively nops, executing them on earlier non-CMT processors is
 * harmless, so we make this the default.
 *
 * On SPARC T4 and later, we can use the processor-specific pause
 * instruction.
 *
 * On SPARC64 VI and its successors we execute the processor-specific
 * sleep instruction.
 */
static __inline void
__mp_lock_spin_hook(void)
{
	__asm volatile(
		"999:	rd	%%ccr, %%g0			\n"
		"	rd	%%ccr, %%g0			\n"
		"	rd	%%ccr, %%g0			\n"
		"	.section .sun4v_pause_patch, \"ax\"	\n"
		"	.word	999b				\n"
		"	.word	0xb7802080	! pause	128	\n"
		"	.word	999b + 4			\n"
		"	nop					\n"
		"	.word	999b + 8			\n"
		"	nop					\n"
		"	.previous				\n"
		"	.section .sun4u_mtp_patch, \"ax\"	\n"
		"	.word	999b				\n"
		"	.word	0x81b01060	! sleep		\n"
		"	.word	999b + 4			\n"
		"	nop					\n"
		"	.word	999b + 8			\n"
		"	nop					\n"
		"	.previous				\n"
		: : : "memory");
}

#define SPINLOCK_SPIN_HOOK __mp_lock_spin_hook()

static __inline void
__mp_lock_spin(struct __mp_lock *mpl, u_int me)
{
#ifndef MP_LOCKDEBUG
	while (mpl->mpl_ticket != me)
		SPINLOCK_SPIN_HOOK;
#else
	int ticks = __mp_lock_spinout;

	while (mpl->mpl_ticket != me && --ticks > 0)
		SPINLOCK_SPIN_HOOK;

	if (ticks == 0) {
		db_printf("__mp_lock(%p): lock spun out", mpl);
		Debugger();
	}
#endif
}

void
__mp_lock(struct __mp_lock *mpl)
{
	struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()];
	u_int64_t s;

	s = intr_disable();
	if (cpu->mplc_depth++ == 0)
		cpu->mplc_ticket = atomic_inc_int_nv(&mpl->mpl_users);
	intr_restore(s);

	__mp_lock_spin(mpl, cpu->mplc_ticket);
	sparc_membar(LoadLoad | LoadStore);
}

void
__mp_unlock(struct __mp_lock *mpl)
{
	struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()];
	u_int64_t s;

	s = intr_disable();
	if (--cpu->mplc_depth == 0) {
		mpl->mpl_ticket++;
		sparc_membar(StoreStore | LoadStore);
	}
	intr_restore(s);
}

int
__mp_release_all(struct __mp_lock *mpl)
{
	struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()];
	u_int64_t s;
	int rv;

	s = intr_disable();
	rv = cpu->mplc_depth;
	cpu->mplc_depth = 0;
	mpl->mpl_ticket++;
	sparc_membar(StoreStore | LoadStore);
	intr_restore(s);

	return (rv);
}

int
__mp_release_all_but_one(struct __mp_lock *mpl)
{
	struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()];
	u_int64_t s;
	int rv;

	s = intr_disable();
	rv = cpu->mplc_depth;
	cpu->mplc_depth = 1;
	intr_restore(s);

	return (rv - 1);
}

void
__mp_acquire_count(struct __mp_lock *mpl, int count)
{
	while (count--)
		__mp_lock(mpl);
}

int
__mp_lock_held(struct __mp_lock *mpl)
{
	struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()];

	return (cpu->mplc_ticket == mpl->mpl_ticket && cpu->mplc_depth > 0);
}