code:
/* $OpenBSD: machdep.c,v 1.149 2015/05/13 08:01:21 mpi Exp $ */
/* $NetBSD: machdep.c,v 1.108 2000/09/13 15:00:23 thorpej Exp $	 */

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

#include <sys/signal.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/extent.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/user.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/msgbuf.h>
#include <sys/buf.h>
#include <sys/mbuf.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/timeout.h>
#include <sys/device.h>
#include <sys/exec.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <sys/ptrace.h>
#include <sys/sysctl.h>
#include <sys/core.h>
#include <sys/kcore.h>

#include <dev/cons.h>

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

#include <netinet/in.h>
#include <netinet/ip_var.h>
#include "ppp.h"	/* For NPPP */
#if NPPP > 0
#include <net/ppp_defs.h>
#include <net/if_ppp.h>
#endif

#include <machine/sid.h>
#include <machine/db_machdep.h>
#include <machine/kcore.h>
#include <vax/vax/gencons.h>
#include <machine/rpb.h>
#include <machine/cca.h>

#ifdef DDB
#include <ddb/db_sym.h>
#include <ddb/db_extern.h>
#endif
#include <vax/vax/db_disasm.h>

#include "led.h"

extern int virtual_avail, virtual_end;
/*
 * We do these external declarations here, maybe they should be done
 * somewhere else...
 */
int		want_resched;
char		machine[] = MACHINE;		/* from <machine/param.h> */
int		physmem;
int		cold = 1; /* coldstart */
struct cpmbx	*cpmbx;

/*
 * safepri is a safe priority for sleep to set for a spin-wait
 * during autoconfiguration or after a panic.
 */
int   safepri = 0;

/*
 * XXX some storage space must be allocated statically because of
 * early console init
 */
#define	IOMAPSZ	100
char extiospace[EXTENT_FIXED_STORAGE_SIZE(IOMAPSZ)];

struct extent *extio;
extern vaddr_t iospace;

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

#ifdef DEBUG
int iospace_inited = 0;
#endif

/* sysctl settable */
#if NLED > 0
int	vax_led_blink = 1;
#endif

struct cpu_info cpu_info_store;

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

void dumpconf(void);

void
cpu_startup()
{
	vaddr_t		minaddr, maxaddr;
	extern char	cpu_model[];

	/*
	 * Initialize error message buffer.
	 */
	initmsgbuf((caddr_t)msgbufp, round_page(MSGBUFSIZE));

	/*
	 * Good {morning,afternoon,evening,night}.
	 * Also call CPU init on systems that need that.
	 */
	printf("%s%s [%08X %08X]\n", version,
	    cpu_model, vax_cpudata, vax_siedata);
        if (dep_call->cpu_conf)
                (*dep_call->cpu_conf)();

	printf("real mem = %lu (%luMB)\n", ptoa(physmem),
	    ptoa(physmem)/1024/1024);
	mtpr(AST_NO, PR_ASTLVL);
	spl0();

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

#if VAX46 || VAX48 || VAX49 || VAX53 || VAX60
	/*
	 * Allocate a submap for physio.  This map effectively limits the
	 * number of processes doing physio at any one time.
	 *
	 * Note that machines on which all mass storage I/O controllers
	 * can perform address translation, do not need this.
	 */
	if (vax_boardtype == VAX_BTYP_46 || vax_boardtype == VAX_BTYP_48 ||
	    vax_boardtype == VAX_BTYP_49 || vax_boardtype == VAX_BTYP_1303 ||
	    vax_boardtype == VAX_BTYP_60)
		phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
		    VM_PHYS_SIZE, 0, FALSE, NULL);
#endif

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

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

	bufinit();
#ifdef DDB
	if (boothowto & RB_KDB)
		Debugger();
#endif

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

long	dumpmag = 0x8fca0101;
int	dumpsize = 0;
long	dumplo = 0;
cpu_kcore_hdr_t cpu_kcore_hdr;

void
dumpconf(void)
{
	int nblks;

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

	dumpsize = physmem;
	if (dumpsize > atop(dbtob(nblks - dumplo)))
		dumpsize = atop(dbtob(nblks - dumplo));
	else if (dumplo == 0)
		dumplo = nblks - btodb(ptoa(dumpsize));

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

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

	/* memory is contiguous on vax */
	cpu_kcore_hdr.ram_segs[0].start = 0;
	cpu_kcore_hdr.ram_segs[0].size = ptoa(physmem);
	cpu_kcore_hdr.sysmap = (vaddr_t)Sysmap;
}

int
cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
	int *name;
	u_int namelen;
	void *oldp;
	size_t *oldlenp;
	void *newp;
	size_t newlen;
	struct proc *p;
{
#if NLED > 0
	int oldval, ret;
#endif
	dev_t consdev;

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

	switch (name[0]) {
	case CPU_CONSDEV:
		if (cn_tab != NULL)
			consdev = cn_tab->cn_dev;
		else
			consdev = NODEV;
		return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev,
		    sizeof consdev));
	case CPU_LED_BLINK:
#if NLED > 0
		oldval = vax_led_blink;
		ret =  sysctl_int(oldp, oldlenp, newp, newlen, &vax_led_blink);
		if (oldval != vax_led_blink) {
			extern void led_blink(void *);
			led_blink(NULL);
		}
		return (ret);
#else
		return (EOPNOTSUPP);
#endif
	default:
		return (EOPNOTSUPP);
	}
	/* NOTREACHED */
}

void
setstatclockrate(hzrate)
	int hzrate;
{
	/* nothing to do */
}

void
consinit()
{
	/*
	 * Init I/O memory extent. Must be done before cninit()
	 * is called; we may want to use iospace in the console routines.
	 *
	 * XXX console code uses the first page at iospace, so do not make
	 * the extent start at iospace.
	 */
	extio = extent_create("extio",
	    (u_long)iospace + VAX_NBPG, (u_long)iospace + IOSPSZ * VAX_NBPG,
	    M_DEVBUF, extiospace, sizeof(extiospace), EX_NOWAIT);
#ifdef DEBUG
	iospace_inited = 1;
#endif
	cninit();
#ifdef DDB
	ddb_init();
#ifdef DEBUG
	if (sizeof(struct user) > REDZONEADDR)
		panic("struct user inside red zone");
#endif
#endif
}

/*
 * Old sigcontext structure, still used by userland until setjmp is fixed.
 */
struct	osigcontext {
	int	__sc_unused;
	int	sc_mask;		/* signal mask to restore */
	int	sc_sp;			/* sp to restore */
	int	sc_fp;			/* fp to restore */
	int	sc_ap;			/* ap to restore */
	int	sc_pc;			/* pc to restore */
	int	sc_ps;			/* psl to restore */
};

/*
 * Internal flags in the low order bits of sc_ap, to know whether this
 * is an osigcontext or a sigcontext.
 */
#define	SIGCONTEXT_NEW		0x01

int
sys_sigreturn(p, v, retval)
	struct proc *p;
	void *v;
	register_t *retval;
{
	struct sys_sigreturn_args {
		syscallarg(struct sigcontext *) sigcntxp;
	} *uap = v;
	struct trapframe *scf;
	struct sigcontext *cntx;
	struct sigcontext ksc;
	int error;

	scf = p->p_addr->u_pcb.framep;
	cntx = SCARG(uap, sigcntxp);

	error = copyin((caddr_t)cntx, (caddr_t)&ksc,
	    sizeof(struct osigcontext));
	if (error == 0 && (ksc.sc_ap & SIGCONTEXT_NEW)) {
		error = copyin((caddr_t)cntx + sizeof(struct osigcontext),
		    (caddr_t)&ksc.sc_r,
		    sizeof(struct sigcontext) - sizeof(struct osigcontext));
	}
	if (error != 0)
		return (error);

	/* Compatibility mode? */
	if ((ksc.sc_ps & (PSL_IPL | PSL_IS)) ||
	    ((ksc.sc_ps & (PSL_U | PSL_PREVU)) != (PSL_U | PSL_PREVU)) ||
	    (ksc.sc_ps & PSL_CM)) {
		return (EINVAL);
	}
	/* Restore signal mask. */
	p->p_sigmask = ksc.sc_mask & ~sigcantmask;

	scf->fp = ksc.sc_fp;
	scf->ap = ksc.sc_ap & ~SIGCONTEXT_NEW;
	scf->sp = ksc.sc_sp;
	if (ksc.sc_ap & SIGCONTEXT_NEW) {
		scf->r0 = ksc.sc_r[0];
		scf->r1 = ksc.sc_r[1];
		scf->r2 = ksc.sc_r[2];
		scf->r3 = ksc.sc_r[3];
		scf->r4 = ksc.sc_r[4];
		scf->r5 = ksc.sc_r[5];
		scf->r6 = ksc.sc_r[6];
		scf->r7 = ksc.sc_r[7];
		scf->r8 = ksc.sc_r[8];
		scf->r9 = ksc.sc_r[9];
		scf->r10 = ksc.sc_r[10];
		scf->r11 = ksc.sc_r[11];
	}
	scf->pc = ksc.sc_pc;
	scf->psl = ksc.sc_ps;
	return (EJUSTRETURN);
}

struct sigframe {
	/* arguments of the signal handler */
	int		 sf_signum;
	siginfo_t 	*sf_sip;
	struct sigcontext *sf_scp;
	/* address of the signal handler */
	register_t 	 sf_pc;
	/* sigcontext pointer for sigreturn */
	register_t	 sf_arg;

	siginfo_t 	 sf_si;
	struct sigcontext sf_sc;
};

void
sendsig(catcher, sig, mask, code, type, val)
	sig_t		catcher;
	int		sig, mask;
	u_long		code;
	int 		type;
	union sigval 	val;
{
	struct	proc	*p = curproc;
	struct	sigacts *psp = p->p_p->ps_sigacts;
	struct	trapframe *syscf;
	struct	sigframe *sigf, gsigf;
	unsigned int	cursp;

	syscf = p->p_addr->u_pcb.framep;

	/* Allocate space for the signal handler context. */
	if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 &&
	    !sigonstack(syscf->sp) && (psp->ps_sigonstack & sigmask(sig)))
		cursp = ((int)p->p_sigstk.ss_sp + p->p_sigstk.ss_size);
	else
		cursp = syscf->sp;

	/* Set up positions for structs on stack */
	sigf = (struct sigframe *) (cursp - sizeof(struct sigframe));

	bzero(&gsigf, sizeof gsigf);
	gsigf.sf_pc = (register_t)catcher;
	gsigf.sf_scp = &sigf->sf_sc;
	gsigf.sf_arg = (register_t)&sigf->sf_sc;
	gsigf.sf_signum = sig;

	if (psp->ps_siginfo & sigmask(sig)) {
		gsigf.sf_sip = &sigf->sf_si;
		initsiginfo(&gsigf.sf_si, sig, code, type, val);
	}

	gsigf.sf_sc.sc_mask = mask;
	gsigf.sf_sc.sc_sp = syscf->sp;
	gsigf.sf_sc.sc_fp = syscf->fp;
	gsigf.sf_sc.sc_ap = syscf->ap | SIGCONTEXT_NEW;
	gsigf.sf_sc.sc_pc = syscf->pc;
	gsigf.sf_sc.sc_ps = syscf->psl;
	gsigf.sf_sc.sc_r[0] = syscf->r0;
	gsigf.sf_sc.sc_r[1] = syscf->r1;
	gsigf.sf_sc.sc_r[2] = syscf->r2;
	gsigf.sf_sc.sc_r[3] = syscf->r3;
	gsigf.sf_sc.sc_r[4] = syscf->r4;
	gsigf.sf_sc.sc_r[5] = syscf->r5;
	gsigf.sf_sc.sc_r[6] = syscf->r6;
	gsigf.sf_sc.sc_r[7] = syscf->r7;
	gsigf.sf_sc.sc_r[8] = syscf->r8;
	gsigf.sf_sc.sc_r[9] = syscf->r9;
	gsigf.sf_sc.sc_r[10] = syscf->r10;
	gsigf.sf_sc.sc_r[11] = syscf->r11;

	if (copyout(&gsigf, sigf, sizeof(gsigf)))
		sigexit(p, SIGILL);

	syscf->pc = p->p_p->ps_sigcode;
	syscf->psl = PSL_U | PSL_PREVU;
	/*
	 * Place sp at the beginning of sigf; this ensures that possible
	 * further calls to sendsig won't overwrite this struct
	 * sigframe/struct sigcontext pair with their own. Also, set up
	 * ap for the sigreturn call from sigcode.
	 */
	syscf->sp = (unsigned)sigf;
	syscf->ap = (unsigned)sigf + offsetof(struct sigframe, sf_pc);
}

int	waittime = -1;
static	volatile int showto; /* Must be volatile to survive MM on -> MM off */

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

	if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
		waittime = 0;
		vfs_shutdown();

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

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

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

haltsys:
	config_suspend_all(DVACT_POWERDOWN);

	if ((howto & RB_HALT) != 0) {
		if (dep_call->cpu_halt)
			(*dep_call->cpu_halt) ();
		printf("halting (in tight loop); hit\n\t^P\n\tHALT\n\n");
		for (;;) ;
	} else {
		showto = howto;
#ifdef notyet
		/*
		 * If we are provided with a bootstring, parse it and send
		 * it to the boot program.
		 */
		if (b)
			while (*b) {
				showto |= (*b == 'a' ? RB_ASKBOOT : (*b == 'd' ?
				    RB_DEBUG : (*b == 's' ? RB_SINGLE : 0)));
				b++;
			}
#endif
		/*
		 * Now it's time to:
		 *  0. Save some registers that are needed in new world.
		 *  1. Change stack to somewhere that will survive MM off.
		 * (RPB page is good page to save things in).
		 *  2. Actually turn MM off.
		 *  3. Dump away memory to disk, if asked.
		 *  4. Reboot as asked.
		 * The RPB page is _always_ first page in memory, we can
		 * rely on that.
		 */
#ifdef notyet
		asm("	movl	sp, (0x80000200);"
		"	movl	0x80000200, sp;"
		"	mfpr	$0x10, -(sp);	# PR_PCBB"
		"	mfpr	$0x11, -(sp);	# PR_SCBB"
		"	mfpr	$0xc, -(sp);	# PR_SBR"
		"	mfpr	$0xd, -(sp);	# PR_SLR"
		"	mtpr	$0, $0x38;	# PR_MAPEN"
		);
#endif

		if (dep_call->cpu_reboot)
			(*dep_call->cpu_reboot)(showto);

		/* cpus that don't handle reboots get the standard reboot. */
		while ((mfpr(PR_TXCS) & GC_RDY) == 0)
			;

		mtpr(GC_CONS|GC_BTFL, PR_TXDB);
	}
	asm("movl %0, %%r5":: "g" (showto)); /* How to boot */
	asm("movl %0, %%r11":: "r"(showto)); /* ??? */
	asm("halt");
	for (;;) ;
	/* NOTREACHED */
}

void
dumpsys()
{
	int maj, psize, pg;
	daddr_t blkno;
	int (*dump)(dev_t, daddr_t, caddr_t, size_t);
	paddr_t maddr;
	int error;
	kcore_seg_t *kseg_p;
	cpu_kcore_hdr_t *chdr_p;
	char dump_hdr[dbtob(1)];	/* XXX assume hdr fits in 1 block */
	extern int msgbufmapped;

	msgbufmapped = 0;
	if (dumpdev == NODEV)
		return;
	/*
	 * For dumps during autoconfiguration, if dump device has already
	 * configured...
	 */
	if (dumpsize == 0) {
		dumpconf();
		if (dumpsize == 0)
			return;
	}
	maj = major(dumpdev);
	if (dumplo <= 0) {
		printf("\ndump to dev %u,%u not possible\n", maj,
		    minor(dumpdev));
		return;
	}
	dump = bdevsw[maj].d_dump;
	blkno = dumplo;

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

#ifdef UVM_SWAP_ENCRYPT
	uvm_swap_finicrypt_all();
#endif

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

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

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

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

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

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

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

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

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

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

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

int
process_read_regs(p, regs)
	struct proc    *p;
	struct reg     *regs;
{
	struct trapframe *tf = p->p_addr->u_pcb.framep;

	bcopy(&tf->r0, &regs->r0, 12 * sizeof(int));
	regs->ap = tf->ap;
	regs->fp = tf->fp;
	regs->sp = tf->sp;
	regs->pc = tf->pc;
	regs->psl = tf->psl;
	return 0;
}

#ifdef PTRACE

int
process_write_regs(p, regs)
	struct proc    *p;
	struct reg     *regs;
{
	struct trapframe *tf = p->p_addr->u_pcb.framep;

	bcopy(&regs->r0, &tf->r0, 12 * sizeof(int));
	tf->ap = regs->ap;
	tf->fp = regs->fp;
	tf->sp = regs->sp;
	tf->pc = regs->pc;
	tf->psl = (regs->psl|PSL_U|PSL_PREVU) &
		~(PSL_MBZ|PSL_IS|PSL_IPL1F|PSL_CM);
	return 0;
}

int
process_set_pc(p, addr)
	struct	proc *p;
	caddr_t addr;
{
	struct	trapframe *tf;
	void	*ptr;

	ptr = (char *) p->p_addr->u_pcb.framep;
	tf = ptr;

	tf->pc = (unsigned) addr;

	return (0);
}

int
process_sstep(p, sstep)
	struct proc    *p;
{
	void	       *ptr;
	struct trapframe *tf;

	ptr = p->p_addr->u_pcb.framep;
	tf = ptr;

	if (sstep)
		tf->psl |= PSL_T;
	else
		tf->psl &= ~PSL_T;

	return (0);
}

#endif	/* PTRACE */

#undef PHYSMEMDEBUG
/*
 * Allocates a virtual range suitable for mapping in physical memory.
 * This differs from the bus_space routines in that it allocates on
 * physical page sizes instead of logical sizes. This implementation
 * uses an extent to manage allocated space from the IOMAP submap.
 * The implementation is similar to the uba resource map handling. Size
 * is given in pages.
 * If the page requested is bigger than a logical page, space is
 * allocated from the kernel map instead.
 *
 * It is known that the first page in the iospace area is unused; it may
 * be use by console device drivers (before the map system is initted).
 */
vaddr_t
vax_map_physmem(phys, size)
	paddr_t phys;
	int size;
{
	vaddr_t addr;
	int error;
	static int warned = 0;

#ifdef DEBUG
	if (!iospace_inited)
		panic("vax_map_physmem: called before rminit()?!?");
#endif
	if (size >= LTOHPN) {
		addr = uvm_km_valloc(kernel_map, size * VAX_NBPG);
		if (addr == 0)
			panic("vax_map_physmem: kernel map full");
	} else {
		error = extent_alloc(extio, size * VAX_NBPG, VAX_NBPG, 0,
		    EX_NOBOUNDARY, EX_NOWAIT | EX_MALLOCOK, (u_long *)&addr);
		if (error != 0) {
			if (warned++ == 0) /* Warn only once */
				printf("vax_map_physmem: iomap too small");
			return 0;
		}
	}
	ioaccess(addr, phys, size);
#ifdef PHYSMEMDEBUG
	printf("vax_map_physmem: alloc'ed %d pages for paddr %lx, at %lx\n",
	    size, phys, addr);
#endif
	return addr | (phys & VAX_PGOFSET);
}

/*
 * Unmaps the previous mapped (addr, size) pair.
 */
void
vax_unmap_physmem(addr, size)
	vaddr_t addr;
	int size;
{
#ifdef PHYSMEMDEBUG
	printf("vax_unmap_physmem: unmapping %d pages at addr %lx\n",
	    size, addr);
#endif
	iounaccess(addr, size);
	if (size >= LTOHPN)
		uvm_km_free(kernel_map, addr, size * VAX_NBPG);
	else
		extent_free(extio, (u_long)addr & ~VAX_PGOFSET,
		    size * VAX_NBPG, EX_NOWAIT);
}

/*
 * The following is a very stripped-down db_disasm.c, with only the logic
 * to skip instructions.
 */

long skip_operand(long, int);
long skip_opcode(long);

static u_int8_t get_byte(long);

static __inline__ u_int8_t
get_byte(ib)
	long    ib;
{
	return *((u_int8_t *)ib);
}

long
skip_opcode(ib)
	long    ib;
{
	u_int opc;
	int size;
	char *argp;	/* pointer into argument-list */

	opc = get_byte(ib++);
	if (opc >= 0xfd) {
		/* two byte op-code */
		opc = opc << 8;
		opc += get_byte(ib++);
		argp = vax_inst2[INDEX_OPCODE(opc)].argdesc;
	} else
		argp = vax_inst[opc].argdesc;

	if (argp == NULL)
		return ib;

	while (*argp) {
		switch (*argp) {

		case 'b':	/* branch displacement */
			switch (*(++argp)) {
			case 'b':
				ib++;
				break;
			case 'w':
				ib += 2;
				break;
			case 'l':
				ib += 4;
				break;
			}
			break;

		case 'a':	/* absolute addressing mode */
			/* FALLTHROUGH */
		default:
			switch (*(++argp)) {
			case 'b':	/* Byte */
				size = 1;
				break;
			case 'w':	/* Word */
				size = 2;
				break;
			case 'l':	/* Long-Word */
			case 'f':	/* F_Floating */
				size = 4;
				break;
			case 'q':	/* Quad-Word */
			case 'd':	/* D_Floating */
			case 'g':	/* G_Floating */
				size = 8;
				break;
			case 'o':	/* Octa-Word */
			case 'h':	/* H_Floating */
				size = 16;
				break;
			default:
				size = 0;
			}
			ib = skip_operand(ib, size);
		}

		if (!*argp || !*++argp)
			break;
		if (*argp++ != ',')
			break;
	}

	return ib;
}

long
skip_operand(ib, size)
	long    ib;
	int	size;
{
	int c = get_byte(ib++);

	switch (c >> 4) { /* mode */
	case 4:		/* indexed */
		ib = skip_operand(ib, 0);
		break;

	case 9:		/* autoincrement deferred */
		if (c == 0x9f) {	/* pc: immediate deferred */
			/*
			 * addresses are always longwords!
			 */
			ib += 4;
		}
		break;
	case 8:		/* autoincrement */
		if (c == 0x8f) {	/* pc: immediate ==> special syntax */
			ib += size;
		}
		break;

	case 11:	/* byte displacement deferred/ relative deferred  */
	case 10:	/* byte displacement / relative mode */
		ib++;
		break;

	case 13:		/* word displacement deferred */
	case 12:		/* word displacement */
		ib += 2;
		break;

	case 15:		/* long displacement referred */
	case 14:		/* long displacement */
		ib += 4;
		break;
	}

	return ib;
}

void
generic_halt()
{
	if (cpmbx->user_halt != UHALT_DEFAULT) {
		if (cpmbx->mbox_halt != 0)
			cpmbx->mbox_halt = 0;	/* let console override */
	} else if (cpmbx->mbox_halt != MHALT_HALT)
		cpmbx->mbox_halt = MHALT_HALT;	/* the os decides */

	asm("halt");
}

void
generic_reboot(int arg)
{
	if (cpmbx->user_halt != UHALT_DEFAULT) {
		if (cpmbx->mbox_halt != 0)
			cpmbx->mbox_halt = 0;
	} else if (cpmbx->mbox_halt != MHALT_REBOOT)
		cpmbx->mbox_halt = MHALT_REBOOT;

	asm("halt");
}

#ifdef DIAGNOSTIC
void
splassert_check(int wantipl, const char *func)
{
	extern int oldvsbus;
	int oldipl = mfpr(PR_IPL);

	/*
	 * Do not complain for older vsbus systems where vsbus interrupts
	 * at 0x14, instead of the expected 0x15. Since these systems are
	 * not expandable and all their devices interrupt at the same
	 * level, there is no risk of them interrupting each other while
	 * they are servicing an interrupt, even at level 0x14.
	 */
	if (oldvsbus != 0 && oldipl == 0x14)
		oldipl = 0x15;

	/*
	 * ... and then, IPL_TYY is now 0x16 because of KA60 interrupt
	 * assignments, so we should not mind if splassert(IPL_TTY) and
	 * IPL 0x15 on other machines.
	 */
	if (wantipl == IPL_TTY && oldipl == 0x15) {
#ifdef VAX60
		if (vax_boardtype != VAX_BTYP_60)
#endif
			oldipl = 0x16;
	}

	if (oldipl < wantipl) {
		splassert_fail(wantipl, oldipl, func);
		/*
		 * If the splassert_ctl is set to not panic, raise the ipl
		 * in a feeble attempt to reduce damage.
		 */
		mtpr(wantipl, PR_IPL);
	}
}
#endif

void	_start(struct rpb *);
void	main(void);

extern	paddr_t avail_end;
extern	int physmem;
paddr_t	esym;
u_int	proc0paddr;
char	cpu_model[100];

/*
 * The strict cpu-dependent information is set up here, in
 * form of a pointer to a struct that is specific for each cpu.
 */
extern struct cpu_dep ka43_calls;
extern struct cpu_dep ka46_calls;
extern struct cpu_dep ka48_calls;
extern struct cpu_dep ka49_calls;
extern struct cpu_dep ka53_calls;
extern struct cpu_dep ka410_calls;
extern struct cpu_dep ka630_calls;
extern struct cpu_dep ka650_calls;
extern struct cpu_dep ka660_calls;
extern struct cpu_dep ka670_calls;
extern struct cpu_dep ka680_calls;
extern struct cpu_dep ka60_calls;
extern struct cpu_dep vxt_calls;

/*
 * Start is called from boot; the first routine that is called
 * in kernel. Kernel stack is setup somewhere in a safe place;
 * but we need to move it to a better known place. Memory
 * management is disabled, and no interrupt system is active.
 */
void
_start(struct rpb *prpb)
{
	extern vaddr_t scratch;
	int preserve_cca = 0;

	mtpr(AST_NO, PR_ASTLVL); /* Turn off ASTs */

	findcpu(); /* Set up the CPU identifying variables */

	if (vax_confdata & 0x80)
		strlcpy(cpu_model, "MicroVAX ", sizeof cpu_model);
	else
		strlcpy(cpu_model, "VAXstation ", sizeof cpu_model);

	switch (vax_boardtype) {
#if VAX410
	case VAX_BTYP_420: /* They are very similar */
		dep_call = &ka410_calls;
		strlcat(cpu_model, "3100", sizeof cpu_model);
		switch (vax_cpustype) {
		case 0x00:
			strlcat(cpu_model, "/m{30,40}", sizeof cpu_model);
			break;
		case 0x01:
			strlcat(cpu_model, "/m{38,48}", sizeof cpu_model);
			break;
		case 0x02:
			strlcat(cpu_model, "/m{10,20}{,e}", sizeof cpu_model);
			break;
		}
		break;

	case VAX_BTYP_410:
		dep_call = &ka410_calls;
		strlcat(cpu_model, "2000", sizeof cpu_model);
		break;
#endif
#if VAX43
	case VAX_BTYP_43:
		dep_call = &ka43_calls;
		strlcat(cpu_model, "3100/m76", sizeof cpu_model);
		break;
#endif
#if VAX46
	case VAX_BTYP_46:
		dep_call = &ka46_calls;
		switch (vax_siedata & 0xff) {
		case VAX_VTYP_47:
			strlcpy(cpu_model, "MicroVAX 3100 m80", sizeof cpu_model);
			break;
		case VAX_VTYP_46:
			strlcpy(cpu_model, "VAXstation 4000/60", sizeof cpu_model);
			break;
		default:
			strlcat(cpu_model, " - Unknown Mariah", sizeof cpu_model);
		}
		break;
#endif
#ifdef VXT
	case VAX_BTYP_VXT:
		dep_call = &vxt_calls;
		strlcpy(cpu_model, "VXT2000", sizeof cpu_model);
		break;
#endif
#if VAX48
	case VAX_BTYP_48:
		dep_call = &ka48_calls;
		switch (vax_cpustype) {
		case VAX_STYP_45:
			strlcpy(cpu_model, "MicroVAX 3100/m{30,40}", sizeof cpu_model);
			break;
		case VAX_STYP_48:
			strlcpy(cpu_model, "VAXstation 4000/VLC", sizeof cpu_model);
			break;
		default:
			strlcat(cpu_model, " - Unknown SOC", sizeof cpu_model);
		}
		break;
#endif
#if VAX49
	case VAX_BTYP_49:
		dep_call = &ka49_calls;
		strlcpy(cpu_model, "VAXstation 4000/90", sizeof cpu_model);
		break;
#endif
#if VAX53
	case VAX_BTYP_1303:
		dep_call = &ka53_calls;
		switch (vax_cpustype) {
		case VAX_STYP_50:
			strlcpy(cpu_model, "MicroVAX 3100 model 85 or 90", sizeof cpu_model);
			break;
		case VAX_STYP_51:
			strlcpy(cpu_model, "MicroVAX 3100 model 90 or 95", sizeof cpu_model);
			break;
		case VAX_STYP_52:
			strlcpy(cpu_model, "VAX 4000 100", sizeof cpu_model);
			break;
		case VAX_STYP_53:
			strlcpy(cpu_model, "VAX 4000 105A", sizeof cpu_model);
			break;
		default:
			strlcpy(cpu_model, "VAX - Unknown Cheetah Class", sizeof cpu_model);
		}
		break;
#endif
#if VAX630
	case VAX_BTYP_630:
		dep_call = &ka630_calls;
		strlcpy(cpu_model,"MicroVAX II", sizeof cpu_model);
		break;
#endif
#if VAX650
	case VAX_BTYP_650:
		dep_call = &ka650_calls;
		strlcpy(cpu_model,"MicroVAX ", sizeof cpu_model);
		switch (vax_cpustype) {
		case VAX_STYP_640:
			strlcat(cpu_model, "3300/3400", sizeof cpu_model);
			break;

		case VAX_STYP_650:
			strlcat(cpu_model, "3500/3600", sizeof cpu_model);
			break;

		case VAX_STYP_655:
			strlcat(cpu_model, "3800/3900", sizeof cpu_model);
			break;

		default:
			strlcat(cpu_model, "III", sizeof cpu_model);
			break;
		}
		break;
#endif
#if VAX660
	case VAX_BTYP_660:
		dep_call = &ka660_calls;
		strlcpy(cpu_model,"VAX 4000 200", sizeof cpu_model);
		break;
#endif
#if VAX670
	case VAX_BTYP_670:
		dep_call = &ka670_calls;
		strlcpy(cpu_model,"VAX 4000 300", sizeof cpu_model);
		break;
#endif
#if VAX680
	case VAX_BTYP_1301:
		dep_call = &ka680_calls;
		strlcpy(cpu_model,"VAX 4000 ", sizeof cpu_model);
		switch (vax_cpustype) {
		case VAX_STYP_675:
			strlcat(cpu_model,"400", sizeof cpu_model);
			break;
		case VAX_STYP_680:
			strlcat(cpu_model,"500", sizeof cpu_model);
			break;
		case VAX_STYP_690:
			strlcat(cpu_model,"600", sizeof cpu_model);
			break;
		default:
			strlcat(cpu_model,"- Unknown Omega Class", sizeof cpu_model);
		}
		break;
	case VAX_BTYP_1305:
		dep_call = &ka680_calls;
		strlcpy(cpu_model,"VAX 4000 ", sizeof cpu_model);
		switch (vax_cpustype) {
		case VAX_STYP_681:
			strlcat(cpu_model,"500A", sizeof cpu_model);
			break;
		case VAX_STYP_691:
			strlcat(cpu_model,"605A", sizeof cpu_model);
			break;
		case VAX_STYP_694:
			if (vax_cpudata & 0x1000)
				strlcat(cpu_model,"705A", sizeof cpu_model);
			else
				strlcat(cpu_model,"700A", sizeof cpu_model);
			break;
		default:
			strlcat(cpu_model,"- Unknown Legacy Class", sizeof cpu_model);
		}
		break;
#endif
#ifdef VAX60
	case VAX_BTYP_60:
		dep_call = &ka60_calls;
		preserve_cca = 1;
		/* cpu_model will be set in ka60_init */
		break;
#endif
	default:
		/* CPU not supported, just give up */
		asm("halt");
	}

	/*
	 * Machines older than MicroVAX II have their boot blocks
	 * loaded directly or the boot program loaded from console
	 * media, so we need to figure out their memory size.
	 * This is not easily done on MicroVAXen, so we get it from
	 * VMB instead.
	 *
	 * In post-1.4 a RPB is always provided from the boot blocks.
	 */
#if 1 /* compat with old bootblocks */
	if (prpb == 0) {
		bzero((caddr_t)proc0paddr + REDZONEADDR, sizeof(struct rpb));
		prpb = (struct rpb *)(proc0paddr + REDZONEADDR);
		prpb->pfncnt = avail_end >> VAX_PGSHIFT;
		prpb->rpb_base = (void *)-1;    /* RPB is fake */
	} else
#endif
	bcopy(prpb, (caddr_t)proc0paddr + REDZONEADDR, sizeof(struct rpb));
	if (prpb->pfncnt)
		avail_end = prpb->pfncnt << VAX_PGSHIFT;
	else
		while (badaddr((caddr_t)avail_end, 4) == 0)
			avail_end += VAX_NBPG * 128;
	boothowto = prpb->rpb_bootr5;

	physmem = atop(avail_end);

	/*
	 * If we need to use the Console Communication Area, make sure
	 * we will not stomp over it.
	 *
	 * On KA60 systems, the PROM apparently forgets to keep the CCA
	 * out of the reported memory size.  It's no real surprise, as
	 * the memory bitmap pointed to by the CCA reports all physical
	 * memory (including itself and the CCA) as available!
	 * (which means the bitmap is not worth looking at either)
	 */

	if (preserve_cca) {
		if (prpb->cca_addr != 0 && avail_end > prpb->cca_addr) {
			struct cca *cca = (struct cca *)prpb->cca_addr;

			/*
			 * XXX Should validate the CCA image here.
			 */

			avail_end = prpb->cca_addr;
			if (cca->cca_bitmap != 0 && avail_end > cca->cca_bitmap)
				avail_end = cca->cca_bitmap;
		}
	}

        avail_end = trunc_page(avail_end); /* be sure */

	proc0.p_addr = (struct user *)proc0paddr; /* XXX */
	bzero((struct user *)proc0paddr, sizeof(struct user));
	proc0.p_addr->u_pcb.pcb_paddr = (paddr_t)proc0paddr - KERNBASE;

	pmap_bootstrap();

	/* Now running virtual. set red zone for proc0 */
	*kvtopte((u_int)proc0.p_addr + REDZONEADDR) &= ~PG_V;

	((struct pcb *)proc0paddr)->framep = (void *)scratch;

	/*
	 * Change mode down to userspace is done by faking a stack
	 * frame that is setup in cpu_set_kpc(). Not done by returning
	 * from main anymore.
	 */
	main();
	/* NOTREACHED */
}


code:
/*	$OpenBSD: mem.c,v 1.18 2015/02/10 22:44:35 miod Exp $	*/
/*	$NetBSD: mem.c,v 1.15 1999/03/24 05:51:17 mrg Exp $	*/

/*
 * Copyright (c) 1988 University of Utah.
 * Copyright (c) 1982, 1986, 1990, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department.
 *
 * 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.
 *
 *	@(#)mem.c	8.3 (Berkeley) 1/12/94
 */

/*
 * Memory special file
 */

#include <sys/param.h>
#include <sys/conf.h>
#include <sys/buf.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/malloc.h>
#include <sys/proc.h>

#include <machine/pte.h>
#include <machine/mtpr.h>

#include <uvm/uvm_extern.h>

caddr_t zeropage;

#define	mmread	mmrw
#define	mmwrite	mmrw
cdev_decl(mm);

/*ARGSUSED*/
int
mmopen(dev, flag, mode, p)
	dev_t dev;
	int flag, mode;
	struct proc *p;
{

	switch (minor(dev)) {
		case 0:
		case 1:
		case 2:
		case 12:
			return (0);
		default:
			return (ENXIO);
	}
}

/*ARGSUSED*/
int
mmclose(dev, flag, mode, p)
	dev_t dev;
	int flag, mode;
	struct proc *p;
{

	return (0);
}

/*ARGSUSED*/
int
mmrw(dev, uio, flags)
	dev_t dev;
	struct uio *uio;
	int flags;
{
	vaddr_t v;
	size_t c;
	struct iovec *iov;
	int error = 0;

	while (uio->uio_resid > 0 && error == 0) {
		iov = uio->uio_iov;
		if (iov->iov_len == 0) {
			uio->uio_iov++;
			uio->uio_iovcnt--;
			if (uio->uio_iovcnt < 0)
				panic("mmrw");
			continue;
		}
		switch (minor(dev)) {

/* minor device 0 is physical memory */
		case 0:
			v = uio->uio_offset;
			if (v < 0 || v >= ptoa(physmem)) {
				return (EFAULT);
			}

			c = ulmin(iov->iov_len, MAXPHYS);
			error = uiomove((caddr_t)v + KERNBASE, c, uio);
			continue;
/* minor device 1 is kernel memory */
		case 1:
			v = uio->uio_offset;
			c = ulmin(iov->iov_len, MAXPHYS);
			if (!uvm_kernacc((caddr_t)v, c,
			    uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
				return (EFAULT);
			error = uiomove((caddr_t)v, c, uio);
			continue;

/* minor device 2 is EOF/RATHOLE */
		case 2:
			if (uio->uio_rw == UIO_WRITE)
				uio->uio_resid = 0;
			return (0);

/* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
		case 12:
			if (uio->uio_rw == UIO_WRITE) {
				c = iov->iov_len;
				break;
			}
			if (zeropage == NULL)
				zeropage = malloc(PAGE_SIZE, M_TEMP,
				    M_WAITOK | M_ZERO);
			c = ulmin(iov->iov_len, PAGE_SIZE);
			error = uiomove(zeropage, c, uio);
			continue;

		default:
			return (ENXIO);
		}
		if (error)
			break;
		iov->iov_base = (caddr_t)iov->iov_base + c;
		iov->iov_len -= c;
		uio->uio_offset += c;
		uio->uio_resid -= c;
	}
	return (error);
}

paddr_t
mmmmap(dev, off, prot)
	dev_t dev;
	off_t off;
	int prot;
{

	return (-1);
}

int
mmioctl(dev, cmd, data, flags, p)
	dev_t dev;
	u_long cmd;
	caddr_t data;
	int flags;
	struct proc *p;
{
	return (EOPNOTSUPP);
}

license: unknown


code:
/*	$OpenBSD: mutex.c,v 1.7 2011/04/21 04:34:12 miod Exp $	*/

/*
 * Copyright (c) 2004 Artur Grabowski <art@openbsd.org>
 * 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. 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 ``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/mutex.h>
#include <sys/systm.h>

#include <machine/intr.h>

#ifdef MULTIPROCESSOR
#error This code needs more work
#endif

/*
 * Single processor systems don't need any mutexes, but they need the spl
 * raising semantics of the mutexes.
 */
void
mtx_init(struct mutex *mtx, int wantipl)
{
	mtx->mtx_oldipl = 0;
	mtx->mtx_wantipl = wantipl;
	mtx->mtx_lock = 0;
}

void
mtx_enter(struct mutex *mtx)
{
	if (mtx->mtx_wantipl != IPL_NONE)
		mtx->mtx_oldipl = _splraise(mtx->mtx_wantipl);

	MUTEX_ASSERT_UNLOCKED(mtx);
	mtx->mtx_lock = 1;
#ifdef DIAGNOSTIC
	curcpu()->ci_mutex_level++;
#endif
}

int
mtx_enter_try(struct mutex *mtx)
{
	if (mtx->mtx_wantipl != IPL_NONE)
		mtx->mtx_oldipl = _splraise(mtx->mtx_wantipl);
	MUTEX_ASSERT_UNLOCKED(mtx);
	mtx->mtx_lock = 1;
#ifdef DIAGNOSTIC
	curcpu()->ci_mutex_level++;
#endif

	return 1;
}

void
mtx_leave(struct mutex *mtx)
{
	MUTEX_ASSERT_LOCKED(mtx);
#ifdef DIAGNOSTIC
	curcpu()->ci_mutex_level--;
#endif
	mtx->mtx_lock = 0;
	if (mtx->mtx_wantipl != IPL_NONE)
		splx(mtx->mtx_oldipl);
}


code:
/*	$OpenBSD: opcodes.c,v 1.1 2002/05/16 07:37:44 miod Exp $	*/

/*
 * Copyright (c) 2002, Miodrag Vallat.
 * Copyright (c) 1996 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 <vax/vax/db_disasm.h>

/* one-byte instructions */
vax_instr_t vax_inst[256] = {
/* 0x00 */	{	"halt", 	NULL			},
/* 0x01 */	{	"nop", 		NULL			},
/* 0x02 */	{	"rei", 		NULL			},
/* 0x03 */	{	"bpt", 		NULL			},
/* 0x04 */	{	"ret", 		NULL			},
/* 0x05 */	{	"rsb", 		NULL			},
/* 0x06 */	{	"ldpctx", 	NULL			},
/* 0x07 */	{	"svpctx", 	NULL			},
/* 0x08 */	{	"cvtps", 	"rw,ab,rw,ab"		},
/* 0x09 */	{	"cvtsp", 	"rw,ab,rw,ab"		},
/* 0x0a */	{	"index", 	"rl,rl,rl,rl,rl,wl" 	},
/* 0x0b */	{	"crc", 		"ab,rl,rw,ab"		},
/* 0x0c */	{	"prober", 	"rb,rw,ab"		},
/* 0x0d */	{	"probew", 	"rb,rw,ab"		},
/* 0x0e */	{	"insque", 	"ab,wl"			},
/* 0x0f */	{	"remque", 	"ab,wl"			},

/* 0x10 */	{	"bsbb", 	"bb"			},
/* 0x11 */	{	"brb", 		"bb"			},
/* 0x12 */	{	"*bneq",	"bb"			},
/* 0x13 */	{	"*beql", 	"bb"			},
/* 0x14 */	{	"bgtr", 	"bb"			},
/* 0x15 */	{	"bleq", 	"bb"			},
/* 0x16 */	{	"jsb", 		"ab"			},
/* 0x17 */	{	"jmp", 		"ab"			},
/* 0x18 */	{	"bgeq", 	"bb"			},
/* 0x19 */	{	"blss", 	"bb"			},
/* 0x1a */	{	"bgtru", 	"bb"			},
/* 0x1b */	{	"blequ", 	"bb"			},
/* 0x1c */	{	"bvc", 		"bb"			},
/* 0x1d */	{	"bvs", 		"bb"			},
/* 0x1e */	{	"*bcc", 	"bb"			},
/* 0x1f */	{	"*bcs", 	"bb"			},

/* 0x20 */	{	"addp4", 	"rw,ab,rw,ab"		},
/* 0x21 */	{	"addp6", 	"rw,ab,rw,ab,rw,ab"	},
/* 0x22 */	{	"subp4", 	"rw,ab,rw,ab"		},
/* 0x23 */	{	"subp6", 	"rw,ab,rw,ab,rw,ab"	},
/* 0x24 */	{	"cvtpt", 	"rw,ab,ab,rw,ab"	},
/* 0x25 */	{	"mulp", 	"rw,ab,rw,ab,rw,ab"	},
/* 0x26 */	{	"cvttp", 	"rw,ab,ab,rw,ab"	},
/* 0x27 */	{	"divp", 	"rw,ab,rw,ab,rw,ab"	},
/* 0x28 */	{	"movc3", 	"rw,ab,ab"		},
/* 0x29 */	{	"cmpc3", 	"rw,ab,ab"		},
/* 0x2a */	{	"scanc", 	"rw,ab,ab,rb"		},
/* 0x2b */	{	"spanc", 	"rw,ab,ab,rb"		},
/* 0x2c */	{	"movc5", 	"rw,ab,rb,rw,ab"	},
/* 0x2d */	{	"cmpc5", 	"rw,ab,rb,rw,ab"	},
/* 0x2e */	{	"movtc", 	"rw,ab,rb,ab,rw,ab"	},
/* 0x2f */	{	"movtuc", 	"rw,ab,rb,ab,rw,ab"	},

/* 0x30 */	{	"bsbw", 	"bw"			},
/* 0x31 */	{	"brw", 		"bw"			},
/* 0x32 */	{	"cvtwl", 	"rw,wl"			},
/* 0x33 */	{	"cvtwb", 	"rw,wb"			},
/* 0x34 */	{	"movp", 	"rw,ab,ab"		},
/* 0x35 */	{	"cmpp3", 	"rw,ab,ab"		},
/* 0x36 */	{	"cvtpl", 	"rw,ab,wl"		},
/* 0x37 */	{	"cmpp4", 	"rw,ab,rw,ab"		},
/* 0x38 */	{	"editpc", 	"rw,ab,ab,ab"		},
/* 0x39 */	{	"matchc", 	"rw,ab,rw,ab"		},
/* 0x3a */	{	"locc", 	"rb,rw,ab"		},
/* 0x3b */	{	"skpc", 	"rb,rw,ab"		},
/* 0x3c */	{	"movzwl", 	"rw,wl"			},
/* 0x3d */	{	"acbw", 	"rw,rw,mw,bw"		},
/* 0x3e */	{	"movaw", 	"aw,wl"			},
/* 0x3f */	{	"pushaw", 	"aw"			},

/* 0x40 */	{	"addf2", 	"rf,mf"			},
/* 0x41 */	{	"addf3", 	"rf,rf,wf"		},
/* 0x42 */	{	"subf2", 	"rf,mf"			},
/* 0x43 */	{	"subf3", 	"rf,rf,wf"		},
/* 0x44 */	{	"mulf2", 	"rf,mf"			},
/* 0x45 */	{	"mulf3", 	"rf,rf,wf"		},
/* 0x46 */	{	"divf2", 	"rf,mf"			},
/* 0x47 */	{	"divf3", 	"rf,rf,wf"		},
/* 0x48 */	{	"cvtfb", 	"rf,wb"			},
/* 0x49 */	{	"cvtfw", 	"rf,ww"			},
/* 0x4a */	{	"cvtfl", 	"rf,wl"			},
/* 0x4b */	{	"cvtrfl", 	"rf,wl"			},
/* 0x4c */	{	"cvtbf", 	"rb,wf"			},
/* 0x4d */	{	"cvtwf", 	"rw,wf"			},
/* 0x4e */	{	"cvtlf", 	"rl,wf"			},
/* 0x4f */	{	"acbf", 	"rf,rf,rf,bw"		},

/* 0x50 */	{	"movf", 	"rf,wf"			},
/* 0x51 */	{	"cmpf", 	"rf,rf"			},
/* 0x52 */	{	"mnegf", 	"rf,wf"			},
/* 0x53 */	{	"tstf", 	"rf"			},
/* 0x54 */	{	"emodf", 	"rf,rb,rf,wl,wf"	},
/* 0x55 */	{	"polyf", 	"rf,rw,ab"		},
/* 0x56 */	{	"cvtfd", 	"rf,wd"			},
/* 0x57 */	{	NULL, 		NULL			},
/* 0x58 */	{	"adawi", 	"rw,mw"			},
/* 0x59 */	{	NULL, 		NULL			},
/* 0x5a */	{	NULL, 		NULL			},
/* 0x5b */	{	NULL, 		NULL			},
/* 0x5c */	{	"insqhi", 	"ab,aq"			},
/* 0x5d */	{	"insqti", 	"ab,aq"			},
/* 0x5e */	{	"remqhi", 	"aq,wl"			},
/* 0x5f */	{	"remqti", 	"aq,wl"			},

/* 0x60 */	{	"addd2", 	"rd,md"			},
/* 0x61 */	{	"addd3", 	"rd,rd,wd"		},
/* 0x62 */	{	"subd2", 	"rd,md"			},
/* 0x63 */	{	"subd3", 	"rd,rd,wd"		},
/* 0x64 */	{	"muld2", 	"rd,md"			},
/* 0x65 */	{	"muld3", 	"rd,rd,wd"		},
/* 0x66 */	{	"divd2", 	"rd,md"			},
/* 0x67 */	{	"divd3", 	"rd,rd,wd"		},
/* 0x68 */	{	"cvtdb", 	"rd,wb"			},
/* 0x69 */	{	"cvtdw", 	"rd,ww"			},
/* 0x6a */	{	"cvtdl", 	"rd,wl"			},
/* 0x6b */	{	"cvtrdl", 	"rd,wl"			},
/* 0x6c */	{	"cvtbd", 	"rb,wd"			},
/* 0x6d */	{	"cvtwd", 	"rw,wd"			},
/* 0x6e */	{	"cvtld", 	"rl,wd"			},
/* 0x6f */	{	"acbd", 	"rd,rd,md,bw"		},

/* 0x70 */	{	"movd", 	"rd,wd"			},
/* 0x71 */	{	"cmpd", 	"rd,rd"			},
/* 0x72 */	{	"mnegd", 	"rd,wd"			},
/* 0x73 */	{	"tstd", 	"rd"			},
/* 0x74 */	{	"emodd", 	"rd,rb,rd,wl,wd"	},
/* 0x75 */	{	"polyd", 	"rd,rw,ab"		},
/* 0x76 */	{	"cvtdf", 	"rd,wf"			},
/* 0x77 */	{	NULL, 		NULL			},
/* 0x78 */	{	"ashl", 	"rb,rl,wl"		},
/* 0x79 */	{	"ashq", 	"rb,rq,wq"		},
/* 0x7a */	{	"emul", 	"rl,rl,rl,wq"		},
/* 0x7b */	{	"ediv", 	"rl,rq,wl,wl"		},
/* 0x7c */	{	"*clrq", 	"wq"			},
/* 0x7d */	{	"movq", 	"rq,wq"			},
/* 0x7e */	{	"*movaq", 	"aq,wl"			},
/* 0x7f */	{	"*pushaq", 	"aq"			},

/* 0x80 */	{	"addb2", 	"rb,mb"			},
/* 0x81 */	{	"addb3", 	"rb,rb,wb"		},
/* 0x82 */	{	"subb2", 	"rb,mb"			},
/* 0x83 */	{	"subb3", 	"rb,rb,wb"		},
/* 0x84 */	{	"mulb2", 	"rb,mb"			},
/* 0x85 */	{	"mulb3", 	"rb,rb,wb"		},
/* 0x86 */	{	"divb2", 	"rb,mb"			},
/* 0x87 */	{	"divb3", 	"rb,rb,wb"		},
/* 0x88 */	{	"bisb2", 	"rb,mb"			},
/* 0x89 */	{	"bisb3", 	"rb,rb,wb"		},
/* 0x8a */	{	"bicb2", 	"rb,mb"			},
/* 0x8b */	{	"bicb3", 	"rb,rb,wb"		},
/* 0x8c */	{	"xorb2", 	"rb,mb"			},
/* 0x8d */	{	"xorb3", 	"rb,rb,wb"		},
/* 0x8e */	{	"mnegb", 	"rb,wb"			},
/* 0x8f */	{	"caseb", 	"rb,rb,rb,bw-list"	},

/* 0x90 */	{	"movb", 	"rb,wb"			},
/* 0x91 */	{	"cmpb", 	"rb,rb"			},
/* 0x92 */	{	"mcomb", 	"rb,wb"			},
/* 0x93 */	{	"bitb", 	"rb,rb"			},
/* 0x94 */	{	"clrb", 	"wb"			},
/* 0x95 */	{	"tstb", 	"rb"			},
/* 0x96 */	{	"incb", 	"mb"			},
/* 0x97 */	{	"decb", 	"mb"			},
/* 0x98 */	{	"cvtbl", 	"rb,wl"			},
/* 0x99 */	{	"cvtbw", 	"rb,ww"			},
/* 0x9a */	{	"movzbl", 	"rb,wl"			},
/* 0x9b */	{	"movzbw", 	"wb,ww"			},
/* 0x9c */	{	"rotl", 	"rb,rl,wl"		},
/* 0x9d */	{	"acbb", 	"rb,rb,mb,bw"		},
/* 0x9e */	{	"movab", 	"ab,wl"			},
/* 0x9f */	{	"pushab", 	"ab"			},

/* 0xa0 */	{	"addw2", 	"rw,mw"			},
/* 0xa1 */	{	"addw3", 	"rw,rw,ww"		},
/* 0xa2 */	{	"subw2", 	"rw,mw"			},
/* 0xa3 */	{	"subw3", 	"rw,rw,ww"		},
/* 0xa4 */	{	"mulw2", 	"rw,mw"			},
/* 0xa5 */	{	"mulw3", 	"rw,rw,ww"		},
/* 0xa6 */	{	"divw2", 	"rw,mw"			},
/* 0xa7 */	{	"divw3", 	"rw,rw,ww"		},
/* 0xa8 */	{	"bisw2", 	"rw,mw"			},
/* 0xa9 */	{	"bisw3", 	"rw,rw,ww"		},
/* 0xaa */	{	"bicw2", 	"rw,mw"			},
/* 0xab */	{	"bicw3", 	"rw,rw,ww"		},
/* 0xac */	{	"xorw2", 	"rw,mw"			},
/* 0xad */	{	"xorw3", 	"rw,rw,ww"		},
/* 0xae */	{	"mnegw", 	"rw,ww"			},
/* 0xaf */	{	"casew", 	"rw,rw,rw,bw-list"	},

/* 0xb0 */	{	"movw", 	"rw,ww"			},
/* 0xb1 */	{	"cmpw", 	"rw,rw"			},
/* 0xb2 */	{	"mcomw", 	"rw,ww"			},
/* 0xb3 */	{	"bitw", 	"rw,rw"			},
/* 0xb4 */	{	"clrw", 	"mw"			},
/* 0xb5 */	{	"tstw", 	"rw"			},
/* 0xb6 */	{	"incw", 	"mw"			},
/* 0xb7 */	{	"decw", 	"mw"			},
/* 0xb8 */	{	"bispsw", 	"rw"			},
/* 0xb9 */	{	"bicpsw", 	"rw"			},
/* 0xba */	{	"popr", 	"rw"			},
/* 0xbb */	{	"pushr", 	"rw"			},
/* 0xbc */	{	"chmk", 	"rw"			},
/* 0xbd */	{	"chme", 	"rw"			},
/* 0xbe */	{	"chms", 	"rw"			},
/* 0xbf */	{	"chmu", 	"rw"			},

/* 0xc0 */	{	"addl2", 	"rl,ml"			},
/* 0xc1 */	{	"addl3", 	"rl,rl,wl"		},
/* 0xc2 */	{	"subl2", 	"rl,ml"			},
/* 0xc3 */	{	"subl3", 	"rl,rl,wl"		},
/* 0xc4 */	{	"mull2", 	"rl,ml"			},
/* 0xc5 */	{	"mull3", 	"rl,rl,wl"		},
/* 0xc6 */	{	"divl2", 	"rl,ml"			},
/* 0xc7 */	{	"divl3", 	"rl,rl,wl"		},
/* 0xc8 */	{	"bisl2", 	"rl,ml"			},
/* 0xc9 */	{	"bisl3", 	"rl,rl,wl"		},
/* 0xca */	{	"bicl2", 	"rl,ml"			},
/* 0xcb */	{	"bicl3", 	"rl,rl,wl"		},
/* 0xcc */	{	"xorl2", 	"rl,ml"			},
/* 0xcd */	{	"xorl3", 	"rl,rl,wl"		},
/* 0xce */	{	"mnegl", 	"rl,wl"			},
/* 0xcf */	{	"casel", 	"rl,rl,rl,bw-list"	},

/* 0xd0 */	{	"movl", 	"rl,wl"			},
/* 0xd1 */	{	"cmpl", 	"rl,rl"			},
/* 0xd2 */	{	"mcoml", 	"rl,wl"			},
/* 0xd3 */	{	"bitl", 	"rl,rl"			},
/* 0xd4 */	{	"*clrl", 	"wl"			},
/* 0xd5 */	{	"tstl", 	"rl"			},
/* 0xd6 */	{	"incl", 	"ml"			},
/* 0xd7 */	{	"decl", 	"ml"			},
/* 0xd8 */	{	"adwc", 	"rl,ml"			},
/* 0xd9 */	{	"sbwc", 	"rl,ml"			},
/* 0xda */	{	"mtpr", 	"rl,rl"			},
/* 0xdb */	{	"mfpr", 	"rl,wl"			},
/* 0xdc */	{	"movpsl", 	"wl"			},
/* 0xdd */	{	"pushl", 	"rl"			},
/* 0xde */	{	"*moval", 	"al,wl"			},
/* 0xdf */	{	"*pushal", 	"al"			},

/* 0xe0 */	{	"bbs", 		"rl,vb,bb"		},
/* 0xe1 */	{	"bbc", 		"rl,vb,bb"		},
/* 0xe2 */	{	"bbss", 	"rl,vb,bb"		},
/* 0xe3 */	{	"bbcs", 	"rl,vb,bb"		},
/* 0xe4 */	{	"bbsc", 	"rl,vb,bb"		},
/* 0xe5 */	{	"bbcc", 	"rl,vb,bb"		},
/* 0xe6 */	{	"bbssi", 	"rl,vb,bb"		},
/* 0xe7 */	{	"bbcci", 	"rl,vb,bb"		},
/* 0xe8 */	{	"blbs", 	"rl,bb"			},
/* 0xe9 */	{	"blbc", 	"rl,bb"			},
/* 0xea */	{	"ffs", 		"rl,rb,vb"		},
/* 0xeb */	{	"ffc", 		"rl,rb,vb"		},
/* 0xec */	{	"cmpv", 	"rl,rb,vb,rl"		},
/* 0xed */	{	"cmpzv", 	"rl,rb,vb,rl"		},
/* 0xee */	{	"extv", 	"rl,rb,vb,wl"		},
/* 0xef */	{	"extzv", 	"rl,rb,vb,wl"		},

/* 0xf0 */	{	"insv", 	"rl,rl,rb,vb"		},
/* 0xf1 */	{	"acbl", 	"rl,rl,ml,bw"		},
/* 0xf2 */	{	"aoblss", 	"rl,ml,bb"		},
/* 0xf3 */	{	"aobleq", 	"rl,ml,bb"		},
/* 0xf4 */	{	"sobgeq", 	"ml,bb"			},
/* 0xf5 */	{	"sobgtr", 	"ml,bb"			},
/* 0xf6 */	{	"cvtlb", 	"rl,wb"			},
/* 0xf7 */	{	"cvtlw", 	"rl,ww"			},
/* 0xf8 */	{	"ashp", 	"rb,rw,ab,rb,rw,ab"	},
/* 0xf9 */	{	"cvtlp", 	"rl,rw,ab"		},
/* 0xfa */	{	"callg", 	"ab,ab"			},
/* 0xfb */	{	"calls", 	"rl,ab"			},
/* 0xfc */	{	"xfc", 		"?"			},
/* 0xfd */	{	"-two-byte-", 	NULL			},
/* 0xfe */	{	"-two-byte-", 	NULL			},
/* 0xff */	{	"-two-byte-", 	NULL			},
};

/* two-byte instructions */
vax_instr_t vax_inst2[0x56] = {
/* reserved */	{	NULL,		NULL			},
/* 0xfd31 */	{	NULL,		NULL			},
/* 0xfd32 */	{	"cvtdh",	"rd,wh"			},
/* 0xfd33 */	{	"cvtgf",	"rg,wf"			},
/* 0xfd34 */	{	NULL,		NULL			},
/* 0xfd35 */	{	NULL,		NULL			},
/* 0xfd36 */	{	NULL,		NULL			},
/* 0xfd37 */	{	NULL,		NULL			},
/* 0xfd38 */	{	NULL,		NULL			},
/* 0xfd39 */	{	NULL,		NULL			},
/* 0xfd3a */	{	NULL,		NULL			},
/* 0xfd3b */	{	NULL,		NULL			},
/* 0xfd3c */	{	NULL,		NULL			},
/* 0xfd3d */	{	NULL,		NULL			},
/* 0xfd3e */	{	NULL,		NULL			},
/* 0xfd3f */	{	NULL,		NULL			},

/* 0xfd40 */	{	"addg2",	"rg,mg"			},
/* 0xfd41 */	{	"addg3",	"rg,rg,wg"		},
/* 0xfd42 */	{	"subg2",	"rg,mg"			},
/* 0xfd43 */	{	"subg3",	"rg,rg,wg"		},
/* 0xfd44 */	{	"mulg2",	"rg,mg"			},
/* 0xfd45 */	{	"mulg3",	"rg,rg,wg"		},
/* 0xfd46 */	{	"divg2",	"rg,mg"			},
/* 0xfd47 */	{	"divg3",	"rg,rg,wg"		},
/* 0xfd48 */	{	"cvtgb",	"rg,wb"			},
/* 0xfd49 */	{	"cvtgw",	"rg,ww"			},
/* 0xfd4a */	{	"cvtgl",	"rg,wl"			},
/* 0xfd4b */	{	"cvtrgl",	"rg,wl"			},
/* 0xfd4c */	{	"cvtbg",	"rb,wg"			},
/* 0xfd4d */	{	"cvtwg",	"rw,wg"			},
/* 0xfd4e */	{	"cvtlg",	"rl,wg"			},
/* 0xfd4f */	{	"acbg",		"rg,rg,mg,bg"		},

/* 0xfd50 */	{	"movg",		"rg,wg"			},
/* 0xfd51 */	{	"cmpg",		"rg,rg"			},
/* 0xfd52 */	{	"mnegg",	"rg,wg"			},
/* 0xfd53 */	{	"tstg",		"rg"			},
/* 0xfd54 */	{	"emodg",	"rg,rb,rg,wl,wg"	},
/* 0xfd55 */	{	"polyg",	"rg,rw,ab"			},
/* 0xfd56 */	{	"cvtgh",	"rg,wh"			},
/* 0xfd57 */	{	NULL,		NULL			},
/* 0xfd58 */	{	NULL,		NULL			},
/* 0xfd59 */	{	NULL,		NULL			},
/* 0xfd5a */	{	NULL,		NULL			},
/* 0xfd5b */	{	NULL,		NULL			},
/* 0xfd5c */	{	NULL,		NULL			},
/* 0xfd5d */	{	NULL,		NULL			},
/* 0xfd5e */	{	NULL,		NULL			},
/* 0xfd5f */	{	NULL,		NULL			},

/* 0xfd60 */	{	"addh2",	"rh,mh"			},
/* 0xfd61 */	{	"addh3",	"rh,rh,wh"		},
/* 0xfd62 */	{	"subh2",	"rh,mh"			},
/* 0xfd63 */	{	"subh3",	"rh,rh,wh"		},
/* 0xfd64 */	{	"mulh2",	"rh,mh"			},
/* 0xfd65 */	{	"mulh3",	"rh,rh,wh"		},
/* 0xfd66 */	{	"divh2",	"rh,mh"			},
/* 0xfd67 */	{	"divh3",	"rh,rh,wh"		},
/* 0xfd68 */	{	"cvthb",	"wh,rb"			},
/* 0xfd69 */	{	"cvthw",	"rh,ww"			},
/* 0xfd6a */	{	"cvthl",	"rh,wl"			},
/* 0xfd6b */	{	"cvtrhl",	"rh,wl"			},
/* 0xfd6c */	{	"cvtbh",	"rb,wh"			},
/* 0xfd6d */	{	"cvtwh",	"rw,wh"			},
/* 0xfd6e */	{	"cvtlh",	"rl,wh"			},
/* 0xfd6f */	{	"acbh",		"rh,rh,mh,bh"		},

/* 0xfd70 */	{	"movh",		"rh,wh"			},
/* 0xfd71 */	{	"cmph",		"rh,rh"			},
/* 0xfd72 */	{	"mnegh",	"rh,wh"			},
/* 0xfd73 */	{	"tsth",		"rh"			},
/* 0xfd74 */	{	"emodh"		"rh,rb,rh,wl,wh"	},
/* 0xfd75 */	{	"polyh",	"rh,rw,ab"		},
/* 0xfd76 */	{	"cvthg",	"rh,wg"			},
/* 0xfd77 */	{	NULL,		NULL			},
/* 0xfd78 */	{	NULL,		NULL			},
/* 0xfd79 */	{	NULL,		NULL			},
/* 0xfd7a */	{	NULL,		NULL			},
/* 0xfd7b */	{	NULL,		NULL			},
/* 0xfd7c */	{	"clrh",		"wh"			},
/* 0xfd7d */	{	"movo",		"ro,wo"			},
/* 0xfd7e */	{	"*mova",	"ao,wl"			},
/* 0xfd7f */	{	"*pusha",	"ao"			},

/* 0xfd98 */	{	"cvtfh",	"rf,wh"			},
/* 0xfd99 */	{	"cvtfg",	"rf,wg"			},
/* 0xfdf6 */	{	"cvthf",	"rh,wf"			},
/* 0xfdf7 */	{	"cvthd",	"rh,wd"			},
/* 0xfffd */	{	"bugl",		"bl"			},
/* 0xfffe */	{	"bugw",		"bw"			},
};


code:
/*	$OpenBSD: pmap.c,v 1.77 2015/06/17 17:15:07 miod Exp $ */
/*	$NetBSD: pmap.c,v 1.74 1999/11/13 21:32:25 matt Exp $	   */
/*
 * Copyright (c) 1994, 1998, 1999, 2003 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/queue.h>
#include <sys/malloc.h>
#include <sys/extent.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/msgbuf.h>
#include <sys/pool.h>

#ifdef PMAPDEBUG
#include <dev/cons.h>
#endif

#include <uvm/uvm.h>

#include <machine/pte.h>
#include <machine/pcb.h>
#include <machine/mtpr.h>
#include <machine/macros.h>
#include <machine/sid.h>
#include <machine/cpu.h>
#include <machine/scb.h>
#include <machine/rpb.h>

#define ISTACK_SIZE (NBPG * 2)
vaddr_t	istack;

struct pmap kernel_pmap_store;

pt_entry_t *Sysmap;		/* System page table */
u_int	sysptsize;

/*
 * Scratch pages usage:
 * Page 1: initial frame pointer during autoconfig. Stack and pcb for
 *	   processes during exit on boot CPU only.
 * Page 2: unused
 * Page 3: unused
 * Page 4: unused
 */
vaddr_t scratch;
#define	SCRATCHPAGES	4

vaddr_t	iospace;

vaddr_t ptemapstart, ptemapend;
struct	extent *ptemap;
#define	PTMAPSZ	EXTENT_FIXED_STORAGE_SIZE(100)
char	ptmapstorage[PTMAPSZ];

struct pool pmap_pmap_pool;
struct pool pmap_ptp_pool;
struct pool pmap_pv_pool;

#define	NPTEPG		0x80	/* # of PTEs per page (logical or physical) */
#define	PPTESZ		sizeof(pt_entry_t)
#define	NPTEPERREG	0x200000

#define	SEGTYPE(x)	(((vaddr_t)(x)) >> 30)
#define	P0SEG		0
#define	P1SEG		1
#define	SYSSEG		2

#define USRPTSIZE	((MAXTSIZ + MAXDSIZ + BRKSIZ + MAXSSIZ) / VAX_NBPG)
#define	NPTEPGS		(USRPTSIZE / (NBPG / (sizeof(pt_entry_t) * LTOHPN)))

/* Mapping macros used when allocating SPT */
#define MAPVIRT(ptr, count)						\
do {									\
	ptr = virtual_avail;						\
	virtual_avail += (count) * VAX_NBPG;				\
} while (0)

#ifdef PMAPDEBUG
volatile int recurse;
#define RECURSESTART							\
do {									\
	if (recurse)							\
		printf("enter at %d, previous %d\n", __LINE__, recurse);\
	recurse = __LINE__;						\
} while (0)
#define RECURSEEND							\
do {									\
	recurse = 0;							\
} while (0)
int	startpmapdebug = 0;
#define PMDEBUG(x) if (startpmapdebug) printf x
#else
#define RECURSESTART
#define RECURSEEND
#define	PMDEBUG(x)
#endif

vsize_t	calc_kvmsize(vsize_t);
u_long	pmap_extwrap(vsize_t);
void	rmpage(struct pmap *, pt_entry_t *);
void	update_pcbs(struct pmap *);
void	rmspace(struct pmap *);
int	pmap_rmproc(struct pmap *);
vaddr_t	pmap_getusrptes(struct pmap *, vsize_t, int);
void	rmptep(pt_entry_t *);
boolean_t grow_p0(struct pmap *, u_long, int);
boolean_t grow_p1(struct pmap *, u_long, int);
pt_entry_t *vaddrtopte(const struct pv_entry *pv);
void	pmap_remove_pcb(struct pmap *, struct pcb *);

/*
 * Map in a virtual page.
 */
static inline void
mapin8(pt_entry_t *ptep, pt_entry_t pte)
{
	ptep[0] = pte;
	ptep[1] = pte + 1;
	ptep[2] = pte + 2;
	ptep[3] = pte + 3;
	ptep[4] = pte + 4;
	ptep[5] = pte + 5;
	ptep[6] = pte + 6;
	ptep[7] = pte + 7;
}

/*
 * Check if page table page is in use.
 */
static inline int
ptpinuse(pt_entry_t *pte)
{
	pt_entry_t *pve = (pt_entry_t *)vax_trunc_page(pte);
	uint i;

	for (i = 0; i < NPTEPG; i += LTOHPN)
		if (pve[i] != PG_NV)
			return 1;
	return 0;
}

vaddr_t   avail_start, avail_end;
vaddr_t   virtual_avail, virtual_end; /* Available virtual memory */

#define	get_pventry()    (struct pv_entry *)pool_get(&pmap_pv_pool, PR_NOWAIT)
#define	free_pventry(pv) pool_put(&pmap_pv_pool, (void *)pv)

static inline
paddr_t
get_ptp(boolean_t waitok)
{
	pt_entry_t *ptp;

	ptp = (pt_entry_t *)pool_get(&pmap_ptp_pool,
	    PR_ZERO | (waitok ? PR_WAITOK : PR_NOWAIT));
	if (ptp == NULL)
		return 0;
	return ((paddr_t)ptp) & ~KERNBASE;
}

#define	free_ptp(pa)	pool_put(&pmap_ptp_pool, (void *)(pa | KERNBASE))

/*
 * Calculation of the System Page Table is somewhat a pain, because it
 * must be in contiguous physical memory and all size calculations must
 * be done before memory management is turned on.
 * Arg is usrptsize in ptes.
 */
vsize_t
calc_kvmsize(vsize_t usrptsize)
{
	vsize_t kvmsize;

	/*
	 * Compute the number of pages kmem_map will have.
	 */
	kmeminit_nkmempages();

	/* All physical memory (reverse mapping struct) */
	kvmsize = avail_end;
	/* User Page table area. This may be large */
	kvmsize += usrptsize * sizeof(pt_entry_t);
	/* Kernel stacks per process */
	kvmsize += USPACE * maxthread;
	/* kernel malloc arena */
	kvmsize += nkmempages * PAGE_SIZE;
	/* IO device register space */
	kvmsize += IOSPSZ * VAX_NBPG;
	/* Pager allocations */
	kvmsize += PAGER_MAP_SIZE;
	/* kernel malloc arena */
	kvmsize += avail_end;

	/* Exec arg space */
	kvmsize += 16 * NCARGS;
#if VAX46 || VAX48 || VAX49 || VAX53 || VAX60
	/* Physmap */
	kvmsize += VM_PHYS_SIZE;
#endif

	return round_page(kvmsize);
}

/*
 * pmap_bootstrap().
 * Called as part of vm bootstrap, allocates internal pmap structures.
 * Assumes that nothing is mapped, and that kernel stack is located
 * immediately after end.
 */
void
pmap_bootstrap()
{
	unsigned int i;
	extern	unsigned int etext, proc0paddr;
	struct pcb *pcb = (struct pcb *)proc0paddr;
	struct pmap *pmap = pmap_kernel();
	vsize_t kvmsize, usrptsize, minusrptsize;

	/* Set logical page size */
	uvmexp.pagesize = NBPG;
	uvm_setpagesize();

	/*
	 * Compute how much page table space a process reaching all its
	 * limits would need. Try to afford four times such this space,
	 * but try and limit ourselves to 5% of the free memory.
	 */
	minusrptsize = (MAXTSIZ + MAXDSIZ + BRKSIZ + MAXSSIZ) / VAX_NBPG;
	usrptsize = 4 * minusrptsize;
	if (vax_btop(usrptsize * PPTESZ) > avail_end / 20)
		usrptsize = (avail_end / (20 * PPTESZ)) * VAX_NBPG;
	if (usrptsize < minusrptsize)
		usrptsize = minusrptsize;

	kvmsize = calc_kvmsize(usrptsize);
	sysptsize = vax_btop(kvmsize);

	/*
	 * Virtual_* and avail_* is used for mapping of system page table.
	 * The need for kernel virtual memory is linear dependent of the
	 * amount of physical memory also, therefore sysptsize is
	 * a variable here that is changed dependent of the physical
	 * memory size.
	 */
	virtual_avail = avail_end + KERNBASE;
	virtual_end = KERNBASE + sysptsize * VAX_NBPG;
	/* clear SPT before using it */
	memset(Sysmap, 0, sysptsize * sizeof(pt_entry_t));

	/*
	 * The first part of Kernel Virtual memory is the physical
	 * memory mapped in. This makes some mm routines both simpler
	 * and faster, but takes ~0.75% more memory.
	 */
	pmap_map(KERNBASE, 0, avail_end, PROT_READ | PROT_WRITE);

	/* make sure kernel text is read-only */
	for (i = 0; i < ((unsigned)&etext & ~KERNBASE) >> VAX_PGSHIFT; i++)
		Sysmap[i] = (Sysmap[i] & ~PG_PROT) | PG_KR;

	/* Map System Page Table and zero it,  Sysmap already set. */
	mtpr((vaddr_t)Sysmap - KERNBASE, PR_SBR);

	/* Map Interrupt stack and set red zone */
	istack = (vaddr_t)Sysmap + round_page(sysptsize * sizeof(pt_entry_t));
	mtpr(istack + ISTACK_SIZE, PR_ISP);
	*kvtopte(istack) &= ~PG_V;

	/* Some scratch pages */
	scratch = istack + ISTACK_SIZE;

	avail_start = (vaddr_t)(scratch + SCRATCHPAGES * VAX_NBPG) - KERNBASE;

	/* Kernel message buffer */
	avail_end -= round_page(MSGBUFSIZE);
	msgbufp = (void *)(avail_end + KERNBASE);
	msgbufp->msg_magic = MSG_MAGIC-1; 	/* ensure that it will be zeroed */

	/* zero all mapped physical memory from Sysmap to here */
	memset((void *)istack, 0, (avail_start + KERNBASE) - istack);

	/* User page table map. This is big. */
	MAPVIRT(ptemapstart, vax_atop(usrptsize * sizeof(pt_entry_t)));
	ptemapend = virtual_avail;

	MAPVIRT(iospace, IOSPSZ); /* Device iospace mapping area */

	/* Init SCB and set up stray vectors. */
	avail_start = scb_init(avail_start);
	bcopy((caddr_t)proc0paddr + REDZONEADDR, 0, sizeof(struct rpb));

	if (dep_call->cpu_init)
		(*dep_call->cpu_init)();

	avail_start = round_page(avail_start);
	virtual_avail = round_page(virtual_avail);
	virtual_end = trunc_page(virtual_end);

#if 0 /* Breaks cninit() on some machines */
	cninit();
	printf("Sysmap %p, istack %p, scratch %p\n", Sysmap, istack, scratch);
	printf("etext %p\n", &etext);
	printf("SYSPTSIZE %x usrptsize %lx\n",
	    sysptsize, usrptsize * sizeof(pt_entry_t));
	printf("ptemapstart %lx ptemapend %lx\n", ptemapstart, ptemapend);
	printf("avail_start %lx, avail_end %lx\n", avail_start, avail_end);
	printf("virtual_avail %lx,virtual_end %lx\n",
	    virtual_avail, virtual_end);
	printf("startpmapdebug %p\n",&startpmapdebug);
#endif

	/* Init kernel pmap */
	pmap->pm_p1br = (pt_entry_t *)KERNBASE;
	pmap->pm_p0br = (pt_entry_t *)KERNBASE;
	pmap->pm_p1lr = NPTEPERREG;
	pmap->pm_p0lr = 0;
	pmap->pm_stats.wired_count = pmap->pm_stats.resident_count = 0;
	    /* btop(virtual_avail - KERNBASE); */

	pmap->pm_count = 1;

	/* Activate the kernel pmap. */
	pcb->P1BR = pmap->pm_p1br;
	pcb->P0BR = pmap->pm_p0br;
	pcb->P1LR = pmap->pm_p1lr;
	pcb->P0LR = pmap->pm_p0lr | AST_PCB;
	pcb->pcb_pm = pmap;
	pcb->pcb_pmnext = pmap->pm_pcbs;
	pmap->pm_pcbs = pcb;
	mtpr((register_t)pcb->P1BR, PR_P1BR);
	mtpr((register_t)pcb->P0BR, PR_P0BR);
	mtpr(pcb->P1LR, PR_P1LR);
	mtpr(pcb->P0LR, PR_P0LR);

	/* Create the pmap, ptp and pv_entry pools. */
	pool_init(&pmap_pmap_pool, sizeof(struct pmap), 0, 0, 0,
	    "pmap_pool", NULL);
	pool_init(&pmap_ptp_pool, VAX_NBPG, 0, 0, 0, "ptp_pool", NULL);
	pool_init(&pmap_pv_pool, sizeof(struct pv_entry), 0, 0, 0,
	    "pv_pool", NULL);

	/*
	 * Now everything should be complete, start virtual memory.
	 */
	uvm_page_physload(atop(avail_start), atop(avail_end),
	    atop(avail_start), atop(avail_end), 0);
	mtpr(sysptsize, PR_SLR);
	rpb.sbr = mfpr(PR_SBR);
	rpb.slr = mfpr(PR_SLR);
	mtpr(1, PR_MAPEN);
}

void
pmap_virtual_space(vaddr_t *vstartp, vaddr_t *vendp)
{
	*vstartp = virtual_avail;
	*vendp = virtual_end;
}

/*
 * Let the VM system do early memory allocation from the direct-mapped
 * physical memory instead.
 */
vaddr_t
pmap_steal_memory(vsize_t size, vaddr_t *vstartp, vaddr_t *vendp)
{
	vaddr_t v;
	int npgs;

	PMDEBUG(("pmap_steal_memory: size 0x%lx start %p end %p\n",
	    size, vstartp, vendp));

	size = round_page(size);
	npgs = atop(size);

#ifdef DIAGNOSTIC
	if (uvm.page_init_done == TRUE)
		panic("pmap_steal_memory: called _after_ bootstrap");
#endif

	/*
	 * A vax only has one segment of memory.
	 */

	v = (vm_physmem[0].avail_start << PAGE_SHIFT) | KERNBASE;
	vm_physmem[0].avail_start += npgs;
	vm_physmem[0].start += npgs;
	if (vstartp)
		*vstartp = virtual_avail;
	if (vendp)
		*vendp = virtual_end;
	bzero((caddr_t)v, size);
	return v;
}

/*
 * pmap_init() is called as part of vm init after memory management
 * is enabled. It is meant to do machine-specific allocations.
 * The extent for the user page tables is initialized here.
 */
void
pmap_init()
{
        /*
         * Create the extent map used to manage the page table space.
         */
        ptemap = extent_create("ptemap", ptemapstart, ptemapend,
            M_VMPMAP, ptmapstorage, PTMAPSZ, EX_NOCOALESCE);
        if (ptemap == NULL)
		panic("pmap_init");
}

u_long
pmap_extwrap(vsize_t nsize)
{
	int res;
	u_long rv;

	for (;;) {
		res = extent_alloc(ptemap, nsize, PAGE_SIZE, 0, 0,
		    EX_WAITOK | EX_MALLOCOK, &rv);
		if (res == 0)
			return rv;
		if (res == EAGAIN)
			return 0;
	}
}

/*
 * Do a page removal from the pv list. A page is identified by its
 * virtual address combined with its struct pmap in the page's pv list.
 */
void
rmpage(struct pmap *pm, pt_entry_t *br)
{
	struct pv_entry *pv, *pl, *pf;
	vaddr_t vaddr;
	struct vm_page *pg;
	int s, found = 0;

	/*
	 * Check that we are working on a managed page.
	 */
	pg = PHYS_TO_VM_PAGE((*br & PG_FRAME) << VAX_PGSHIFT);
	if (pg == NULL)
		return;

	if (pm == pmap_kernel()) {
#ifdef DIAGNOSTIC
		if (br - Sysmap >= sysptsize)
			panic("%s: bogus Sysmap pte pointer %p", __func__, br);
#endif
		vaddr = (br - Sysmap) * VAX_NBPG + 0x80000000;
	} else if (br >= pm->pm_p0br && br < pm->pm_p0br + pm->pm_p0lr)
		vaddr = (br - pm->pm_p0br) * VAX_NBPG;
	else {
		vaddr = (br - pm->pm_p1br) * VAX_NBPG + 0x40000000;
#ifdef DIAGNOSTIC
		if (vaddr < 0x40000000 || vaddr >= 0x80000000)
			panic("%s: bogus pmap %p P1 pte pointer %p", __func__, pm, br);
#endif
	}

	s = splvm();
	for (pl = NULL, pv = pg->mdpage.pv_head; pv != NULL; pl = pv, pv = pf) {
		pf = pv->pv_next;
		if (pv->pv_pmap == pm && pv->pv_va == vaddr) {
			if ((pg->mdpage.pv_attr & (PG_V|PG_M)) != (PG_V|PG_M)) {
				switch (br[0] & PG_PROT) {
				case PG_URKW:
				case PG_KW:
				case PG_RW:
					pg->mdpage.pv_attr |=
					    br[0] | br[1] | br[2] | br[3] |
					    br[4] | br[5] | br[6] | br[7];
					break;
				}
			}
			if (pf != NULL) {
				*pv = *pf;
				free_pventry(pf);
			} else {
				if (pl != NULL)
					pl->pv_next = pv->pv_next;
				else
					pg->mdpage.pv_head = NULL;
				free_pventry(pv);
			}
			found++;
			break;
		}
	}
	splx(s);
	if (found == 0)
		panic("rmpage: pg %p br %p", pg, br);
}

/*
 * Update the PCBs using this pmap after a change.
 */
void
update_pcbs(struct pmap *pm)
{
	struct pcb *pcb;

	PMDEBUG(("update_pcbs pm %p\n", pm));

	for (pcb = pm->pm_pcbs; pcb != NULL; pcb = pcb->pcb_pmnext) {
		KASSERT(pcb->pcb_pm == pm);
		pcb->P0BR = pm->pm_p0br;
		pcb->P0LR = pm->pm_p0lr | AST_PCB;
		pcb->P1BR = pm->pm_p1br;
		pcb->P1LR = pm->pm_p1lr;
	}

	/* If curproc uses this pmap update the regs too */
	if (pm == curproc->p_vmspace->vm_map.pmap) {
		PMDEBUG(("update_pcbs: %08x %08x %08x %08x\n",
		    pm->pm_p0br, pm->pm_p0lr, pm->pm_p1br, pm->pm_p1lr));
                mtpr((register_t)pm->pm_p0br, PR_P0BR);
                mtpr(pm->pm_p0lr | AST_PCB, PR_P0LR);
                mtpr((register_t)pm->pm_p1br, PR_P1BR);
                mtpr(pm->pm_p1lr, PR_P1LR);
	}
}

/*
 * Remove a full process space. Update all processes pcbs.
 */
void
rmspace(struct pmap *pm)
{
	u_long lr, i, j;
	pt_entry_t *ptpp, *br;
	int s;

	if (pm->pm_p0lr == 0 && pm->pm_p1lr == NPTEPERREG)
		return; /* Already free */

	lr = pm->pm_p0lr / NPTEPG;
	for (i = 0; i < lr; i++) {
		ptpp = kvtopte((vaddr_t)&pm->pm_p0br[i * NPTEPG]);
		if (*ptpp == PG_NV)
			continue;
		br = &pm->pm_p0br[i * NPTEPG];
		for (j = 0; j < NPTEPG; j += LTOHPN) {
			if (br[j] == 0)
				continue;
			rmpage(pm, &br[j]);
		}
		free_ptp((*ptpp & PG_FRAME) << VAX_PGSHIFT);
		*ptpp = PG_NV;
	}
	lr = pm->pm_p1lr / NPTEPG;
	for (i = lr; i < NPTEPERREG / NPTEPG; i++) {
		ptpp = kvtopte((vaddr_t)&pm->pm_p1br[i * NPTEPG]);
		if (*ptpp == PG_NV)
			continue;
		br = &pm->pm_p1br[i * NPTEPG];
		for (j = 0; j < NPTEPG; j += LTOHPN) {
			if (br[j] == 0)
				continue;
			rmpage(pm, &br[j]);
		}
		free_ptp((*ptpp & PG_FRAME) << VAX_PGSHIFT);
		*ptpp = PG_NV;
	}

	s = splsched();

	if (pm->pm_p0lr != 0)
		extent_free(ptemap, (u_long)pm->pm_p0br,
		    pm->pm_p0lr * PPTESZ, EX_WAITOK);
	if (pm->pm_p1lr != NPTEPERREG)
		extent_free(ptemap, (u_long)pm->pm_p1ap,
		    (NPTEPERREG - pm->pm_p1lr) * PPTESZ, EX_WAITOK);
	pm->pm_p0br = pm->pm_p1br = (pt_entry_t *)KERNBASE;
	pm->pm_p0lr = 0;
	pm->pm_p1lr = NPTEPERREG;
	pm->pm_p1ap = NULL;
	update_pcbs(pm);

	splx(s);
}

/*
 * Find a process to remove the process space for. *sigh*
 * Avoid to remove ourselves. Logic is designed after uvm_swapout_threads().
 */

int
pmap_rmproc(struct pmap *pm)
{
	struct process *pr, *outpr;
	struct pmap *ppm;
	struct proc *p, *slpp;
	int outpri;
	int didswap = 0;
	extern int maxslp;

	outpr = NULL;
	outpri = 0;
	LIST_FOREACH(pr, &allprocess, ps_list) {
		if (pr->ps_flags & (PS_SYSTEM | PS_EXITING))
			continue;
		ppm = pr->ps_vmspace->vm_map.pmap;
		if (ppm == pm)		/* Don't swap ourself */
			continue;
		if (ppm->pm_p0lr == 0 && ppm->pm_p1lr == NPTEPERREG)
			continue;	/* Already swapped */

		/*
		 * slpp: the sleeping or stopped thread in pr with
		 * the smallest p_slptime
		 */
		slpp = NULL;
		TAILQ_FOREACH(p, &pr->ps_threads, p_thr_link) {
			switch (p->p_stat) {
			case SRUN:
			case SONPROC:
				goto next_process;

			case SSLEEP:
			case SSTOP:
				if (slpp == NULL ||
				    slpp->p_slptime < p->p_slptime)
					slpp = p;
				continue;
			}
		}
		if (slpp != NULL) {
			if (slpp->p_slptime >= maxslp) {
				rmspace(ppm);
				didswap++;
			} else if (slpp->p_slptime > outpri) {
				outpr = pr;
				outpri = slpp->p_slptime;
			}
		}
		if (didswap)
			break;
next_process:	;
	}

	if (didswap == 0 && outpr != NULL) {
		rmspace(outpr->ps_vmspace->vm_map.pmap);
		didswap++;
	}
	return didswap;
}

/*
 * Allocate space for user page tables, from ptemap.
 * If the map is full then:
 * 1) Remove processes idle for more than 20 seconds or stopped.
 * 2) Remove processes idle for less than 20 seconds.
 *
 * Argument is needed space, in bytes.
 * Returns a pointer to the newly allocated space, or zero if space could not
 * be allocated and failure is allowed. Panics otherwise.
 */
vaddr_t
pmap_getusrptes(struct pmap *pm, vsize_t nsize, int canfail)
{
	u_long rv;

#ifdef DEBUG
	if (nsize & PAGE_MASK)
		panic("pmap_getusrptes: bad size %lx", nsize);
#endif
	for (;;) {
		rv = pmap_extwrap(nsize);
		if (rv != 0)
			return rv;
		if (pmap_rmproc(pm) == 0) {
			if (canfail)
				return 0;
			else
				panic("out of space in usrptmap");
		}
	}
}

/*
 * Remove a pte page when all references are gone.
 */
void
rmptep(pt_entry_t *pte)
{
	pt_entry_t *ptpp = kvtopte((vaddr_t)pte);

	PMDEBUG(("rmptep: pte %p -> ptpp %p\n", pte, ptpp));

#ifdef DEBUG
	{
		int i;
		pt_entry_t *ptr = (pt_entry_t *)vax_trunc_page(pte);
		for (i = 0; i < NPTEPG; i++)
			if (ptr[i] != 0)
				panic("rmptep: ptr[%d] != 0", i);
	}
#endif

	free_ptp((*ptpp & PG_FRAME) << VAX_PGSHIFT);
	*ptpp = PG_NV;
}

boolean_t
grow_p0(struct pmap *pm, u_long reqlen, int canfail)
{
	vaddr_t nptespc;
	pt_entry_t *from, *to;
	size_t srclen, dstlen;
	u_long p0br, p0lr, len;
	int inuse;
	int s;

	PMDEBUG(("grow_p0: pmap %p reqlen %x\n", pm, reqlen));

	/* Get new pte space */
	p0lr = pm->pm_p0lr;
	inuse = p0lr != 0;
	len = round_page((reqlen + 1) * PPTESZ);
	RECURSEEND;
	nptespc = pmap_getusrptes(pm, len, canfail);
	if (nptespc == 0)
		return FALSE;
	RECURSESTART;

	s = splsched();

	/*
	 * Copy the old ptes to the new space.
	 * Done by moving on system page table.
	 */
	srclen = vax_btop(p0lr * PPTESZ) * PPTESZ;
	dstlen = vax_atop(len) * PPTESZ;
	from = kvtopte((vaddr_t)pm->pm_p0br);
	to = kvtopte(nptespc);

	PMDEBUG(("grow_p0: from %p to %p src %x dst %x\n",
	    from, to, srclen, dstlen));

	if (inuse)
		memcpy(to, from, srclen);
	bzero((char *)to + srclen, dstlen - srclen);

	p0br = (u_long)pm->pm_p0br;
	pm->pm_p0br = (pt_entry_t *)nptespc;
	pm->pm_p0lr = len / PPTESZ;
	update_pcbs(pm);

	splx(s);

	if (inuse)
		extent_free(ptemap, p0br, p0lr * PPTESZ, EX_WAITOK);

	return TRUE;
}

boolean_t
grow_p1(struct pmap *pm, u_long len, int canfail)
{
	vaddr_t nptespc, optespc;
	pt_entry_t *from, *to;
	size_t nlen, olen;
	int s;

	PMDEBUG(("grow_p1: pm %p len %x\n", pm, len));

	/* Get new pte space */
	nlen = (NPTEPERREG * PPTESZ) - trunc_page(len * PPTESZ);
	RECURSEEND;
	nptespc = pmap_getusrptes(pm, nlen, canfail);
	if (nptespc == 0)
		return FALSE;
	RECURSESTART;

	s = splsched();

	olen = (NPTEPERREG - pm->pm_p1lr) * PPTESZ;
	optespc = (vaddr_t)pm->pm_p1ap;

	/*
	 * Copy the old ptes to the new space.
	 * Done by moving on system page table.
	 */
	from = kvtopte(optespc);
	to = kvtopte(nptespc);

	PMDEBUG(("grow_p1: from %p to %p src %x dst %x\n",
	    from, to, vax_btop(olen), vax_btop(nlen)));

	bzero(to, vax_btop(nlen - olen) * PPTESZ);
	if (optespc)
		memcpy(kvtopte(nptespc + nlen - olen), from,
		    vax_btop(olen) * PPTESZ);

	pm->pm_p1ap = (pt_entry_t *)nptespc;
	pm->pm_p1br = (pt_entry_t *)(nptespc + nlen - (NPTEPERREG * PPTESZ));
	pm->pm_p1lr = NPTEPERREG - nlen / PPTESZ;
	update_pcbs(pm);

	splx(s);

	if (optespc)
		extent_free(ptemap, optespc, olen, EX_WAITOK);

	return TRUE;
}

/*
 * pmap_create() creates a pmap for a new task.
 */
struct pmap *
pmap_create()
{
	struct pmap *pmap;

	pmap = pool_get(&pmap_pmap_pool, PR_WAITOK | PR_ZERO);

	/*
	 * Do not allocate any pte's here, we don't know the size and
	 * we'll get a page fault anyway when some page is referenced,
	 * so defer until then.
	 */
	pmap->pm_p0br = pmap->pm_p1br = (pt_entry_t *)KERNBASE;
	pmap->pm_p0lr = 0;
	pmap->pm_p1lr = NPTEPERREG;
	pmap->pm_p1ap = NULL;

	PMDEBUG(("pmap_create: pmap %p p0br=%p p0lr=0x%lx p1br=%p p1lr=0x%lx\n",
    	    pmap, pmap->pm_p0br, pmap->pm_p0lr, pmap->pm_p1br, pmap->pm_p1lr));

	pmap->pm_count = 1;
	/* pmap->pm_stats.resident_count = pmap->pm_stats.wired_count = 0; */

	return pmap;
}

void
pmap_remove_holes(struct vmspace *vm)
{
	struct vm_map *map = &vm->vm_map;
	struct pmap *pmap = map->pmap;
	vaddr_t shole, ehole;

	if (pmap == pmap_kernel())	/* can of worms */
		return;

	shole = MAXTSIZ + MAXDSIZ + BRKSIZ;
	ehole = (vaddr_t)vm->vm_maxsaddr;
	shole = max(vm_map_min(map), shole);
	ehole = min(vm_map_max(map), ehole);

	if (ehole <= shole)
		return;

	(void)uvm_map(map, &shole, ehole - shole, NULL, UVM_UNKNOWN_OFFSET, 0,
	    UVM_MAPFLAG(PROT_NONE, PROT_NONE, MAP_INHERIT_SHARE, MADV_RANDOM,
	      UVM_FLAG_NOMERGE | UVM_FLAG_HOLE | UVM_FLAG_FIXED));
}

void
pmap_unwire(struct pmap *pmap, vaddr_t va)
{
	pt_entry_t *pte;
	uint i;

	RECURSESTART;
	if (va & KERNBASE) {
		pte = Sysmap;
		i = vax_btop(va - KERNBASE);
	} else {
		if (va < 0x40000000)
			pte = pmap->pm_p0br;
		else
			pte = pmap->pm_p1br;
		i = PG_PFNUM(va);
	}

	pte[i] &= ~PG_W;
	RECURSEEND;
	pmap->pm_stats.wired_count--;
}

/*
 * pmap_destroy(pmap): Remove a reference from the pmap.
 * If this was the last reference, release all its resources.
 */
void
pmap_destroy(struct pmap *pmap)
{
	int count;
#ifdef DEBUG
	vaddr_t saddr, eaddr;
#endif

	PMDEBUG(("pmap_destroy: pmap %p\n",pmap));

	count = --pmap->pm_count;
	if (count != 0)
		return;

#ifdef DIAGNOSTIC
	if (pmap->pm_pcbs)
		panic("pmap_destroy used pmap");
#endif

	if (pmap->pm_p0br != 0) {
#ifdef DEBUG
		saddr = (vaddr_t)pmap->pm_p0br;
		eaddr = saddr + pmap->pm_p0lr * PPTESZ;
		for (; saddr < eaddr; saddr += PAGE_SIZE)
			if ((*kvtopte(saddr) & PG_FRAME) != 0)
				panic("pmap_release: P0 page mapped");
		saddr = (vaddr_t)pmap->pm_p1br + pmap->pm_p1lr * PPTESZ;
		eaddr = VM_MAXUSER_ADDRESS;
		for (; saddr < eaddr; saddr += PAGE_SIZE)
			if ((*kvtopte(saddr) & PG_FRAME) != 0)
				panic("pmap_release: P1 page mapped");
#endif
	}

	if (pmap->pm_p0lr != 0)
		extent_free(ptemap, (u_long)pmap->pm_p0br,
		    pmap->pm_p0lr * PPTESZ, EX_WAITOK);
	if (pmap->pm_p1lr != NPTEPERREG)
		extent_free(ptemap, (u_long)pmap->pm_p1ap,
		    (NPTEPERREG - pmap->pm_p1lr) * PPTESZ, EX_WAITOK);

	pool_put(&pmap_pmap_pool, pmap);
}

pt_entry_t *
vaddrtopte(const struct pv_entry *pv)
{
	struct pmap *pm;

	if (pv->pv_va & KERNBASE)
		return &Sysmap[(pv->pv_va & ~KERNBASE) >> VAX_PGSHIFT];
	pm = pv->pv_pmap;
	if (pv->pv_va & 0x40000000)
		return &pm->pm_p1br[vax_btop(pv->pv_va & ~0x40000000)];
	else
		return &pm->pm_p0br[vax_btop(pv->pv_va)];
}

/*
 * New (real nice!) function that allocates memory in kernel space
 * without tracking it in the MD code.
 */
void
pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
{
	pt_entry_t *ptp, opte;

	ptp = kvtopte(va);

	PMDEBUG(("pmap_kenter_pa: va: %lx, pa %lx, prot %x ptp %p\n",
	    va, pa, prot, ptp));

	opte = ptp[0];
	if ((opte & PG_FRAME) == 0) {
		pmap_kernel()->pm_stats.resident_count++;
		pmap_kernel()->pm_stats.wired_count++;
	}
	mapin8(ptp, PG_V | ((prot & PROT_WRITE) ? PG_KW : PG_KR) |
	    PG_PFNUM(pa) | PG_W | PG_SREF);
	if (opte & PG_V) {
		mtpr(0, PR_TBIA);
	}
}

void
pmap_kremove(vaddr_t va, vsize_t len)
{
	pt_entry_t *pte;
#ifdef PMAPDEBUG
	int i;
#endif

	PMDEBUG(("pmap_kremove: va: %lx, len %lx, ptp %p\n",
	    va, len, kvtopte(va)));

	pte = kvtopte(va);

#ifdef PMAPDEBUG
	/*
	 * Check if any pages are on the pv list.
	 * This shouldn't happen anymore.
	 */
	len >>= PAGE_SHIFT;
	for (i = 0; i < len; i++) {
		if ((*pte & PG_FRAME) == 0)
			continue;
		pmap_kernel()->pm_stats.resident_count--;
		pmap_kernel()->pm_stats.wired_count--;
		if ((*pte & PG_SREF) == 0)
			panic("pmap_kremove");
		bzero(pte, LTOHPN * sizeof(pt_entry_t));
		pte += LTOHPN;
	}
#else
	len >>= PAGE_SHIFT;
	pmap_kernel()->pm_stats.resident_count -= len;
	pmap_kernel()->pm_stats.wired_count -= len;
	bzero(pte, len * LTOHPN * sizeof(pt_entry_t));
#endif
	mtpr(0, PR_TBIA);
}

/*
 * pmap_enter() is the main routine that puts in mappings for pages, or
 * upgrades mappings to more "rights".
 */
int
pmap_enter(struct pmap *pmap, vaddr_t v, paddr_t p, vm_prot_t prot, int flags)
{
	struct pv_entry *pv;
	struct vm_page *pg;
	pt_entry_t newpte, oldpte;
	pt_entry_t *pteptr;	/* current pte to write mapping info to */
	pt_entry_t *ptpptr;	/* ptr to page table page */
	u_long pteidx;
	int s;

	PMDEBUG(("pmap_enter: pmap %p v %lx p %lx prot %x wired %d flags %x\n",
	    pmap, v, p, prot, (flags & PMAP_WIRED) != 0, flags));

	RECURSESTART;

	/* Find address of correct pte */
	switch (SEGTYPE(v)) {
	case SYSSEG:
		pteptr = Sysmap + vax_btop(v - KERNBASE);
		newpte = prot & PROT_WRITE ? PG_KW : PG_KR;
		break;
	case P0SEG:
		pteidx = vax_btop(v);
		if (pteidx >= pmap->pm_p0lr) {
			if (!grow_p0(pmap, pteidx, flags & PMAP_CANFAIL))
				return ENOMEM;
		}
		pteptr = pmap->pm_p0br + pteidx;
		newpte = prot & PROT_WRITE ? PG_RW : PG_RO;
		break;
	case P1SEG:
		pteidx = vax_btop(v - 0x40000000);
		if (pteidx < pmap->pm_p1lr) {
			if (!grow_p1(pmap, pteidx, flags & PMAP_CANFAIL))
				return ENOMEM;
		}
		pteptr = pmap->pm_p1br + pteidx;
		newpte = prot & PROT_WRITE ? PG_RW : PG_RO;
		break;
	default:
		panic("bad seg");
	}
	newpte |= vax_btop(p);

	if (SEGTYPE(v) != SYSSEG) {
		/*
		 * Check if a pte page must be mapped in.
		 */
		ptpptr = kvtopte((vaddr_t)pteptr);

		if (*ptpptr == PG_NV) {
			paddr_t pa;

			pa = get_ptp((flags & PMAP_CANFAIL) != 0);
			if (pa == 0) {
				RECURSEEND;
				return ENOMEM;
			}
			*ptpptr = PG_V | PG_KW | PG_PFNUM(pa);
		}
	}

	/*
	 * Do not keep track of anything if mapping IO space.
	 */
	pg = PHYS_TO_VM_PAGE(p);
	if (pg == NULL) {
		mapin8(pteptr, newpte);
		RECURSEEND;
		return 0;
	}

	if (flags & PMAP_WIRED)
		newpte |= PG_W;

	oldpte = *pteptr & ~(PG_V | PG_M);

	/* just a wiring change ? */
	if ((newpte ^ oldpte) == PG_W) {
		if (flags & PMAP_WIRED) {
			pmap->pm_stats.wired_count++;
			*pteptr |= PG_W;
		} else {
			pmap->pm_stats.wired_count--;
			*pteptr &= ~PG_W;
		}
		RECURSEEND;
		return 0;
	}

	/* mapping unchanged? just return. */
	if (newpte == oldpte) {
		RECURSEEND;
		return 0;
	}

	/* Changing mapping? */
	if ((newpte & PG_FRAME) == (oldpte & PG_FRAME)) {
		/* protection change. */
#if 0 /* done below */
		mtpr(0, PR_TBIA);
#endif
	} else {
		/*
		 * Mapped before? Remove it then.
		 */
		if (oldpte & PG_FRAME) {
			pmap->pm_stats.resident_count--;
			if (oldpte & PG_W)
				pmap->pm_stats.wired_count--;
			RECURSEEND;
			if ((oldpte & PG_SREF) == 0)
				rmpage(pmap, pteptr);
			else
				panic("pmap_enter on PG_SREF page");
			RECURSESTART;
		}

		s = splvm();
		pv = get_pventry();
		if (pv == NULL) {
			if (flags & PMAP_CANFAIL) {
				splx(s);
				RECURSEEND;
				return ENOMEM;
			}
			panic("pmap_enter: could not allocate pv_entry");
		}
		pv->pv_va = v;
		pv->pv_pmap = pmap;
		pv->pv_next = pg->mdpage.pv_head;
		pg->mdpage.pv_head = pv;
		splx(s);
		pmap->pm_stats.resident_count++;
		if (newpte & PG_W)
			pmap->pm_stats.wired_count++;
	}

	if (flags & PROT_READ) {
		pg->mdpage.pv_attr |= PG_V;
		newpte |= PG_V;
	}
	if (flags & PROT_WRITE)
		pg->mdpage.pv_attr |= PG_M;

	if (flags & PMAP_WIRED)
		newpte |= PG_V; /* Not allowed to be invalid */

	mapin8(pteptr, newpte);
	RECURSEEND;

	mtpr(0, PR_TBIA); /* Always; safety belt */
	return 0;
}

vaddr_t
pmap_map(vaddr_t va, paddr_t pstart, paddr_t pend, int prot)
{
	vaddr_t count;
	pt_entry_t *pentry;

	PMDEBUG(("pmap_map: virt %lx, pstart %lx, pend %lx, Sysmap %p\n",
	    va, pstart, pend, Sysmap));

	pstart &= 0x7fffffffUL;
	pend &= 0x7fffffffUL;
	va &= 0x7fffffffUL;
	pentry = Sysmap + vax_btop(va);
	for (count = pstart; count < pend; count += VAX_NBPG) {
		*pentry++ = vax_btop(count) | PG_V |
		    (prot & PROT_WRITE ? PG_KW : PG_KR);
	}
	return va + (count - pstart) + KERNBASE;
}

boolean_t
pmap_extract(struct pmap *pmap, vaddr_t va, paddr_t *pap)
{
	pt_entry_t *pte;
	ulong sva;

	PMDEBUG(("pmap_extract: pmap %p, va %lx",pmap, va));

	sva = PG_PFNUM(va);
	if (va & KERNBASE) {
		if (sva >= sysptsize || (Sysmap[sva] & PG_V) == 0)
			goto fail;
		*pap = ((Sysmap[sva] & PG_FRAME) << VAX_PGSHIFT) |
		    (va & VAX_PGOFSET);
		PMDEBUG((" -> pa %lx\n", *pap));
		return TRUE;
	}

	if (va < 0x40000000) {
		if (sva >= pmap->pm_p0lr)
			goto fail;
		pte = pmap->pm_p0br;
	} else {
		if (sva < pmap->pm_p1lr)
			goto fail;
		pte = pmap->pm_p1br;
	}
	/*
	 * Since the PTE tables are sparsely allocated, make sure the page
	 * table page actually exists before dereferencing the pte itself.
	 */
	if ((*kvtopte((vaddr_t)&pte[sva]) & PG_V) && (pte[sva] & PG_V)) {
		*pap = ((pte[sva] & PG_FRAME) << VAX_PGSHIFT) |
		    (va & VAX_PGOFSET);
		PMDEBUG((" -> pa %lx\n", *pap));
		return TRUE;
	}

fail:
	PMDEBUG((" -> no mapping\n"));
	return FALSE;
}

/*
 * Sets protection for a given region to prot. If prot == none then
 * unmap region. pmap_remove is implemented as pmap_protect with
 * protection none.
 */
void
pmap_protect(struct pmap *pmap, vaddr_t start, vaddr_t end, vm_prot_t prot)
{
	pt_entry_t *pt, *pts, *ptd;
	pt_entry_t pr, lr;

	PMDEBUG(("pmap_protect: pmap %p, start %lx, end %lx, prot %x\n",
	    pmap, start, end,prot));

	RECURSESTART;

	switch (SEGTYPE(start)) {
	case SYSSEG:
		pt = Sysmap;
#ifdef DIAGNOSTIC
		if (PG_PFNUM(end) > mfpr(PR_SLR))
			panic("pmap_protect: outside SLR: %lx", end);
#endif
		start &= ~KERNBASE;
		end &= ~KERNBASE;
		pr = (prot & PROT_WRITE ? PG_KW : PG_KR);
		break;

	case P1SEG:
		if (vax_btop(end - 0x40000000) <= pmap->pm_p1lr) {
			RECURSEEND;
			return;
		}
		if (vax_btop(start - 0x40000000) < pmap->pm_p1lr)
			start = pmap->pm_p1lr * VAX_NBPG;
		pt = pmap->pm_p1br;
		start &= 0x3fffffff;
		end = (end == KERNBASE ? 0x40000000 : end & 0x3fffffff);
		pr = (prot & PROT_WRITE ? PG_RW : PG_RO);
		break;

	case P0SEG:
		lr = pmap->pm_p0lr;

		/* Anything to care about at all? */
		if (vax_btop(start) > lr) {
			RECURSEEND;
			return;
		}
		if (vax_btop(end) > lr)
			end = lr * VAX_NBPG;
		pt = pmap->pm_p0br;
		pr = (prot & PROT_WRITE ? PG_RW : PG_RO);
		break;
	default:
		panic("unsupported segtype: %d", (int)SEGTYPE(start));
	}

	pts = &pt[start >> VAX_PGSHIFT];
	ptd = &pt[end >> VAX_PGSHIFT];
#ifdef DEBUG
	if (((int)pts - (int)pt) & 7)
		panic("pmap_remove: pts not even");
	if (((int)ptd - (int)pt) & 7)
		panic("pmap_remove: ptd not even");
#endif

	while (pts < ptd) {
		if ((*kvtopte((vaddr_t)pts) & PG_FRAME) != 0 && *pts != PG_NV) {
			if (prot == PROT_NONE) {
				pmap->pm_stats.resident_count--;
				if ((*pts & PG_W))
					pmap->pm_stats.wired_count--;
				RECURSEEND;
				if ((*pts & PG_SREF) == 0)
					rmpage(pmap, pts);
				RECURSESTART;
				bzero(pts, sizeof(pt_entry_t) * LTOHPN);
				if (pt != Sysmap) {
					if (ptpinuse(pts) == 0)
						rmptep(pts);
				}
			} else {
				pts[0] = (pts[0] & ~PG_PROT) | pr;
				pts[1] = (pts[1] & ~PG_PROT) | pr;
				pts[2] = (pts[2] & ~PG_PROT) | pr;
				pts[3] = (pts[3] & ~PG_PROT) | pr;
				pts[4] = (pts[4] & ~PG_PROT) | pr;
				pts[5] = (pts[5] & ~PG_PROT) | pr;
				pts[6] = (pts[6] & ~PG_PROT) | pr;
				pts[7] = (pts[7] & ~PG_PROT) | pr;
			}
		}
		pts += LTOHPN;
	}
	RECURSEEND;
	mtpr(0,PR_TBIA);
}

/*
 * Called from interrupt vector routines if we get a page invalid fault.
 * Returns 0 if normal call, 1 if CVAX bug detected.
 */
int pmap_simulref(int, vaddr_t);
int
pmap_simulref(int bits, vaddr_t va)
{
	pt_entry_t *pte;
	struct vm_page *pg;
	paddr_t	pa;

	PMDEBUG(("pmap_simulref: bits %x addr %x\n", bits, va));
#ifdef DEBUG
	if (bits & 1)
		panic("pte trans len");
#endif
	/* Set address to logical page boundary */
	va &= ~PGOFSET;

	if (va & KERNBASE) {
		pte = kvtopte(va);
		pa = (paddr_t)pte & ~KERNBASE;
	} else {
		if (va < 0x40000000)
			pte = (pt_entry_t *)mfpr(PR_P0BR);
		else
			pte = (pt_entry_t *)mfpr(PR_P1BR);
		pte += PG_PFNUM(va);
		if (bits & 2) { /* PTE reference */
			pte = kvtopte(vax_trunc_page(pte));
			if (pte[0] == 0) /* Check for CVAX bug */
				return 1;
			pa = (paddr_t)pte & ~KERNBASE;
		} else
			pa = (Sysmap[PG_PFNUM(pte)] & PG_FRAME) << VAX_PGSHIFT;
	}

	pte[0] |= PG_V;
	pte[1] |= PG_V;
	pte[2] |= PG_V;
	pte[3] |= PG_V;
	pte[4] |= PG_V;
	pte[5] |= PG_V;
	pte[6] |= PG_V;
	pte[7] |= PG_V;

	pa = trunc_page(pa);
	pg = PHYS_TO_VM_PAGE(pa);
	if (pg != NULL) {
		pg->mdpage.pv_attr |= PG_V; /* Referenced */
		if (bits & 4)	/* (will be) modified. XXX page tables  */
			pg->mdpage.pv_attr |= PG_M;
	}
	return 0;
}

/*
 * Checks if page is referenced; returns true or false depending on result.
 */
boolean_t
pmap_is_referenced(struct vm_page *pg)
{
	PMDEBUG(("pmap_is_referenced: pg %p pv_attr %x\n",
	    pg, pg->mdpage.pv_attr));

	if (pg->mdpage.pv_attr & PG_V)
		return 1;

	return 0;
}

/*
 * Clears valid bit in all ptes referenced to this physical page.
 */
boolean_t
pmap_clear_reference(struct vm_page *pg)
{
	struct pv_entry *pv;
	pt_entry_t *pte;
	boolean_t ref = FALSE;
	int s;

	PMDEBUG(("pmap_clear_reference: pg %p\n", pg));

	if (pg->mdpage.pv_attr & PG_V)
		ref = TRUE;

	pg->mdpage.pv_attr &= ~PG_V;

	RECURSESTART;
	s = splvm();
	for (pv = pg->mdpage.pv_head; pv != NULL; pv = pv->pv_next) {
		pte = vaddrtopte(pv);
		pte[0] &= ~PG_V;
		pte[1] &= ~PG_V;
		pte[2] &= ~PG_V;
		pte[3] &= ~PG_V;
		pte[4] &= ~PG_V;
		pte[5] &= ~PG_V;
		pte[6] &= ~PG_V;
		pte[7] &= ~PG_V;
	}
	splx(s);

	RECURSEEND;
	mtpr(0, PR_TBIA);
	return ref;
}

/*
 * Checks if page is modified; returns true or false depending on result.
 */
boolean_t
pmap_is_modified(struct vm_page *pg)
{
	struct pv_entry *pv;
	pt_entry_t *pte;
	boolean_t rv = FALSE;
	int s;

	PMDEBUG(("pmap_is_modified: pg %p pv_attr %x\n",
	    pg, pg->mdpage.pv_attr));

	if (pg->mdpage.pv_attr & PG_M)
		return TRUE;

	s = splvm();
	for (pv = pg->mdpage.pv_head; pv != NULL; pv = pv->pv_next) {
		pte = vaddrtopte(pv);
		if ((pte[0] | pte[1] | pte[2] | pte[3] | pte[4] | pte[5] |
		     pte[6] | pte[7]) & PG_M) {
			rv = TRUE;
			break;
		}
	}
	splx(s);

	return rv;
}

/*
 * Clears modify bit in all ptes referenced to this physical page.
 */
boolean_t
pmap_clear_modify(struct vm_page *pg)
{
	struct pv_entry *pv;
	pt_entry_t *pte;
	boolean_t rv = FALSE;
	int s;

	PMDEBUG(("pmap_clear_modify: pg %p\n", pg));

	if (pg->mdpage.pv_attr & PG_M)
		rv = TRUE;
	pg->mdpage.pv_attr &= ~PG_M;

	s = splvm();
	for (pv = pg->mdpage.pv_head; pv != NULL; pv = pv->pv_next) {
		pte = vaddrtopte(pv);
		if ((pte[0] | pte[1] | pte[2] | pte[3] | pte[4] | pte[5] |
		     pte[6] | pte[7]) & PG_M) {
			rv = TRUE;

			pte[0] &= ~PG_M;
			pte[1] &= ~PG_M;
			pte[2] &= ~PG_M;
			pte[3] &= ~PG_M;
			pte[4] &= ~PG_M;
			pte[5] &= ~PG_M;
			pte[6] &= ~PG_M;
			pte[7] &= ~PG_M;
		}
	}
	splx(s);

	return rv;
}

/*
 * Lower the permission for all mappings to a given page.
 * Lower permission can only mean setting protection to either read-only
 * or none; where none is unmapping of the page.
 */
void
pmap_page_protect(struct vm_page *pg, vm_prot_t prot)
{
	pt_entry_t *pte;
	struct	pv_entry *pv, *npv;
	int	s;

	PMDEBUG(("pmap_page_protect: pg %p, prot %x\n", pg, prot));

	if (pg->mdpage.pv_head == NULL)
		return;

	if (prot == PROT_MASK) /* 'cannot happen' */
		return;

	RECURSESTART;
	s = splvm();
	if (prot == PROT_NONE) {
		npv = pg->mdpage.pv_head;
		pg->mdpage.pv_head = NULL;
		while ((pv = npv) != NULL) {
			npv = pv->pv_next;
			pte = vaddrtopte(pv);
			pv->pv_pmap->pm_stats.resident_count--;
			if (pte[0] & PG_W)
				pv->pv_pmap->pm_stats.wired_count--;
			if ((pg->mdpage.pv_attr & (PG_V|PG_M)) != (PG_V|PG_M))
				pg->mdpage.pv_attr |=
				    pte[0] | pte[1] | pte[2] | pte[3] |
				    pte[4] | pte[5] | pte[6] | pte[7];
			bzero(pte, sizeof(pt_entry_t) * LTOHPN);
			if (pv->pv_pmap != pmap_kernel()) {
				if (ptpinuse(pte) == 0)
					rmptep(pte);
			}
			free_pventry(pv);
		}
	} else { /* read-only */
		for (pv = pg->mdpage.pv_head; pv != NULL; pv = pv->pv_next) {
			pt_entry_t pr;

			pte = vaddrtopte(pv);
			pr = (vaddr_t)pte < ptemapstart ?
			    PG_KR : PG_RO;

			pte[0] = (pte[0] & ~PG_PROT) | pr;
			pte[1] = (pte[1] & ~PG_PROT) | pr;
			pte[2] = (pte[2] & ~PG_PROT) | pr;
			pte[3] = (pte[3] & ~PG_PROT) | pr;
			pte[4] = (pte[4] & ~PG_PROT) | pr;
			pte[5] = (pte[5] & ~PG_PROT) | pr;
			pte[6] = (pte[6] & ~PG_PROT) | pr;
			pte[7] = (pte[7] & ~PG_PROT) | pr;
		}
	}
	splx(s);
	RECURSEEND;
	mtpr(0, PR_TBIA);
}

void
pmap_remove_pcb(struct pmap *pm, struct pcb *thispcb)
{
	struct pcb *pcb, **pcbp;

	PMDEBUG(("pmap_remove_pcb pm %p pcb %p\n", pm, thispcb));

	for (pcbp = &pm->pm_pcbs; (pcb = *pcbp) != NULL;
	    pcbp = &pcb->pcb_pmnext) {
#ifdef DIAGNOSTIC
		if (pcb->pcb_pm != pm)
			panic("%s: pcb %p (pm %p) not owned by pmap %p",
			    __func__, pcb, pcb->pcb_pm, pm);
#endif
		if (pcb == thispcb) {
			*pcbp = pcb->pcb_pmnext;
			thispcb->pcb_pm = NULL;
			return;
		}
	}
#ifdef DIAGNOSTIC
	panic("%s: pmap %p: pcb %p not in list", __func__, pm, thispcb);
#endif
}

/*
 * Activate the address space for the specified process.
 * Note that if the process to activate is the current process, then
 * the processor internal registers must also be loaded; otherwise
 * the current process will have wrong pagetables.
 */
void
pmap_activate(struct proc *p)
{
	struct pcb *pcb = &p->p_addr->u_pcb;
	struct pmap *pmap = p->p_vmspace->vm_map.pmap;
	int s;

	PMDEBUG(("pmap_activate: p %p pcb %p pm %p (%08x %08x %08x %08x)\n",
	    p, pcb, pmap, pmap->pm_p0br, pmap->pm_p0lr, pmap->pm_p1br,
	    pmap->pm_p1lr));

	pcb->P0BR = pmap->pm_p0br;
	pcb->P0LR = pmap->pm_p0lr | AST_PCB;
	pcb->P1BR = pmap->pm_p1br;
	pcb->P1LR = pmap->pm_p1lr;

	if (pcb->pcb_pm != pmap) {
		s = splsched();
		if (pcb->pcb_pm != NULL)
			pmap_remove_pcb(pcb->pcb_pm, pcb);
		pcb->pcb_pmnext = pmap->pm_pcbs;
		pmap->pm_pcbs = pcb;
		pcb->pcb_pm = pmap;
		splx(s);
	}

	if (p == curproc) {
		mtpr((register_t)pmap->pm_p0br, PR_P0BR);
		mtpr(pmap->pm_p0lr | AST_PCB, PR_P0LR);
		mtpr((register_t)pmap->pm_p1br, PR_P1BR);
		mtpr(pmap->pm_p1lr, PR_P1LR);
		mtpr(0, PR_TBIA);
	}
}

void
pmap_deactivate(struct proc *p)
{
	struct pcb *pcb = &p->p_addr->u_pcb;
	struct pmap *pmap = p->p_vmspace->vm_map.pmap;
	int s;

	PMDEBUG(("pmap_deactivate: p %p pcb %p\n", p, pcb));

	if (pcb->pcb_pm != NULL) {
		s = splsched();
#ifdef DIAGNOSTIC
		if (pcb->pcb_pm != pmap)
			panic("%s: proc %p pcb %p not owned by pmap %p",
			    __func__, p, pcb, pmap);
#endif
		pmap_remove_pcb(pmap, pcb);
		splx(s);
	}
}


code:
/*	$OpenBSD: scb.c,v 1.7 2012/11/25 22:13:46 jsg Exp $	*/
/*	$NetBSD: scb.c,v 1.12 2000/06/04 06:16:59 matt Exp $ */
/*
 * Copyright (c) 1999 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.
 */
/*
 * Routines for dynamic allocation/release of SCB vectors.
 */

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

#include <machine/trap.h>
#include <machine/scb.h>
#include <machine/frame.h>
#include <machine/cpu.h>
#include <machine/sid.h>
#include <machine/mtpr.h>

struct scb *scb;
struct ivec_dsp *scb_vec;

static	volatile int vector, ipl, gotintr;

/*
 * Generates a new SCB.
 */
paddr_t
scb_init(paddr_t avail_start)
{
	struct	ivec_dsp **ivec = (struct ivec_dsp **)avail_start;
	struct	ivec_dsp **old = (struct ivec_dsp **)KERNBASE;
	vaddr_t	vavail = avail_start + KERNBASE;
	int	scb_size = dep_call->cpu_scbsz;
	int	i;

	scb = (struct scb *)vavail;
	scb_vec = (struct ivec_dsp *)(vavail + (scb_size * VAX_NBPG));

	/* Init the whole SCB with interrupt catchers */
	for (i = 0; i < (scb_size * VAX_NBPG)/4; i++) {
		ivec[i] = (struct ivec_dsp *)
		    ((vaddr_t)&scb_vec[i] | SCB_ISTACK); /* On istack, please */
		scb_vec[i] = idsptch;
		scb_vec[i].hoppaddr = scb_stray;
		scb_vec[i].pushlarg = (void *) (i * 4);
		scb_vec[i].ev = NULL;
	}
	/*
	 * Copy all pre-set interrupt vectors to the new SCB.
	 * It is known that these vectors is at KERNBASE from the
	 * beginning, and that if the vector is zero it should call
	 * stray instead.
	 */
	for (i = 0; i < 64; i++)
		if (old[i])
			ivec[i] = old[i];

	/* Last action: set the SCB */
	mtpr(avail_start, PR_SCBB);

	/* Return new avail_start. Also save space for the dispatchers. */
	return avail_start + (1 + sizeof(struct ivec_dsp) / sizeof(void *))
	    * scb_size * VAX_NBPG;
};

/*
 * Stray interrupt handler.
 * This function must _not_ save any registers (in the reg save mask).
 */
void
scb_stray(void *arg)
{
	gotintr = 1;
	vector = ((int) arg) & ~3;
	ipl = mfpr(PR_IPL);

	if (cold == 0)
		printf("stray interrupt: vector %d, ipl %d\n", vector, ipl);
	else {
		struct icallsframe *icf = (void *) __builtin_frame_address(0);

		icf->ica_psl = (icf->ica_psl & ~PSL_IPL) | ipl << 16;
	}

	mtpr(ipl + 1, PR_IPL);
}

/*
 * Fake interrupt handler, to fool some bus' autodetect system.
 * (May I say DW780? :-)
 */
void
scb_fake(vec, br)
	int vec, br;
{
	vector = vec;
	ipl = br;
	gotintr = 1;
}

/*
 * Returns last vector/ipl referenced. Clears vector/ipl after reading.
 */
int
scb_vecref(rvec, ripl)
	int *rvec, *ripl;
{
	int save;

	if (rvec)
		*rvec = vector;
	if (ripl)
		*ripl = ipl;
	save = gotintr;
	gotintr = vector = ipl = 0;
	mtpr(0, PR_IPL);
	return save;
}

/*
 * Sets a vector to the specified function.
 * Arg may not be greater than 63.
 */

void
scb_vecalloc(vecno, func, arg, stack, ev)
	int vecno;
	void (*func)(void *);
	void *arg;
	int stack;
	struct evcount *ev;
{
	struct ivec_dsp *dsp = &scb_vec[vecno / 4];
	dsp->hoppaddr = func;
	dsp->pushlarg = arg;
	dsp->ev = ev;
	((u_int *) scb)[vecno/4] = (u_int)(dsp) | stack;
}