code:
/*	$OpenBSD: sgmap.c,v 1.10 2008/09/30 20:00:29 miod Exp $	*/
/* $NetBSD: sgmap.c,v 1.8 2000/06/29 07:14:34 mrg Exp $ */

/*-
 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
 * NASA Ames Research Center.
 *
 * 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/kernel.h>
#include <sys/proc.h>
#include <sys/malloc.h>

#include <uvm/uvm_extern.h>

#include <machine/bus.h>
#include <machine/sgmap.h>

void
vax_sgmap_init(t, sgmap, name, sgvabase, sgvasize, ptva, minptalign)
	bus_dma_tag_t t;
	struct vax_sgmap *sgmap;
	const char *name;
	bus_addr_t sgvabase;
	bus_size_t sgvasize;
	pt_entry_t *ptva;
	bus_size_t minptalign;
{
	bus_dma_segment_t seg;
	size_t ptsize;
	int rseg;

	if (sgvasize & PGOFSET) {
		printf("size botch for sgmap `%s'\n", name);
		goto die;
	}

	sgmap->aps_sgvabase = sgvabase;
	sgmap->aps_sgvasize = sgvasize;

	if (ptva != NULL) {
		/*
		 * We already have a page table; this may be a system
		 * where the page table resides in bridge-resident SRAM.
		 */
		sgmap->aps_pt = ptva;
	} else {
		/*
		 * Compute the page table size and allocate it.  At minimum,
		 * this must be aligned to the page table size.  However,
		 * some platforms have more strict alignment reqirements.
		 */
		ptsize = (sgvasize / VAX_NBPG) * sizeof(pt_entry_t);
		if (minptalign != 0) {
			if (minptalign < ptsize)
				minptalign = ptsize;
		} else
			minptalign = ptsize;
		if (bus_dmamem_alloc(t, ptsize, minptalign, 0, &seg, 1, &rseg,
		    BUS_DMA_NOWAIT)) {
			panic("unable to allocate page table for sgmap `%s'",
			    name);
			goto die;
		}
		sgmap->aps_pt = (pt_entry_t *)(seg.ds_addr | KERNBASE);
	}

	/*
	 * Create the extent map used to manage the virtual address
	 * space.
	 */
	sgmap->aps_ex = extent_create((char *)name, sgvabase, sgvasize - 1,
	    M_DEVBUF, NULL, 0, EX_NOWAIT|EX_NOCOALESCE);
	if (sgmap->aps_ex == NULL) {
		printf("unable to create extent map for sgmap `%s'\n", name);
		goto die;
	}

	return;
 die:
	panic("vax_sgmap_init");
}

int
vax_sgmap_alloc(map, origlen, sgmap, flags)
	bus_dmamap_t map;
	bus_size_t origlen;
	struct vax_sgmap *sgmap;
	int flags;
{
	int error;
	bus_size_t len = origlen;

#ifdef DIAGNOSTIC
	if (map->_dm_flags & DMAMAP_HAS_SGMAP)
		panic("vax_sgmap_alloc: already have sgva space");
#endif

	/* If we need a spill page (for the VS4000 SCSI), make sure we
	 * allocate enough space for an extra page.
	 */
	if (flags & VAX_BUS_DMA_SPILLPAGE) {
		len += VAX_NBPG;
	}

	map->_dm_sgvalen = vax_round_page(len);
#if 0
	printf("len %x -> %x, _dm_sgvalen %x _dm_boundary %x boundary %x -> ",
	    origlen, len, map->_dm_sgvalen, map->_dm_boundary, boundary);
#endif

	error = extent_alloc(sgmap->aps_ex, map->_dm_sgvalen, VAX_NBPG, 0,
	    0, (flags & BUS_DMA_NOWAIT) ? EX_NOWAIT : EX_WAITOK,
	    &map->_dm_sgva);
#if 0
	printf("error %d _dm_sgva %x\n", error, map->_dm_sgva);
#endif

	if (error == 0)
		map->_dm_flags |= DMAMAP_HAS_SGMAP;
	else
		map->_dm_flags &= ~DMAMAP_HAS_SGMAP;

	return (error);
}

void
vax_sgmap_free(map, sgmap)
	bus_dmamap_t map;
	struct vax_sgmap *sgmap;
{

#ifdef DIAGNOSTIC
	if ((map->_dm_flags & DMAMAP_HAS_SGMAP) == 0)
		panic("vax_sgmap_free: no sgva space to free");
#endif

	if (extent_free(sgmap->aps_ex, map->_dm_sgva, map->_dm_sgvalen,
	    EX_NOWAIT))
		panic("vax_sgmap_free");

	map->_dm_flags &= ~DMAMAP_HAS_SGMAP;
}

int
vax_sgmap_load(t, map, buf, buflen, p, flags, sgmap)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	void *buf;
	bus_size_t buflen;
	struct proc *p;
	int flags;
	struct vax_sgmap *sgmap;
{
	vaddr_t endva, va = (vaddr_t)buf;
	paddr_t pa;
	bus_addr_t dmaoffset;
	bus_size_t dmalen;
	long *pte, *page_table = (long *)sgmap->aps_pt;
	int pteidx, error;
	struct pmap *pmap;

	if (p != NULL)
		pmap = p->p_vmspace->vm_map.pmap;
	else
		pmap = pmap_kernel();

	/*
	 * Make sure that on error condition we return "no valid mappings".
	 */
	map->dm_mapsize = 0;
	map->dm_nsegs = 0;

	if (buflen > map->_dm_size)
		return (EINVAL);

	/*
	 * Remember the offset into the first page and the total
	 * transfer length.
	 */
	dmaoffset = ((u_long)buf) & VAX_PGOFSET;
	dmalen = buflen;

	/*
	 * Allocate the necessary virtual address space for the
	 * mapping.  Round the size, since we deal with whole pages.
	 */
	endva = vax_round_page(va + buflen);
	va = vax_trunc_page(va);
	if ((map->_dm_flags & DMAMAP_HAS_SGMAP) == 0) {
		error = vax_sgmap_alloc(map, (endva - va), sgmap, flags);
		if (error)
			return (error);
	}

	pteidx = map->_dm_sgva >> VAX_PGSHIFT;
	pte = &page_table[pteidx];

	/*
	 * Generate the DMA address.
	 */
	map->dm_segs[0].ds_addr = map->_dm_sgva + dmaoffset;
	map->dm_segs[0].ds_len = dmalen;

	map->_dm_pteidx = pteidx;
	map->_dm_ptecnt = 0;

	/*
	 * Create the bus-specific page tables.
	 * Can be done much more efficient than this.
	 */
	for (; va < endva; va += VAX_NBPG, pte++, map->_dm_ptecnt++) {
		/*
		 * Get the physical address for this segment.
		 */
		(void)pmap_extract(pmap, va, &pa);

		/*
		 * Load the current PTE with this page.
		 */
		*pte = (pa >> VAX_PGSHIFT) | PG_V;
	}
	/* The VS4000 SCSI prefetcher doesn't like to end on a page boundary
	 * so add an extra page to quiet it down.
	 */
	if (flags & VAX_BUS_DMA_SPILLPAGE) {
		*pte = pte[-1];
		map->_dm_ptecnt++;
	}

	map->dm_mapsize = buflen;
	map->dm_nsegs = 1;
	return (0);
}

int
vax_sgmap_load_mbuf(t, map, m, flags, sgmap)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	struct mbuf *m;
	int flags;
	struct vax_sgmap *sgmap;
{

	panic("vax_sgmap_load_mbuf : not implemented");
}

int
vax_sgmap_load_uio(t, map, uio, flags, sgmap)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	struct uio *uio;
	int flags;
	struct vax_sgmap *sgmap;
{

	panic("vax_sgmap_load_uio : not implemented");
}

int
vax_sgmap_load_raw(t, map, segs, nsegs, size, flags, sgmap)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	bus_dma_segment_t *segs;
	int nsegs;
	bus_size_t size;
	int flags;
	struct vax_sgmap *sgmap;
{

	panic("vax_sgmap_load_raw : not implemented");
}

void
vax_sgmap_unload(t, map, sgmap)
	bus_dma_tag_t t;
	bus_dmamap_t map;
	struct vax_sgmap *sgmap;
{
	long *pte, *page_table = (long *)sgmap->aps_pt;
	int ptecnt;

	/*
	 * Invalidate the PTEs for the mapping.
	 */
	for (ptecnt = map->_dm_ptecnt, pte = &page_table[map->_dm_pteidx];
		ptecnt-- != 0; ) {
		*pte++ = 0;
	}

	/*
	 * Free the virtual address space used by the mapping
	 * if necessary.
	 */
	if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
		vax_sgmap_free(map, sgmap);
	/*
	 * Mark the mapping invalid.
	 */
	map->dm_mapsize = 0;
	map->dm_nsegs = 0;
}


code:
/*	$OpenBSD: softintr.c,v 1.5 2014/12/23 21:39:12 miod Exp $	*/
/*	$NetBSD: softintr.c,v 1.2 2003/07/15 00:24:39 lukem Exp $	*/

/*
 * Copyright (c) 2001 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
 *
 * 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 for the NetBSD Project by
 *	Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
 * 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/mutex.h>
#include <sys/malloc.h>

#include <uvm/uvm_extern.h>

#include <machine/atomic.h>
#include <machine/intr.h>
#include <machine/mtpr.h>

void	softintr_dispatch(void);

struct soft_intrq soft_intrq[SI_NQUEUES];

struct soft_intrhand *softnet_intrhand;

void	netintr(void);

/*
 * Initialize the software interrupt system.
 */
void
softintr_init(void)
{
	struct soft_intrq *siq;
	int i;

	for (i = 0; i < SI_NQUEUES; i++) {
		siq = &soft_intrq[i];
		TAILQ_INIT(&siq->siq_list);
		siq->siq_si = IPL_SOFT + i;
		mtx_init(&siq->siq_mtx, IPL_HIGH);
	}

	/* XXX Establish legacy software interrupt handlers. */
	softnet_intrhand = softintr_establish(IPL_SOFTNET,
	    (void (*)(void *))netintr, NULL);
}

/*
 * Process pending software interrupts.  The corresponding queue is
 * computed from the current interrupt level.
 */
void
softintr_dispatch()
{
	struct soft_intrq *siq;
	struct soft_intrhand *sih;
	int si;

	si = mfpr(PR_IPL) - IPL_SOFT;
	siq = &soft_intrq[si];

	for (;;) {
		mtx_enter(&siq->siq_mtx);
		sih = TAILQ_FIRST(&siq->siq_list);
		if (sih == NULL) {
			mtx_leave(&siq->siq_mtx);
			break;
		}

		TAILQ_REMOVE(&siq->siq_list, sih, sih_list);
		sih->sih_pending = 0;

		uvmexp.softs++;

		mtx_leave(&siq->siq_mtx);

		(*sih->sih_func)(sih->sih_arg);
	}
}

/*
 * Register a software interrupt handler.
 */
void *
softintr_establish(int ipl, void (*func)(void *), void *arg)
{
	struct soft_intrhand *sih;
	int si;

	si = ipl - IPL_SOFT;
	if (si < 0 || si > SI_NQUEUES) {
		printf("softintr_establish: unknown soft IPL %d\n", ipl);
		return NULL;
	}

	sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT);
	if (__predict_true(sih != NULL)) {
		sih->sih_func = func;
		sih->sih_arg = arg;
		sih->sih_siq = &soft_intrq[si];
		sih->sih_pending = 0;
	}
	return (sih);
}

/*
 * Unregister a software interrupt handler.
 */
void
softintr_disestablish(void *arg)
{
	struct soft_intrhand *sih = arg;
	struct soft_intrq *siq = sih->sih_siq;

	mtx_enter(&siq->siq_mtx);
	if (sih->sih_pending) {
		TAILQ_REMOVE(&siq->siq_list, sih, sih_list);
		sih->sih_pending = 0;
	}
	mtx_leave(&siq->siq_mtx);

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

/*
 * Schedule a software interrupt.
 */
void
softintr_schedule(void *arg)
{
	struct soft_intrhand *sih = (struct soft_intrhand *)arg;
	struct soft_intrq *siq = sih->sih_siq;

	mtx_enter(&siq->siq_mtx);
	if (sih->sih_pending == 0) {
		TAILQ_INSERT_TAIL(&siq->siq_list, sih, sih_list);
		sih->sih_pending = 1;
		mtpr(siq->siq_si, PR_SIRR);
	}
	mtx_leave(&siq->siq_mtx);
}

license: unknown


code:
/*	$OpenBSD: trap.c,v 1.55 2015/01/20 19:43:21 kettenis Exp $     */
/*	$NetBSD: trap.c,v 1.47 1999/08/21 19:26:20 matt Exp $     */
/*
 * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
 * 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 at Ludd, University of Lule}.
 * 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.
 */

 /* All bugs are subject to removal without further notice */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/syscall.h>
#include <sys/syscall_mi.h>
#include <sys/systm.h>
#include <sys/signalvar.h>
#include <sys/exec.h>

#include <uvm/uvm_extern.h>

#include <machine/mtpr.h>
#include <machine/pte.h>
#include <machine/pcb.h>
#include <machine/trap.h>
#include <machine/pmap.h>
#include <machine/cpu.h>

#ifdef DDB
#include <machine/db_machdep.h>
#endif
#include <kern/syscalls.c>

#ifdef TRAPDEBUG
volatile int startsysc = 0, faultdebug = 0;
#endif

void	arithflt(struct trapframe *);
void	syscall(struct trapframe *);

char *traptypes[]={
	"reserved addressing",
	"privileged instruction",
	"reserved operand",
	"breakpoint instruction",
	"XFC instruction",
	"system call ",
	"arithmetic trap",
	"asynchronous system trap",
	"page table length fault",
	"translation violation fault",
	"trace trap",
	"compatibility mode fault",
	"access violation fault",
	"",
	"",
	"KSP invalid",
	"",
	"kernel debugger trap"
};
int no_traps = 18;

#define USERMODE(framep)   ((((framep)->psl) & (PSL_U)) == PSL_U)
#define FAULTCHK						\
	do if (p->p_addr->u_pcb.iftrap) {			\
		frame->pc = (unsigned)p->p_addr->u_pcb.iftrap;	\
		frame->psl &= ~PSL_FPD;				\
		frame->r0 = EFAULT;				\
		return;						\
	} while (0)

void
arithflt(frame)
	struct trapframe *frame;
{
	u_int	sig = 0, type = frame->trap, trapsig = 1;
	u_int	rv, addr, umode;
	struct	proc *p = curproc;
	struct vm_map *map;
	vm_prot_t ftype;
	int typ;
	union sigval sv;

	sv.sival_int = frame->pc;
	uvmexp.traps++;
	if ((umode = USERMODE(frame))) {
		type |= T_USER;
		p->p_addr->u_pcb.framep = frame;
		refreshcreds(p);
	}

	type&=~(T_WRITE|T_PTEFETCH);

#ifdef TRAPDEBUG
if(frame->trap==7) goto fram;
if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n",
		frame->trap, frame->code, frame->pc, frame->psl);
fram:
#endif
	switch(type){

	default:
#ifdef DDB
		kdb_trap(frame);
#endif
		printf("Trap: type %x, code %x, pc %x, psl %x\n",
		    (u_int)frame->trap, (u_int)frame->code,
		    (u_int)frame->pc, (u_int)frame->psl);
		panic("trap");

	case T_KSPNOTVAL:
		panic("kernel stack invalid");

	case T_TRANSFLT|T_USER:
	case T_TRANSFLT:
		/*
		 * BUG! BUG! BUG! BUG! BUG!
		 * Due to a hardware bug (at in least KA65x CPUs) a double
		 * page table fetch trap will cause a translation fault
		 * even if access in the SPT PTE entry specifies 'no access'.
		 * In for example section 6.4.2 in VAX Architecture
		 * Reference Manual it states that if a page both are invalid
		 * and have no access set, a 'access violation fault' occurs.
		 * Therefore, we must fall through here...
		 */
#ifdef nohwbug
		panic("translation fault");
#endif
	case T_PTELEN|T_USER:	/* Page table length exceeded */
	case T_ACCFLT|T_USER:
		if (frame->code < 0) { /* Check for kernel space */
			sv.sival_int = frame->code;
			sig = SIGSEGV;
			typ = SEGV_ACCERR;
			break;
		}
		/* FALLTHROUGH */

	case T_PTELEN:
	case T_ACCFLT:
#ifdef TRAPDEBUG
if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
			frame->trap, frame->code, frame->pc, frame->psl);
#endif
#ifdef DIAGNOSTIC
		if (p == 0)
			panic("trap: access fault: addr %lx code %lx",
			    frame->pc, frame->code);
#endif

		/*
		 * Page tables are allocated in pmap_enter(). We get
		 * info from below if it is a page table fault, but
		 * UVM may want to map in pages without faults, so
		 * because we must check for PTE pages anyway we don't
		 * bother doing it here.
		 */
		sv.sival_int = frame->code;
		if ((umode == 0) && (frame->code < 0))
			map = kernel_map;
		else
			map = &p->p_vmspace->vm_map;

		if (frame->trap & T_WRITE)
			ftype = PROT_READ | PROT_WRITE;
		else
			ftype = PROT_READ;

		addr = trunc_page((vaddr_t)frame->code);
		rv = uvm_fault(map, addr, 0, ftype);
		if (rv) {
			if (umode == 0) {
				FAULTCHK;
				panic("Segv in kernel mode: pc %x addr %x",
				    (u_int)frame->pc, (u_int)frame->code);
			}
			if (rv == ENOMEM) {
				printf("UVM: pid %d (%s), uid %d killed: "
			           "out of swap\n", p->p_pid, p->p_comm,
			           p->p_ucred ? (int)p->p_ucred->cr_uid : -1);
				sig = SIGKILL;
				typ = 0;
			} else {
				sig = SIGSEGV;
				typ = SEGV_MAPERR;
			}
		} else {
			trapsig = 0;
			if (umode != 0)
				uvm_grow(p, addr);
		}
		break;

	case T_BPTFLT|T_USER:
		typ = TRAP_BRKPT;
		sig = SIGTRAP;
		frame->psl &= ~PSL_T;
		break;

	case T_TRCTRAP|T_USER:
		typ = TRAP_TRACE;
		sig = SIGTRAP;
		frame->psl &= ~PSL_T;
		break;

	case T_PRIVINFLT|T_USER:
	case T_RESOPFLT|T_USER:
		typ = ILL_ILLOPC;
		sig = SIGILL;
		break;

	case T_RESADFLT|T_USER:
		typ = ILL_ILLADR;
		sig = SIGILL;
		break;

	case T_XFCFLT|T_USER:
		typ = EMT_TAGOVF;
		sig = SIGEMT;
		break;

	case T_ARITHFLT|T_USER:
		sv.sival_int = frame->code;
		typ = FPE_FLTINV;
		sig = SIGFPE;
		break;

	case T_ASTFLT|T_USER:
		mtpr(AST_NO,PR_ASTLVL);
		trapsig = 0;
		uvmexp.softs++;
		mi_ast(p, want_resched);
		break;

#ifdef DDB
	case T_BPTFLT: /* Kernel breakpoint */
	case T_KDBTRAP:
	case T_KDBTRAP|T_USER:
	case T_TRCTRAP:
		kdb_trap(frame);
		return;
#endif
	}

	if (trapsig) {
		/*
		 * Arithmetic exceptions can be of two kinds:
		 * - traps (codes 1..7), where pc points to the
		 *   next instruction to execute.
		 * - faults (codes 8..10), where pc points to the
		 *   faulting instruction.
		 * In the latter case, we need to advance pc by ourselves
		 * to prevent a signal loop.
		 *
		 * XXX this is gross -- miod
		 */
		if (type == (T_ARITHFLT | T_USER) && frame->code >= 8) {
			extern long skip_opcode(long);

			frame->pc = skip_opcode(frame->pc);
		}

		trapsignal(p, sig, frame->code, typ, sv);
	}

	if (umode == 0)
		return;

	userret(p);
}

void
setregs(p, pack, stack, retval)
	struct proc *p;
	struct exec_package *pack;
	u_long stack;
	register_t *retval;
{
	struct trapframe *exptr;

	exptr = p->p_addr->u_pcb.framep;
	exptr->pc = pack->ep_entry + 2;
	exptr->sp = stack;
	exptr->r6 = stack;			/* for ELF */
	exptr->r7 = 0;				/* for ELF */
	exptr->r8 = 0;				/* for ELF */
	exptr->r9 = p->p_p->ps_strings;		/* for ELF */

	retval[1] = 0;
}

void
syscall(frame)
	struct	trapframe *frame;
{
	struct sysent *callp;
	int nsys, err;
	long rval[2], args[8];
	struct trapframe *exptr;
	struct proc *p = curproc;

#ifdef TRAPDEBUG
if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n",
	       syscallnames[frame->code], frame->pc, frame->psl,frame->sp,
		curproc->p_pid,frame);
#endif
	uvmexp.syscalls++;

	exptr = p->p_addr->u_pcb.framep = frame;
	callp = p->p_p->ps_emul->e_sysent;
	nsys = p->p_p->ps_emul->e_nsysent;

	if(frame->code == SYS___syscall){
		int g = *(int *)(frame->ap);

		frame->code = *(int *)(frame->ap + 4);
		frame->ap += 8;
		*(int *)(frame->ap) = g - 2;
	}

	if(frame->code < 0 || frame->code >= nsys)
		callp += p->p_p->ps_emul->e_nosys;
	else
		callp += frame->code;

	rval[0] = 0;
	rval[1] = frame->r1;
	if(callp->sy_narg) {
		if ((err = copyin((char *)frame->ap + 4, args,
		    callp->sy_argsize)))
			goto bad;
	}

	err = mi_syscall(p, frame->code, callp, args, rval);

#ifdef TRAPDEBUG
if(startsysc)
	printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, v{rde %d r0 %d, r1 %d, frame %p\n",
	       syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp,
		curproc->p_pid,err,rval[0],rval[1],exptr);
#endif

	switch (err) {
	case 0:
		exptr->r1 = rval[1];
		exptr->r0 = rval[0];
		exptr->psl &= ~PSL_C;
		break;

	case EJUSTRETURN:
		return;

	case ERESTART:
		exptr->pc -= (exptr->code > 63 ? 4 : 2);
		break;

	default:
	bad:
		exptr->r0 = err;
		exptr->psl |= PSL_C;
		break;
	}

	mi_syscall_return(p, frame->code, err, rval);
}

void
child_return(arg)
	void *arg;
{
	struct proc *p = arg;
	struct trapframe *frame;

	frame = p->p_addr->u_pcb.framep;
	frame->r1 = frame->r0 = 0;
	frame->psl &= ~PSL_C;

	mi_child_return(p);
}


code:
/*	$OpenBSD: udiv.s,v 1.5 2013/07/05 21:11:57 miod Exp $	*/
/*	$NetBSD: udiv.s,v 1.2 1994/10/26 08:03:34 cgd Exp $	*/

/*-
 * Copyright (c) 1991 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Donn Seeley at UUNET Technologies, Inc.
 *
 * 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.
 *
 *	@(#)udiv.s      5.6 (Berkeley) 4/15/91
 */

#include <machine/asm.h>

/*
 * Unsigned division, PCC flavor.
 * udiv() takes an ordinary dividend/divisor pair;
 * audiv() takes a pointer to a dividend and an ordinary divisor.
 */

#define	DIVIDEND	4(%ap)
#define	DIVISOR		8(%ap)

ASENTRY(__udiv, 0)
	movl	DIVISOR,%r2
	jlss	Leasy		# big divisor: settle by comparison
	movl	DIVIDEND,%r0
	jlss	Lhard		# big dividend: extended division
	divl2	%r2,%r0		# small divisor and dividend: signed division
	ret
Lhard:
	clrl	%r1
	ediv	%r2,%r0,%r0,%r1
	ret
Leasy:
	cmpl	DIVIDEND,%r2
	jgequ	Lone		# if dividend is as big or bigger, return 1
	clrl	%r0		# else return 0
	ret
Lone:
	movl	$1,%r0
	ret


code:
/*	$OpenBSD: unimpl_emul.s,v 1.9 2013/07/05 21:11:57 miod Exp $	*/
/*	$NetBSD: unimpl_emul.s,v 1.2 2000/08/14 11:16:52 ragge Exp $	*/

/*
 * Copyright (c) 2001 Brandon Creighton.  All rights reserved.
 * Copyright (c) 2000 Ludd, University of Lule}, Sweden. 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 at Ludd, University of
 *      Lule}, Sweden and its contributors.
 * 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>
#include <machine/psl.h>

# Only intended for debugging emulation code (security hole)
#undef	EMULATE_INKERNEL

# Defines to fetch register operands
#define	S_R0	(%fp)
#define	S_R1	4(%fp)
#define	S_R2	8(%fp)
#define	S_R3	12(%fp)
#define	S_R4	16(%fp)
#define	S_R5	20(%fp)
#define	S_R6	24(%fp)
#define	S_R7	28(%fp)
#define	S_R8	32(%fp)
#define	S_R9	36(%fp)
#define	S_R10	40(%fp)
#define	S_R11	44(%fp)
#define	S_AP	48(%fp)
#define	S_FP	52(%fp)
#define	S_SP	56(%fp)
#define	S_PC	60(%fp)
#define	S_PSL	64(%fp)

#define PSL_Q  	(PSL_N | PSL_Z | PSL_V | PSL_C)

#
# Emulation of instruction trapped via SCB vector 0x18. (reserved op)
#
.globl unimemu; unimemu:
	pushl	%r0
	movl	8(%sp),%r0	# get trap address
	movzbl	(%r0),%r0	# fetch insn generating trap
	caseb	%r0,$0x74,$1	# case to jump to address
0:	.word	emodd-0b
	.word	polyd-0b

1:	movl	(%sp)+,%r0	# restore reg
	rsb			# continue fault

#
# switch the code back over to user mode.
# puts the psl + pc (+ jsb return address) on top of user stack.
#
#ifdef EMULATE_INKERNEL
touser:	movl	(%sp),-52(%sp)	# save rsb address on top of new stack
	movl	4(%sp),%r0	# restore saved reg
	addl2	$12,%sp		# pop junk from stack
	pushr	$0x7fff		# save all regs
	movl	%sp,%fp		# new frame pointer
	tstl	-(%sp)		# remember old rsb address
	incl	S_PC		# skip matching insn
	rsb
#else
touser:	mfpr	$PR_USP,%r0	# get user stack pointer
	movl	4(%sp),-68(%r0)	# move already saved r0
	movl	(%sp),-72(%r0)	# move return address
	movq	12(%sp),-8(%r0)	# move pc + psl
	addl2	$12,%sp		# remove moved fields from stack
	movl	$1f,(%sp)	# change return address
	rei
1:	subl2	$8,%sp		# trapaddr + psl already on stack
	pushr	$0x7ffe		# r0 already saved
	subl2	$8,%sp		# do not trash r0 + retaddr
	movab	4(%sp),%fp
	incl	S_PC		# skip matching insn
	rsb
#endif

#
# Restore registers, cleanup and continue
#
goback:	movl	%fp,%sp		# be sure
	popr	$0x7fff		# restore all regs
	rei

/*
 * getval: is used by the getval_* functions.  Gets the value specified by the
 * current operand specifier pointed to by S_PC.  It also increments S_PC.
 */
getval:
	clrq	%r0
	pushr	$(R2+R3+R4+R5+R6)
	movl	S_PC,%r3	# argument address
	extzv	$4,$4,(%r3),%r2	# get mode
	caseb	%r2,$0,$0xf
0:	.word	getval_literal-0b		# 0-3 literal
	.word	getval_literal-0b
	.word	getval_literal-0b
	.word	getval_literal-0b
	.word	2f-0b		# 4 indexed
	.word	getval_reg-0b			# 5 register
	.word	getval_regdefer-0b		# 6 register deferred
	.word	2f-0b		# 7 register deferred
	.word	getval_ai-0b			# 8 autoincrement
	.word	2f-0b		# 9 autoincrement deferred
	.word	getval_bytedis-0b		# A byte displacement
	.word	2f-0b		# B byte displacement deferred
	.word	2f-0b		# C word displacement
	.word	2f-0b		# D word displacement deferred
	.word	getval_longdis-0b		# E longword displacement
	.word	2f-0b		# F longword displacement deferred
#ifdef EMULATE_INKERNEL
2:	movab	0f,%r0
	movl	%r2,%r1
	brw	die
0:	.asciz	"getval: missing address mode %d\n"
#else
2:	.word 	0xffff		# reserved operand
#endif

	/*
	 * 0x00-0x03
	 * Literal mode.  Note:  getval_{d,f}float will *never* use this routine
	 * to get literal values, since they treat them differently (see those routines
	 * for details).
	 */
getval_literal:
	movzbl	(%r3)+,%r0	# correct operand
	brw 4f

	/*
	 * 0x05
     * Register mode.  Grab the register number, yank the value out.
	 */
getval_reg:
	extzv	$0,$4,(%r3),%r2	# Get reg number
	incl	%r3
	ashl	$2,%r2,%r2
	addl3	%fp,%r2,%r5
	bsbw	emul_extract
	brw		4f

	/*
	 * 0x06
     * Register deferred mode.  Grab the register number, yank the value out,
	 * use that as the address to get the real value.
	 */
getval_regdefer:
	extzv	$0,$4,(%r3),%r2	# Get reg number
	incl	%r3
	ashl	$2,%r2,%r2
	addl2	%fp,%r2
	movl	(%r2),%r5
	bsbw	emul_extract
	brw		4f

	/*
	 * 0x08 Autoincrement mode
     * Get the value in the register, use that as the address of our target,
	 * then increment the register.
	 */
getval_ai:
	extzv	$0,$4,(%r3),%r2	# Get reg number
	incl	%r3

	/*
	 * In the case of the register being PC (0xf), this is called immediate mode;
	 * we can treat it the same as any other register, as long as we keep r3
     * and S_PC in sync.  We do that here.
	 */
	movl 	%r3,S_PC

	ashl	$2,%r2,%r2
	addl2	%fp,%r2
	movl	(%r2),%r5
	bsbw	emul_extract
	addl2	%r6,(%r2)

	movl	S_PC,%r3	/* if PC did change, S_PC was changed too */
	brw		4f

	/*
	 * 0xA
	 * Byte displacement mode.
     */
getval_bytedis:
	extzv	$0, $4, (%r3), %r2	# get register
	incl	%r3
	ashl	$2,%r2,%r2
	addl2	%fp,%r2
	movl	(%r2),%r5
	movzbl	(%r3),%r4
	incl	%r3
	addl2	%r4, %r5
	bsbw	emul_extract
	brw		4f

	/*
	 * 0xE
	 * Longword displacement mode.
     */
getval_longdis:
	extzv	$0, $4, (%r3), %r2	# get register
	incl	%r3
	ashl	$2,%r2,%r2
	addl2	%fp,%r2
	movl	(%r2),%r5
	movl	(%r3)+,%r4
	addl2	%r4, %r5
	bsbw	emul_extract

4:	movl	%r3,S_PC
	popr	$(R2+R3+R4+R5+R6)
	rsb

/*
 * emul_extract: used by the getval functions.  This extracts exactly r6 bytes
 * from the address in r5 and places them in r0 and r1 (if necessary).
 * 8 is the current maximum length.
 */
emul_extract:
	cmpl $0x8, %r6
	bgeq 1f
	.word 	0xffff		# reserved operand
1:
	caseb %r6, $0x1, $0x7
0:	.word 1f-0b			# 1: byte
	.word 2f-0b			# 2: word
	.word 9f-0b			# unknown
	.word 4f-0b			# 4: longword
	.word 9f-0b			# unknown
	.word 9f-0b			# unknown
	.word 9f-0b			# unknown
	.word 8f-0b			# 8: quadword

1:	movzbl (%r5), %r0
	rsb

2:	movzwl (%r5), %r0
	rsb

4:	movl (%r5), %r0
	rsb

8:	movq (%r5), %r0
	rsb

9:
	.word 	0xffff		# reserved operand
	rsb

getval_dfloat:
	clrq	%r0
	pushr	$(R2+R3+R6)	# use r2+r3 as scratch reg
	movl	S_PC,%r3	# argument address
	extzv	$4,$4,(%r3),%r2	# get mode
	caseb	%r2,$0,$0x3
0:	.word	1f-0b		# 0-3 literal
	.word	1f-0b
	.word	1f-0b
	.word	1f-0b

	movl	$0x8, %r6
	bsbw	getval
	brw		4f

1:	insv	(%r3),$0,$3,%r0	# insert fraction
	extzv	$3,$3,(%r3),%r2	# get exponent
	addl2	$128,%r2	# bias the exponent
	insv	%r2,$7,$8,%r0	# insert exponent
	tstb	(%r3)+
	movl	%r3,S_PC
4:
	popr	$(R2+R3+R6)
	rsb

getval_long:
	clrl	%r0
	pushr	$(R6+R1)
	movl	$0x4, %r6
	bsbw	getval
	popr	$(R6+R1)
	rsb

getval_word:
	clrl	%r0
	pushr	$(R6+R1)
	movl	$0x2, %r6
	bsbw	getval
	popr	$(R6+R1)
	rsb

getval_byte:
	clrl	%r0
	pushr	$(R6+R1)	# use r2+r3 as scratch reg
	movl	$0x1, %r6
	bsbw	getval
	popr	$(R6+R1)
	rsb

#
# getaddr_byte get 4 bytes and stores them in r0. Increases PC.
#
getaddr_byte:
	clrl	%r0
	pushr	$(R2+R3)	# use r2+r3 as scratch reg
	movl	S_PC,%r3	# argument address
	extzv	$4,$4,(%r3),%r2	# get mode
	caseb	%r2,$0,$0xf
0:	.word	2f-0b		# 0-3 literal
	.word	2f-0b
	.word	2f-0b
	.word	2f-0b
	.word	2f-0b		# 4
	.word	6f-0b		# 5 register
	.word	5f-0b		# 6 deferred
	.word	2f-0b		# 7 autodecr (missing)
	.word	2f-0b		# 8 autoincr (missing)
	.word	2f-0b		# 9 autoincr deferred (missing)
	.word	7f-0b		# 10 byte disp
	.word	2f-0b		# 11 byte disp deferred (missing)
	.word	8f-0b		# 12 word disp
	.word	2f-0b		# 13 word disp deferred (missing)
	.word	1f-0b		# 14 long disp
	.word	2f-0b		# 15 long disp deferred (missing)
#ifdef EMULATE_INKERNEL
2:	movab	3f,%r0
	movl	%r2,%r1
	brw	die		# reserved operand
3:	.asciz	"getaddr_byte: missing address mode %d\n"
#else
2:	.word	0xffff		# reserved operand
#endif

1:	extzv	$0,$4,(%r3),%r2	# Get reg number
	incl	%r3
	movl	(%fp)[%r2],%r0	# Register contents
	addl2	(%r3),%r0	# add displacement
	cmpl	%r2,$15		# pc?
	bneq	0f		# no, skip
	addl2	$5,%r0		# compensate for displacement size
0:	addl2	$4,%r3		# increase pc
	brw	4f

5:	extzv	$0,$4,(%r3),%r2	# Get reg number
	incl	%r3
	movl	(%fp)[%r2],%r0
	brw		4f

7:
	extzv	$0, $4, (%r3), %r2	# get register
	incl	%r3
	movl	(%fp)[%r2],%r0	# Register contents
	pushl	%r4
	cvtbl	(%r3),%r4
	addl2	%r4,%r0		# add displacement
	movl	(%sp)+,%r4
	cmpl	%r2,$15		# pc?
	bneq	0f		# no, skip
	addl2	$2,%r0		# compensate for displacement size
0:	incl	%r3		# increase pc
	brw	4f

8:
	extzv	$0, $4, (%r3), %r2	# get register
	incl	%r3
	movl	(%fp)[%r2],%r0	# Register contents
	pushl	%r4
	cvtwl	(%r3),%r4
	addl2	%r4,%r0		# add displacement
	movl	(%sp)+,%r4
	cmpl	%r2,$15		# pc?
	bneq	0f		# no, skip
	addl2	$3,%r0		# compensate for displacement size
0:	addl2	$2,%r3		# increase pc
	brw	4f

6:	extzv	$0,$4,(%r3),%r2	# Get reg number
	incl	%r3
	moval	(%fp)[%r2],%r0

4:	movl	%r3,S_PC
	popr	$(R2+R3)
	rsb

#
# Polynomial calculation, d-float
# Uses d-float instructions, so hopefully d-float is available.
#
# polyd MISSING:
#	- check for bad arguments
#	- set PSL flags
#	- do not use d-float instructions (may be emulated)
#
polyd:	bsbw	touser		# go back to user mode
	bsbw	getval_dfloat	# fetches argument to r0/r1
	movq	%r0,%r6
	bsbw	getval_word
	movl	%r0,%r4
	bsbw	getaddr_byte
	movl	%r0,%r3
	clrq	%r0
# Ok, do the real calculation (Horner's method)
0:	addd2	(%r3)+,%r0	# add constant
	tstl	%r4		# more?
	beql	1f		# no, exit
	muld2	%r6,%r0		# multiply with arg
	decl	%r4		# lower degree
	brb	0b

1:	movq	%r0,(%fp)
	clrl	S_R2
	movl	%r3,S_R3
	clrq	S_R4
	brw	goback

#ifdef EMULATE_INKERNEL
# When we end up somewhere we don't want.
die:	pushl	%r1
	pushl	%r0
	calls	$2,_printf
	movl	%fp,%sp
	brw	goback		# anything may happen
#endif

# these emodd-related
#define TMPSIZE 0x20	/* temp bytes -- be careful with this! */
#define PRECIS 0x7
#define TMPFRAC1 (%ap)
#define TMPFRAC2 32(%ap)
#define TMPFRACTGT 64(%ap)
#
# Extended multiply/modulus
# XXX just EMODD for now
emodd:	bsbw	touser

	/* Clear the condition codes; we will set them as needed later. */
	bicl2 $PSL_Q, S_PSL

	/*
	 * We temporarily appropriate ap for the use of TMPFRAC*.
	 */
	pushl %ap
	subl2 $(3*TMPSIZE), %sp
	movl %sp, %ap

	movc5 $0x0, TMPFRAC1, $0x0, $TMPSIZE, TMPFRAC1
	movc5 $0x0, TMPFRAC2, $0x0, $TMPSIZE, TMPFRAC2
	movc5 $0x0, TMPFRACTGT, $0x0, $TMPSIZE, TMPFRACTGT

	clrl -(%sp)
	movl %sp, %r3		/* r3 = addr of exp space (1) */
	clrl -(%sp)
	movl %sp, %r5		/* r5 = addr of exp space (2) */
	subl2 $0x10, %sp
	movl %sp, %r6		/* r6 = addr of allocated target space */

	/*
	 * Now we package both numbers up and call fltext_De, which
	 * will remove the exponent and sign; this will make them
	 * easier to work with.  They will be in TMPFRAC1 and
	 * TMPFRAC2 when done.
	 */
	bsbw getval_dfloat 	# get operand into r0 and r1

	/* Check for sign = 0 and exp = 0; if it is, zeroexit. */
	bicl3 $0x7f, %r0, %r4
	cmpl %r4, $0x0
	bneq 1f
	bsbw getval_byte	# get multiplier extension operand
	bsbw getval_dfloat	# get target operand
	jmp zeroexit
1:

	/* Check for sign = 1 and exp = 0; if it is, do a resopflt. */
	cmpw %r0, $0x8000
	bneq 1f
	bsbw getval_byte	# get multiplier extension operand
	bsbw getval_dfloat 	# get operand into r0 and r1
	extzv $0, $0xff, %r0, %r0	# generate a resopflt -- XXX is this ok?
1:
	movd %r0, TMPFRACTGT
	bicl3 $0xffff7fff, %r0, %r6 # Extract the sign while we're here.
	bsbw getval_byte	# get multiplier extension operand
	movzbl %r0, -(%sp)
	movd %r9, %r0
	pushl %r3
	pushab TMPFRAC1
	movab TMPFRACTGT, -(%sp)
	calls $0x4, fltext_De

	bsbw getval_dfloat 	# get operand into r0 and r1

	/* Check for sign = 0 and exp = 0; if it is, zeroexit. */
	bicl3 $0x7f, %r0, %r4
	cmpl %r4, $0x0
	bneq 1f
	bsbw getval_byte	# get multiplier extension operand
	bsbw getval_dfloat	# get target operand
	jmp zeroexit
1:
	/* Check for sign = 1 and exp = 0; if it is, do a resopflt. */
	cmpw %r0, $0x8000
	bneq 1f
	bsbw getval_byte	# get multiplier extension operand
	bsbw getval_dfloat 	# get operand into r0 and r1
	extzv $0, $0xff, %r0, %r0	# generate a resopflt -- XXX is this ok?
1:

	movd %r0, TMPFRACTGT
	bicl3 $0xffff7fff, %r0, %r7 # Extract the sign while we're here.
	movzbl $0x0, -(%sp)	# no multiplier extension here
	pushl %r5
	pushab TMPFRAC2
	movab TMPFRACTGT, -(%sp)
	calls $0x4, fltext_De

	/* first, add exponents */
	addl3 (%r5), (%r3), %r9	/* r9 = exponent (used later) */
	subl2 $0x80, %r9		/* we are excess-128 */

	/*
	 * Let's calculate the target sign.  Signs from multipliers are in r6 and
	 * r7, and both the fraction and integer parts have the same sign.
	 */
	xorl2 %r7, %r6

	pushab TMPFRAC1
	calls $0x1, bitcnt
	movl %r0, %r1			/* r1 = bitcount of TMPFRAC1 */
	pushab TMPFRAC2
	calls $0x1, bitcnt
	movl %r0, %r2			/* r2 = bitcount of TMPFRAC2 */

	/*
	 * Now we get ready to multiply.  This multiplies a byte at a time,
	 * converting to double with CVTLD and adding partial results to
	 * TMPFRACTGT.  There's probably a faster way to do this.
	 */
	clrd TMPFRACTGT
	pushr $0x7fc
	subl2 $0x8, %sp			/* make some temporary space */
	movl %sp, %r1
	subl2 $0x8, %sp
	movl %sp, %r2

	movl $PRECIS, %r5			/* r5 = TMPFRAC1 byte count */
	movl $PRECIS, %r6			/* r6 = TMPFRAC2 byte count */
	clrl %r7

1:
#	addl3 %r5, $TMPFRAC1, %r3	/* r3 - current byte in tmpfrac1 */
	movab TMPFRAC1, %r7
	addl3 %r5, %r7, %r3
#	addl3 %r6, $TMPFRAC2, %r4	/* r4 - current byte in tmpfrac2 */
	movab TMPFRAC2, %r7
	addl3 %r6, %r7, %r4

	movzbl (%r3), %r10
	movzbl (%r4), %r11
	mull3 %r10, %r11, %r7
	movl %r7, %r3
	cvtld %r7, (%r2)

	subl3 %r5, $0x8, %r8
	subl3 %r6, $0x8, %r9
	addl2 %r8, %r9
	mull2 $0x8, %r9
	subl2 $0x40, %r9
	blss 9f

	/* This may be bigger than a longword.  Break it up. */
5:	cmpl %r9, $0x1e
	bleq 6f
	subl2 $0x1e, %r9

	ashl $0x1e, $0x1, %r8
	cvtld %r8, (%r1)
	muld2 (%r1), (%r2)
	jmp 5b
6:
	ashl %r9, $0x1, %r8
	cvtld %r8, (%r1)
	muld2 (%r1), (%r2)
	addd2 (%r2), TMPFRACTGT

9:
	cmpl %r5, $0x0
	beql 2f
	decl %r5
	jmp 1b
2:	cmpl %r6, $0x0
	beql 3f
	decl %r6
	movl $PRECIS, %r5
	jmp 1b
3:

	/*
	 * At this point, r9 might not reflect the final exponent we will use;
	 * i.e., we need post-normalization.  Luckily, we still have (in r7)
	 * the results from the last individual multiplication handy.  Here
	 * we calculate how many bits it will take to shift the value in r7
	 * so that bit 15 = 1.
	 */
	addl2 $0x10, %sp
	movl %r7, 0x14(%sp)	/* move r7 onto the frame we're about to pop off */
   	popr  $0x7fc

	clrl %r3		/* r3 = counter */
	movl %r7, %r8		/* r8 = temp */
1:
	bicl3 $0xffff7fff, %r8, %r5
	bneq 2f
	incl %r3
	ashl $0x1, %r8, %r5
	movl %r5, %r8
	jmp 1b
2:

	/*
	 * Now we do post-normalization (by subtracting r3) and
	 * put the exponent (in r9) into TMPFRACTGT.
	 */
	subl2 %r3, %r9
	insv %r9, $0x7, $0x8, TMPFRACTGT

	bisl2 %r6, TMPFRACTGT	# set the sign

	/*
	 * Now we need to separate.  CVT* won't work in the case of a
	 * >32-bit integer, so we count the integer bits and use ASHQ to
	 * shift them away.
	 */
	cmpl $0x80, %r9
	blss 7f		/* if we are less than 1.0, we can avoid this */
	brw 8f
7:
	subl3 $0x80, %r9, %r8

	movq TMPFRACTGT, TMPFRAC1
	/*
	 * Check for integer overflow by comparing the integer bit count.
	 * If this is the case, set V in PSL.
	 */
	cmpl %r8, $0x20
	blss 3f
	bisl2 $PSL_V, S_PSL
3:
	cmpl %r8, $0x38
	blss 1f
	/*
	 * In the case where we have more than 55 bits in the integer,
	 * there aren't any bits left for the fraction.  Therefore we're
	 * done here;  TMPFRAC1 is equal to TMPFRACTGT and TMPFRAC2 is 0.
	 */
	movq $0f0.0, TMPFRAC2
	jmp 9f		/* we're done, move on */
1:
	/*
	 * We do the mod by using ASHQ to shift and truncate the bits.
	 * Before that happens, we have to arrange the bits in a quadword such
	 * that the significance increases from start to finish.
	 */

	movab TMPFRACTGT, %r0
	movab TMPFRAC1, %r1
	movb (%r0), 7(%r1)
	bisb2 $0x80, 7(%r1)
	movw 2(%r0), 5(%r1)
	movw 4(%r0), 3(%r1)
	movb 7(%r0), 2(%r1)
	movb 6(%r0), 1(%r1)

	/* Calculate exactly how many bits to shift. */
	subl3 %r8, $0x40, %r7
	mnegl %r7, %r6
	ashq %r6, TMPFRAC1, %r0			# shift right
	ashq %r7, %r0, TMPFRAC2			# shift left

	/* Now put it back into a D_. */
	movab TMPFRAC2, %r0
	movab TMPFRAC1, %r1
 	extv $0x18, $0x7, 4(%r0), (%r1)
	extzv $0x7, $0x9, TMPFRACTGT, %r2
	insv %r2, $0x7, $0x9, (%r1)

	movw 5(%r0), 2(%r1)
	movw 3(%r0), 4(%r1)
	movw 1(%r0), 6(%r1)

	# we have the integer in TMPFRAC1, now get the fraction in TMPFRAC2
	subd3 TMPFRAC1, TMPFRACTGT, TMPFRAC2
	jmp 9f

8:
	/*
	 * We are less than 1.0; TMPFRAC1 should be 0, and TMPFRAC2 should
	 * be equal to TMPFRACTGT.
	 */
	movd $0f0.0, TMPFRAC1
	movd TMPFRACTGT, TMPFRAC2
9:
	/*
	 * We're done. We can use CVTDL here, since EMODD is supposed to
	 * truncate.
	 */
	cvtdl TMPFRAC1, %r4
	bsbw getaddr_byte
	movl %r4, (%r0)

	bsbw getaddr_byte
	movq TMPFRAC2, (%r0)
	movd TMPFRAC2, %r0		/* move this here so we can test it later */

	/* Clean up sp. */

	addl2 $0x74, %sp
	movl (%sp)+, %ap

	/*
	 * Now set condition codes.  We know Z == 0; C is always 0; and V
	 * is set above as necessary.  Check to see if TMPFRAC2 is
	 * negative; if it is, set N.
	 */
	tstd %r0
	bgeq 1f /* branch if N == 0 */
	bisl2 $PSL_N, S_PSL
1:
	brw goback
zeroexit:
	/* Z == 1, everything else has been cleared already */
	bisl2 $PSL_Z, S_PSL
	bsbw getaddr_byte
	movl $0x0, (%r0)
	bsbw getaddr_byte
	movd $0f0, (%r0)
	brw goback

/*
 * bitcnt: counts significant bits backwards in a quadword
 * returns number of bits, unless there aren't any;
 * in that case it will return $0xffffffff
 */
ASENTRY(bitcnt, R1|R2|R3|R4|R5|R6|R7|R8|R9|R10|R11)
	/*
	 * Our goal is to factor a common power of 2 out of each of the
	 * two factors involved in the multiplication.  Once we have that,
	 * we can multiply them as integers.  More below.
	 * Right now we are counting bits, starting from the highest octet
	 * of each (the *least* significant bit at this point!) and doing
	 * FFSes until we find a bit set.
	 */
	movl 4(%ap), %r0
	movl $0x8, %r1
1:	decl %r1
	addl3 %r1, %r0, %r4
	movzbl (%r4), %r2
	ffs $0, $0x20, %r2, %r3
	bneq 2f		/* if we found a bit, Z == 0, continue */
	cmpl %r1, $0x0
	jeql 3f /* if r1 is zero and there's no bit set, qw is 0 */
	jmp 1b			/* else continue with the loop */

2:	/*
	 * We found a bit; its position in the byte is in r3, and r1 is the
	 * position of the byte in the quadword.
	 */
	subl3 %r3, $0x8, %r0
	ashl $0x5, %r1, %r2
	addl2 %r2, %r0
	ret

3:	/* this quadword is 0 */
	movl $0xffffffff, %r0
	ret

/*
 * The fltext_X routines separate fraction and exponent* bits.
 * They return (via r0) the amount of bits in the fraction.
 *
 * *: exponents are left in excess-128 form
 *        D_ floating point first word:
 *         F E      7 6     0
 *        +-+--------+-------+
 * sign-> |s|exponent| fract.|  (10-3F = fraction bits)
 *        +-+--------+-------+
 *        Significance order: 0-6, 10-1F, 20-2F, 30-3F
 *
 * The fourth argument to fltext_De is the eight extra bits for use
 * in EMOD*, et al.  If these bits are not in use, specify 0.
 */
ASENTRY(fltext_De, R0|R1|R2)
	movl 0x4(%ap), %r0	# r0 - addr of source
	movl 0x8(%ap), %r1	# r1 - addr of fraction destination

	movb (%r0), (%r1)
	bisb2 $0x80, (%r1)+	# This is the hidden bit.

	movb 3(%r0), (%r1)+
	movb 2(%r0), (%r1)+
	movb 5(%r0), (%r1)+
	movb 4(%r0), (%r1)+
	movb 7(%r0), (%r1)+
	movb 6(%r0), (%r1)+

	/*
	 * if there are extension bits (EMOD EDIV etc.) they are
	 * low-order
	 */
	movb 0x10(%ap), (%r1)

	movl 0x4(%ap), %r0	# r0 - addr of source
	movl 0xc(%ap), %r2	# r2 - addr of exponent destination
	extzv $0x7, $0x8, (%r0), (%r2)		# get exponent out
	ret


code:
/*	$OpenBSD: urem.s,v 1.5 2013/07/05 21:11:57 miod Exp $	*/
/*	$NetBSD: urem.s,v 1.2 1994/10/26 08:03:37 cgd Exp $	*/

/*-
 * Copyright (c) 1991 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Donn Seeley at UUNET Technologies, Inc.
 *
 * 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.
 *
 *	@(#)urem.s      5.6 (Berkeley) 4/15/91
 */

#include <machine/asm.h>

/*
 * Unsigned modulus, PCC flavor.
 * urem() takes an ordinary dividend/divisor pair;
 */

#define	DIVIDEND	4(%ap)
#define	DIVISOR		8(%ap)

ASENTRY(__urem, 0)
	movl	8(%ap),%r2
	jlss	Leasy		# big divisor: settle by comparison
	movl	4(%ap),%r0
	jlss	Lhard		# big dividend: need extended division
	divl3	%r2,%r0,%r1	# small divisor and dividend: signed modulus
	mull2	%r2,%r1
	subl2	%r1,%r0
	ret
Lhard:
	clrl	%r1
	ediv	%r2,%r0,%r1,%r0
	ret
Leasy:
	subl3	%r2,DIVIDEND,%r0
	jcc	Ldifference	# if divisor goes in once, return difference
	movl	DIVIDEND,%r0	# if divisor is bigger, return dividend
Ldifference:
	ret


code:
/*	$OpenBSD: vm_machdep.c,v 1.43 2015/05/05 02:13:47 guenther Exp $	*/
/*	$NetBSD: vm_machdep.c,v 1.67 2000/06/29 07:14:34 mrg Exp $	     */

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

#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/user.h>
#include <sys/exec.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/device.h>

#include <uvm/uvm_extern.h>

#include <machine/vmparam.h>
#include <machine/mtpr.h>
#include <machine/pmap.h>
#include <machine/pte.h>
#include <machine/macros.h>
#include <machine/trap.h>
#include <machine/pcb.h>
#include <machine/frame.h>
#include <machine/cpu.h>
#include <machine/sid.h>

#include <sys/syscallargs.h>

void
cpu_exit(struct proc *p)
{
	pmap_deactivate(p);
	sched_exit(p);
}

/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the pcb and trap frame, making the child ready to run.
 *
 * Rig the child's kernel stack so that it will start out in
 * proc_trampoline() and call child_return() with p2 as an
 * argument. This causes the newly-created child process to go
 * directly to user level with an apparent return value of 0 from
 * fork(), while the parent process returns normally.
 *
 * p1 is the process being forked;
 *
 * If an alternate user-level stack is requested (with non-zero values
 * in both the stack and stacksize args), set up the user stack pointer
 * accordingly.
 *
 * cpu_fork() copies parent process trapframe directly into child PCB
 * so that when we swtch() to the child process it will go directly
 * back to user mode without any need to jump back through kernel.
 * We also take away mapping for the second page after pcb, so that
 * we get something like a "red zone".
 * No need for either double-map kernel stack or relocate it when
 * forking.
 */
void
cpu_fork(p1, p2, stack, stacksize, func, arg)
	struct proc *p1, *p2;
	void *stack;
	size_t stacksize;
	void (*func)(void *);
	void *arg;
{
	struct pcb *pcb;
	struct trapframe *tf;
	struct callsframe *cf;
	extern int sret; /* Return address in trap routine */

#ifdef DIAGNOSTIC
	/*
	 * if p1 != curproc && p1 == &proc0, we're creating a kernel thread.
	 */
	if (p1 != curproc && p1 != &proc0)
		panic("cpu_fork: curproc");
#endif

	/*
	 * Clear new pcb
	 */
	pcb = &p2->p_addr->u_pcb;
	bzero(pcb, sizeof (*pcb));

	/*
	 * Copy the trap frame.
	 */
	tf = (struct trapframe *)((u_int)p2->p_addr + USPACE) - 1;
	p2->p_addr->u_pcb.framep = tf;
	bcopy(p1->p_addr->u_pcb.framep, tf, sizeof(*tf));

	/*
	 * Activate address space for the new process.
	 * This writes the page table registers to the PCB.
	 */
	pcb->pcb_pm = NULL;
	pmap_activate(p2);

	/* Mark guard page invalid in kernel stack */
	*kvtopte((u_int)p2->p_addr + REDZONEADDR) &= ~PG_V;

	/*
	 * Set up the calls frame above (below) the trapframe
	 * and populate it with something good.
	 * This is so that we can simulate that we were called by a
	 * CALLS insn in the function given as argument.
	 */
	cf = (struct callsframe *)tf - 1;
	cf->ca_cond = 0;
	cf->ca_maskpsw = 0x20000000;	/* CALLS stack frame, no registers */
	cf->ca_pc = (unsigned)&sret;	/* return PC; userspace trampoline */
	cf->ca_argno = 1;
	cf->ca_arg1 = (int)arg;

	/*
	 * Set up internal defs in PCB. This matches the "fake" CALLS frame
	 * that we constructed earlier.
	 */
	pcb->iftrap = NULL;
	pcb->KSP = (long)cf;
	pcb->FP = (long)cf;
	pcb->AP = (long)&cf->ca_argno;
	pcb->PC = (int)func + 2;	/* Skip save mask */
	pcb->pcb_paddr = kvtophys((vaddr_t)pcb);

	/*
	 * If specified, give the child a different stack.
	 */
	if (stack != NULL)
		tf->sp = (u_long)stack + stacksize;

	tf->r0 = p1->p_pid; /* parent pid. (shouldn't be needed) */
	tf->r1 = 1;
	tf->psl = PSL_U|PSL_PREVU;
}

int
sys_sysarch(p, v, retval)
	struct proc *p;
	void *v;
	register_t *retval;
{

	return (ENOSYS);
};

/*
 * Map in a bunch of pages read/writeable for the kernel.
 */
void
ioaccess(vaddr, paddr, npgs)
	vaddr_t vaddr;
	paddr_t paddr;
	int npgs;
{
	u_int *pte = (u_int *)kvtopte(vaddr), template;

	template = PG_V | PG_KW | PG_PFNUM(paddr);
	while (npgs-- != 0)
		*pte++ = template++;
	mtpr(0, PR_TBIA);
}

/*
 * Opposite to the above: just forget their mapping.
 */
void
iounaccess(vaddr, npgs)
	vaddr_t vaddr;
	int npgs;
{
	u_int *pte = (u_int *)kvtopte(vaddr);

	while (npgs-- != 0)
		*pte++ = PG_NV;
	mtpr(0, PR_TBIA);
}

/*
 * Map a user I/O request into kernel virtual address space.
 * Note: the pages are already locked by uvm_vslock(), so we
 * do not need to pass an access_type to pmap_enter().
 */
void
vmapbuf(bp, len)
	struct buf *bp;
	vsize_t len;
{
#if VAX46 || VAX48 || VAX49 || VAX53 || VAX60
	vaddr_t faddr, taddr, off;
	paddr_t pa;
	struct proc *p;

	if (phys_map == NULL)
		return;
	if ((bp->b_flags & B_PHYS) == 0)
		panic("vmapbuf");
	p = bp->b_proc;
	faddr = trunc_page((vaddr_t)(bp->b_saveaddr = bp->b_data));
	off = (vaddr_t)bp->b_data - faddr;
	len = round_page(off + len);
	taddr = uvm_km_valloc_wait(phys_map, len);
	bp->b_data = (caddr_t)(taddr + off);
	len = atop(len);
	while (len--) {
		if (pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map), faddr,
				&pa) == FALSE)
			panic("vmapbuf: null page frame");
		pmap_enter(vm_map_pmap(phys_map), taddr, trunc_page(pa),
		    PROT_READ | PROT_WRITE,
		    PROT_READ | PROT_WRITE | PMAP_WIRED);
		faddr += PAGE_SIZE;
		taddr += PAGE_SIZE;
	}
	pmap_update(vm_map_pmap(phys_map));
#endif
}

/*
 * Unmap a previously-mapped user I/O request.
 */
void
vunmapbuf(bp, len)
	struct buf *bp;
	vsize_t len;
{
#if VAX46 || VAX48 || VAX49 || VAX53 || VAX60
	vaddr_t addr, off;

	if (phys_map == NULL)
		return;
	if ((bp->b_flags & B_PHYS) == 0)
		panic("vunmapbuf");
	addr = trunc_page((vaddr_t)bp->b_data);
	off = (vaddr_t)bp->b_data - addr;
	len = round_page(off + len);
	pmap_remove(vm_map_pmap(phys_map), addr, addr + len);
	pmap_update(vm_map_pmap(phys_map));
	uvm_km_free_wakeup(phys_map, addr, len);
	bp->b_data = bp->b_saveaddr;
	bp->b_saveaddr = NULL;
#endif
}


code:
/*	$OpenBSD: vxt.c,v 1.8 2011/09/15 00:48:24 miod Exp $	*/
/*
 * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * This code is derived from software contributed to Ludd by Bertram Barth.
 *
 * 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 at Ludd, University of
 *	Lule}, Sweden and its contributors.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

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

#include <uvm/uvm_extern.h>

#include <machine/cpu.h>
#include <machine/mtpr.h>
#include <machine/ka48.h>
#include <machine/clock.h>

static	void	vxt_conf(void);
static	void	vxt_init(void);
static	void	vxt_memerr(void);
static	int	vxt_mchk(caddr_t);
static	void	vxt_halt(void);
static	void	vxt_reboot(int);
static	void	vxt_cache_enable(void);
static	int	missing_clkread(struct timespec *, time_t);
static	void	missing_clkwrite(void);

/*
 * Declaration of vxt-specific calls.
 */

struct	cpu_dep vxt_calls = {
	vxt_init,
	vxt_mchk,
	vxt_memerr,
	vxt_conf,
	missing_clkread,
	missing_clkwrite,
	6,      /* ~VUPS */
	2,	/* SCB pages */
	vxt_halt,
	vxt_reboot,
	NULL,
	hardclock
};

void
vxt_conf()
{
	printf("cpu: VXT\n");
}

void
vxt_cache_enable()
{
	int i, *tmp;
	long *par_ctl = (long *)KA48_PARCTL;

	/* Disable cache */
	mtpr(0, PR_CADR);		/* disable */
	*par_ctl &= ~KA48_PARCTL_INVENA;	/* clear ? invalid enable */
	mtpr(2, PR_CADR);		/* flush */

	/* Clear caches */
	tmp = (void *)KA48_INVFLT;	/* inv filter */
	for (i = 0; i < KA48_INVFLTSZ / sizeof(int); i++)
		tmp[i] = 0;
	*par_ctl |= KA48_PARCTL_INVENA;	/* Enable ???? */
	mtpr(4, PR_CADR);		/* enable cache */
	*par_ctl |= (KA48_PARCTL_AGS |	/* AGS? */
	    KA48_PARCTL_NPEN |		/* N? Parity Enable */
	    KA48_PARCTL_CPEN);		/* Cpu parity enable */
}

void
vxt_memerr()
{
	printf("Memory err!\n");
}

int
vxt_mchk(addr)
	caddr_t addr;
{
	panic("Machine check");
	return 0;
}

void
vxt_init()
{
	/* Turn on caches (to speed up execution a bit) */
	vxt_cache_enable();
}

static void
vxt_halt()
{
	asm("halt");
}

static void
vxt_reboot(arg)
	int arg;
{
	asm("halt");
}

int
missing_clkread(struct timespec *ts, time_t base)
{
	printf("WARNING: no TOY clock");
	return EINVAL;
}

void
missing_clkwrite()
{
}


code:
/*	$OpenBSD: wscons_machdep.c,v 1.6 2008/08/20 19:00:01 miod Exp $	*/
/*
 * Copyright (c) 2006 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.
 */

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

#include <machine/nexus.h>
#include <machine/vsbus.h>
#include <machine/scb.h>
#include <machine/sid.h>
#include <machine/cpu.h>

#include "wsdisplay.h"
#include "wskbd.h"

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/wscons/wskbdvar.h>

#include "dzkbd.h"

#include <vax/qbus/dzreg.h>
#include <vax/qbus/dzvar.h>
#include <vax/dec/dzkbdvar.h>

#include "qsckbd.h"

#include <vax/vxt/qscvar.h>

#include "gpx.h"
#include "lcg.h"
#include "lcspx.h"
#include "legss.h"
#include "smg.h"

int (*wsfbcninit)(void) = NULL;

#define	FRAMEBUFFER_PROTOS(fb) \
extern int fb##cnprobe(void); \
extern int fb##cninit(void);

#define	FRAMEBUFFER_PROBE(fb) \
do { \
	if (fb##cnprobe()) { \
		wsfbcninit = fb##cninit; \
		goto found; \
	} \
} while (0)

FRAMEBUFFER_PROTOS(gpx);
FRAMEBUFFER_PROTOS(lcg);
FRAMEBUFFER_PROTOS(lcspx);
FRAMEBUFFER_PROTOS(legss);
FRAMEBUFFER_PROTOS(smg);

#include <dev/cons.h>
cons_decl(ws);

int	wscn_ignore = 0;	/* nonzero if forcing a new console election */

void
wscnprobe(struct consdev *cp)
{
	extern int getmajor(void *);	/* conf.c */
	int major;

	/*
	 * If we forced a console device reelection, mark ourselves as
	 * non-working.
	 */
	if (wscn_ignore != 0) {
		cp->cn_pri = CN_DEAD;
		return;
	}

	major = getmajor(wsdisplayopen);
	if (major < 0)
		return;

#if NGPX > 0
	FRAMEBUFFER_PROBE(gpx);
#endif
#if NLCG > 0
	FRAMEBUFFER_PROBE(lcg);
#endif
#if NLCSPX > 0
	FRAMEBUFFER_PROBE(lcspx);
#endif
#if NLEGSS > 0
	FRAMEBUFFER_PROBE(legss);
#endif
#if NSMG > 0
	FRAMEBUFFER_PROBE(smg);
#endif
	return;

found:
	cp->cn_pri = CN_MIDPRI;
	cp->cn_dev = makedev(major, 0);
}

void
wscninit(struct consdev *cp)
{
	if ((*wsfbcninit)()) {
		/*
		 * For some reason, the console initialization failed.
		 * Fallback to serial console, by re-electing a console.
		 */
		wscn_ignore = 1;
		cninit();
		return;
	}

	switch (vax_bustype) {
	case VAX_MBUS:
	case VAX_VSBUS:
#if NDZKBD > 0
		dzkbd_cnattach();
#endif
		break;
	case VAX_VXTBUS:
#if NQSCKBD > 0
		qsckbd_cnattach(QSC_LINE_KEYBOARD);
#endif
		break;
	}
}

void
wscnputc(dev_t dev, int c)
{
#if NWSDISPLAY > 0
	wsdisplay_cnputc(dev, c);
#endif
}

int
wscngetc(dev_t dev)
{
#if NWSKBD > 0
	return (wskbd_cngetc(dev));
#else
	return (0);
#endif
}

void
wscnpollc(dev_t dev, int on)
{
#if NWSKBD > 0
	wskbd_cnpollc(dev, on);
#endif
}


code: src/sys/arch/vax/vsa

path: sys/arch/vax/vsa/CVS/Repository


code:
/*	$OpenBSD: asc_vsbus.c,v 1.17 2015/02/09 22:38:18 miod Exp $	*/
/*	$NetBSD: asc_vsbus.c,v 1.22 2001/02/04 20:36:32 ragge Exp $	*/

/*-
 * Copyright (c) 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Charles M. Hannum.
 *
 * 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/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/device.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/reboot.h>
#include <sys/queue.h>

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

#include <machine/bus.h>
#include <machine/vmparam.h>

#include <dev/ic/ncr53c9xreg.h>
#include <dev/ic/ncr53c9xvar.h>

#include <machine/cpu.h>
#include <machine/sid.h>
#include <machine/scb.h>
#include <machine/vsbus.h>
#include <machine/clock.h>	/* for SCSI ctlr ID# XXX */

struct asc_vsbus_softc {
	struct ncr53c9x_softc sc_ncr53c9x;	/* Must be first */
	struct evcount sc_intrcnt;		/* count interrupts */
	int	sc_cvec;			/* vector */
	bus_space_tag_t sc_bst;			/* bus space tag */
	bus_space_handle_t sc_bsh;		/* bus space handle */
	bus_space_handle_t sc_dirh;		/* scsi direction handle */
	bus_space_handle_t sc_adrh;		/* scsi address handle */
	bus_space_handle_t sc_ncrh;		/* ncr bus space handle */
	bus_dma_tag_t sc_dmat;			/* bus dma tag */
	bus_dmamap_t sc_dmamap;
	caddr_t *sc_dmaaddr;
	size_t *sc_dmalen;
	size_t sc_dmasize;
	unsigned int sc_flags;
#define	ASC_FROMMEMORY		0x0001		/* Must be 1 */
#define	ASC_DMAACTIVE		0x0002
#define	ASC_MAPLOADED		0x0004
	unsigned long sc_xfers;
};

#define	ASC_REG_KA46_ADR	0x0000
#define	ASC_REG_KA46_DIR	0x000C
#define	ASC_REG_KA49_ADR	0x0000
#define	ASC_REG_KA49_DIR	0x0004
#define	ASC_REG_NCR		0x0080
#define	ASC_REG_END		0x00B0

#define	ASC_MAXXFERSIZE		65536
#define	ASC_FREQUENCY		25000000

extern struct cfdriver sd_cd;

int asc_vsbus_match(struct device *, void *, void *);
void asc_vsbus_attach(struct device *, struct device *, void *);

struct cfattach asc_vsbus_ca = {
	sizeof(struct asc_vsbus_softc), asc_vsbus_match, asc_vsbus_attach
};

struct cfdriver asc_cd = {
	NULL, "asc", DV_DULL
};

/*
 * Functions and the switch for the MI code
 */
u_char	asc_vsbus_read_reg(struct ncr53c9x_softc *, int);
void	asc_vsbus_write_reg(struct ncr53c9x_softc *, int, u_char);
int	asc_vsbus_dma_isintr(struct ncr53c9x_softc *);
void	asc_vsbus_dma_reset(struct ncr53c9x_softc *);
int	asc_vsbus_dma_intr(struct ncr53c9x_softc *);
int	asc_vsbus_dma_setup(struct ncr53c9x_softc *, caddr_t *,
	    size_t *, int, size_t *);
void	asc_vsbus_dma_go(struct ncr53c9x_softc *);
void	asc_vsbus_dma_stop(struct ncr53c9x_softc *);
int	asc_vsbus_dma_isactive(struct ncr53c9x_softc *);
int	asc_vsbus_controller_id(void);

static struct ncr53c9x_glue asc_vsbus_glue = {
	asc_vsbus_read_reg,
	asc_vsbus_write_reg,
	asc_vsbus_dma_isintr,
	asc_vsbus_dma_reset,
	asc_vsbus_dma_intr,
	asc_vsbus_dma_setup,
	asc_vsbus_dma_go,
	asc_vsbus_dma_stop,
	asc_vsbus_dma_isactive,
	NULL,
};

static u_int8_t asc_attached;		/* can't have more than one asc */

int
asc_vsbus_match(struct device *parent, void *conf, void *aux)
{
	struct vsbus_attach_args *va = aux;
	struct cfdata *cf = conf;
	volatile u_int8_t *ncr_regs;
	volatile int dummy;

	if (asc_attached)
		return 0;

	switch (vax_boardtype) {
	case VAX_BTYP_46:
	case VAX_BTYP_48:
		if (cf->cf_loc[0] != (SCA_REGS | 0x80))
			return 0;
		break;
	case VAX_BTYP_49:
	case VAX_BTYP_1303:
		if (cf->cf_loc[0] != (SCA_REGS_KA49 | 0x80))
			return 0;
		break;
	default:
		return 0;
	}

	ncr_regs = (volatile u_int8_t *) va->va_addr;

	/*  *** need to generate an interrupt here
	 * From trial and error, I've determined that an INT is generated
	 * only when the following sequence of events occurs:
	 *   1) The interrupt status register (0x05) must be read.
	 *   2) SCSI bus reset interrupt must be enabled
	 *   3) SCSI bus reset command must be sent
	 *   4) NOP command must be sent
	 */

	dummy = ncr_regs[NCR_INTR << 2] & 0xFF;
        ncr_regs[NCR_CFG1 << 2] = asc_vsbus_controller_id(); /* turn on INT
							   for SCSI reset */
        ncr_regs[NCR_CMD << 2] = NCRCMD_RSTSCSI;	/* send the reset */
        ncr_regs[NCR_CMD << 2] = NCRCMD_NOP;		/* send a NOP */
	DELAY(10000);

	dummy = ncr_regs[NCR_INTR << 2] & 0xFF;
	return (dummy & NCRINTR_SBR) != 0;
}

/*
 * Attach this instance, and then all the sub-devices
 */
void
asc_vsbus_attach(struct device *parent, struct device *self, void *aux)
{
	struct vsbus_attach_args *va = aux;
	struct asc_vsbus_softc *asc = (void *)self;
	struct ncr53c9x_softc *sc = &asc->sc_ncr53c9x;
	int error;

	asc_attached = 1;
	/*
	 * Set up glue for MI code early; we use some of it here.
	 */
	sc->sc_glue = &asc_vsbus_glue;

	asc->sc_bst = va->va_iot;
	asc->sc_dmat = va->va_dmat;

	error = bus_space_map(asc->sc_bst, va->va_paddr - ASC_REG_NCR,
	    ASC_REG_END, 0, &asc->sc_bsh);
	if (error) {
		printf(": failed to map registers: error=%d\n", error);
		return;
	}
	error = bus_space_subregion(asc->sc_bst, asc->sc_bsh, ASC_REG_NCR,
	    ASC_REG_END - ASC_REG_NCR, &asc->sc_ncrh);
	if (error) {
		printf(": failed to map ncr registers: error=%d\n", error);
		return;
	}
	if (vax_boardtype == VAX_BTYP_46 || vax_boardtype == VAX_BTYP_48) {
		error = bus_space_subregion(asc->sc_bst, asc->sc_bsh,
		    ASC_REG_KA46_ADR, sizeof(u_int32_t), &asc->sc_adrh);
		if (error) {
			printf(": failed to map adr register: error=%d\n",
			     error);
			return;
		}
		error = bus_space_subregion(asc->sc_bst, asc->sc_bsh,
		    ASC_REG_KA46_DIR, sizeof(u_int32_t), &asc->sc_dirh);
		if (error) {
			printf(": failed to map dir register: error=%d\n",
			     error);
			return;
		}
	} else {
		/* This is a gross and disgusting kludge but it'll
		 * save a bunch of ugly code.  Unlike the VS4000/60,
		 * the SCSI Address and direction registers are not
		 * near the SCSI NCR registers and are inside the
		 * block of general VAXstation registers.  So we grab
		 * them from there and knowing the internals of the
		 * bus_space implementation, we cast to bus_space_handles.
		 */
		struct vsbus_softc *vsc = (struct vsbus_softc *) parent;
		asc->sc_adrh = (bus_space_handle_t) (vsc->sc_vsregs + ASC_REG_KA49_ADR);
		asc->sc_dirh = (bus_space_handle_t) (vsc->sc_vsregs + ASC_REG_KA49_DIR);
#if 0
		printf("\n%s: adrh=0x%08lx dirh=0x%08lx", self->dv_xname,
		       asc->sc_adrh, asc->sc_dirh);
		ncr53c9x_debug = NCR_SHOWDMA|NCR_SHOWINTS|NCR_SHOWCMDS|NCR_SHOWPHASE|NCR_SHOWSTART|NCR_SHOWMSGS;
#endif
	}
	error = bus_dmamap_create(asc->sc_dmat, ASC_MAXXFERSIZE, 1,
	    ASC_MAXXFERSIZE, 0, BUS_DMA_NOWAIT, &asc->sc_dmamap);

	sc->sc_id = asc_vsbus_controller_id();
	sc->sc_freq = ASC_FREQUENCY;

	/* gimme MHz */
	sc->sc_freq /= 1000000;

	scb_vecalloc(va->va_cvec, (void (*)(void *)) ncr53c9x_intr,
	    &asc->sc_ncr53c9x, SCB_ISTACK, &asc->sc_intrcnt);
	asc->sc_cvec = va->va_cvec;
	evcount_attach(&asc->sc_intrcnt, self->dv_xname, &asc->sc_cvec);

	/*
	 * XXX More of this should be in ncr53c9x_attach(), but
	 * XXX should we really poke around the chip that much in
	 * XXX the MI code?  Think about this more...
	 */

	/*
	 * Set up static configuration info.
	 */
	sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
	sc->sc_cfg2 = NCRCFG2_SCSI2;
	sc->sc_cfg3 = 0;
	sc->sc_rev = NCR_VARIANT_NCR53C94;

	/*
	 * XXX minsync and maxxfer _should_ be set up in MI code,
	 * XXX but it appears to have some dependency on what sort
	 * XXX of DMA we're hooked up to, etc.
	 */

	/*
	 * This is the value used to start sync negotiations
	 * Note that the NCR register "SYNCTP" is programmed
	 * in "clocks per byte", and has a minimum value of 4.
	 * The SCSI period used in negotiation is one-fourth
	 * of the time (in nanoseconds) needed to transfer one byte.
	 * Since the chip's clock is given in MHz, we have the following
	 * formula: 4 * period = (1000 / freq) * 4
	 */
	sc->sc_minsync = (1000 / sc->sc_freq);
	sc->sc_maxxfer = 64 * 1024;

	/* Do the common parts of attachment. */
	ncr53c9x_attach(sc);
}

/*
 * Return the host controllers SCSI ID.
 * The factory default is 6 (unlike most vendors who use 7), but this can
 * be changed in the prom.
 */
int
asc_vsbus_controller_id()
{
	switch (vax_boardtype) {
#if defined(VAX46) || defined(VAX48) || defined(VAX49)
	case VAX_BTYP_46:
	case VAX_BTYP_48:
	case VAX_BTYP_49:
		return (clk_page[0xbc / 2] >> clk_tweak) & 7;
#endif
	default:
		return 6;	/* XXX need to get this from VMB */
	}
}

/*
 * Glue functions.
 */

u_char
asc_vsbus_read_reg(struct ncr53c9x_softc *sc, int reg)
{
	struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;

	return bus_space_read_1(asc->sc_bst, asc->sc_ncrh,
	    reg * sizeof(u_int32_t));
}

void
asc_vsbus_write_reg(struct ncr53c9x_softc *sc, int reg, u_char val)
{
	struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;

	bus_space_write_1(asc->sc_bst, asc->sc_ncrh,
	    reg * sizeof(u_int32_t), val);
}

int
asc_vsbus_dma_isintr(struct ncr53c9x_softc *sc)
{
	struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;
	return bus_space_read_1(asc->sc_bst, asc->sc_ncrh,
	    NCR_STAT * sizeof(u_int32_t)) & NCRSTAT_INT;
}

void
asc_vsbus_dma_reset(struct ncr53c9x_softc *sc)
{
	struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;

	if (asc->sc_flags & ASC_MAPLOADED)
		bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
	asc->sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED);
}

int
asc_vsbus_dma_intr(struct ncr53c9x_softc *sc)
{
	struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;
	u_int tcl, tcm;
	int trans, resid;

	if ((asc->sc_flags & ASC_DMAACTIVE) == 0)
		panic("asc_vsbus_dma_intr: DMA wasn't active");

	asc->sc_flags &= ~ASC_DMAACTIVE;

	if (asc->sc_dmasize == 0) {
		/* A "Transfer Pad" operation completed */
		tcl = NCR_READ_REG(sc, NCR_TCL);
		tcm = NCR_READ_REG(sc, NCR_TCM);
		NCR_DMA(("asc_vsbus_intr: discarded %d bytes (tcl=%d, tcm=%d)\n",
		    tcl | (tcm << 8), tcl, tcm));
		return 0;
	}

	resid = 0;
	if ((resid = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF)) != 0) {
		NCR_DMA(("asc_vsbus_intr: empty FIFO of %d ", resid));
		DELAY(1);
	}
	if (asc->sc_flags & ASC_MAPLOADED) {
		bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
				0, asc->sc_dmasize,
				asc->sc_flags & ASC_FROMMEMORY
					? BUS_DMASYNC_POSTWRITE
					: BUS_DMASYNC_POSTREAD);
		bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
	}
	asc->sc_flags &= ~ASC_MAPLOADED;

	resid += (tcl = NCR_READ_REG(sc, NCR_TCL));
	resid += (tcm = NCR_READ_REG(sc, NCR_TCM)) << 8;

	trans = asc->sc_dmasize - resid;
	if (trans < 0) {			/* transferred < 0 ? */
		printf("%s: xfer (%d) > req (%lu)\n",
		    __func__, trans, (u_long) asc->sc_dmasize);
		trans = asc->sc_dmasize;
	}
	NCR_DMA(("asc_vsbus_intr: tcl=%d, tcm=%d; trans=%d, resid=%d\n",
	    tcl, tcm, trans, resid));

	*asc->sc_dmalen -= trans;
	*asc->sc_dmaaddr += trans;

	asc->sc_xfers++;
	return 0;
}

int
asc_vsbus_dma_setup(struct ncr53c9x_softc *sc, caddr_t *addr, size_t *len,
		    int datain, size_t *dmasize)
{
	struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;

	asc->sc_dmaaddr = addr;
	asc->sc_dmalen = len;
	if (datain) {
		asc->sc_flags &= ~ASC_FROMMEMORY;
	} else {
		asc->sc_flags |= ASC_FROMMEMORY;
	}
#ifdef DIAGNOSTIC
	if ((vaddr_t) *asc->sc_dmaaddr < VM_MIN_KERNEL_ADDRESS)
		panic("asc_vsbus_dma_setup: dma address (%p) outside of kernel",
		    *asc->sc_dmaaddr);
#endif

        NCR_DMA(("%s: start %d@%p,%d\n", sc->sc_dev.dv_xname,
                (int)*asc->sc_dmalen, *asc->sc_dmaaddr, (asc->sc_flags & ASC_FROMMEMORY)));
	*dmasize = asc->sc_dmasize = min(*dmasize, ASC_MAXXFERSIZE);

	if (asc->sc_dmasize) {
		if (bus_dmamap_load(asc->sc_dmat, asc->sc_dmamap,
				*asc->sc_dmaaddr, asc->sc_dmasize,
				NULL /* kernel address */,
				BUS_DMA_NOWAIT|VAX_BUS_DMA_SPILLPAGE))
			panic("%s: cannot load dma map", sc->sc_dev.dv_xname);
		bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
				0, asc->sc_dmasize,
				asc->sc_flags & ASC_FROMMEMORY
					? BUS_DMASYNC_PREWRITE
					: BUS_DMASYNC_PREREAD);
		bus_space_write_4(asc->sc_bst, asc->sc_adrh, 0,
				  asc->sc_dmamap->dm_segs[0].ds_addr);
		bus_space_write_4(asc->sc_bst, asc->sc_dirh, 0,
				  asc->sc_flags & ASC_FROMMEMORY);
		NCR_DMA(("%s: dma-load %lu@0x%08lx\n", sc->sc_dev.dv_xname,
			asc->sc_dmamap->dm_segs[0].ds_len,
			asc->sc_dmamap->dm_segs[0].ds_addr));
		asc->sc_flags |= ASC_MAPLOADED;
	}

	return 0;
}

void
asc_vsbus_dma_go(struct ncr53c9x_softc *sc)
{
	struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;

	asc->sc_flags |= ASC_DMAACTIVE;
}

void
asc_vsbus_dma_stop(struct ncr53c9x_softc *sc)
{
	struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;

	if (asc->sc_flags & ASC_MAPLOADED) {
		bus_dmamap_sync(asc->sc_dmat, asc->sc_dmamap,
				0, asc->sc_dmasize,
				asc->sc_flags & ASC_FROMMEMORY
					? BUS_DMASYNC_POSTWRITE
					: BUS_DMASYNC_POSTREAD);
		bus_dmamap_unload(asc->sc_dmat, asc->sc_dmamap);
	}

	asc->sc_flags &= ~(ASC_DMAACTIVE|ASC_MAPLOADED);
}

int
asc_vsbus_dma_isactive(struct ncr53c9x_softc *sc)
{
	struct asc_vsbus_softc *asc = (struct asc_vsbus_softc *)sc;

	return (asc->sc_flags & ASC_DMAACTIVE) != 0;
}


code:
/*	$OpenBSD: dz_ibus.c,v 1.29 2011/09/11 19:29:01 miod Exp $	*/
/*	$NetBSD: dz_ibus.c,v 1.15 1999/08/27 17:50:42 ragge Exp $ */
/*
 * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
 * 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 at Ludd, University of
 *     Lule}, Sweden and its contributors.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

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

#include <machine/sid.h>
#include <machine/vsbus.h>
#include <machine/cpu.h>
#include <machine/scb.h>

#include <vax/qbus/dzreg.h>
#include <vax/qbus/dzvar.h>

#include <vax/dec/dzkbdvar.h>

#include <dev/cons.h>

#include "dzkbd.h"
#include "dzms.h"

int     dz_vsbus_match(struct device *, struct cfdata *, void *);
void    dz_vsbus_attach(struct device *, struct device *, void *);

struct  cfattach dz_vsbus_ca = {
	sizeof(struct dz_softc), (cfmatch_t)dz_vsbus_match, dz_vsbus_attach
};

#define	DZ_VSBUS_CSR	0
#define	DZ_VSBUS_RBUF	4
#define	DZ_VSBUS_DTR	9
#define	DZ_VSBUS_BREAK	13
#define	DZ_VSBUS_TBUF	12
#define	DZ_VSBUS_TCR	8
#define	DZ_VSBUS_DCD	13
#define	DZ_VSBUS_RING	13

int
dz_vsbus_match(parent, cf, aux)
	struct device *parent;
	struct cfdata *cf;
	void *aux;
{
	struct vsbus_attach_args *va = aux;
	volatile uint16_t *dzP;
	short i;

#if VAX53 || VAX49
	if (vax_boardtype == VAX_BTYP_49 ||
	    vax_boardtype == VAX_BTYP_1303)
		if (cf->cf_loc[0] != DZ_CSR_KA49)
			return 0; /* don't probe unnecessarily */
#endif

	dzP = (volatile uint16_t *)va->va_addr;
	i = dzP[DZ_VSBUS_TCR / 2];
	dzP[DZ_VSBUS_CSR / 2] = DZ_CSR_MSE|DZ_CSR_TXIE;
	dzP[DZ_VSBUS_TCR / 2] = 0;
	DELAY(1000);
	dzP[DZ_VSBUS_TCR / 2] = 1;
	DELAY(100000);
	dzP[DZ_VSBUS_TCR / 2] = i;

	/* If the device doesn't exist, no interrupt has been generated */

	return 1;
}

void
dz_vsbus_attach(parent, self, aux)
	struct device *parent, *self;
	void *aux;
{
	struct dz_softc *sc = (void *)self;
	struct vsbus_attach_args *va = aux;
#if NDZKBD > 0 || NDZMS > 0
	struct dzkm_attach_args daa;
#endif
	extern vaddr_t dz_console_regs;
	vaddr_t dz_regs;

	printf(": ");

	/*
	 * This assumes that systems where dz@vsbus exist and can be
	 * the console device, can only have one instance of dz@vsbus.
	 * So far, so good.
	 */
	if (dz_console_regs != 0) {
		dz_regs = dz_console_regs;
		printf("console, ");
	} else
		dz_regs = vax_map_physmem(va->va_paddr, 1);

	/*
	 * XXX - This is evil and ugly, but...
	 * due to the nature of how bus_space_* works on VAX, this will
	 * be perfectly good until everything is converted.
	 */
	sc->sc_ioh = dz_regs;
	sc->sc_dr.dr_csr = DZ_VSBUS_CSR;
	sc->sc_dr.dr_rbuf = DZ_VSBUS_RBUF;
	sc->sc_dr.dr_dtr = DZ_VSBUS_DTR;
	sc->sc_dr.dr_break = DZ_VSBUS_BREAK;
	sc->sc_dr.dr_tbuf = DZ_VSBUS_TBUF;
	sc->sc_dr.dr_tcr = DZ_VSBUS_TCR;
	sc->sc_dr.dr_dcd = DZ_VSBUS_DCD;
	sc->sc_dr.dr_ring = DZ_VSBUS_RING;

	sc->sc_type = DZ_DZV;

	/* no modem control bits except on line 2 */
	sc->sc_dsr = (1 << 0) | (1 << 1) | (1 << 3);

	sc->sc_rcvec = va->va_cvec;
	scb_vecalloc(sc->sc_rcvec, dzxint, sc, SCB_ISTACK, &sc->sc_tintrcnt);
	sc->sc_tcvec = va->va_cvec - 4;
	scb_vecalloc(sc->sc_tcvec, dzrint, sc, SCB_ISTACK, &sc->sc_rintrcnt);
	evcount_attach(&sc->sc_rintrcnt, sc->sc_dev.dv_xname, &sc->sc_rcvec);
	evcount_attach(&sc->sc_tintrcnt, sc->sc_dev.dv_xname, &sc->sc_tcvec);

	printf("4 lines");

	dzattach(sc);

	if (dz_can_have_kbd()) {
#if NDZKBD > 0
		extern struct consdev wsdisplay_cons;

		daa.daa_line = 0;
		DZ_WRITE_WORD(sc, dr_rbuf, DZ_LPR_RX_ENABLE |
		    (DZ_LPR_B4800 << 8) | DZ_LPR_8_BIT_CHAR | daa.daa_line);
		daa.daa_flags =
		    (cn_tab == &wsdisplay_cons ? DZKBD_CONSOLE : 0);
		config_found(self, &daa, dz_print);
#endif
#if NDZMS > 0
		daa.daa_line = 1;
		DZ_WRITE_WORD(sc, dr_rbuf, DZ_LPR_RX_ENABLE |
		    (DZ_LPR_B4800 << 8) | DZ_LPR_8_BIT_CHAR | DZ_LPR_PARENB |
		    DZ_LPR_OPAR | daa.daa_line);
		daa.daa_flags = 0;
		config_found(self, &daa, dz_print);
#endif
	}

#if 0
	s = spltty();
	dzrint(sc);
	dzxint(sc);
	splx(s);
#endif
}