code:
/*	$OpenBSD: process_machdep.c,v 1.13 2009/03/05 19:52:23 kettenis Exp $	*/
/*	$NetBSD: process_machdep.c,v 1.6 1996/03/14 21:09:26 christos Exp $ */

/*
 * Copyright (c) 1993 The Regents of the University of California.
 * Copyright (c) 1993 Jan-Simon Pendry
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Jan-Simon Pendry.
 *
 * 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: Id: procfs_i386.c,v 4.1 1993/12/17 10:47:45 jsp Rel
 */

/*
 * This file may seem a bit stylized, but that so that it's easier to port.
 * Functions to be implemented here are:
 *
 * process_read_regs(proc, regs)
 *	Get the current user-visible register set from the process
 *	and copy it into the regs structure (<machine/reg.h>).
 *	The process is stopped at the time read_regs is called.
 *
 * process_write_regs(proc, regs)
 *	Update the current register set from the passed in regs
 *	structure.  Take care to avoid clobbering special CPU
 *	registers or privileged bits in the PSL.
 *	The process is stopped at the time write_regs is called.
 *
 * process_sstep(proc)
 *	Arrange for the process to trap after executing a single instruction.
 *
 * process_set_pc(proc)
 *	Set the process's program counter.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/vnode.h>
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/frame.h>
#include <sys/ptrace.h>

#include <sparc/sparc/cpuvar.h>

int
process_read_regs(p, regs)
	struct proc *p;
	struct reg *regs;
{
	/* NOTE: struct reg == struct trapframe */
	bcopy(p->p_md.md_tf, (caddr_t)regs, sizeof(struct reg));
	return (0);
}

int
process_read_fpregs(p, regs)
	struct proc	*p;
	struct fpreg	*regs;
{
	extern struct fpstate	initfpstate;
	struct fpstate		*statep = &initfpstate;

	/* NOTE: struct fpreg == struct fpstate */
	if (p->p_md.md_fpstate) {
		if (p == cpuinfo.fpproc)
			savefpstate(p->p_md.md_fpstate);
		statep = p->p_md.md_fpstate;
	}
	bcopy(statep, regs, sizeof(struct fpreg));
	return 0;
}

#ifdef PTRACE

int
process_write_regs(p, regs)
	struct proc *p;
	struct reg *regs;
{
	int	psr = p->p_md.md_tf->tf_psr & ~PSR_ICC;

	if (((regs->r_pc | regs->r_npc) & 0x03) != 0)
		return (EINVAL);

	bcopy((caddr_t)regs, p->p_md.md_tf, sizeof(struct reg));
	p->p_md.md_tf->tf_psr = psr | (regs->r_psr & PSR_ICC);
	return (0);
}

int
process_sstep(p, sstep)
	struct proc *p;
	int sstep;
{
	if (sstep)
		return EINVAL;
	return (0);
}

int
process_set_pc(p, addr)
	struct proc *p;
	caddr_t addr;
{
	if (((u_int)addr & 0x03) != 0)
		return (EINVAL);

	p->p_md.md_tf->tf_pc = (u_int)addr;
	p->p_md.md_tf->tf_npc = (u_int)addr + 4;
	return (0);
}

int
process_write_fpregs(p, regs)
	struct proc	*p;
	struct fpreg	*regs;
{
	/* NOTE: struct fpreg == struct fpstate */
	if (p->p_md.md_fpstate == NULL) {
		p->p_md.md_fpstate = malloc(sizeof(struct fpstate),
		    M_SUBPROC, M_WAITOK);
	}

	if (p == cpuinfo.fpproc) {
		/* Release the fpu. */
		savefpstate(p->p_md.md_fpstate);
		cpuinfo.fpproc = NULL;
	}

	bcopy(regs, p->p_md.md_fpstate, sizeof(struct fpreg));
	return 0;
}

#endif	/* PTRACE */

register_t
process_get_wcookie(p)
	struct proc *p;
{
	return p->p_addr->u_pcb.pcb_wcookie;
}

license: unknown


code:
/*	$OpenBSD: sys_machdep.c,v 1.6 2003/06/02 23:27:55 millert Exp $	*/
/*	$NetBSD: sys_machdep.c,v 1.7 1996/03/14 21:09:33 christos Exp $ */

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

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/uio.h>
#include <sys/kernel.h>
#include <sys/mtio.h>
#include <sys/buf.h>

#include <sys/mount.h>
#include <sys/syscallargs.h>

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

	switch(SCARG(uap, op)) {
	default:
		error = EINVAL;
		break;
	}
	return(error);
}


code:
/*	$OpenBSD: timerreg.h,v 1.4 2003/06/02 23:27:55 millert Exp $	*/
/*	$NetBSD: timerreg.h,v 1.6 1996/10/28 00:20:32 abrown Exp $ */

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

/*
 * Sun-4c counter/timer registers.  The timers are implemented within
 * the cache chip (!).  The counter and limit fields below could be
 * defined as:
 *
 *	struct {
 *		u_int	t_limit:1,	// limit reached
 *			t_usec:21,	// counter value in microseconds
 *			t_mbz:10;	// always zero
 *	};
 *
 * but this is more trouble than it is worth.
 *
 * These timers work in a rather peculiar fashion.  Most clock counters
 * run to 0 (as, e.g., on the VAX, where the ICR counts up to 0 from a
 * large unsigned number).  On the Sun-4c, it counts up to a limit.  But
 * for some reason, when it reaches the limit, it resets to 1, not 0.
 * Thus, if the limit is set to 4, the counter counts like this:
 *
 *	1, 2, 3, 1, 2, 3, ...
 *
 * and if we want to divide by N we must set the limit register to N+1.
 *
 * Sun-4m counters/timer registers are similar, with these exceptions:
 *
 *	- the limit and counter registers have changed positions..
 *	- both limit and counter registers are 22 bits wide, but
 *	  they count in 500ns increments (bit 9 being the least
 *	  significant bit).
 *
 */
#ifndef _LOCORE
struct timer_4 {
	volatile int	t_counter;		/* counter reg */
	volatile int	t_limit;		/* limit reg */
};

struct timerreg_4 {
	struct	timer_4 t_c10;		/* counter that interrupts at ipl 10 */
	struct	timer_4 t_c14;		/* counter that interrupts at ipl 14 */
};

struct timer_4m {		/* counter that interrupts at ipl 10 */
	volatile int	t_limit;		/* limit register */
	volatile int	t_counter;		/* counter register */
	volatile int	t_limit_nr;		/* limit reg, non-resetting */
	volatile int	t_reserved;
	volatile int	t_cfg;			/* a configuration register */
/*
 * Note: The SparcClassic manual only defines this one bit
 * I suspect there are more in multi-processor machines.
 */
#define TMR_CFG_USER	1
};

struct counter_4m {		/* counter that interrupts at ipl 14 */
	volatile int	t_limit;		/* limit register */
	volatile int	t_counter;		/* counter register */
	volatile int	t_limit_nr;		/* limit reg, non-resetting */
	volatile int	t_ss;			/* Start/Stop register */
#define TMR_USER_RUN	1
};
#endif /* _LOCORE */

#define	TMR_LIMIT	0x80000000	/* counter reached its limit */
#define	TMR_SHIFT	10		/* shift to obtain microseconds */
#define	TMR_MASK	0x1fffff	/* 21 bits */

/*
 * Compute a limit that causes the timer to fire every n microseconds.
 * The Sun4c requires that the timer register be initialized for n+1
 * microseconds, while the Sun4m requires it be initialized for n. Thus
 * the two versions of this function.
 *
 * Note that the manual for the chipset used in the Sun4m suggests that
 * the timer be set at n+0.5 microseconds; in practice, this produces
 * a 50 ppm clock skew, which means that the 0.5 should not be there...
 */
#define	tmr_ustolim(n)	(((n) + 1) << TMR_SHIFT)

/*efine	TMR_SHIFT4M	9		-* shift to obtain microseconds */
/*efine tmr_ustolim4m(n)	(((2*(n)) + 1) << TMR_SHIFT4M)*/
#define tmr_ustolim4m(n)	((n) << TMR_SHIFT)


code:
/*	$OpenBSD: trap.c,v 1.71 2015/03/27 20:25:39 miod Exp $	*/
/*	$NetBSD: trap.c,v 1.58 1997/09/12 08:55:01 pk Exp $ */

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

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/user.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/resource.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sys/syscall_mi.h>
#include <sys/syslog.h>

#include <uvm/uvm_extern.h>

#include <sparc/sparc/asm.h>
#include <machine/cpu.h>
#include <machine/ctlreg.h>
#include <machine/trap.h>
#include <machine/instr.h>
#include <machine/pmap.h>

#ifdef DDB
#include <machine/db_machdep.h>
#else
#include <machine/frame.h>
#endif

#include <sparc/fpu/fpu_extern.h>
#include <sparc/sparc/memreg.h>
#include <sparc/sparc/cpuvar.h>

#ifdef DEBUG
int	rwindow_debug = 0;
#endif

/*
 * Initial FPU state is all registers == all 1s, everything else == all 0s.
 * This makes every floating point register a signalling NaN, with sign bit
 * set, no matter how it is interpreted.  Appendix N of the Sparc V8 document
 * seems to imply that we should do this, and it does make sense.
 */
struct	fpstate initfpstate = {
	{ ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0,
	  ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0, ~0 }
};

/*
 * There are more than 100 trap types, but most are unused.
 *
 * Trap type 0 is taken over as an `Asynchronous System Trap'.
 * This is left-over Vax emulation crap that should be fixed.
 *
 * Note that some of the Sparc v8 traps are actually handled by
 * the corresponding v7 routine, but listed here for completeness.
 * The Fujitsu Turbo-Sparc Guide also alludes to several more
 * unimplemented trap types, but doesn't give the nominal coding.
 */
static const char T[] = "trap";
const char *trap_type[] = {
	/* non-user vectors */
	"ast",			/* 0 */
	"text fault",		/* 1 */
	"illegal instruction",	/* 2 */
	"privileged instruction",/*3 */
	"fp disabled",		/* 4 */
	"window overflow",	/* 5 */
	"window underflow",	/* 6 */
	"alignment fault",	/* 7 */
	"fp exception",		/* 8 */
	"data fault",		/* 9 */
	"tag overflow",		/* 0a */
	"watchpoint",		/* 0b */
	T, T, T, T, T,		/* 0c..10 */
	"level 1 int",		/* 11 */
	"level 2 int",		/* 12 */
	"level 3 int",		/* 13 */
	"level 4 int",		/* 14 */
	"level 5 int",		/* 15 */
	"level 6 int",		/* 16 */
	"level 7 int",		/* 17 */
	"level 8 int",		/* 18 */
	"level 9 int",		/* 19 */
	"level 10 int",		/* 1a */
	"level 11 int",		/* 1b */
	"level 12 int",		/* 1c */
	"level 13 int",		/* 1d */
	"level 14 int",		/* 1e */
	"level 15 int",		/* 1f */
	"v8 r-reg error",	/* 20 */
	"v8 text error",	/* 21 */
	T, T,			/* 22..23 */
	"v8 cp disabled",	/* 24 */
	"v8 unimp flush",	/* 25 */
	T, T,			/* 26..27 */
	"v8 cp exception",	/* 28 */
	"v8 data error",	/* 29 */
	"v8 idiv by zero",	/* 2a */
	"v8 store error",	/* 2b */
	"v8 data access MMU miss",/* 2c */
	T, T, T,		/* 2d..2f */
	T, T, T, T, T, T, T, T,	/* 30..37 */
	T, T, T, T,		/* 38..3b */
	"v8 insn access MMU miss",/* 3c */
	T, T, T,	/* 3d..3f */
	T, T, T, T, T, T, T, T,	/* 40..48 */
	T, T, T, T, T, T, T, T,	/* 48..4f */
	T, T, T, T, T, T, T, T,	/* 50..57 */
	T, T, T, T, T, T, T, T,	/* 58..5f */
	T, T, T, T, T, T, T, T,	/* 60..67 */
	T, T, T, T, T, T, T, T,	/* 68..6f */
	T, T, T, T, T, T, T, T,	/* 70..77 */
	T, T, T, T, T, T, T, T,	/* 78..7f */

	/* user (software trap) vectors */
	"syscall",		/* 80 */
	"breakpoint",		/* 81 */
	"zero divide",		/* 82 */
	"flush windows",	/* 83 */
	"clean windows",	/* 84 */
	"range check",		/* 85 */
	"fix align",		/* 86 */
	"integer overflow",	/* 87 */
	"svr4 syscall",		/* 88 */
	"4.4 syscall",		/* 89 */
	"kgdb exec",		/* 8a */
	T, T, T, T, T,		/* 8b..8f */
	T, T, T, T, T, T, T, T,	/* 9a..97 */
	T, T, T, T, T, T, T, T,	/* 98..9f */
	"svr4 getcc",		/* a0 */
	"svr4 setcc",		/* a1 */
	"svr4 getpsr",		/* a2 */
	"svr4 setpsr",		/* a3 */
	"svr4 gethrtime",	/* a4 */
	"svr4 gethrvtime",	/* a5 */
	T,			/* a6 */
	"svr4 gethrestime",	/* a7 */
};

#define	N_TRAP_TYPES	(sizeof trap_type / sizeof *trap_type)

void trap(unsigned, int, int, struct trapframe *);
static __inline void share_fpu(struct proc *, struct trapframe *);
void mem_access_fault(unsigned, int, u_int, int, int, struct trapframe *);
void mem_access_fault4m(unsigned, u_int, u_int, struct trapframe *);
void syscall(register_t, struct trapframe *, register_t);

int ignore_bogus_traps = 0;

int want_ast = 0;

/*
 * If someone stole the FPU while we were away, do not enable it
 * on return.  This is not done in userret() above as it must follow
 * the ktrsysret() in syscall().  Actually, it is likely that the
 * ktrsysret should occur before the call to userret.
 */
static __inline void share_fpu(p, tf)
	struct proc *p;
	struct trapframe *tf;
{
	if ((tf->tf_psr & PSR_EF) != 0 && cpuinfo.fpproc != p)
		tf->tf_psr &= ~PSR_EF;
}

/*
 * Called from locore.s trap handling, for non-MMU-related traps.
 * (MMU-related traps go through mem_access_fault, below.)
 */
void
trap(type, psr, pc, tf)
	unsigned type;
	int psr, pc;
	struct trapframe *tf;
{
	struct proc *p;
	struct pcb *pcb;
	int n;
	union sigval sv;

        sv.sival_int = pc; /* XXX fix for parm five of trapsignal() */

	/* This steps the PC over the trap. */
#define	ADVANCE (n = tf->tf_npc, tf->tf_pc = n, tf->tf_npc = n + 4)

	uvmexp.traps++;
	/*
	 * Generally, kernel traps cause a panic.  Any exceptions are
	 * handled early here.
	 */
	if (psr & PSR_PS) {
#ifdef DDB
		if (type == T_BREAKPOINT) {
			write_all_windows();
			if (kdb_trap(type, tf)) {
				return;
			}
		}
#endif
#ifdef DIAGNOSTIC
		/*
		 * Currently, we allow DIAGNOSTIC kernel code to
		 * flush the windows to record stack traces.
		 */
		if (type == T_FLUSHWIN) {
			write_all_windows();
			ADVANCE;
			return;
		}
#endif
		/*
		 * Storing %fsr in cpu_attach will cause this trap
		 * even though the fpu has been enabled, if and only
		 * if there is no FPU.
		 */
		if (type == T_FPDISABLED && cold) {
			ADVANCE;
			return;
		}
	dopanic:
		printf("trap type 0x%x: pc=0x%x npc=0x%x psr=%b\n",
		       type, pc, tf->tf_npc, psr, PSR_BITS);
		panic(type < N_TRAP_TYPES ? trap_type[type] : T);
		/* NOTREACHED */
	}
	if ((p = curproc) == NULL)
		p = &proc0;
	pcb = &p->p_addr->u_pcb;
	p->p_md.md_tf = tf;	/* for ptrace/signals */
	refreshcreds(p);

	switch (type) {

	default:
		if (type < 0x80) {
			if (!ignore_bogus_traps)
				goto dopanic;
			printf("trap type 0x%x: pc=0x%x npc=0x%x psr=%b\n",
			       type, pc, tf->tf_npc, psr, PSR_BITS);
			trapsignal(p, SIGILL, type, ILL_ILLOPC, sv);
			break;
		}
		/* the following message is gratuitous */
		/* ... but leave it in until we find anything */
		printf("%s[%d]: unimplemented software trap 0x%x\n",
			p->p_comm, p->p_pid, type);
		trapsignal(p, SIGILL, type, ILL_ILLOPC, sv);
		break;

	case T_AST:
		want_ast = 0;
		uvmexp.softs++;
		mi_ast(p, want_resched);
		break;

	case T_ILLINST:
		if ((n = emulinstr(pc, tf)) == 0) {
			ADVANCE;
			break;
		}
		trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
		break;

	case T_PRIVINST:
		trapsignal(p, SIGILL, 0, ILL_PRVOPC, sv);
		break;

	case T_FPDISABLED: {
		struct fpstate *fs = p->p_md.md_fpstate;

		if (fs == NULL) {
			fs = malloc(sizeof *fs, M_SUBPROC, M_WAITOK);
			*fs = initfpstate;
			p->p_md.md_fpstate = fs;
		}
		/*
		 * If we have not found an FPU, we have to emulate it.
		 */
		if (!foundfpu) {
#ifdef notyet
			fpu_emulate(p, tf, fs);
			break;
#else
			trapsignal(p, SIGFPE, 0, FPE_FLTINV, sv);
			break;
#endif
		}
		/*
		 * We may have more FPEs stored up and/or ops queued.
		 * If they exist, handle them and get out.  Otherwise,
		 * resolve the FPU state, turn it on, and try again.
		 */
		if (fs->fs_qsize) {
			fpu_cleanup(p, fs);
			break;
		}
		if (cpuinfo.fpproc != p) {	/* we do not have it */
			if (cpuinfo.fpproc != NULL) /* someone else had it */
				savefpstate(cpuinfo.fpproc->p_md.md_fpstate);
			loadfpstate(fs);
			cpuinfo.fpproc = p;	/* now we do have it */
			uvmexp.fpswtch++;
		}
		tf->tf_psr |= PSR_EF;
		break;
	}

	case T_WINOF:
		if (rwindow_save(p))
			sigexit(p, SIGILL);
		break;

#define read_rw(src, dst) \
	copyin((caddr_t)(src), (caddr_t)(dst), sizeof(struct rwindow))

	case T_RWRET:
		/*
		 * T_RWRET is a window load needed in order to rett.
		 * It simply needs the window to which tf->tf_out[6]
		 * (%sp) points.  There are no user or saved windows now.
		 * Copy the one from %sp into pcb->pcb_rw[0] and set
		 * nsaved to -1.  If we decide to deliver a signal on
		 * our way out, we will clear nsaved.
		 */
		if (pcb->pcb_uw || pcb->pcb_nsaved)
			panic("trap T_RWRET 1");
#ifdef DEBUG
		if (rwindow_debug)
			printf("%s[%d]: rwindow: pcb<-stack: 0x%x\n",
				p->p_comm, p->p_pid, tf->tf_out[6]);
#endif
		if (read_rw(tf->tf_out[6], &pcb->pcb_rw[0]))
			sigexit(p, SIGILL);
		if (pcb->pcb_nsaved)
			panic("trap T_RWRET 2");
		pcb->pcb_nsaved = -1;		/* mark success */
		break;

	case T_WINUF:
		/*
		 * T_WINUF is a real window underflow, from a restore
		 * instruction.  It needs to have the contents of two
		 * windows---the one belonging to the restore instruction
		 * itself, which is at its %sp, and the one belonging to
		 * the window above, which is at its %fp or %i6---both
		 * in the pcb.  The restore's window may still be in
		 * the cpu; we need to force it out to the stack.
		 */
#ifdef DEBUG
		if (rwindow_debug)
			printf("%s[%d]: rwindow: T_WINUF 0: pcb<-stack: 0x%x\n",
				p->p_comm, p->p_pid, tf->tf_out[6]);
#endif
		write_user_windows();
		if (rwindow_save(p) || read_rw(tf->tf_out[6], &pcb->pcb_rw[0]))
			sigexit(p, SIGILL);
#ifdef DEBUG
		if (rwindow_debug)
			printf("%s[%d]: rwindow: T_WINUF 1: pcb<-stack: 0x%x\n",
				p->p_comm, p->p_pid, pcb->pcb_rw[0].rw_in[6]);
#endif
		if (read_rw(pcb->pcb_rw[0].rw_in[6], &pcb->pcb_rw[1]))
			sigexit(p, SIGILL);
		if (pcb->pcb_nsaved)
			panic("trap T_WINUF");
		pcb->pcb_nsaved = -1;		/* mark success */
		break;

	case T_ALIGN:
		trapsignal(p, SIGBUS, 0, BUS_ADRALN, sv);
		break;

	case T_FPE:
		/*
		 * Clean up after a floating point exception.
		 * fpu_cleanup can (and usually does) modify the
		 * state we save here, so we must `give up' the FPU
		 * chip context.  (The software and hardware states
		 * will not match once fpu_cleanup does its job, so
		 * we must not save again later.)
		 */
		if (p != cpuinfo.fpproc)
			panic("fpe without being the FP user");
		savefpstate(p->p_md.md_fpstate);
		cpuinfo.fpproc = NULL;
		/* tf->tf_psr &= ~PSR_EF; */	/* share_fpu will do this */
		fpu_cleanup(p, p->p_md.md_fpstate);
		/* fpu_cleanup posts signals if needed */
#if 0		/* ??? really never??? */
		ADVANCE;
#endif
		break;

	case T_TAGOF:
		trapsignal(p, SIGEMT, 0, EMT_TAGOVF, sv);
		break;

	case T_CPDISABLED:
		uprintf("coprocessor instruction\n");	/* XXX */
		trapsignal(p, SIGILL, 0, ILL_COPROC, sv);
		break;

	case T_BREAKPOINT:
		trapsignal(p, SIGTRAP, 0, TRAP_BRKPT, sv);
		break;

	case T_DIV0:
	case T_IDIV0:
		ADVANCE;
		trapsignal(p, SIGFPE, 0, FPE_INTDIV, sv);
		break;

	case T_FLUSHWIN:
		write_user_windows();
#ifdef probably_slower_since_this_is_usually_false
		if (pcb->pcb_nsaved && rwindow_save(p))
			sigexit(p, SIGILL);
#endif
		ADVANCE;
		break;

	case T_CLEANWIN:
		uprintf("T_CLEANWIN\n");	/* XXX */
		ADVANCE;
		break;

	case T_RANGECHECK:
		uprintf("T_RANGECHECK\n");	/* XXX */
		ADVANCE;
		trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
		break;

	case T_FIXALIGN:
		uprintf("T_FIXALIGN\n");
		ADVANCE;
		trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
		break;

	case T_INTOF:
		uprintf("T_INTOF\n");		/* XXX */
		ADVANCE;
		trapsignal(p, SIGFPE, FPE_INTOVF_TRAP, FPE_INTOVF, sv);
		break;
	}
	userret(p);
	share_fpu(p, tf);
#undef ADVANCE
}

/*
 * Save windows from PCB into user stack, and return 0.  This is used on
 * window overflow pseudo-traps (from locore.s, just before returning to
 * user mode) and when ptrace or sendsig needs a consistent state.
 * As a side effect, rwindow_save() always sets pcb_nsaved to 0,
 * clobbering the `underflow restore' indicator if it was -1.
 *
 * If the windows cannot be saved, pcb_nsaved is restored and we return -1.
 */
int
rwindow_save(p)
	struct proc *p;
{
	struct pcb *pcb = &p->p_addr->u_pcb;
	struct rwindow *rw = &pcb->pcb_rw[0];
	int i;

	i = pcb->pcb_nsaved;
	if (i < 0) {
		pcb->pcb_nsaved = 0;
		return (0);
	}
	if (i == 0)
		return (0);
#ifdef DEBUG
	if (rwindow_debug)
		printf("%s[%d]: rwindow: pcb->stack:", p->p_comm, p->p_pid);
#endif
	do {
#ifdef DEBUG
		if (rwindow_debug)
			printf(" 0x%x", rw[1].rw_in[6]);
#endif
		if (copyout((caddr_t)rw, (caddr_t)rw[1].rw_in[6],
		    sizeof *rw))
			return (-1);
		rw++;
	} while (--i > 0);
#ifdef DEBUG
	if (rwindow_debug)
		printf("\n");
#endif
	pcb->pcb_nsaved = 0;
	return (0);
}

/*
 * Kill user windows (before exec) by writing back to stack or pcb
 * and then erasing any pcb tracks.  Otherwise we might try to write
 * the registers into the new process after the exec.
 */
void
pmap_unuse_final(p)
	struct proc *p;
{

	write_user_windows();
	p->p_addr->u_pcb.pcb_nsaved = 0;
}

/*
 * Called from locore.s trap handling, for synchronous memory faults.
 *
 * This duplicates a lot of logic in trap() and perhaps should be
 * moved there; but the bus-error-register parameters are unique to
 * this routine.
 *
 * Since synchronous errors accumulate during prefetch, we can have
 * more than one `cause'.  But we do not care what the cause, here;
 * we just want to page in the page and try again.
 */
void
mem_access_fault(type, ser, v, pc, psr, tf)
	unsigned type;
	int ser;
	u_int v;
	int pc, psr;
	struct trapframe *tf;
{
#if defined(SUN4) || defined(SUN4C) || defined(SUN4E)
	struct proc *p;
	struct vmspace *vm;
	vaddr_t va;
	int rv;
	vm_prot_t ftype;
	int onfault;
	union sigval sv;

	uvmexp.traps++;
	if ((p = curproc) == NULL)	/* safety check */
		p = &proc0;

	/*
	 * Figure out what to pass the VM code, and ignore the sva register
	 * value in v on text faults (text faults are always at pc).
	 * Kernel faults are somewhat different: text faults are always
	 * illegal, and data faults are extra complex.  User faults must
	 * set p->p_md.md_tf, in case we decide to deliver a signal.  Check
	 * for illegal virtual addresses early since those can induce more
	 * faults.
	 */
	if (type == T_TEXTFAULT)
		v = pc;
	if (VA_INHOLE(v))
		goto fault;
	ftype = ser & SER_WRITE ? PROT_WRITE : PROT_READ;
	va = trunc_page(v);
	if (psr & PSR_PS) {
#if defined(SUN4)
		extern char Lfsbail[];
#endif
		if (type == T_TEXTFAULT) {
			(void) splhigh();
			printf("text fault: pc=0x%x ser=%b\n", pc,
			       ser, SER_BITS);
			panic("kernel fault");
			/* NOTREACHED */
		}
#if defined(SUN4)
		/*
		 * If this was an access that we shouldn't try to page in,
		 * resume at the fault handler without any action.
		 */
		if (p->p_addr && p->p_addr->u_pcb.pcb_onfault == Lfsbail)
			goto kfault;
#endif

		/*
		 * During autoconfiguration, faults are never OK unless
		 * pcb_onfault is set.  Once running normally we must allow
		 * exec() to cause copy-on-write faults to kernel addresses.
		 */
		if (cold)
			goto kfault;
		if (va >= vm_min_kernel_address) {
			if (uvm_fault(kernel_map, va, 0, ftype) == 0)
				return;
			goto kfault;
		}
	} else
		p->p_md.md_tf = tf;

	/*
	 * mmu_pagein returns -1 if the page is already valid, in which
	 * case we have a hard fault; it returns 1 if it loads a segment
	 * that got bumped out via LRU replacement.
	 */
	vm = p->p_vmspace;
	rv = mmu_pagein(vm->vm_map.pmap, va,
			ser & SER_WRITE ? PROT_WRITE : PROT_READ);
	if (rv < 0)
		goto fault;
	if (rv > 0)
		goto out;

	/* alas! must call the horrible vm code */
	rv = uvm_fault(&vm->vm_map, (vaddr_t)va, 0, ftype);

	/*
	 * If this was a stack access we keep track of the maximum
	 * accessed stack size.  Also, if vm_fault gets a protection
	 * failure it is due to accessing the stack region outside
	 * the current limit and we need to reflect that as an access
	 * error.
	 */
	if ((caddr_t)va >= vm->vm_maxsaddr) {
		if (rv == 0)
			uvm_grow(p, va);
		else if (rv == EACCES)
			rv = EFAULT;
	}
	if (rv == 0) {
		/*
		 * pmap_enter() does not enter all requests made from
		 * vm_fault into the MMU (as that causes unnecessary
		 * entries for `wired' pages).  Instead, we call
		 * mmu_pagein here to make sure the new PTE gets installed.
		 */
		(void) mmu_pagein(vm->vm_map.pmap, va, PROT_NONE);
	} else {
		/*
		 * Pagein failed.  If doing copyin/out, return to onfault
		 * address.  Any other page fault in kernel, die; if user
		 * fault, deliver SIGSEGV.
		 */
fault:
		if (psr & PSR_PS) {
kfault:
			onfault = p->p_addr ?
			    (int)p->p_addr->u_pcb.pcb_onfault : 0;
			if (!onfault) {
				(void) splhigh();
				printf("data fault: pc=0x%x addr=0x%x ser=%b\n",
				       pc, v, ser, SER_BITS);
				panic("kernel fault");
				/* NOTREACHED */
			}
			tf->tf_pc = onfault;
			tf->tf_npc = onfault + 4;
			return;
		}

		sv.sival_int = v;
		trapsignal(p, SIGSEGV, (ser & SER_WRITE) ? PROT_WRITE :
		    PROT_READ, SEGV_MAPERR, sv);
	}
out:
	if ((psr & PSR_PS) == 0) {
		userret(p);
		share_fpu(p, tf);
	}
#endif /* SUN4 || SUN4C || SUN4E */
}

#if defined(SUN4M)	/* 4m version of mem_access_fault() follows */

static int tfaultaddr = (int) 0xdeadbeef;

#ifdef DEBUG
int dfdebug = 0;
#endif

void
mem_access_fault4m(type, sfsr, sfva, tf)
	unsigned type;
	u_int sfsr;
	u_int sfva;
	struct trapframe *tf;
{
	int pc, psr;
	struct proc *p;
	struct vmspace *vm;
	vaddr_t va;
	int rv;
	vm_prot_t ftype;
	int onfault;
	union sigval sv;

	uvmexp.traps++;
	if ((p = curproc) == NULL)	/* safety check */
		p = &proc0;

	pc = tf->tf_pc;			/* These are needed below */
	psr = tf->tf_psr;

	/*
	 * Our first priority is handling serious faults, such as
	 * parity errors or async faults that might have come through here.
	 * If afsr & AFSR_AFO != 0, then we're on a HyperSPARC and we
	 * got an async fault. We pass it on to memerr4m. Similarly, if
	 * the trap was T_STOREBUFFAULT, we pass it on to memerr4m.
	 * If we have a data fault, but SFSR_FAV is not set in the sfsr,
	 * then things are really bizarre, and we treat it as a hard
	 * error and pass it on to memerr4m. See pg. 9-35 in the SuperSPARC
	 * user's guide for more info, and for a possible solution which we
	 * don't implement here.
	 */
	if (type == T_STOREBUFFAULT ||
	    (type == T_DATAFAULT && !(sfsr & SFSR_FAV))) {
		(*cpuinfo.memerr)(type, sfsr, sfva, tf);
		/*
		 * If we get here, exit the trap handler and wait for the
		 * trap to re-occur.
		 */
		goto out;
	}

	/*
	 * Figure out what to pass the VM code. We cannot ignore the sfva
	 * register on text faults, since this might be a trap on an
	 * alternate-ASI access to code space. However, if we're on a
	 * supersparc, we can't help using PC, since we don't get a VA in
	 * sfva.
	 * Kernel faults are somewhat different: text faults are always
	 * illegal, and data faults are extra complex.  User faults must
	 * set p->p_md.md_tf, in case we decide to deliver a signal.  Check
	 * for illegal virtual addresses early since those can induce more
	 * faults.
	 * All translation faults are illegal, and result in a SIGSEGV
	 * being delivered to the running process (or a kernel panic, for
	 * a kernel fault). We check the translation first to make sure
	 * it is not spurious.
	 * Also, note that in the case where we have an overwritten
	 * text fault (OW==1, AT==2,3), we attempt to service the
	 * second (overwriting) fault, then restart the instruction
	 * (which is from the first fault) and allow the first trap
	 * to reappear. XXX is this right? It will probably change...
	 */
	if ((sfsr & SFSR_FT) == SFSR_FT_NONE)
		goto out;	/* No fault. Why were we called? */

	if ((sfsr & SFSR_AT_STORE)) {
		/* stores are never text faults. */
		ftype = PROT_WRITE;
	} else {
		ftype = PROT_READ;
		if ((sfsr & SFSR_AT_TEXT) || (type == T_TEXTFAULT)) {
			ftype |= PROT_EXEC;
		}
	}

	/*
	 * NOTE: the per-CPU fault status register readers (in locore)
	 * may already have decided to pass `pc' in `sfva', so we avoid
	 * testing CPU types here.
	 * Q: test SFSR_FAV in the locore stubs too?
	 */
	if ((sfsr & SFSR_FAV) == 0) {
		if (type == T_TEXTFAULT)
			sfva = pc;
		else
			goto fault;
	}

	if ((sfsr & SFSR_FT) == SFSR_FT_TRANSERR) {
		/* Translation errors are always fatal, as they indicate
		 * a corrupt translation (page) table hierarchy.
		 */
		if (tfaultaddr == sfva)	/* Prevent infinite loops w/a static */
			goto fault;
		tfaultaddr = sfva;
		if ((lda((sfva & 0xFFFFF000) | ASI_SRMMUFP_LN, ASI_SRMMUFP) &
		    SRMMU_TETYPE) != SRMMU_TEPTE)
			goto fault;	/* Translation bad */
		lda(SRMMU_SFSR, ASI_SRMMU);
		goto out;	/* Translation OK, retry operation */
	}

	va = trunc_page(sfva);

	if (((sfsr & SFSR_AT_TEXT) || type == T_TEXTFAULT) &&
	    !(sfsr & SFSR_AT_STORE) && (sfsr & SFSR_OW)) {
		if (psr & PSR_PS)	/* never allow in kernel */
			goto kfault;
#if 0
		/*
		 * Double text fault. The evil "case 5" from the HS manual...
		 * Attempt to handle early fault. Ignores ASI 8,9 issue...may
		 * do a useless VM read.
		 * XXX: Is this really necessary?
		 */
		if (mmumod == SUN4M_MMU_HS) { /* On HS, we have va for both */
			if (vm_fault(kernel_map, trunc_page(pc),
				     PROT_READ, 0))
#ifdef DEBUG
				printf("mem_access_fault: "
					"can't pagein 1st text fault.\n")
#endif
				;
		}
#endif
	}

	/* Now munch on protections... */

	if (psr & PSR_PS) {
		if (sfsr & SFSR_AT_TEXT || type == T_TEXTFAULT) {
			(void) splhigh();
			printf("text fault: pc=0x%x sfsr=%b sfva=0x%x\n", pc,
			       sfsr, SFSR_BITS, sfva);
			panic("kernel fault");
			/* NOTREACHED */
		}

		/*
		 * During autoconfiguration, faults are never OK unless
		 * pcb_onfault is set.  Once running normally we must allow
		 * exec() to cause copy-on-write faults to kernel addresses.
		 */
		if (cold)
			goto kfault;
		if (va >= vm_min_kernel_address) {
			if (uvm_fault(kernel_map, va, 0, ftype) == 0)
				return;
			goto kfault;
		}
	} else
		p->p_md.md_tf = tf;

	vm = p->p_vmspace;

	/* alas! must call the horrible vm code */
	rv = uvm_fault(&vm->vm_map, (vaddr_t)va, 0, ftype);
	/*
	 * If this was a stack access we keep track of the maximum
	 * accessed stack size.  Also, if vm_fault gets a protection
	 * failure it is due to accessing the stack region outside
	 * the current limit and we need to reflect that as an access
	 * error.
	 */
	if ((caddr_t)va >= vm->vm_maxsaddr) {
		if (rv == 0)
			uvm_grow(p, va);
		else if (rv == EACCES)
			rv = EFAULT;
	}
	if (rv != 0) {
		/*
		 * Pagein failed.  If doing copyin/out, return to onfault
		 * address.  Any other page fault in kernel, die; if user
		 * fault, deliver SIGSEGV.
		 */
fault:
		if (psr & PSR_PS) {
kfault:
			onfault = p->p_addr ?
			    (int)p->p_addr->u_pcb.pcb_onfault : 0;
			if (!onfault) {
				(void) splhigh();
				printf("data fault: pc=0x%x sfva=0x%x sfsr=%b\n",
				       pc, sfva, sfsr, SFSR_BITS);
				panic("kernel fault");
				/* NOTREACHED */
			}
			tf->tf_pc = onfault;
			tf->tf_npc = onfault + 4;
			return;
		}

		sv.sival_int = sfva;
		trapsignal(p, SIGSEGV, ftype, SEGV_MAPERR, sv);
	}
out:
	if ((psr & PSR_PS) == 0) {
		userret(p);
		share_fpu(p, tf);
	}
}
#endif

/*
 * System calls.  `pc' is just a copy of tf->tf_pc.
 *
 * Note that the things labelled `out' registers in the trapframe were the
 * `in' registers within the syscall trap code (because of the automatic
 * `save' effect of each trap).  They are, however, the %o registers of the
 * thing that made the system call, and are named that way here.
 */
void
syscall(code, tf, pc)
	register_t code;
	struct trapframe *tf;
	register_t pc;
{
	int i, nsys, *ap, nap;
	struct sysent *callp;
	struct proc *p;
	int error, new;
	struct args {
		register_t i[8];
	} args __aligned(8);
	register_t rval[2] __aligned(8);
#ifdef DIAGNOSTIC
	extern struct pcb *cpcb;
#endif

	uvmexp.syscalls++;
	p = curproc;
#ifdef DIAGNOSTIC
	if (tf->tf_psr & PSR_PS)
		panic("syscall");
	if (cpcb != &p->p_addr->u_pcb)
		panic("syscall cpcb/ppcb");
	if (tf != (struct trapframe *)((caddr_t)cpcb + USPACE) - 1)
		panic("syscall trapframe");
#endif
	p->p_md.md_tf = tf;
	new = code & SYSCALL_G2RFLAG;
	code &= ~SYSCALL_G2RFLAG;

	callp = p->p_p->ps_emul->e_sysent;
	nsys = p->p_p->ps_emul->e_nsysent;

	/*
	 * The first six system call arguments are in the six %o registers.
	 * Any arguments beyond that are in the `argument extension' area
	 * of the user's stack frame (see <machine/frame.h>).
	 *
	 * Check for ``special'' codes that alter this, namely syscall and
	 * __syscall.  The latter takes a quad syscall number, so that other
	 * arguments are at their natural alignments.  Adjust the number
	 * of ``easy'' arguments as appropriate; we will copy the hard
	 * ones later as needed.
	 */
	ap = &tf->tf_out[0];
	nap = 6;

	switch (code) {
	case SYS_syscall:
		code = *ap++;
		nap--;
		break;
	case SYS___syscall:
		if (callp != sysent)
			break;
		code = ap[_QUAD_LOWWORD];
		ap += 2;
		nap -= 2;
		break;
	}

	if (code < 0 || code >= nsys)
		callp += p->p_p->ps_emul->e_nosys;
	else {
		callp += code;
		i = callp->sy_argsize / sizeof(register_t);
		if (i > nap) {	/* usually false */
			if (i > 8)
				panic("syscall nargs");
			if ((error = copyin((caddr_t)tf->tf_out[6] +
			    offsetof(struct frame, fr_argx),
			    &args.i[nap], (i - nap) * sizeof(register_t))))
				goto bad;
			i = nap;
		}
		copywords(ap, args.i, i * sizeof(register_t));
	}

	rval[0] = 0;
	rval[1] = tf->tf_out[1];

	error = mi_syscall(p, code, callp, args.i, rval);

	switch (error) {
	case 0:
		/* Note: fork() does not return here in the child */
		tf->tf_out[0] = rval[0];
		tf->tf_out[1] = rval[1];
		if (new) {
			/* jmp %g2 on success */
			i = tf->tf_global[2];
			if (i & 3) {
				error = EINVAL;
				goto bad;
			}
		} else {
			/* old system call convention: clear C on success */
			tf->tf_psr &= ~PSR_C;	/* success */
			i = tf->tf_npc;
		}
		tf->tf_pc = i;
		tf->tf_npc = i + 4;
		break;

	case ERESTART:
	case EJUSTRETURN:
		/* nothing to do */
		break;

	default:
	bad:
		tf->tf_out[0] = error;
		tf->tf_psr |= PSR_C;	/* fail */
		i = tf->tf_npc;
		tf->tf_pc = i;
		tf->tf_npc = i + 4;
		break;
	}

	mi_syscall_return(p, code, error, rval);
	share_fpu(p, tf);
}

/*
 * Process the tail end of a fork() for the child.
 */
void
child_return(arg)
	void *arg;
{
	struct proc *p = arg;
	struct trapframe *tf = p->p_md.md_tf;

	/*
	 * Return values in the frame set by cpu_fork().
	 */
	tf->tf_out[0] = 0;
	tf->tf_out[1] = 0;
	tf->tf_psr &= ~PSR_C;

	mi_child_return(p);
}


code:
/*	$OpenBSD: vaddrs.h,v 1.8 2010/06/29 21:26:12 miod Exp $	*/
/*	$NetBSD: vaddrs.h,v 1.8 1997/03/10 23:54:41 pk Exp $ */

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

/*
 * Special (fixed) virtual addresses on the SPARC.
 *
 * IO virtual space begins at 0xfe000000 (a segment boundary) and
 * continues up to the DVMA edge at 0xff000000 (on non-SRMMU systems only).
 * (The upper all-1s byte is special anyway since some of the hardware
 * supplies this to pad a 24-bit address space out to 32 bits.  This is a
 * legacy of the IBM PC AT bus, actually, just so you know who to blame.)
 *
 * We reserve several pages at the base of our IO virtual space
 * for `oft-used' devices which must be present anyway in order to
 * configure.  In particular, we want the counter-timer register and
 * the Zilog ZSCC serial port chips to be mapped at fixed VAs to make
 * microtime() and the zs hardware interrupt handlers faster.
 *
 * [sun4/sun4c:]
 * Ideally, we should map the interrupt enable register here as well,
 * but that would require allocating pmegs in locore.s, so instead we
 * use one of the two `wasted' pages at KERNBASE+_MAXNBPG (see locore.s).
 */

#ifndef IODEV_0
#define	IODEV_0		IOSPACE_BASE

#define _MAXNBPG	8192	/* fixed VAs, independent of actual NBPG */
#define _MAXNCPU	4	/* fixed VA allocation allows 4 CPUs */

/* [4m:] interrupt and counter registers take (1 + NCPU) pages. */

#define	TIMERREG_VA	(IODEV_0)
#define	COUNTERREG_VA	(  TIMERREG_VA + _MAXNBPG*_MAXNCPU)	/* [4m] */
#define	ZS0_VA		(COUNTERREG_VA + _MAXNBPG)
#define	ZS1_VA		(       ZS0_VA + _MAXNBPG)
#define	AUXREG_VA	(       ZS1_VA + _MAXNBPG)
#define	TMPMAP_VA	(    AUXREG_VA + _MAXNBPG)
#define	MSGBUF_VA	(    TMPMAP_VA + _MAXNBPG)
#define INTRREG_VA	(    MSGBUF_VA + _MAXNBPG)		/* [4/4c] */
#define PI_INTR_VA	(    MSGBUF_VA + _MAXNBPG)		/* [4m] */
#define SI_INTR_VA	(   PI_INTR_VA + _MAXNBPG*_MAXNCPU)	/* [4m] */
#define	IODEV_BASE	(   SI_INTR_VA + _MAXNBPG)
#define	IODEV_END	(IOSPACE_BASE + IOSPACE_LEN)

#define	DVMA_BASE	0xfff00000
#define	DVMA_END	0xfffc0000

/*
 * The next constant defines the amount of reserved DVMA space on the
 * Sun4m. The amount of space *must* be a multiple of 16MB, and thus
 * (((u_int)0) - DVMA4M_BASE) must be divisible by 16*1024*1024!
 * Note that pagetables must be allocated at a cost of 1k per MB of DVMA
 * space, plus severe alignment restrictions. So don't make DVMA4M_BASE too
 * low (max space = 2G).
 */
#define DVMA4M_BASE	0xfc000000	/* can change subject to above rule */
#define DVMA4M_END	0xfffff000
#define DVMA_D24_BASE	0xff000000
#define DVMA_D24_END	0xfffff000

#define M_SPACE_D24	0x0001

/*
 * Virtual address of the per cpu `cpu_softc' structure.
 */
#define CPUINFO_VA	(KERNBASE+8192)

#endif /* IODEV_0 */


code:
/*	$OpenBSD: vm_machdep.c,v 1.60 2015/05/05 02:13:47 guenther Exp $	*/
/*	$NetBSD: vm_machdep.c,v 1.30 1997/03/10 23:55:40 pk Exp $ */

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

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/user.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/exec.h>
#include <sys/vnode.h>
#include <sys/extent.h>

#include <uvm/uvm_extern.h>

#include <machine/cpu.h>
#include <machine/frame.h>
#include <machine/trap.h>

#include <sparc/sparc/cpuvar.h>

/*
 * Map an IO request into kernel virtual address space.
 */
void
vmapbuf(struct buf *bp, vsize_t sz)
{
	vaddr_t uva, kva;
	vsize_t size, off;
	struct pmap *pmap;
	paddr_t pa;

#ifdef DIAGNOSTIC
	if ((bp->b_flags & B_PHYS) == 0)
		panic("vmapbuf");
#endif
	pmap = vm_map_pmap(&bp->b_proc->p_vmspace->vm_map);

	bp->b_saveaddr = bp->b_data;
	uva = trunc_page((vaddr_t)bp->b_data);
	off = (vaddr_t)bp->b_data - uva;
	size = round_page(off + sz);
	/*
	 * Note that this is an expanded version of:
	 *   kva = uvm_km_valloc_wait(kernel_map, size);
	 * We do it on our own here to be able to specify an offset to uvm_map
	 * so that we can get all benefits of PMAP_PREFER.
	 */
	kva = uvm_km_valloc_prefer_wait(kernel_map, size, uva);
	bp->b_data = (caddr_t)(kva + off);

	while (size > 0) {
		if (pmap_extract(pmap, uva, &pa) == FALSE)
			panic("vmapbuf: null page frame");

		/*
		 * Don't enter uncached if cache is mandatory.
		 *
		 * XXX - there are probably other cases where we don't need
		 *       to uncache, but for now we're conservative.
		 */
		if (!(cpuinfo.flags & CPUFLG_CACHE_MANDATORY))
			pa |= PMAP_NC;

		pmap_enter(pmap_kernel(), kva, pa,
		    PROT_READ | PROT_WRITE, PMAP_WIRED);

		uva += PAGE_SIZE;
		kva += PAGE_SIZE;
		size -= PAGE_SIZE;
	}
	pmap_update(pmap_kernel());
}

/*
 * Free the io map addresses associated with this IO operation.
 */
void
vunmapbuf(bp, sz)
	register struct buf *bp;
	vsize_t sz;
{
	register vaddr_t kva;
	register vsize_t size, off;

	if ((bp->b_flags & B_PHYS) == 0)
		panic("vunmapbuf");

	kva = trunc_page((vaddr_t)bp->b_data);
	off = (vaddr_t)bp->b_data - kva;
	size = round_page(sz + off);

	pmap_remove(pmap_kernel(), kva, kva + size);
	pmap_update(pmap_kernel());
	uvm_km_free_wakeup(kernel_map, kva, size);
	bp->b_data = bp->b_saveaddr;
	bp->b_saveaddr = NULL;
	if (CACHEINFO.c_vactype != VAC_NONE)
		cpuinfo.cache_flush(bp->b_data, bp->b_bcount - bp->b_resid);
}

/*
 * The offset of the topmost frame in the kernel stack.
 */
#define	TOPFRAMEOFF (USPACE-sizeof(struct trapframe)-sizeof(struct frame))

/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the pcb, making the child ready to run, and marking
 * it so that it can return differently than the parent.
 *
 * This function relies on the fact that the pcb is
 * the first element in struct user.
 */
void
cpu_fork(p1, p2, stack, stacksize, func, arg)
	struct proc *p1, *p2;
	void *stack;
	size_t stacksize;
	void (*func)(void *);
	void *arg;
{
	struct pcb *opcb = &p1->p_addr->u_pcb;
	struct pcb *npcb = &p2->p_addr->u_pcb;
	struct trapframe *tf2;
	struct rwindow *rp;

	/*
	 * Save all user registers to p1's stack or, in the case of
	 * user registers and invalid stack pointers, to opcb.
	 * We then copy the whole pcb to p2; when switch() selects p2
	 * to run, it will run at the `proc_trampoline' stub, rather
	 * than returning at the copying code below.
	 *
	 * If process p1 has an FPU state, we must copy it.  If it is
	 * the FPU user, we must save the FPU state first.
	 */

	if (p1 == curproc) {
		write_user_windows();
		opcb->pcb_psr = getpsr();
	}
#ifdef DIAGNOSTIC
	else if (p1 != &proc0)
		panic("cpu_fork: curproc");
#endif

	bcopy((caddr_t)opcb, (caddr_t)npcb, sizeof(struct pcb));
	if (p1->p_md.md_fpstate) {
		if (p1 == cpuinfo.fpproc)
			savefpstate(p1->p_md.md_fpstate);
		p2->p_md.md_fpstate = malloc(sizeof(struct fpstate),
		    M_SUBPROC, M_WAITOK);
		bcopy(p1->p_md.md_fpstate, p2->p_md.md_fpstate,
		    sizeof(struct fpstate));
	} else
		p2->p_md.md_fpstate = NULL;

	/*
	 * Setup (kernel) stack frame that will by-pass the child
	 * out of the kernel. (The trap frame invariably resides at
	 * the tippity-top of the u. area.)
	 */
	tf2 = p2->p_md.md_tf = (struct trapframe *)
			((int)npcb + USPACE - sizeof(*tf2));

	/* Copy parent's trapframe */
	*tf2 = *(struct trapframe *)((int)opcb + USPACE - sizeof(*tf2));

	/* Duplicate efforts of syscall(), but slightly differently */
	if (tf2->tf_global[1] & SYSCALL_G2RFLAG) {
		/* jmp %g2 (or %g7, deprecated) on success */
		tf2->tf_npc = tf2->tf_global[2];
	} else {
		/*
		 * old system call convention: clear C on success
		 * note: proc_trampoline() sets a fresh psr when
		 * returning to user mode.
		 */
		/*tf2->tf_psr &= ~PSR_C;   -* success */
	}

	/* Set return values in child mode */
	tf2->tf_out[0] = 0;
	tf2->tf_out[1] = 1;

	/* Skip trap instruction. */
	tf2->tf_pc = tf2->tf_npc;
	tf2->tf_npc += 4;

	/* Construct kernel frame to return to in cpu_switch() */
	rp = (struct rwindow *)((u_int)npcb + TOPFRAMEOFF);
	rp->rw_local[0] = (int)func;		/* Function to call */
	rp->rw_local[1] = (int)arg;		/* and its argument */

	/*
	 * If specified, give the child a different stack, with space
	 * reserved for the frame, and zero the frame pointer.
	 */
	if (stack != NULL) {
		tf2->tf_out[6] = (u_int)stack + stacksize
		    - sizeof(struct frame);
		rp->rw_in[6] = 0;
	}

	npcb->pcb_pc = (int)proc_trampoline - 8;
	npcb->pcb_sp = (int)rp;
	npcb->pcb_psr &= ~PSR_CWP;	/* Run in window #0 */
	npcb->pcb_wim = 1;		/* Fence at window #1 */

}

/*
 * cpu_exit is called as the last action during exit.
 *
 * We clean up a little and then call sched_exit() with the old proc
 * as an argument.  sched_exit() schedules the old vmspace and stack
 * to be freed, then selects a new process to run.
 */
void
cpu_exit(p)
	struct proc *p;
{
	register struct fpstate *fs;

	if ((fs = p->p_md.md_fpstate) != NULL) {
		if (p == cpuinfo.fpproc) {
			savefpstate(fs);
			cpuinfo.fpproc = NULL;
		}
		free((void *)fs, M_SUBPROC, 0);
	}

	pmap_deactivate(p);
	sched_exit(p);
}


code:
/Makefile/1.9/Sun Nov 25 18:25:33 2007//TOPENBSD_5_8_BASE
/Makefile.inc/1.17/Fri Mar 18 06:21:40 2011//TOPENBSD_5_8_BASE
D/binstall////
D/boot////
D/bootxx////
D/common////
D/installboot////
D/libsa////
D/libz////

path: sys/arch/sparc/stand/CVS/Entries


code: src/sys/arch/sparc/stand

path: sys/arch/sparc/stand/CVS/Repository


code:
#	$OpenBSD: Makefile,v 1.9 2007/11/25 18:25:33 deraadt Exp $
#	$NetBSD: Makefile,v 1.15 1997/06/01 03:39:03 mrg Exp $

.if ${MACHINE} == "sparc"
SUBDIR= libsa libz boot bootxx binstall
.endif

SUBDIR+= installboot

.include <bsd.subdir.mk>

path: sys/arch/sparc/stand/Makefile


code:
#	$OpenBSD: Makefile.inc,v 1.17 2011/03/18 06:21:40 matthew Exp $
#	$NetBSD: Makefile.inc,v 1.5 1996/02/01 22:33:01 mycroft Exp $

BINDIR=	/usr/mdec

# sun4:
#	The first 8MB of physical memory are mapped 1:1.
# sun4c:
#	Worst case sun4c systems have their memory in non-contiguous 4MB
#	areas, therefore we must ensure the boot code never crosses a 4MB
#	boundary.
#	A SPARCstation IPC with 12MB memory in 1MB SIMMs, running PROM 2.9,
#	only maps virtual memory up to 0x3aefff.
# sun4m:
#	The minimal contiguous memory area will be 8MB (SS4/SS5 8MB DIMMs),
#	but there is no guarantee anything will be mapped at address zero
#	if the DIMM are set in a pathological (dis)order, as in:
#		ok cd /memory
#		ok .attributes
#		reg                      00000000  08000000  00800000
#		                         00000000  0a000000  00800000
#		                         00000000  0c000000  00800000
#		                         00000000  0e000000  00800000
#		available                00000000  0e000000  007a6000
#		                         00000000  0c000000  00800000
#		                         00000000  0a000000  00800000
#		                         00000000  08000000  00800000
#		name                     memory
#	where the four 8MB DIMMs are mapped at 32MB intervals from 128MB
#	onwards.
# sun4d:
#	Similar to sun4m, but the minimal contiguous memory area will be 32MB,
#	and all physical memory will be packed contiguous from address zero
#	onwards.
#
# The following values of RELOC and RELOC2 have been choosen to work on as
# many systems as possible, yet allowing small enough kernels to be loaded
# at the beginning of the physical memory.
RELOC=		0x358000
RELOC2=		0x398000

CFLAGS+=	-fno-stack-protector

# XXX <machine/param.h> incorrectly uses STANDALONE instead of _STANDALONE
DEFS=		-DSTANDALONE -D_STANDALONE -DRELOC=${RELOC} -DSUN_BOOTPARAMS \
		-DSUN4 -DSUN4C -DSUN4D -DSUN4M

### Figure out what to use for libsa
LIBSADIR=		${.CURDIR}/../libsa

.if exists(${LIBSADIR}/${__objdir})
LIBSAOBJDIR=		${LIBSADIR}/${__objdir}
.else
LIBSAOBJDIR=		${LIBSADIR}
.endif

LIBSA=			${LIBSAOBJDIR}/libsa.a

### Figure out what to use for libz
LIBZDIR=		${.CURDIR}/../libz

.if exists(${LIBZDIR}/${__objdir})
LIBZOBJDIR=		${LIBZDIR}/${__objdir}
.else
LIBZOBJDIR=		${LIBZDIR}
.endif

LIBZ=			${LIBZOBJDIR}/libz.a


code:
/Makefile/1.3/Sun Sep  2 23:23:51 2012//TOPENBSD_5_8_BASE
/binstall.sh/1.3/Wed Feb 18 08:17:46 1998//TOPENBSD_5_8_BASE
D


code: src/sys/arch/sparc/stand/binstall


path: sys/arch/sparc/stand/binstall/CVS/Tag


code:
#	$OpenBSD: Makefile,v 1.3 2012/09/02 23:23:51 pascal Exp $

NOMAN=	noman

beforeinstall:
	${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
	    ${.CURDIR}/binstall.sh ${DESTDIR}${BINDIR}/binstall

.include <bsd.prog.mk>

path: sys/arch/sparc/stand/binstall/Makefile


code:
#!/bin/sh
#	$OpenBSD: binstall.sh,v 1.3 1998/02/18 08:17:46 deraadt Exp $
#	$NetBSD: binstall.sh,v 1.3 1996/04/07 20:00:12 thorpej Exp $
#

vecho () {
# echo if VERBOSE on
	if [ "$VERBOSE" = "1" ]; then
		echo "$@" 1>&2
	fi
	return 0
}

Usage () {
	echo "Usage: $0 [-hvt] [-m<path>] net|ffs directory"
	exit 1
}

Help () {
	echo "This script copies the boot programs to one of several"
	echo "commonly used places. It takes care of stripping the"
	echo "a.out(5) header off the installed boot program on sun4 machines."
	echo "When installing an \"ffs\" boot program, this script also runs"
	echo "installboot(8) which installs the default proto bootblocks into"
	echo "the appropriate filesystem partition."
	echo "Options:"
	echo "	-h		- display this message"
	echo "	-m<path>	- Look for boot programs in <path> (default: /usr/mdec)"
	echo "	-v		- verbose mode"
	echo "	-t		- test mode (implies -v)"
	exit 0
}

PATH=/bin:/usr/bin:/sbin:/usr/sbin
MDEC=${MDEC:-/usr/mdec}

set -- `getopt "hm:tv" "$@"`
if [ $? -gt 0 ]; then
	Usage
fi

for a in $*
do
	case $1 in
	-h) Help; shift ;;
	-m) MDEC=$2; shift 2 ;;
	-t) TEST=1; VERBOSE=1; shift ;;
	-v) VERBOSE=1; shift ;;
	--) shift; break ;;
	esac
done

INSTALLBOOT=${INSTALLBOOT:-$MDEC/installboot}
if [ ! -x $INSTALLBOOT ]; then
	INSTALLBOOT=/usr/mdec/installboot;
fi

DOIT=${TEST:+echo "=>"}

if [ $# != 2 ]; then
	Usage
fi

WHAT=$1
DEST=$2

if [ ! -d $DEST ]; then
	echo "$DEST: not a directory"
	Usage
fi

SKIP=0

case $WHAT in
"ffs")
	DEV=`mount | while read line; do
		set -- $line
		vecho "Inspecting \"$line\""
		if [ "$2" = "on" -a "$3" = "$DEST" ]; then
			if [ ! -b $1 ]; then
				continue
			fi
			RAW=\`echo -n "$1" | sed -e 's;/dev/;/dev/r;'\`
			if [ ! -c \$RAW ]; then
				continue
			fi
			echo -n $RAW
			break;
		fi
	done`
	if [ "$DEV" = "" ]; then
		echo "Cannot find \"$DEST\" in mount table"
		exit 1
	fi
	TARGET=$DEST/boot
	DEV=`echo $DEV | sed -e 's/a$/c/'`
	vecho Boot device: $DEV
	vecho Target: $TARGET
	$DOIT dd if=${MDEC}/boot of=$TARGET bs=32 skip=$SKIP
	sync; sync; sync
	vecho $INSTALLBOOT ${VERBOSE:+-v} $TARGET ${MDEC}/bootxx $DEV
	$DOIT $INSTALLBOOT ${VERBOSE:+-v} $TARGET ${MDEC}/bootxx $DEV
	;;

"net")
	TARGET=$DEST/boot.sparc.openbsd
	TMP=/tmp/boot.$$
	vecho Target: $TARGET
	vecho Copying to temporary file.
	cp ${MDEC}/boot $TMP; chmod +w $TMP
	vecho Stripping $TMP
	strip $TMP
	vecho Creating header magic.
	printf '\01\03\01\07\060\200\0\07' | dd of=$TARGET bs=32 conv=sync
	vecho Concatenating boot code.
	dd if=$TMP of=$TARGET bs=32 skip=1 seek=1
	rm $TMP
	;;

*)
	echo "$WHAT: not recognised"
	exit 1
	;;
esac

exit $?


path: sys/arch/sparc/stand/boot/CVS/Entries


path: sys/arch/sparc/stand/boot/CVS/Tag


code:
#	$OpenBSD: Makefile,v 1.21 2015/06/14 18:33:53 miod Exp $
#	$NetBSD: Makefile,v 1.2 1995/09/30 21:43:38 pk Exp $

PROG=	boot

NOMAN=	noman
INSTALL_STRIP=
S=	${.CURDIR}/../../../..

.PATH:	${.CURDIR}/../common
SRCS=	srt0.S conf.c dvma.c mmu.c net.c netif_sun.c promdev.c version.c

SRCS+=	boot.c loadfile_sparc.c

.PATH:	${S}/lib/libkern/arch/sparc ${S}/lib/libkern
SRCS+=	bzero.S strlen.c mul.S umul.S strcmp.c sdiv.S urem.S udiv.S rem.S
SRCS+=	moddi3.c muldi3.c qdivrem.c

CFLAGS=	-fno-pie -O2 -I${.CURDIR}/../common -I${.CURDIR}/../../../../arch \
	-I${.CURDIR}/../../../.. -I${.CURDIR}/../../../../lib/libsa ${DEFS}
AFLAGS+=-fno-pie

CLEANFILES+=${PROG}.aout ${PROG}.elf elfclean
LIBS=${LIBSA} ${LIBZ}

elfclean: clean-elf.c
	${HOSTCC} -o elfclean ${.ALLSRC}

${PROG}: ${OBJS} ${LIBS} elfclean
	${LD} -nopie -N -Ttext ${RELOC2} --format a.out-sparc-netbsd \
	    -e start ${OBJS} ${LIBSA} ${LIBZ} -o ${.TARGET}.elf
	./elfclean ${.TARGET}.elf
	objcopy -j .text -j .data -j .bss -O a.out-sparc-netbsd \
	    ${.TARGET}.elf ${.TARGET}.aout
	(echo -n 01 | tr 01 '\01\03'; tail +3c ${.TARGET}.aout) | \
	    dd obs=512 conv=osync > ${.TARGET}
	@rm ${.TARGET}.aout ${.TARGET}.elf

srt0.o: srt0.S
	${CC} ${CFLAGS} -D_LOCORE -c ${.IMPSRC}

.include <bsd.prog.mk>

path: sys/arch/sparc/stand/boot/Makefile


code:
/*	$OpenBSD: boot.c,v 1.14 2015/05/19 20:42:11 miod Exp $	*/
/*	$NetBSD: boot.c,v 1.2 1997/09/14 19:27:21 pk Exp $	*/

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

#include <sys/param.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#define _KERNEL
#include <sys/fcntl.h>
#undef _KERNEL

#include <lib/libsa/loadfile.h>
#include <lib/libsa/stand.h>

#include <sparc/stand/common/promdev.h>

int debug;
int netif_debug;

#define	FOURMB		0x400000
#ifndef	RELOC2
#define	RELOC2		(RELOC + 0x40000)
#endif
#define	LOWSTACK	(16 * 1024)

/*
 * Boot device is derived from ROM provided information.
 */
#define	DEFAULT_KERNEL	"bsd"

extern char	*version;
char		fbuf[80], dbuf[128];
char		rnddata[BOOTRANDOM_MAX];

paddr_t	bstart, bend;	/* physical start & end address of the boot program */
int	compat = 1;	/* try to load in compat mode */
int	rnd_loaded = 0;

typedef void (*entry_t)(u_long, int, int, int, long, long);

int	fdloadfile(int, u_long *, int);
int	loadrandom(const char *, void *, size_t);

static paddr_t
getphysmem(u_long size)
{
	struct	memarr *pmemarr;	/* physical memory regions */
	u_int	npmemarr;		/* number of entries in pmemarr */
	struct memarr *mp;
	int i;
#ifdef DEBUG
	static int arrdpy;
#endif

	/*
	 * Get available physical memory from the prom.
	 */
	npmemarr = prom_makememarr(NULL, 0, MEMARR_AVAILPHYS);
	pmemarr = alloc(npmemarr*sizeof(struct memarr));
	if (pmemarr == NULL)
		return ((paddr_t)-1);
	npmemarr = prom_makememarr(pmemarr, npmemarr, MEMARR_AVAILPHYS);

#ifdef DEBUG
	if (arrdpy == 0) {
		arrdpy = 1;
		printf("Available physical memory:\n");
		for (mp = pmemarr, i = (int)npmemarr; --i >= 0; mp++) {
			uint64_t addr;
			addr = pmemarr[i].addr_hi;
			addr <<= 32;
			addr |= pmemarr[i].addr_lo;
			printf("%p at 0x%llx\n", pmemarr[i].len, addr);
		}
	}
#endif

	/*
	 * Find a suitable loading address.
	 */
	for (mp = pmemarr, i = (int)npmemarr; --i >= 0; mp++) {
		paddr_t pa;
		u_long len;

		/* Skip memory ranges the kernel can't use yet on sun4d */
		if (pmemarr[i].addr_hi != 0)
			continue;
		pa = (paddr_t)pmemarr[i].addr_lo;
		if (pa >= 0x80000000)
			continue;
		len = (u_long)pmemarr[i].len;
		if (len >= 0x80000000)
			len = 0x80000000;
		if (pa + len > 0x80000000)
			len = 0x80000000 - pa;

		if (len < size)
			continue;

		/* Check whether it will fit in front of us */
		if (pa < bstart && len >= size && (bstart - pa) >= size)
			return (pa);

		/* Skip the boot program memory */
		if (pa < bend) {
			if (len < bend - pa)
				/* Not large enough */
				continue;

			/* Shrink this segment */
			len -=  bend - pa;
			pa = bend;
		}

		/* Does it fit in the remainder of this segment? */
		if (len >= size)
			return (pa);
	}
	return ((paddr_t)-1);
}

static int
loadk(char *file, u_long *marks)
{
	int fd, error, flags;
	vaddr_t va;
	paddr_t pa;
	u_long minsize, size;
	vaddr_t extra;

	marks[MARK_RANDOM] = marks[MARK_ERANDOM] = 0;

	/*
	 * Regardless of the address where we load the kernel, we need to
	 * make sure it has enough valid space to use during pmap_bootstrap.
	 * locore.s tries to use the 512KB following the kernel image, and
	 * we need to make sure this extra room does not overwrite PROM data
	 * (such as the PROM page tables which are immediately below 4MB on
	 * most sun4c).
	 */
	extra = 512 * 1024;

	if ((fd = open(file, O_RDONLY)) < 0)
		return (errno ? errno : ENOENT);

	/*
	 * We need to know whether we are booting off a tape or not,
	 * because we can not seek backwards off tapes.
	 */

	if (files[fd].f_flags & F_RAW) {
		flags = (COUNT_KERNEL & ~COUNT_SYM) | (LOAD_KERNEL & ~LOAD_SYM);
		if (rnd_loaded == 0)
			flags &= ~LOAD_RANDOM;
		minsize = FOURMB;
		va = 0xf8000000;		/* KERNBASE */
#ifdef DEBUG
		printf("Tape boot: expecting a bsd.rd kernel smaller than %p\n",
		    minsize);
#endif
		/* compensate for extra room below */
		minsize -= extra;
	} else {
		flags = LOAD_KERNEL;
		if (rnd_loaded == 0)
			flags &= ~LOAD_RANDOM;

		/*
		 * Even though we just have opened the file, the gzip code
		 * has tried to read from it. Be sure to reset position in
		 * case the file is not compressed (transparent mode isn't
		 * so transparent...)
		 */
		if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
			error = errno;
			goto out;
		}

		marks[MARK_START] = 0;
		if ((error = fdloadfile(fd, marks, COUNT_KERNEL)) != 0)
			goto out;

		/* rewind file for the actual load operation later */
		if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
			error = errno;
			goto out;
		}

		minsize = marks[MARK_END] - marks[MARK_START];

		/* We want that leading 16K in front of the kernel image */
		minsize += PROM_LOADADDR;
		va = marks[MARK_START] - PROM_LOADADDR;
	}

	/*
	 * If the kernel would entirely fit under the boot code, and the
	 * boot code has been loaded 1:1, we do not need to allocate
	 * breathing room after it.
	 */
	size = minsize + extra;
	if (CPU_ISSUN4M || CPU_ISSUN4D)
		size += 1024 * 1024;
	if (compat != 0) {
		if (size <= RELOC2 - LOWSTACK)
			size = RELOC2 - LOWSTACK;
		else
			compat = 0;
	}

	/* Get a physical load address */
#ifdef DEBUG
	printf("kernel footprint %p, requesting %p\n", minsize, size);
#endif
	pa = getphysmem(size);
	if (pa == (paddr_t)-1) {
		/*
		 * The extra bootstrap memory estimate might have been
		 * too much, if physical memory doesn't have any contiguous
		 * large chunks (e.g. on sun4c systems with 4MB regions).
		 * If that increase caused us to cross a 4MB boundary, try
		 * to limit ourselves to a 4MB multiple.
		 */
		if (compat == 0 && size / FOURMB != minsize / FOURMB) {
			size = roundup(minsize, FOURMB);
#ifdef DEBUG
			printf("now trying %p\n", size);
#endif
			pa = getphysmem(size);
		}
		if (pa == (paddr_t)-1) {
			error = EFBIG;
			goto out;
		}
	}

	printf("Loading at physical address %lx\n", pa);
	if (pmap_map(va, pa, size) != 0) {
		error = EFAULT;
		goto out;
	}

	/* try and double-map at VA 0 for compatibility */
	if (pa + size > bstart) {
#ifdef DEBUG
		printf("WARNING: %s is too large for compat mode.\n"
		    "If your kernel is too old, it will not run correctly.\n",
		    file);
#endif
	} else {
		if (pa != 0 && pmap_map(0, pa, size) != 0) {
			error = EFAULT;
			goto out;
		}
	}

	marks[MARK_START] = 0;
	error = fdloadfile(fd, marks, flags);

	/*
	 * If we did not load a random.seed file yet, and we know we can try,
	 * load one.
	 */
	if (error == 0 && rnd_loaded == 0 && marks[MARK_RANDOM] != 0) {
		/*
		 * Some PROM do not like having a network device open()ed
		 * twice; better close the kernel fd before trying to get
		 * randomness.
		 */
		close(fd);

		rnd_loaded = loadrandom(BOOTRANDOM, rnddata, sizeof(rnddata));
		if (rnd_loaded != 0) {
			while (marks[MARK_RANDOM] < marks[MARK_ERANDOM]) {
				u_long m;
				m = MIN(marks[MARK_ERANDOM] -
				    marks[MARK_RANDOM], sizeof(rnddata));
				memcpy((void *)marks[MARK_RANDOM], rnddata, m);
				marks[MARK_RANDOM] += m;
			}
		}

		return 0;
	}

out:
	close(fd);
	return (error);
}

int
main(int argc, char *argv[])
{
	int	error;
	char	*file;
	u_long	marks[MARK_MAX];
	extern char start[];		/* top of stack (see srt0.S) */
	vaddr_t	bstart_va;

	prom_init();
	mmu_init();

	printf(">> OpenBSD BOOT %s\n", version);

	/*
	 * Find the physical memory area that's in use by the boot loader.
	 * Our stack grows down from label `start'; assume we need no more
	 * than 16K of stack space.
	 * The top of the boot loader is the next 4MB boundary.
	 */
	bstart_va = (vaddr_t)start - LOWSTACK;
	if (pmap_extract(bstart_va, &bstart) != 0)
		panic("can't figure out where we have been loaded");

	if (bstart != bstart_va)
		compat = 0;

	bend = roundup(bstart, FOURMB);
#ifdef DEBUG
	printf("bstart %p bend %p\n", bstart, bend);
#endif

	file = prom_bootfile;
	if (file == 0 || *file == 0)
		file = DEFAULT_KERNEL;

	for (;;) {
		if (prom_boothow & RB_ASKNAME) {
			printf("device[%s]: ", prom_bootdevice);
			gets(dbuf);
			if (dbuf[0])
				prom_bootdevice = dbuf;
			printf("boot: ");
			gets(fbuf);
			if (fbuf[0])
				file = fbuf;
		}

		printf("Booting %s\n", file);
		if ((error = loadk(file, marks)) == 0)
			break;

		printf("Cannot load %s: error=%d\n", file, error);
		prom_boothow |= RB_ASKNAME;
	}

	/* Note: args 2-4 not used due to conflicts with SunOS loaders */
	(*(entry_t)marks[MARK_ENTRY])(cputyp == CPU_SUN4 ?
	    PROM_LOADADDR : (u_long)promvec, 0, 0, 0,
	    marks[MARK_END], DDB_MAGIC1);

	_rtt();
}

int
loadrandom(const char *path, void *buf, size_t buflen)
{
	struct stat sb;
	int fd;
	int rc = 0;

	fd = open(path, O_RDONLY);
	if (fd == -1) {
		if (errno != EPERM)
			printf("cannot open %s: %s\n", path, strerror(errno));
		return 0;
	}
	if (fstat(fd, &sb) == -1 || sb.st_uid != 0 || !S_ISREG(sb.st_mode) ||
	    (sb.st_mode & (S_IWOTH|S_IROTH)))
		goto fail;
	(void) read(fd, buf, buflen);
	rc = 1;
fail:
	close(fd);
	return rc;
}


code:
/* $OpenBSD: loadfile_sparc.c,v 1.4 2015/05/19 20:42:11 miod Exp $ */

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

/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Ralph Campbell.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. 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.
 *
 *	@(#)boot.c	8.1 (Berkeley) 6/10/93
 */

#include <lib/libkern/libkern.h>
#include <lib/libsa/stand.h>

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

#include "loadfile.h"

#include <sys/exec_elf.h>

int	elf32_exec(int, off_t, Elf_Ehdr *, u_long *, int);

/*
 * If we're booting off tape, we can't seek.
 * Emulate forward moves with reads, and give up on backward moves.
 * bsd.rd ought to be correctly ordered.
 */
static off_t relseek(int fd, off_t relpos)
{
	struct open_file *f = &files[fd];
#define DUMBBUFSIZE     4096
	char dumbbuf[DUMBBUFSIZE];
	int len;

	if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) {
		errno = EBADF;
		return (-1);
	}

	if (f->f_flags & F_RAW) {
		if (relpos < 0) {
#ifdef DEBUG
			printf("relseek: attempting to seek backward\n");
#endif
			errno = EIO;
			return -1;
		}

		while (relpos != 0) {
			len = relpos > DUMBBUFSIZE ? DUMBBUFSIZE : relpos;
			if (read(fd, dumbbuf, len) != len)
				return -1;
			relpos -= len;
		}

		return 0;
	}

	return lseek(fd, relpos, SEEK_CUR);
}

/*
 * Read in program from the given file descriptor.
 * Caller is reponsible for seeking the file descriptor at the correct
 * position.
 * Returns error code (0 on success).
 * Fills in marks.
 */
int
fdloadfile(int fd, u_long *marks, int flags)
{
	union {
		Elf32_Ehdr elf32;
	} hdr;
	ssize_t nr;
	int rval;

	/* Read the exec header. */
	nr = read(fd, &hdr, sizeof(hdr));
	if (nr == -1) {
		WARN(("read header failed"));
		goto err;
	}
	if (nr != sizeof(hdr)) {
		WARN(("read header short"));
		errno = EFTYPE;
		goto err;
	}

	if (memcmp(hdr.elf32.e_ident, ELFMAG, SELFMAG) == 0 &&
	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
		rval = elf32_exec(fd, (off_t)sizeof(hdr), &hdr.elf32,
		    marks, flags);
	} else {
		rval = 1;
		errno = EFTYPE;
	}

	if (rval == 0) {
		if ((flags & LOAD_ALL) != 0)
			PROGRESS(("=0x%lx\n",
			    marks[MARK_END] - marks[MARK_START]));
		return 0;
	}
err:
	return errno;
}

int
elf32_exec(int fd, off_t filepos, Elf_Ehdr *elf, u_long *marks, int flags)
{
	Elf_Shdr *shp;
	Elf_Phdr *phdr;
	Elf_Off off;
	int i;
	size_t sz;
	int first;
	int havesyms;
	paddr_t minp = ~0, maxp = 0, pos = 0;
	paddr_t shpp, elfp;
	off_t newpos;

	sz = elf->e_phnum * sizeof(Elf_Phdr);
	phdr = ALLOC(sz);

	newpos = (off_t)elf->e_phoff;
	if (relseek(fd, newpos - filepos) == -1) {
		WARN(("lseek phdr"));
		FREE(phdr, sz);
		return 1;
	}
	filepos = newpos;
	if (read(fd, phdr, sz) != sz) {
		WARN(("read program headers"));
		FREE(phdr, sz);
		return 1;
	}
	filepos += sz;

	for (first = 1, i = 0; i < elf->e_phnum; i++) {
		if (phdr[i].p_type == PT_OPENBSD_RANDOMIZE) {
			int m;

			/* Fill segment is asked for. */
			if (flags & LOAD_RANDOM) {
				for (pos = 0; pos < phdr[i].p_filesz;
				    pos += m) {
					m = MIN(phdr[i].p_filesz - pos,
					    sizeof(rnddata));
					BCOPY(rnddata, phdr[i].p_paddr + pos,
					    m);
				}
			}
			if (flags & (LOAD_RANDOM | COUNT_RANDOM)) {
				marks[MARK_RANDOM] = LOADADDR(phdr[i].p_paddr);
				marks[MARK_ERANDOM] =
				    marks[MARK_RANDOM] + phdr[i].p_filesz;
			}
			continue;
		}

		if (phdr[i].p_type != PT_LOAD ||
		    (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0)
			continue;

#ifdef CHECK_PHDR
		if (CHECK_PHDR(ELFSIZE, &phdr[i])) {
			FREE(phdr, sz);
			return 1;
		}
#endif

#define IS_TEXT(p)	(p.p_flags & PF_X)
#define IS_DATA(p)	((p.p_flags & PF_X) == 0)
#define IS_BSS(p)	(p.p_filesz < p.p_memsz)
		/*
		 * XXX: Assume first address is lowest
		 */
		if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) ||
		    (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {

			/* Read in segment. */
			PROGRESS(("%s%lu", first ? "" : "+",
			    (u_long)phdr[i].p_filesz));

			newpos = (off_t)phdr[i].p_offset;
			if (relseek(fd, newpos - filepos) == -1) {
				WARN(("lseek text"));
				FREE(phdr, sz);
				return 1;
			}
			filepos = newpos;
			if (READ(fd, phdr[i].p_paddr, phdr[i].p_filesz) !=
			    phdr[i].p_filesz) {
				WARN(("read text"));
				FREE(phdr, sz);
				return 1;
			}
			filepos += phdr[i].p_filesz;

			first = 0;
		}

		if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT | COUNT_TEXT))) ||
		    (IS_DATA(phdr[i]) && (flags & (LOAD_DATA | COUNT_TEXT)))) {
			pos = phdr[i].p_paddr;
			if (minp > pos)
				minp = pos;
			pos += phdr[i].p_filesz;
			if (maxp < pos)
				maxp = pos;
		}

		/* Zero out BSS. */
		if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) {
			PROGRESS(("+%lu",
			    (u_long)(phdr[i].p_memsz - phdr[i].p_filesz)));
			BZERO((phdr[i].p_paddr + phdr[i].p_filesz),
			    phdr[i].p_memsz - phdr[i].p_filesz);
		}
		if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) {
			pos += phdr[i].p_memsz - phdr[i].p_filesz;
			if (maxp < pos)
				maxp = pos;
		}
	}
	FREE(phdr, sz);

	/*
	 * Copy the ELF and section headers.
	 */
	elfp = maxp = roundup(maxp, sizeof(Elf_Addr));
	if (flags & (LOAD_HDR | COUNT_HDR))
		maxp += sizeof(Elf_Ehdr);

	if (flags & (LOAD_SYM | COUNT_SYM)) {
		newpos = (off_t)elf->e_shoff;
		if (relseek(fd, newpos - filepos) == -1) {
			WARN(("lseek section headers"));
			return 1;
		}
		filepos = newpos;
		sz = elf->e_shnum * sizeof(Elf_Shdr);
		shp = ALLOC(sz);

		if (read(fd, shp, sz) != sz) {
			WARN(("read section headers"));
			FREE(shp, sz);
			return 1;
		}
		filepos += sz;

		shpp = maxp;
		maxp += roundup(sz, sizeof(Elf_Addr));

		/*
		 * Now load the symbol sections themselves. Make sure the
		 * sections are aligned. Don't bother with string tables if
		 * there are no symbol sections.
		 */
		off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(Elf_Addr));

		for (havesyms = i = 0; i < elf->e_shnum; i++)
			if (shp[i].sh_type == SHT_SYMTAB)
				havesyms = 1;

		for (first = 1, i = 0; i < elf->e_shnum; i++) {
			if (shp[i].sh_type == SHT_SYMTAB ||
			    shp[i].sh_type == SHT_STRTAB) {
				if (havesyms && (flags & LOAD_SYM)) {
					PROGRESS(("%s%ld", first ? " [" : "+",
					    (u_long)shp[i].sh_size));
					newpos = (off_t)shp[i].sh_offset;
					if (relseek(fd, newpos - filepos) == -1) {
						WARN(("lseek symbols"));
						FREE(shp, sz);
						return 1;
					}
					filepos = newpos;
					if (READ(fd, maxp, shp[i].sh_size) !=
					    shp[i].sh_size) {
						WARN(("read symbols"));
						FREE(shp, sz);
						return 1;
					}
					filepos += shp[i].sh_size;
				}
				maxp += roundup(shp[i].sh_size,
				    sizeof(Elf_Addr));
				shp[i].sh_offset = off;
				off += roundup(shp[i].sh_size, sizeof(Elf_Addr));
				first = 0;
			}
		}
		if (flags & LOAD_SYM) {
			BCOPY(shp, shpp, sz);

			if (havesyms && first == 0)
				PROGRESS(("]"));
		}
		FREE(shp, sz);
	}

	/*
	 * Frob the copied ELF header to give information relative
	 * to elfp.
	 */
	if (flags & LOAD_HDR) {
		elf->e_phoff = 0;
		elf->e_shoff = sizeof(Elf_Ehdr);
		elf->e_phentsize = 0;
		elf->e_phnum = 0;
		BCOPY(elf, elfp, sizeof(*elf));
	}

	marks[MARK_START] = LOADADDR(minp);
	marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
	marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
	marks[MARK_SYM] = LOADADDR(elfp);
	marks[MARK_END] = LOADADDR(maxp);

	return 0;
}


path: sys/arch/sparc/stand/bootxx/CVS/Entries


path: sys/arch/sparc/stand/bootxx/CVS/Tag


code:
#	$OpenBSD: Makefile,v 1.13 2015/03/17 19:59:39 miod Exp $
#	$NetBSD: Makefile,v 1.2 1995/09/30 21:43:38 pk Exp $

.PATH:	${.CURDIR}/../common

PROG=	bootxx

NOMAN=	noman
INSTALL_STRIP=
S=	${.CURDIR}/../../../..

SRCS=	srt0.S bootxx.c closeall.c dvma.c promdev.c
CLEANFILES+=${PROG}.aout ${PROG}.elf elfclean

.PATH:	${S}/lib/libkern/arch/sparc ${S}/lib/libkern
SRCS+=	__main.o bzero.o urem.o udiv.o

.PATH:	${S}/lib/libsa
SRCS+=	printf.c

# pre-built bits of libsa
SOBJS=	alloc.o exit.o memcpy.o memset.o
_SOBJS=${SOBJS:S,^,${LIBSAOBJDIR}/,g}

CFLAGS= -fno-pie -O2 -I${.CURDIR}/../common -I${.CURDIR}/../../../../arch \
	-I${.CURDIR}/../../../.. -I${.CURDIR}/../../../../lib/libsa -DBOOTXX \
	${DEFS}
AFLAGS+=-fno-pie

elfclean: clean-elf.c
	${HOSTCC} -o elfclean ${.ALLSRC}

${PROG}: ${OBJS} elfclean
	${LD} -nopie -N -Ttext ${RELOC} -e start ${OBJS} ${_SOBJS} \
	    -o ${.TARGET}.elf
	./elfclean ${.TARGET}.elf
	objcopy -j .text -j .data -j .bss -O a.out-sparc-netbsd \
	    ${.TARGET}.elf ${.TARGET}.aout
	(echo -n 01 | tr 01 '\01\03'; tail +3c ${.TARGET}.aout) > ${.TARGET}
	@rm ${.TARGET}.aout ${.TARGET}.elf

srt0.o: srt0.S
	${CC} ${CFLAGS} -D_LOCORE -c ${.IMPSRC}

.include <bsd.prog.mk>
# for libsa printf
DEFS+=	-DSTRIPPED

path: sys/arch/sparc/stand/bootxx/Makefile


code:
/*	$OpenBSD: bootxx.c,v 1.8 2011/04/14 18:27:49 miod Exp $	*/
/*	$NetBSD: bootxx.c,v 1.2 1997/09/14 19:28:17 pk Exp $	*/

/*
 * Copyright (c) 1994 Paul Kranenburg
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Paul Kranenburg.
 * 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/time.h>
#include <a.out.h>

#include <lib/libsa/stand.h>

#include <sparc/stand/common/promdev.h>

int debug;
int netif_debug;

/*
 * Boot device is derived from ROM provided information.
 */
char		progname[] = "bootxx";
struct open_file	io;

/*
 * The contents of the block_* variables below is set by installboot(8)
 * to hold the filesystem data of the second-stage boot program
 * (typically `/boot'): filesystem block size, # of filesystem blocks and
 * the block numbers themselves.
 */
#define MAXBLOCKNUM	256	/* enough for a 2MB boot program (bs 8K) */
int32_t			block_size = 0;
int32_t			block_count = MAXBLOCKNUM;
daddr32_t		block_table[MAXBLOCKNUM] = { 0 };

void	loadboot(struct open_file *, caddr_t);

int
main(int argc, char *argv[])
{
	char	*dummy;
	register void (*entry)(caddr_t) = (void (*)(caddr_t))PROM_LOADADDR;

	prom_init();
	io.f_flags = F_RAW;
	if (devopen(&io, 0, &dummy)) {
		panic("%s: can't open device", progname);
	}

	(void)loadboot(&io, (caddr_t)PROM_LOADADDR);
	(io.f_dev->dv_close)(&io);
	(*entry)(cputyp == CPU_SUN4 ? (caddr_t)PROM_LOADADDR : (caddr_t)promvec);
	_rtt();
}

void
loadboot(f, addr)
	register struct open_file	*f;
	register char			*addr;
{
	register int	i;
	register char	*buf;
	size_t		n;
	daddr32_t	blk;

	/*
	 * Allocate a buffer that we can map into DVMA space; only
	 * needed for sun4 architecture, but use it for all machines
	 * to keep code size down as much as possible.
	 */
	buf = alloc(block_size);
	if (buf == NULL)
		panic("%s: alloc failed", progname);

	for (i = 0; i < block_count; i++) {
		if ((blk = block_table[i]) == 0)
			panic("%s: block table corrupt", progname);

#ifdef DEBUG
		printf("%s: block # %d = %d\n", progname, i, blk);
#endif
		if ((f->f_dev->dv_strategy)(f->f_devdata, F_READ,
					    blk, block_size, buf, &n)) {
			panic("%s: read failure", progname);
		}
		bcopy(buf, addr, block_size);
		if (n != block_size)
			panic("%s: short read", progname);
		if (i == 0) {
			register int m = N_GETMAGIC(*(struct exec *)addr);
			if (m == ZMAGIC || m == NMAGIC || m == OMAGIC) {
				/* Move exec header out of the way */
				bcopy(addr, addr - sizeof(struct exec), n);
				addr -= sizeof(struct exec);
			}
		}
		addr += n;
	}

}


code:
/*	$OpenBSD: closeall.c,v 1.2 2003/08/14 17:13:57 deraadt Exp $	*/

void
closeall(void)
{
}


path: sys/arch/sparc/stand/common/CVS/Entries


path: sys/arch/sparc/stand/common/CVS/Tag


code:
/*	$OpenBSD: clean-elf.c,v 1.2 2003/11/03 07:01:33 david Exp $	*/
/*
 * Public domain. I don't even want my name on this.
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <err.h>
#include <elf_abi.h>
#include <fcntl.h>

int
elf_is_okay(Elf_Ehdr *ehdr)
{
	int retval = 0;

	/*
	 * We need to check magic, class size, endianess,
	 * and version before we look at the rest of the
	 * Elf_Ehdr structure.  These few elements are
	 * represented in a machine independent fashion.
	 */

	if (IS_ELF(*ehdr) &&
	    ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS &&
	    ehdr->e_ident[EI_DATA] == ELF_TARG_DATA &&
	    ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) {
		/* Now check the machine dependant header */
		if (ehdr->e_machine == ELF_TARG_MACH &&
		    ehdr->e_version == ELF_TARG_VER)
			retval = 1;
	}

	return retval;
}

void
cleanit(caddr_t addr)
{
	Elf_Ehdr *ehdr;
	Elf_Shdr *shdr;
	char *strtab;
	int i;

	ehdr = (Elf_Ehdr *)addr;
	shdr = (Elf_Shdr *)(addr + ehdr->e_shoff);

	strtab = shdr[ehdr->e_shstrndx].sh_offset + addr;

	/*
	 * Simple. find a .text section, verify that the next section is
	 * .rodata and merge them.
	 */

	for (i = 0; i < ehdr->e_shnum; i++) {
		Elf_Shdr *t = &shdr[i];
		Elf_Shdr *r = &shdr[i + 1];

#if 0
		printf("foo: %s %d\n", strtab + t->sh_name, t->sh_type);
		continue;
#endif
		if (strcmp(strtab + t->sh_name, ".text"))
			continue;
		if (strcmp(strtab + r->sh_name, ".rodata"))
			errx(1, "sorry, rodata merge not possible.");

		t->sh_size += r->sh_size + (r->sh_offset - t->sh_offset - t->sh_size);
		r->sh_type = SHT_NULL;
		r->sh_name = 0;
	}
}

int
main(int argc, char **argv)
{
	int fd;
	void *addr;
	off_t len;
	int pgsz = getpagesize();

	if (argc != 2)
		errx(1, "usage");

	if ((fd = open(argv[1], O_RDWR)) < 0)
		err(1, "open");

	if ((len = lseek(fd, 0, SEEK_END)) < 0)
		err(1, "lseek");

	len = ((len + pgsz - 1) & ~(pgsz - 1));

	if ((addr = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) ==
	    MAP_FAILED)
		err(1, "mmap");

	if (!elf_is_okay((Elf_Ehdr *)addr))
		errx(1, "not an elf file");

	cleanit(addr);

	msync(addr, len, MS_SYNC|MS_INVALIDATE);

	close(fd);
	return (0);
}


code:
/*	$OpenBSD: conf.c,v 1.1 1997/09/17 10:46:17 downsj Exp $	*/
/*	$NetBSD: conf.c,v 1.2 1995/09/18 21:31:45 pk Exp $ */

/*
 * Copyright (c) 1993 Philip A. Nelson.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Philip A. Nelson.
 * 4. The name of Philip A. Nelson may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY PHILIP NELSON ``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 PHILIP NELSON 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 <lib/libsa/stand.h>
#include <lib/libsa/ufs.h>
#include <netinet/in.h>
#include <lib/libsa/cd9660.h>
#include <lib/libsa/nfs.h>

struct fs_ops file_system_ufs[] = {
	{ ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat },
};
struct fs_ops file_system_cd9660[] = {
	{ cd9660_open, cd9660_close, cd9660_read, cd9660_write, cd9660_seek,
	  cd9660_stat },
};
struct fs_ops file_system_nfs[] = {
	{ nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, nfs_stat },
};
struct fs_ops file_system[2];
int nfsys = 1;


code:
/*	$OpenBSD: dvma.c,v 1.7 2014/07/12 21:03:38 tedu Exp $	*/
/*	$NetBSD: dvma.c,v 1.2 1995/09/17 00:50:56 pk Exp $	*/
/*
 * Copyright (c) 1995 Gordon W. Ross
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 4. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Gordon Ross
 *
 * 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.
 */

/*
 * The easiest way to deal with the need for DVMA mappings is to just
 * map the entire megabyte of RAM where we are loaded into DVMA space.
 * That way, dvma_mapin can just compute the DVMA alias address, and
 * dvma_mapout does nothing.  Note that this assumes all standalone
 * programs stay in the range `base_va' .. `base_va + DVMA_MAPLEN'
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <machine/pte.h>
#include <machine/ctlreg.h>

#include <sparc/sparc/asm.h>

#define	DVMA_BASE	0xFFF00000
#define DVMA_MAPLEN	0xE0000	/* 1 MB - 128K (save MONSHORTSEG) */

static int base_va;

/*
 * This module is only used on sun4, so:
 */
#define getsegmap(va)		(lduha(va, ASI_SEGMAP))
#define setsegmap(va, pmeg)	do stha(va, ASI_SEGMAP, pmeg); while(0)

void
dvma_init(void)
{
	u_int segva, dmava;
	int nseg;
	extern int start;

	/*
	 * Align our address base with the DVMA segment.
	 * Allocate one DVMA segment to cover the stack, which
	 * grows downward from `start'.
	 */
	dmava = DVMA_BASE;
	base_va = segva = (((int)&start) & -NBPSG) - NBPSG;

	/* Then double-map the DVMA addresses */
	nseg = (DVMA_MAPLEN + NBPSG - 1) >> SGSHIFT;
	while (nseg-- > 0) {
		setsegmap(dmava, getsegmap(segva));
		segva += NBPSG;
		dmava += NBPSG;
	}
}

/*
 * Convert a local address to a DVMA address.
 */
char *
dvma_mapin(char *addr, size_t len)
{
	int va = (int)addr;

	va -= base_va;

#ifndef BOOTXX
	/* Make sure the address is in the DVMA map. */
	if (va < 0 || va >= DVMA_MAPLEN)
		panic("dvma_mapin");
#endif

	va += DVMA_BASE;

	return ((char *)va);
}

/*
 * Convert a DVMA address to a local address.
 */
char *
dvma_mapout(char *addr, size_t len)
{
	int va = (int)addr;

	va -= DVMA_BASE;

#ifndef BOOTXX
	/* Make sure the address is in the DVMA map. */
	if (va < 0 || va >= DVMA_MAPLEN)
		panic("dvma_mapout");
#endif

	va += base_va;

	return ((char *)va);
}

extern char *alloc(int);

char *
dvma_alloc(int len)
{
	char *mem;

	mem = alloc(len);
	if (!mem)
		return (mem);
	return (dvma_mapin(mem, len));
}

extern void free(void *ptr, int len);
void
dvma_free(char *dvma, int len)
{
	char *mem;

	mem = dvma_mapout(dvma, len);
	if (mem)
		free(mem, len);
}