code:
/*	$OpenBSD: sys_machdep.c,v 1.34 2014/12/09 06:58:28 doug Exp $	*/
/*	$NetBSD: sys_machdep.c,v 1.28 1996/05/03 19:42:29 christos Exp $	*/

/*-
 * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
 * Copyright (c) 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * William Jolitz.
 *
 * 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	5.5 (Berkeley) 1/19/91
 */

#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/user.h>
#include <sys/uio.h>
#include <sys/kernel.h>
#include <sys/mtio.h>
#include <sys/buf.h>
#include <sys/signal.h>
#include <sys/malloc.h>

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

#include <uvm/uvm_extern.h>

#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/gdt.h>
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/sysarch.h>

#ifdef VM86
#include <machine/vm86.h>
#endif

extern struct vm_map *kernel_map;

int i386_iopl(struct proc *, void *, register_t *);
int i386_get_ioperm(struct proc *, void *, register_t *);
int i386_set_ioperm(struct proc *, void *, register_t *);

#ifdef USER_LDT

#ifdef LDT_DEBUG
static void i386_print_ldt(int, const struct segment_descriptor *);

static void
i386_print_ldt(int i, const struct segment_descriptor *d)
{
	printf("[%d] lolimit=0x%x, lobase=0x%x, type=%u, dpl=%u, p=%u, "
	    "hilimit=0x%x, xx=%x, def32=%u, gran=%u, hibase=0x%x\n",
	    i, d->sd_lolimit, d->sd_lobase, d->sd_type, d->sd_dpl, d->sd_p,
	    d->sd_hilimit, d->sd_xx, d->sd_def32, d->sd_gran, d->sd_hibase);
}
#endif

int
i386_get_ldt(struct proc *p, void *args, register_t *retval)
{
	int error;
	pmap_t pmap = p->p_vmspace->vm_map.pmap;
	int nldt, num;
	union descriptor *lp, *cp;
	struct i386_get_ldt_args ua;

	if (user_ldt_enable == 0)
		return (ENOSYS);

	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
		return (error);

#ifdef	LDT_DEBUG
	printf("i386_get_ldt: start=%d num=%d descs=%p\n", ua.start,
	    ua.num, ua.desc);
#endif

	if (ua.start < 0 || ua.num < 0 || ua.start > 8192 || ua.num > 8192 ||
	    ua.start + ua.num > 8192)
		return (EINVAL);

	cp = mallocarray(ua.num, sizeof(union descriptor), M_TEMP, M_WAITOK);

	if (pmap->pm_flags & PMF_USER_LDT) {
		nldt = pmap->pm_ldt_len;
		lp = pmap->pm_ldt;
	} else {
		nldt = NLDT;
		lp = ldt;
	}

	if (ua.start > nldt) {
		free(cp, M_TEMP, 0);
		return (EINVAL);
	}

	lp += ua.start;
	num = min(ua.num, nldt - ua.start);
#ifdef LDT_DEBUG
	{
		int i;
		for (i = 0; i < num; i++)
			i386_print_ldt(i, &lp[i].sd);
	}
#endif

	memcpy(cp, lp, num * sizeof(union descriptor));

	error = copyout(cp, ua.desc, num * sizeof(union descriptor));
	if (error == 0)
		*retval = num;

	free(cp, M_TEMP, 0);
	return (error);
}

int
i386_set_ldt(struct proc *p, void *args, register_t *retval)
{
	int error, i, n;
	struct pcb *pcb = &p->p_addr->u_pcb;
	pmap_t pmap = p->p_vmspace->vm_map.pmap;
	struct i386_set_ldt_args ua;
	union descriptor *descv;
	size_t old_len, new_len, ldt_len;
	union descriptor *old_ldt, *new_ldt;

	if (user_ldt_enable == 0)
		return (ENOSYS);

	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
		return (error);

	if (ua.start < 0 || ua.num < 0 || ua.start > 8192 || ua.num > 8192 ||
	    ua.start + ua.num > 8192)
		return (EINVAL);

	descv = mallocarray(ua.num, sizeof(*descv), M_TEMP, M_NOWAIT);
	if (descv == NULL)
		return (ENOMEM);

	if ((error = copyin(ua.desc, descv, sizeof (*descv) * ua.num)) != 0)
		goto out;

	/* Check descriptors for access violations. */
	for (i = 0; i < ua.num; i++) {
		union descriptor *desc = &descv[i];

		switch (desc->sd.sd_type) {
		case SDT_SYSNULL:
			desc->sd.sd_p = 0;
			break;
		case SDT_SYS286CGT:
		case SDT_SYS386CGT:
			/*
			 * Only allow call gates targeting a segment
			 * in the LDT or a user segment in the fixed
			 * part of the gdt.  Segments in the LDT are
			 * constrained (below) to be user segments.
			 */
			if (desc->gd.gd_p != 0 &&
			    !ISLDT(desc->gd.gd_selector) &&
			    ((IDXSEL(desc->gd.gd_selector) >= NGDT) ||
			     (gdt[IDXSEL(desc->gd.gd_selector)].sd.sd_dpl !=
				 SEL_UPL))) {
				error = EACCES;
				goto out;
			}
			break;
		case SDT_MEMEC:
		case SDT_MEMEAC:
		case SDT_MEMERC:
		case SDT_MEMERAC:
			/* Must be "present" if executable and conforming. */
			if (desc->sd.sd_p == 0) {
				error = EACCES;
				goto out;
			}
			break;
		case SDT_MEMRO:
		case SDT_MEMROA:
		case SDT_MEMRW:
		case SDT_MEMRWA:
		case SDT_MEMROD:
		case SDT_MEMRODA:
		case SDT_MEMRWD:
		case SDT_MEMRWDA:
		case SDT_MEME:
		case SDT_MEMEA:
		case SDT_MEMER:
		case SDT_MEMERA:
			break;
		default:
			/*
			 * Make sure that unknown descriptor types are
			 * not marked present.
			 */
			if (desc->sd.sd_p != 0) {
				error = EACCES;
				goto out;
			}
			break;
		}

		if (desc->sd.sd_p != 0) {
			/* Only user (ring-3) descriptors may be present. */
			if (desc->sd.sd_dpl != SEL_UPL) {
				error = EACCES;
				goto out;
			}
		}
	}

	/* allocate user ldt */
	if (pmap->pm_ldt == 0 || (ua.start + ua.num) > pmap->pm_ldt_len) {
		if (pmap->pm_flags & PMF_USER_LDT)
			ldt_len = pmap->pm_ldt_len;
		else
			ldt_len = 512;
		while ((ua.start + ua.num) > ldt_len)
			ldt_len *= 2;
		new_len = ldt_len * sizeof(union descriptor);

		new_ldt = (union descriptor *)uvm_km_alloc(kernel_map,
		    new_len);
		if (new_ldt == NULL) {
			error = ENOMEM;
			goto out;
		}

		if (pmap->pm_ldt != NULL && ldt_len <= pmap->pm_ldt_len) {
			/*
			 * Another thread (re)allocated the LDT to
			 * sufficient size while we were blocked in
			 * uvm_km_alloc. Oh well. The new entries
			 * will quite probably not be right, but
			 * hey.. not our problem if user applications
			 * have race conditions like that.
			 */
			uvm_km_free(kernel_map, (vaddr_t)new_ldt, new_len);
			goto copy;
		}

		old_ldt = pmap->pm_ldt;

		if (old_ldt != NULL) {
			old_len = pmap->pm_ldt_len * sizeof(union descriptor);
		} else {
			old_len = NLDT * sizeof(union descriptor);
			old_ldt = ldt;
		}

		memcpy(new_ldt, old_ldt, old_len);
		memset((caddr_t)new_ldt + old_len, 0, new_len - old_len);

		if (old_ldt != ldt)
			uvm_km_free(kernel_map, (vaddr_t)old_ldt, old_len);

		pmap->pm_ldt = new_ldt;
		pmap->pm_ldt_len = ldt_len;

		if (pmap->pm_flags & PMF_USER_LDT)
			ldt_free(pmap);
		else
			pmap->pm_flags |= PMF_USER_LDT;
		ldt_alloc(pmap, new_ldt, new_len);
		pcb->pcb_ldt_sel = pmap->pm_ldt_sel;
		if (pcb == curpcb)
			lldt(pcb->pcb_ldt_sel);

	}
copy:
	/* Now actually replace the descriptors. */
	for (i = 0, n = ua.start; i < ua.num; i++, n++)
		pmap->pm_ldt[n] = descv[i];

	*retval = ua.start;

out:
	free(descv, M_TEMP, 0);
	return (error);
}
#endif	/* USER_LDT */

#ifdef APERTURE
extern int allowaperture;
#endif

int
i386_iopl(struct proc *p, void *args, register_t *retval)
{
	int error;
	struct trapframe *tf = p->p_md.md_regs;
	struct i386_iopl_args ua;

	if ((error = suser(p, 0)) != 0)
		return error;
#ifdef APERTURE
	if (!allowaperture && securelevel > 0)
		return EPERM;
#else
	if (securelevel > 0)
		return EPERM;
#endif

	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
		return error;

	if (ua.iopl)
		tf->tf_eflags |= PSL_IOPL;
	else
		tf->tf_eflags &= ~PSL_IOPL;

	return 0;
}

int
i386_get_ioperm(struct proc *p, void *args, register_t *retval)
{
	int error;
	struct pcb *pcb = &p->p_addr->u_pcb;
	struct i386_get_ioperm_args ua;

	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
		return (error);

	return copyout(pcb->pcb_iomap, ua.iomap, sizeof(pcb->pcb_iomap));
}

int
i386_set_ioperm(struct proc *p, void *args, register_t *retval)
{
	int error;
	struct pcb *pcb = &p->p_addr->u_pcb;
	struct i386_set_ioperm_args ua;

	if ((error = suser(p, 0)) != 0)
		return error;

#ifdef APERTURE
	if (!allowaperture && securelevel > 0)
		return EPERM;
#else
	if (securelevel > 0)
		return EPERM;
#endif
	if ((error = copyin(args, &ua, sizeof(ua))) != 0)
		return (error);

	return copyin(ua.iomap, pcb->pcb_iomap, sizeof(pcb->pcb_iomap));
}

uint32_t
i386_get_threadbase(struct proc *p, int which)
{
	struct segment_descriptor *sdp =
	    &p->p_addr->u_pcb.pcb_threadsegs[which];
	return sdp->sd_hibase << 24 | sdp->sd_lobase;
}

int
i386_set_threadbase(struct proc *p, uint32_t base, int which)
{
	struct segment_descriptor *sdp;

	/*
	 * We can't place a limit on the segment used by the library
	 * thread register (%gs) because the ELF ABI for i386 places
	 * data structures both before and after base pointer, using
	 * negative offsets for some bits (the static (load-time)
	 * TLS slots) and non-negative for others (the TCB block,
	 * including the pointer to the TLS dynamic thread vector).
	 * Protection must be provided by the paging subsystem.
	 */
	sdp = &p->p_addr->u_pcb.pcb_threadsegs[which];
	setsegment(sdp, (void *)base, 0xfffff, SDT_MEMRWA, SEL_UPL, 1, 1);

	if (p == curproc) {
		curcpu()->ci_gdt[which == TSEG_FS ? GUFS_SEL : GUGS_SEL].sd
		    = *sdp;
	}
	return 0;
}

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

	switch(SCARG(uap, op)) {
#ifdef	USER_LDT
	case I386_GET_LDT:
		error = i386_get_ldt(p, SCARG(uap, parms), retval);
		break;

	case I386_SET_LDT:
		error = i386_set_ldt(p, SCARG(uap, parms), retval);
		break;
#endif

	case I386_IOPL:
		error = i386_iopl(p, SCARG(uap, parms), retval);
		break;

	case I386_GET_IOPERM:
		error = i386_get_ioperm(p, SCARG(uap, parms), retval);
		break;

	case I386_SET_IOPERM:
		error = i386_set_ioperm(p, SCARG(uap, parms), retval);
		break;

#ifdef VM86
	case I386_VM86:
		error = i386_vm86(p, SCARG(uap, parms), retval);
		break;
#endif

	case I386_GET_FSBASE:
	      {
		uint32_t base = i386_get_threadbase(p, TSEG_FS);

		error = copyout(&base, SCARG(uap, parms), sizeof(base));
		break;
	      }

	case I386_SET_FSBASE:
	      {
		uint32_t base;

		if ((error = copyin(SCARG(uap, parms), &base, sizeof(base))))
			break;
		error = i386_set_threadbase(p, base, TSEG_FS);
		break;
	      }

	case I386_GET_GSBASE:
	      {
		uint32_t base = i386_get_threadbase(p, TSEG_GS);

		error = copyout(&base, SCARG(uap, parms), sizeof(base));
		break;
	      }

	case I386_SET_GSBASE:
	      {
		uint32_t base;

		if ((error = copyin(SCARG(uap, parms), &base, sizeof(base))))
			break;
		error = i386_set_threadbase(p, base, TSEG_GS);
		break;
	      }

	default:
		error = EINVAL;
		break;
	}
	return (error);
}


code:
/*	$OpenBSD: trap.c,v 1.123 2015/06/28 01:11:27 guenther Exp $	*/
/*	$NetBSD: trap.c,v 1.95 1996/05/05 06:50:02 mycroft Exp $	*/

/*-
 * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
 * Copyright (c) 1990 The Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the University of Utah, and William Jolitz.
 *
 * 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.
 *
 *	@(#)trap.c	7.4 (Berkeley) 5/13/91
 */

/*
 * 386 Trap and System call handling
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/user.h>
#include <sys/acct.h>
#include <sys/kernel.h>
#include <sys/signal.h>
#include <sys/syscall.h>
#include <sys/syscall_mi.h>

#include <uvm/uvm_extern.h>

#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/trap.h>
#ifdef DDB
#include <machine/db_machdep.h>
#endif

#ifdef KGDB
#include <sys/kgdb.h>
#endif

#include <sys/exec.h>
#ifdef COMPAT_LINUX
#include <compat/linux/linux_syscall.h>
extern struct emul emul_linux_elf;
#endif
#ifdef KVM86
#include <machine/kvm86.h>
#define KVM86MODE (kvm86_incall)
#endif

#include "isa.h"
#include "npx.h"

void trap(struct trapframe *);
void ast(struct trapframe *);
void syscall(struct trapframe *);

char	*trap_type[] = {
	"privileged instruction fault",		/*  0 T_PRIVINFLT */
	"breakpoint trap",			/*  1 T_BPTFLT */
	"arithmetic trap",			/*  2 T_ARITHTRAP */
	"reserved trap",			/*  3 T_RESERVED */
	"protection fault",			/*  4 T_PROTFLT */
	"trace trap",				/*  5 T_TRCTRAP */
	"page fault",				/*  6 T_PAGEFLT */
	"alignment fault",			/*  7 T_ALIGNFLT */
	"integer divide fault",			/*  8 T_DIVIDE */
	"non-maskable interrupt",		/*  9 T_NMI */
	"overflow trap",			/* 10 T_OFLOW */
	"bounds check fault",			/* 11 T_BOUND */
	"FPU not available fault",		/* 12 T_DNA */
	"double fault",				/* 13 T_DOUBLEFLT */
	"FPU operand fetch fault",		/* 14 T_FPOPFLT (![P]Pro) */
	"invalid TSS fault",			/* 15 T_TSSFLT */
	"segment not present fault",		/* 16 T_SEGNPFLT */
	"stack fault",				/* 17 T_STKFLT */
	"machine check",			/* 18 T_MACHK ([P]Pro) */
	"SIMD FP fault",			/* 19 T_XFTRAP */
};
int	trap_types = sizeof trap_type / sizeof trap_type[0];

#ifdef DEBUG
int	trapdebug = 0;
#endif

/*
 * trap(frame):
 *	Exception, fault, and trap interface to BSD kernel. This
 * common code is called from assembly language IDT gate entry
 * routines that prepare a suitable stack frame, and restore this
 * frame after the exception has been processed.
 */
void
trap(struct trapframe *frame)
{
	struct proc *p = curproc;
	int type = frame->tf_trapno;
	struct pcb *pcb = NULL;
	extern char resume_iret[], resume_pop_ds[], resume_pop_es[],
	    resume_pop_fs[], resume_pop_gs[];
	struct trapframe *vframe;
	int resume;
	vm_prot_t vftype, ftype;
	union sigval sv;
	caddr_t onfault;
	uint32_t cr2;

	uvmexp.traps++;

	/* SIGSEGV and SIGBUS need this */
	if (frame->tf_err & PGEX_W) {
		vftype = PROT_WRITE;
		ftype = PROT_READ | PROT_WRITE;
	} else if (frame->tf_err & PGEX_I) {
		ftype = vftype = PROT_EXEC;
	} else
		ftype = vftype = PROT_READ;

#ifdef DEBUG
	if (trapdebug) {
		printf("trap %d code %x eip %x cs %x eflags %x cr2 %x cpl %x\n",
		    frame->tf_trapno, frame->tf_err, frame->tf_eip,
		    frame->tf_cs, frame->tf_eflags, rcr2(), lapic_tpr);
		printf("curproc %p\n", curproc);
	}
#endif

	if (!KERNELMODE(frame->tf_cs, frame->tf_eflags)) {
		type |= T_USER;
		p->p_md.md_regs = frame;
		refreshcreds(p);
	}

	switch (type) {

	/* trace trap */
	case T_TRCTRAP:
#if !(defined(DDB) || defined(KGDB))
		return;	/* Just return if no kernel debugger */
#endif
		/* FALLTHROUGH */

	default:
	we_re_toast:
#ifdef KGDB
		if (kgdb_trap(type, frame))
			return;
		else {
			/*
			 * If this is a breakpoint, don't panic
			 * if we're not connected.
			 */
			if (type == T_BPTFLT) {
				printf("kgdb: ignored %s\n", trap_type[type]);
				return;
			}
		}
#endif

#ifdef DDB
		if (kdb_trap(type, 0, frame))
			return;
#endif
		if (frame->tf_trapno < trap_types)
			printf("fatal %s (%d)", trap_type[frame->tf_trapno],
				frame->tf_trapno);
		else
			printf("unknown trap %d", frame->tf_trapno);
		printf(" in %s mode\n", (type & T_USER) ? "user" : "supervisor");
		printf("trap type %d code %x eip %x cs %x eflags %x cr2 %x cpl %x\n",
		    type, frame->tf_err, frame->tf_eip, frame->tf_cs, frame->tf_eflags, rcr2(), lapic_tpr);

		panic("trap type %d, code=%x, pc=%x",
		    type, frame->tf_err, frame->tf_eip);
		/*NOTREACHED*/

	case T_PROTFLT:
#ifdef KVM86
		if (KVM86MODE) {
			kvm86_gpfault(frame);
			return;
		}
#endif
	case T_SEGNPFLT:
	case T_ALIGNFLT:
		/* Check for copyin/copyout fault. */
		if (p && p->p_addr) {
			pcb = &p->p_addr->u_pcb;
			if (pcb->pcb_onfault != 0) {
			copyfault:
				frame->tf_eip = (int)pcb->pcb_onfault;
				return;
			}
		}

		/*
		 * Check for failure during return to user mode.
		 *
		 * We do this by looking at the instruction we faulted on.  The
		 * specific instructions we recognize only happen when
		 * returning from a trap, syscall, or interrupt.
		 *
		 * XXX
		 * The heuristic used here will currently fail for the case of
		 * one of the 2 pop instructions faulting when returning from a
		 * a fast interrupt.  This should not be possible.  It can be
		 * fixed by rearranging the trap frame so that the stack format
		 * at this point is the same as on exit from a `slow'
		 * interrupt.
		 */
		switch (*(u_char *)frame->tf_eip) {
		case 0xcf:	/* iret */
			vframe = (void *)((int)&frame->tf_esp -
			    offsetof(struct trapframe, tf_eip));
			resume = (int)resume_iret;
			break;
		case 0x1f:	/* popl %ds */
			vframe = (void *)((int)&frame->tf_esp -
			    offsetof(struct trapframe, tf_ds));
			resume = (int)resume_pop_ds;
			break;
		case 0x07:	/* popl %es */
			vframe = (void *)((int)&frame->tf_esp -
			    offsetof(struct trapframe, tf_es));
			resume = (int)resume_pop_es;
			break;
		case 0x0f:	/* 0x0f prefix */
			switch (*(u_char *)(frame->tf_eip + 1)) {
			case 0xa1:		/* popl %fs */
				vframe = (void *)((int)&frame->tf_esp -
				    offsetof(struct trapframe, tf_fs));
				resume = (int)resume_pop_fs;
				break;
			case 0xa9:		/* popl %gs */
				vframe = (void *)((int)&frame->tf_esp -
				    offsetof(struct trapframe, tf_gs));
				resume = (int)resume_pop_gs;
				break;
			default:
				goto we_re_toast;
			}
			break;
		default:
			goto we_re_toast;
		}
		if (KERNELMODE(vframe->tf_cs, vframe->tf_eflags))
			goto we_re_toast;

		frame->tf_eip = resume;
		return;

	case T_PROTFLT|T_USER:		/* protection fault */
		KERNEL_LOCK();
#ifdef VM86
		if (frame->tf_eflags & PSL_VM) {
			vm86_gpfault(p, type & ~T_USER);
			KERNEL_UNLOCK();
			goto out;
		}
#endif
		/* If pmap_exec_fixup does something, let's retry the trap. */
		if (pmap_exec_fixup(&p->p_vmspace->vm_map, frame,
		    &p->p_addr->u_pcb)) {
			KERNEL_UNLOCK();
			goto out;
		}

		sv.sival_int = frame->tf_eip;
		trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
		KERNEL_UNLOCK();
		goto out;

	case T_TSSFLT|T_USER:
		sv.sival_int = frame->tf_eip;
		KERNEL_LOCK();
		trapsignal(p, SIGBUS, vftype, BUS_OBJERR, sv);
		KERNEL_UNLOCK();
		goto out;

	case T_SEGNPFLT|T_USER:
	case T_STKFLT|T_USER:
		sv.sival_int = frame->tf_eip;
		KERNEL_LOCK();
		trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
		KERNEL_UNLOCK();
		goto out;

	case T_ALIGNFLT|T_USER:
		sv.sival_int = frame->tf_eip;
		KERNEL_LOCK();
		trapsignal(p, SIGBUS, vftype, BUS_ADRALN, sv);
		KERNEL_UNLOCK();
		goto out;

	case T_PRIVINFLT|T_USER:	/* privileged instruction fault */
		sv.sival_int = frame->tf_eip;
		KERNEL_LOCK();
		trapsignal(p, SIGILL, type &~ T_USER, ILL_PRVOPC, sv);
		KERNEL_UNLOCK();
		goto out;

	case T_FPOPFLT|T_USER:		/* coprocessor operand fault */
		sv.sival_int = frame->tf_eip;
		KERNEL_LOCK();
		trapsignal(p, SIGILL, type &~ T_USER, ILL_COPROC, sv);
		KERNEL_UNLOCK();
		goto out;

	case T_DNA|T_USER: {
		printf("pid %d killed due to lack of floating point\n",
		    p->p_pid);
		sv.sival_int = frame->tf_eip;
		KERNEL_LOCK();
		trapsignal(p, SIGKILL, type &~ T_USER, FPE_FLTINV, sv);
		KERNEL_UNLOCK();
		goto out;
	}

	case T_BOUND|T_USER:
		sv.sival_int = frame->tf_eip;
		KERNEL_LOCK();
		trapsignal(p, SIGFPE, type &~ T_USER, FPE_FLTSUB, sv);
		KERNEL_UNLOCK();
		goto out;
	case T_OFLOW|T_USER:
		sv.sival_int = frame->tf_eip;
		KERNEL_LOCK();
		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv);
		KERNEL_UNLOCK();
		goto out;
	case T_DIVIDE|T_USER:
		sv.sival_int = frame->tf_eip;
		KERNEL_LOCK();
		trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTDIV, sv);
		KERNEL_UNLOCK();
		goto out;

	case T_ARITHTRAP|T_USER:
		sv.sival_int = frame->tf_eip;
		KERNEL_LOCK();
		trapsignal(p, SIGFPE, frame->tf_err, FPE_INTOVF, sv);
		KERNEL_UNLOCK();
		goto out;

	case T_XFTRAP|T_USER:
		npxtrap(frame);
		goto out;

	case T_PAGEFLT:			/* allow page faults in kernel mode */
		if (p == 0 || p->p_addr == 0)
			goto we_re_toast;

		pcb = &p->p_addr->u_pcb;
#if 0
		/* XXX - check only applies to 386's and 486's with WP off */
		if (frame->tf_err & PGEX_P)
			goto we_re_toast;
#endif
		cr2 = rcr2();
		KERNEL_LOCK();
		/* This will only trigger if SMEP is enabled */
		if (cr2 <= VM_MAXUSER_ADDRESS && frame->tf_err & PGEX_I)
			panic("attempt to execute user address %p "
			    "in supervisor mode", (void *)cr2);
		/* This will only trigger if SMAP is enabled */
		if (pcb->pcb_onfault == NULL && cr2 <= VM_MAXUSER_ADDRESS &&
		    frame->tf_err & PGEX_P)
			panic("attempt to access user address %p "
			    "in supervisor mode", (void *)cr2);
		goto faultcommon;

	case T_PAGEFLT|T_USER: {	/* page fault */
		vaddr_t va, fa;
		struct vmspace *vm;
		struct vm_map *map;
		int rv;

		cr2 = rcr2();
		KERNEL_LOCK();
	faultcommon:
		vm = p->p_vmspace;
		if (vm == NULL)
			goto we_re_toast;
		fa = (vaddr_t)cr2;
		va = trunc_page(fa);
		/*
		 * It is only a kernel address space fault iff:
		 *	1. (type & T_USER) == 0  and
		 *	2. pcb_onfault not set or
		 *	3. pcb_onfault set but supervisor space fault
		 * The last can occur during an exec() copyin where the
		 * argument space is lazy-allocated.
		 */
		if (type == T_PAGEFLT && va >= KERNBASE)
			map = kernel_map;
		else
			map = &vm->vm_map;

#ifdef DIAGNOSTIC
		if (map == kernel_map && va == 0) {
			printf("trap: bad kernel access at %lx\n", va);
			goto we_re_toast;
		}
#endif

		if (curcpu()->ci_inatomic == 0 || map == kernel_map) {
			onfault = p->p_addr->u_pcb.pcb_onfault;
			p->p_addr->u_pcb.pcb_onfault = NULL;
			rv = uvm_fault(map, va, 0, ftype);
			p->p_addr->u_pcb.pcb_onfault = onfault;
		} else
			rv = EFAULT;

		if (rv == 0) {
			if (map != kernel_map)
				uvm_grow(p, va);
			if (type == T_PAGEFLT) {
				KERNEL_UNLOCK();
				return;
			}
			KERNEL_UNLOCK();
			goto out;
		}

		if (type == T_PAGEFLT) {
			if (pcb->pcb_onfault != 0) {
				KERNEL_UNLOCK();
				goto copyfault;
			}
			printf("uvm_fault(%p, 0x%lx, 0, %d) -> %x\n",
			    map, va, ftype, rv);
			goto we_re_toast;
		}
		sv.sival_int = fa;
		trapsignal(p, SIGSEGV, vftype, SEGV_MAPERR, sv);
		KERNEL_UNLOCK();
		break;
	}

#if 0  /* Should this be left out?  */
#if !defined(DDB) && !defined(KGDB)
	/* XXX need to deal with this when DDB is present, too */
	case T_TRCTRAP: /* kernel trace trap; someone single stepping lcall's */
			/* syscall has to turn off the trace bit itself */
		return;
#endif
#endif

	case T_BPTFLT|T_USER:		/* bpt instruction fault */
		sv.sival_int = rcr2();
		KERNEL_LOCK();
		trapsignal(p, SIGTRAP, type &~ T_USER, TRAP_BRKPT, sv);
		KERNEL_UNLOCK();
		break;
	case T_TRCTRAP|T_USER:		/* trace trap */
		sv.sival_int = rcr2();
		KERNEL_LOCK();
		trapsignal(p, SIGTRAP, type &~ T_USER, TRAP_TRACE, sv);
		KERNEL_UNLOCK();
		break;

#if	NISA > 0
	case T_NMI:
	case T_NMI|T_USER:
#if defined(DDB) || defined(KGDB)
		/* NMI can be hooked up to a pushbutton for debugging */
		printf ("NMI ... going to debugger\n");
#ifdef KGDB
		if (kgdb_trap(type, frame))
			return;
#endif
#ifdef DDB
		if (kdb_trap(type, 0, frame))
			return;
#endif
#endif /* DDB || KGDB */
		/* machine/parity/power fail/"kitchen sink" faults */
		if (isa_nmi() == 0)
			return;
		else
			goto we_re_toast;
#endif
	}

	if ((type & T_USER) == 0)
		return;
out:
	userret(p);
}

/*
 * ast(frame):
 *	AST handler.  This is called from assembly language stubs when
 *	returning to userspace after a syscall, trap, or interrupt.
 */
void
ast(struct trapframe *frame)
{
	struct proc *p = curproc;

	uvmexp.traps++;
	KASSERT(!KERNELMODE(frame->tf_cs, frame->tf_eflags));
	p->p_md.md_regs = frame;
	refreshcreds(p);
	uvmexp.softs++;
	mi_ast(p, want_resched);
	userret(p);
}

/*
 * syscall(frame):
 *	System call request from POSIX system call gate interface to kernel.
 */
/*ARGSUSED*/
void
syscall(struct trapframe *frame)
{
	caddr_t params;
	struct sysent *callp;
	struct proc *p;
	int error, nsys;
	register_t code, args[8], rval[2];
#ifdef DIAGNOSTIC
	int ocpl = lapic_tpr;
#endif
	short argsize;

	uvmexp.syscalls++;
#ifdef DIAGNOSTIC
	if (!USERMODE(frame->tf_cs, frame->tf_eflags))
		panic("syscall");
#endif
	p = curproc;
	p->p_md.md_regs = frame;
	code = frame->tf_eax;

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

	params = (caddr_t)frame->tf_esp + sizeof(int);

#ifdef VM86
	/*
	 * VM86 mode application found our syscall trap gate by accident; let
	 * it get a SIGSYS and have the VM86 handler in the process take care
	 * of it.
	 */
	if (frame->tf_eflags & PSL_VM)
		code = -1;
	else
#endif

	switch (code) {
	case SYS_syscall:
#ifdef COMPAT_LINUX
		/* Linux has a special system setup call as number 0 */
		if (p->p_p->ps_emul == &emul_linux_elf)
			break;
#endif
		/*
		 * Code is first argument, followed by actual args.
		 */
		copyin(params, &code, sizeof(int));
		params += sizeof(int);
		break;
	case SYS___syscall:
		/*
		 * Like syscall, but code is a quad, so as to maintain
		 * quad alignment for the rest of the arguments.
		 */
		if (callp != sysent)
			break;
		copyin(params + _QUAD_LOWWORD * sizeof(int), &code, sizeof(int));
		params += sizeof(quad_t);
		break;
	default:
		break;
	}
	if (code < 0 || code >= nsys)
		callp += p->p_p->ps_emul->e_nosys;		/* illegal */
	else
		callp += code;
	argsize = callp->sy_argsize;
#ifdef COMPAT_LINUX
	/* XXX extra if() for every emul type.. */
	if (p->p_p->ps_emul == &emul_linux_elf) {
		/*
		 * Linux passes the args in ebx, ecx, edx, esi, edi, ebp, in
		 * increasing order.
		 */
		switch (argsize) {
		case 24:
			args[5] = frame->tf_ebp;
		case 20:
			args[4] = frame->tf_edi;
		case 16:
			args[3] = frame->tf_esi;
		case 12:
			args[2] = frame->tf_edx;
		case 8:
			args[1] = frame->tf_ecx;
		case 4:
			args[0] = frame->tf_ebx;
		case 0:
			break;
		default:
			panic("linux syscall with weird argument size %d",
			    argsize);
			break;
		}
	}
	else
#endif
	if (argsize && (error = copyin(params, args, argsize)))
		goto bad;

	rval[0] = 0;
	rval[1] = frame->tf_edx;

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

	switch (error) {
	case 0:
		frame->tf_eax = rval[0];
		frame->tf_edx = rval[1];
		frame->tf_eflags &= ~PSL_C;	/* carry bit */
		break;
	case ERESTART:
		/* Back up over the int$80 (2 bytes) that made the syscall */
		frame->tf_eip -= 2;
		break;
	case EJUSTRETURN:
		/* nothing to do */
		break;
	default:
	bad:
		if (p->p_p->ps_emul->e_errno && error >= 0 && error <= ELAST)
			frame->tf_eax = p->p_p->ps_emul->e_errno[error];
		else
			frame->tf_eax = error;
		frame->tf_eflags |= PSL_C;	/* carry bit */
		break;
	}

	mi_syscall_return(p, code, error, rval);

#ifdef DIAGNOSTIC
	if (lapic_tpr != ocpl) {
		printf("WARNING: SPL (0x%x) NOT LOWERED ON "
		    "syscall(0x%lx, 0x%lx, 0x%lx, 0x%lx...) EXIT, PID %d\n",
		    lapic_tpr, code, args[0], args[1], args[2], p->p_pid);
		lapic_tpr = ocpl;
	}
#endif
}

void
child_return(void *arg)
{
	struct proc *p = (struct proc *)arg;
	struct trapframe *tf = p->p_md.md_regs;

	tf->tf_eax = 0;
	tf->tf_eflags &= ~PSL_C;

	KERNEL_UNLOCK();

	mi_child_return(p);
}

license: unknown


code:
/*	$OpenBSD: vector.s,v 1.20 2015/06/28 01:11:27 guenther Exp $	*/
/*	$NetBSD: vector.s,v 1.32 1996/01/07 21:29:47 mycroft Exp $	*/

/*
 * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.  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 Charles M. Hannum.
 * 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 <machine/i8259.h>
#include <dev/isa/isareg.h>

/*
 * Macros for interrupt entry, call to handler, and exit.
 *
 * XXX
 * The interrupt frame is set up to look like a trap frame.  This may be a
 * waste.  The only handler which needs a frame is the clock handler, and it
 * only needs a few bits.  Xdoreti() needs a trap frame for handling ASTs, but
 * it could easily convert the frame on demand.
 *
 * The direct costs of setting up a trap frame are two pushl's (error code and
 * trap number), an addl to get rid of these, and pushing and popping the
 * callee-saved registers %esi, %edi, %ebx, and %ebp twice.
 *
 * If the interrupt frame is made more flexible,  INTR can push %eax first and
 * decide the ipending case with less overhead, e.g., by avoiding loading the
 * segment registers.
 */

	.globl	_C_LABEL(isa_strayintr)

#define voidop(num)

/*
 * Normal vectors.
 *
 * We cdr down the intrhand chain, calling each handler with its appropriate
 * argument (0 meaning a pointer to the frame, for clock interrupts).
 *
 * The handler returns one of three values:
 *   0 - This interrupt wasn't for me.
 *   1 - This interrupt was for me.
 *  -1 - This interrupt might have been for me, but I don't know.
 * If there are no handlers, or they all return 0, we flag it as a `stray'
 * interrupt.  On a system with level-triggered interrupts, we could terminate
 * immediately when one of them returns 1; but this is a PC.
 *
 * On exit, we jump to Xdoreti(), to process soft interrupts and ASTs.
 */
#define	INTRSTUB(name, num, early_ack, late_ack, mask, unmask, level_mask) \
IDTVEC(resume_##name##num)						;\
	push	%ebx							;\
	cli								;\
	jmp	1f							;\
IDTVEC(recurse_##name##num)						;\
	pushfl								;\
	pushl	%cs							;\
	pushl	%esi							;\
	subl	$8,%esp			/* space for tf_{err,trapno} */ ;\
	movl	%ebx,%esi						;\
	INTRENTRY							;\
	MAKE_FRAME							;\
	push	%esi							;\
	cli								;\
	jmp	1f							;\
_C_LABEL(Xintr_##name##num):						;\
	subl	$8,%esp			/* space for tf_{err,trapno} */ ;\
	INTRENTRY							;\
	MAKE_FRAME							;\
	mask(num)			/* mask it in hardware */	;\
	early_ack(num)			/* and allow other intrs */	;\
	incl	_C_LABEL(uvmexp)+V_INTR	/* statistical info */		;\
	movl	_C_LABEL(iminlevel) + (num) * 4, %eax			;\
	movl	CPL,%ebx						;\
	cmpl	%eax,%ebx						;\
	jae	_C_LABEL(Xhold_##name##num)/* currently masked; hold it */;\
	pushl	%ebx			/* cpl to restore on exit */	;\
1:									;\
	movl	_C_LABEL(imaxlevel) + (num) * 4,%eax			;\
	movl	%eax,CPL		/* block enough for this irq */	;\
	sti				/* safe to take intrs now */	;\
	movl	_C_LABEL(intrhand) + (num) * 4,%ebx	/* head of chain */ ;\
	testl	%ebx,%ebx						;\
	jz	_C_LABEL(Xstray_##name##num)	/* no handlers; we're stray */	;\
	STRAY_INITIALIZE		/* nobody claimed it yet */	;\
	incl	CPUVAR(IDEPTH)						;\
7:	movl	%esp, %eax		/* save frame pointer in eax */	;\
	pushl	%ebx			/* arg 2: ih structure */	;\
	pushl	%eax			/* arg 1: frame pointer */	;\
	call	_C_LABEL(intr_handler)	/* call it */			;\
	addl	$8, %esp		/* toss args */			;\
	STRAY_INTEGRATE			/* maybe he claimed it */	;\
	orl	%eax,%eax		/* should it be counted? */	;\
	jz	5f			/* no, skip it */		;\
	addl	$1,IH_COUNT(%ebx)	/* count the intrs */		;\
	adcl	$0,IH_COUNT+4(%ebx)					;\
	cmpl	$0,_C_LABEL(intr_shared_edge)				;\
	jne	5f			 /* if no shared edges ... */	;\
	orl	%eax,%eax		/* ... 1 means stop trying */	;\
	jns	8f							;\
5:	movl	IH_NEXT(%ebx),%ebx	/* next handler in chain */	;\
	testl	%ebx,%ebx						;\
	jnz	7b							;\
8:	decl	CPUVAR(IDEPTH)						;\
	STRAY_TEST(name,num)		/* see if it's a stray */	;\
6:	unmask(num)			/* unmask it in hardware */	;\
	late_ack(num)							;\
	jmp	_C_LABEL(Xdoreti)	/* lower spl and do ASTs */	;\
IDTVEC(stray_##name##num)						;\
	pushl	$num							;\
	call	_C_LABEL(isa_strayintr)					;\
	addl	$4,%esp							;\
	jmp	6b							;\
IDTVEC(hold_##name##num)						;\
	orb	$IRQ_BIT(num),CPUVAR(IPENDING) + IRQ_BYTE(num)	;\
	INTRFASTEXIT

#if defined(DEBUG)
#define	STRAY_INITIALIZE \
	xorl	%esi,%esi
#define	STRAY_INTEGRATE \
	orl	%eax,%esi
#define	STRAY_TEST(name,num) \
	testl	%esi,%esi						;\
	jz	_C_LABEL(Xstray_##name##num)
#else /* !DEBUG */
#define	STRAY_INITIALIZE
#define	STRAY_INTEGRATE
#define	STRAY_TEST(name,num)
#endif /* DEBUG */

#ifdef DDB
#define	MAKE_FRAME \
	leal	-8(%esp),%ebp
#else /* !DDB */
#define	MAKE_FRAME
#endif /* DDB */

#define ICUADDR IO_ICU1

INTRSTUB(legacy,0, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,1, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,2, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,3, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,4, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,5, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,6, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,7, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)

#undef ICUADDR
#define ICUADDR IO_ICU2

INTRSTUB(legacy,8, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,9, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,10, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,11, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,12, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,13, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,14, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)
INTRSTUB(legacy,15, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
    voidop)

/*
 * These tables are used by the ISA configuration code.
 */
/* interrupt service routine entry points */
IDTVEC(intr)
	.long   _C_LABEL(Xintr_legacy0), _C_LABEL(Xintr_legacy1)
	.long	_C_LABEL(Xintr_legacy2), _C_LABEL(Xintr_legacy3)
	.long	_C_LABEL(Xintr_legacy4), _C_LABEL(Xintr_legacy5)
	.long	_C_LABEL(Xintr_legacy6), _C_LABEL(Xintr_legacy7)
	.long	_C_LABEL(Xintr_legacy8), _C_LABEL(Xintr_legacy9)
	.long	_C_LABEL(Xintr_legacy10), _C_LABEL(Xintr_legacy11)
	.long	_C_LABEL(Xintr_legacy12), _C_LABEL(Xintr_legacy13)
	.long	_C_LABEL(Xintr_legacy14), _C_LABEL(Xintr_legacy15)

/*
 * These tables are used by Xdoreti() and Xspllower().
 */
/* resume points for suspended interrupts */
IDTVEC(resume)
	.long	_C_LABEL(Xresume_legacy0), _C_LABEL(Xresume_legacy1)
	.long	_C_LABEL(Xresume_legacy2), _C_LABEL(Xresume_legacy3)
	.long	_C_LABEL(Xresume_legacy4), _C_LABEL(Xresume_legacy5)
	.long	_C_LABEL(Xresume_legacy6), _C_LABEL(Xresume_legacy7)
	.long	_C_LABEL(Xresume_legacy8), _C_LABEL(Xresume_legacy9)
	.long	_C_LABEL(Xresume_legacy10), _C_LABEL(Xresume_legacy11)
	.long	_C_LABEL(Xresume_legacy12), _C_LABEL(Xresume_legacy13)
	.long	_C_LABEL(Xresume_legacy14), _C_LABEL(Xresume_legacy15)
	/* for soft interrupts */
	.long	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	.long	_C_LABEL(Xsofttty), _C_LABEL(Xsoftnet), _C_LABEL(Xsoftclock)
	.long	0, 0
/* fake interrupts to resume from splx() */
IDTVEC(recurse)
	.long	_C_LABEL(Xrecurse_legacy0), _C_LABEL(Xrecurse_legacy1)
	.long	_C_LABEL(Xrecurse_legacy2), _C_LABEL(Xrecurse_legacy3)
	.long	_C_LABEL(Xrecurse_legacy4), _C_LABEL(Xrecurse_legacy5)
	.long	_C_LABEL(Xrecurse_legacy6), _C_LABEL(Xrecurse_legacy7)
	.long	_C_LABEL(Xrecurse_legacy8), _C_LABEL(Xrecurse_legacy9)
	.long	_C_LABEL(Xrecurse_legacy10), _C_LABEL(Xrecurse_legacy11)
	.long	_C_LABEL(Xrecurse_legacy12), _C_LABEL(Xrecurse_legacy13)
	.long	_C_LABEL(Xrecurse_legacy14), _C_LABEL(Xrecurse_legacy15)
	/* for soft interrupts */
	.long	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
	.long	_C_LABEL(Xsofttty), _C_LABEL(Xsoftnet), _C_LABEL(Xsoftclock)
	.long	0, 0


code:
/*	$OpenBSD: via.c,v 1.34 2014/12/09 06:58:28 doug Exp $	*/
/*	$NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $	*/

/*-
 * Copyright (c) 2003 Jason Wright
 * Copyright (c) 2003, 2004 Theo de Raadt
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/signalvar.h>
#include <sys/kernel.h>
#include <sys/exec.h>
#include <sys/buf.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/timeout.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/extent.h>
#include <sys/sysctl.h>

#ifdef CRYPTO
#include <crypto/cryptodev.h>
#include <crypto/rijndael.h>
#include <crypto/xform.h>
#include <crypto/cryptosoft.h>
#endif

#include <uvm/uvm_extern.h>

#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/gdt.h>
#include <machine/pio.h>
#include <machine/bus.h>
#include <machine/psl.h>
#include <machine/reg.h>
#include <machine/specialreg.h>
#include <machine/biosvar.h>

#include <dev/rndvar.h>

void	viac3_rnd(void *);

#ifdef CRYPTO

struct viac3_session {
	u_int32_t	ses_ekey[4 * (AES_MAXROUNDS + 1) + 4];	/* 128 bit aligned */
	u_int32_t	ses_dkey[4 * (AES_MAXROUNDS + 1) + 4];	/* 128 bit aligned */
	u_int32_t	ses_cw0;
	struct swcr_data *swd;
	int		ses_klen;
	int		ses_used;
};

struct viac3_softc {
	u_int32_t		op_cw[4];		/* 128 bit aligned */
	u_int8_t		op_iv[16];		/* 128 bit aligned */
	void			*op_buf;

	/* normal softc stuff */
	int32_t			sc_cid;
	int			sc_nsessions;
	struct viac3_session	*sc_sessions;
};

#define VIAC3_SESSION(sid)		((sid) & 0x0fffffff)
#define	VIAC3_SID(crd,ses)		(((crd) << 28) | ((ses) & 0x0fffffff))

static struct viac3_softc *vc3_sc;
extern int i386_has_xcrypt;

extern const u_int8_t hmac_ipad_buffer[HMAC_MAX_BLOCK_LEN];
extern const u_int8_t hmac_opad_buffer[HMAC_MAX_BLOCK_LEN];

void viac3_crypto_setup(void);
int viac3_crypto_newsession(u_int32_t *, struct cryptoini *);
int viac3_crypto_process(struct cryptop *);
int viac3_crypto_swauth(struct cryptop *, struct cryptodesc *,
    struct swcr_data *, caddr_t);
int viac3_crypto_encdec(struct cryptop *, struct cryptodesc *,
    struct viac3_session *, struct viac3_softc *, caddr_t);
int viac3_crypto_freesession(u_int64_t);
static __inline void viac3_cbc(void *, void *, void *, void *, int, void *);

void
viac3_crypto_setup(void)
{
	int algs[CRYPTO_ALGORITHM_MAX + 1];

	vc3_sc = malloc(sizeof(*vc3_sc), M_DEVBUF, M_NOWAIT|M_ZERO);
	if (vc3_sc == NULL)
		return;	/* YYY bitch? */

	bzero(algs, sizeof(algs));
	algs[CRYPTO_AES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
	algs[CRYPTO_MD5_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
	algs[CRYPTO_SHA1_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
	algs[CRYPTO_RIPEMD160_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
	algs[CRYPTO_SHA2_256_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
	algs[CRYPTO_SHA2_384_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
	algs[CRYPTO_SHA2_512_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;

	vc3_sc->sc_cid = crypto_get_driverid(0);
	if (vc3_sc->sc_cid < 0) {
		free(vc3_sc, M_DEVBUF, 0);
		return;		/* YYY bitch? */
	}

	crypto_register(vc3_sc->sc_cid, algs, viac3_crypto_newsession,
	    viac3_crypto_freesession, viac3_crypto_process);
}

int
viac3_crypto_newsession(u_int32_t *sidp, struct cryptoini *cri)
{
	struct cryptoini	*c;
	struct viac3_softc	*sc = vc3_sc;
	struct viac3_session	*ses = NULL;
	struct auth_hash	*axf;
	struct swcr_data	*swd;
	int			 sesn, i, cw0;

	if (sc == NULL || sidp == NULL || cri == NULL)
		return (EINVAL);

	if (sc->sc_sessions == NULL) {
		ses = sc->sc_sessions = malloc(sizeof(*ses), M_DEVBUF,
		    M_NOWAIT);
		if (ses == NULL)
			return (ENOMEM);
		sesn = 0;
		sc->sc_nsessions = 1;
	} else {
		for (sesn = 0; sesn < sc->sc_nsessions; sesn++) {
			if (sc->sc_sessions[sesn].ses_used == 0) {
				ses = &sc->sc_sessions[sesn];
				break;
			}
		}

		if (ses == NULL) {
			sesn = sc->sc_nsessions;
			ses = mallocarray(sesn + 1, sizeof(*ses), M_DEVBUF,
			    M_NOWAIT);
			if (ses == NULL)
				return (ENOMEM);
			bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses));
			explicit_bzero(sc->sc_sessions, sesn * sizeof(*ses));
			free(sc->sc_sessions, M_DEVBUF, 0);
			sc->sc_sessions = ses;
			ses = &sc->sc_sessions[sesn];
			sc->sc_nsessions++;
		}
	}

	bzero(ses, sizeof(*ses));
	ses->ses_used = 1;

	for (c = cri; c != NULL; c = c->cri_next) {
		switch (c->cri_alg) {
		case CRYPTO_AES_CBC:
			switch (c->cri_klen) {
			case 128:
				cw0 = C3_CRYPT_CWLO_KEY128;
				break;
			case 192:
				cw0 = C3_CRYPT_CWLO_KEY192;
				break;
			case 256:
				cw0 = C3_CRYPT_CWLO_KEY256;
				break;
			default:
				viac3_crypto_freesession(sesn);
				return (EINVAL);
			}
			cw0 |= C3_CRYPT_CWLO_ALG_AES | C3_CRYPT_CWLO_KEYGEN_SW |
			    C3_CRYPT_CWLO_NORMAL;

			ses->ses_klen = c->cri_klen;
			ses->ses_cw0 = cw0;

			/* Build expanded keys for both directions */
			rijndaelKeySetupEnc(ses->ses_ekey, c->cri_key,
			    c->cri_klen);
			rijndaelKeySetupDec(ses->ses_dkey, c->cri_key,
			    c->cri_klen);
			for (i = 0; i < 4 * (AES_MAXROUNDS + 1); i++) {
				ses->ses_ekey[i] = ntohl(ses->ses_ekey[i]);
				ses->ses_dkey[i] = ntohl(ses->ses_dkey[i]);
			}

			break;

		case CRYPTO_MD5_HMAC:
			axf = &auth_hash_hmac_md5_96;
			goto authcommon;
		case CRYPTO_SHA1_HMAC:
			axf = &auth_hash_hmac_sha1_96;
			goto authcommon;
		case CRYPTO_RIPEMD160_HMAC:
			axf = &auth_hash_hmac_ripemd_160_96;
			goto authcommon;
		case CRYPTO_SHA2_256_HMAC:
			axf = &auth_hash_hmac_sha2_256_128;
			goto authcommon;
		case CRYPTO_SHA2_384_HMAC:
			axf = &auth_hash_hmac_sha2_384_192;
			goto authcommon;
		case CRYPTO_SHA2_512_HMAC:
			axf = &auth_hash_hmac_sha2_512_256;
		authcommon:
			swd = malloc(sizeof(struct swcr_data), M_CRYPTO_DATA,
			    M_NOWAIT|M_ZERO);
			if (swd == NULL) {
				viac3_crypto_freesession(sesn);
				return (ENOMEM);
			}
			ses->swd = swd;

			swd->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
			    M_NOWAIT);
			if (swd->sw_ictx == NULL) {
				viac3_crypto_freesession(sesn);
				return (ENOMEM);
			}

			swd->sw_octx = malloc(axf->ctxsize, M_CRYPTO_DATA,
			    M_NOWAIT);
			if (swd->sw_octx == NULL) {
				viac3_crypto_freesession(sesn);
				return (ENOMEM);
			}

			for (i = 0; i < c->cri_klen / 8; i++)
				c->cri_key[i] ^= HMAC_IPAD_VAL;

			axf->Init(swd->sw_ictx);
			axf->Update(swd->sw_ictx, c->cri_key, c->cri_klen / 8);
			axf->Update(swd->sw_ictx, hmac_ipad_buffer,
			    axf->blocksize - (c->cri_klen / 8));

			for (i = 0; i < c->cri_klen / 8; i++)
				c->cri_key[i] ^= (HMAC_IPAD_VAL ^
				    HMAC_OPAD_VAL);

			axf->Init(swd->sw_octx);
			axf->Update(swd->sw_octx, c->cri_key, c->cri_klen / 8);
			axf->Update(swd->sw_octx, hmac_opad_buffer,
			    axf->blocksize - (c->cri_klen / 8));

			for (i = 0; i < c->cri_klen / 8; i++)
				c->cri_key[i] ^= HMAC_OPAD_VAL;

			swd->sw_axf = axf;
			swd->sw_alg = c->cri_alg;

			break;
		default:
			viac3_crypto_freesession(sesn);
			return (EINVAL);
		}
	}

	*sidp = VIAC3_SID(0, sesn);
	return (0);
}

int
viac3_crypto_freesession(u_int64_t tid)
{
	struct viac3_softc *sc = vc3_sc;
	struct swcr_data *swd;
	struct auth_hash *axf;
	int sesn;
	u_int32_t sid = ((u_int32_t)tid) & 0xffffffff;

	if (sc == NULL)
		return (EINVAL);
	sesn = VIAC3_SESSION(sid);
	if (sesn >= sc->sc_nsessions)
		return (EINVAL);

	if (sc->sc_sessions[sesn].swd) {
		swd = sc->sc_sessions[sesn].swd;
		axf = swd->sw_axf;

		if (swd->sw_ictx) {
			explicit_bzero(swd->sw_ictx, axf->ctxsize);
			free(swd->sw_ictx, M_CRYPTO_DATA, 0);
		}
		if (swd->sw_octx) {
			explicit_bzero(swd->sw_octx, axf->ctxsize);
			free(swd->sw_octx, M_CRYPTO_DATA, 0);
		}
		free(swd, M_CRYPTO_DATA, 0);
	}

	explicit_bzero(&sc->sc_sessions[sesn], sizeof(sc->sc_sessions[sesn]));
	return (0);
}

static __inline void
viac3_cbc(void *cw, void *src, void *dst, void *key, int rep,
    void *iv)
{
	unsigned int creg0;

	creg0 = rcr0();		/* Permit access to SIMD/FPU path */
	lcr0(creg0 & ~(CR0_EM|CR0_TS));

	/* Do the deed */
	__asm volatile("pushfl; popfl");
	__asm volatile("rep xcryptcbc" :
	    : "a" (iv), "b" (key), "c" (rep), "d" (cw), "S" (src), "D" (dst)
	    : "memory", "cc");

	lcr0(creg0);
}

int
viac3_crypto_swauth(struct cryptop *crp, struct cryptodesc *crd,
    struct swcr_data *sw, caddr_t buf)
{
	int	type;

	if (crp->crp_flags & CRYPTO_F_IMBUF)
		type = CRYPTO_BUF_MBUF;
	else
		type= CRYPTO_BUF_IOV;

	return (swcr_authcompute(crp, crd, sw, buf, type));
}

int
viac3_crypto_encdec(struct cryptop *crp, struct cryptodesc *crd,
    struct viac3_session *ses, struct viac3_softc *sc, caddr_t buf)
{
	u_int32_t *key;
	int	err = 0;

	if ((crd->crd_len % 16) != 0) {
		err = EINVAL;
		return (err);
	}

	sc->op_buf = malloc(crd->crd_len, M_DEVBUF, M_NOWAIT);
	if (sc->op_buf == NULL) {
		err = ENOMEM;
		return (err);
	}

	if (crd->crd_flags & CRD_F_ENCRYPT) {
		sc->op_cw[0] = ses->ses_cw0 | C3_CRYPT_CWLO_ENCRYPT;
		key = ses->ses_ekey;
		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
			bcopy(crd->crd_iv, sc->op_iv, 16);
		else
			arc4random_buf(sc->op_iv, 16);

		if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
			if (crp->crp_flags & CRYPTO_F_IMBUF)
				err = m_copyback((struct mbuf *)crp->crp_buf,
				    crd->crd_inject, 16, sc->op_iv, M_NOWAIT);
			else if (crp->crp_flags & CRYPTO_F_IOV)
				cuio_copyback((struct uio *)crp->crp_buf,
				    crd->crd_inject, 16, sc->op_iv);
			else
				bcopy(sc->op_iv,
				    crp->crp_buf + crd->crd_inject, 16);
			if (err)
				return (err);
		}
	} else {
		sc->op_cw[0] = ses->ses_cw0 | C3_CRYPT_CWLO_DECRYPT;
		key = ses->ses_dkey;
		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
			bcopy(crd->crd_iv, sc->op_iv, 16);
		else {
			if (crp->crp_flags & CRYPTO_F_IMBUF)
				m_copydata((struct mbuf *)crp->crp_buf,
				    crd->crd_inject, 16, sc->op_iv);
			else if (crp->crp_flags & CRYPTO_F_IOV)
				cuio_copydata((struct uio *)crp->crp_buf,
				    crd->crd_inject, 16, sc->op_iv);
			else
				bcopy(crp->crp_buf + crd->crd_inject,
				    sc->op_iv, 16);
		}
	}

	if (crp->crp_flags & CRYPTO_F_IMBUF)
		m_copydata((struct mbuf *)crp->crp_buf,
		    crd->crd_skip, crd->crd_len, sc->op_buf);
	else if (crp->crp_flags & CRYPTO_F_IOV)
		cuio_copydata((struct uio *)crp->crp_buf,
		    crd->crd_skip, crd->crd_len, sc->op_buf);
	else
		bcopy(crp->crp_buf + crd->crd_skip, sc->op_buf, crd->crd_len);

	sc->op_cw[1] = sc->op_cw[2] = sc->op_cw[3] = 0;
	viac3_cbc(&sc->op_cw, sc->op_buf, sc->op_buf, key,
	    crd->crd_len / 16, sc->op_iv);

	if (crp->crp_flags & CRYPTO_F_IMBUF)
		m_copyback((struct mbuf *)crp->crp_buf,
		    crd->crd_skip, crd->crd_len, sc->op_buf, M_NOWAIT);
	else if (crp->crp_flags & CRYPTO_F_IOV)
		cuio_copyback((struct uio *)crp->crp_buf,
		    crd->crd_skip, crd->crd_len, sc->op_buf);
	else
		bcopy(sc->op_buf, crp->crp_buf + crd->crd_skip,
		    crd->crd_len);

	if (sc->op_buf != NULL) {
		explicit_bzero(sc->op_buf, crd->crd_len);
		free(sc->op_buf, M_DEVBUF, 0);
		sc->op_buf = NULL;
	}

	return (err);
}

int
viac3_crypto_process(struct cryptop *crp)
{
	struct viac3_softc *sc = vc3_sc;
	struct viac3_session *ses;
	struct cryptodesc *crd;
	int sesn, err = 0;

	if (crp == NULL || crp->crp_callback == NULL)
		return (EINVAL);

	sesn = VIAC3_SESSION(crp->crp_sid);
	if (sesn >= sc->sc_nsessions) {
		err = EINVAL;
		goto out;
	}
	ses = &sc->sc_sessions[sesn];
	if (ses->ses_used == 0) {
		err = EINVAL;
		goto out;
	}

	for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
		switch (crd->crd_alg) {
		case CRYPTO_AES_CBC:
			if ((err = viac3_crypto_encdec(crp, crd, ses, sc,
			    crp->crp_buf)) != 0)
				goto out;
			break;

		case CRYPTO_MD5_HMAC:
		case CRYPTO_SHA1_HMAC:
		case CRYPTO_RIPEMD160_HMAC:
		case CRYPTO_SHA2_256_HMAC:
		case CRYPTO_SHA2_384_HMAC:
		case CRYPTO_SHA2_512_HMAC:
			if ((err = viac3_crypto_swauth(crp, crd, ses->swd,
			    crp->crp_buf)) != 0)
				goto out;
			break;

		default:
			err = EINVAL;
			goto out;
		}
	}
out:
	crp->crp_etype = err;
	crypto_done(crp);
	return (err);
}

#endif /* CRYPTO */

/*
 * Note, the VIA C3 Nehemiah provides 4 internal 8-byte buffers, which
 * store random data, and can be accessed a lot quicker than waiting
 * for new data to be generated.  As we are using every 8th bit only
 * due to whitening. Since the RNG generates in excess of 21KB/s at
 * its worst, collecting 64 bytes worth of entropy should not affect
 * things significantly.
 *
 * Note, due to some weirdness in the RNG, we need at least 7 bytes
 * extra on the end of our buffer.  Also, there is an outside chance
 * that the VIA RNG can "wedge", as the generated bit-rate is variable.
 * We could do all sorts of startup testing and things, but
 * frankly, I don't really see the point.  If the RNG wedges, then the
 * chances of you having a defective CPU are very high.  Let it wedge.
 *
 * Adding to the whole confusion, in order to access the RNG, we need
 * to have FXSR support enabled, and the correct FPU enable bits must
 * be there to enable the FPU in kernel.  It would be nice if all this
 * mumbo-jumbo was not needed in order to use the RNG.  Oh well, life
 * does go on...
 */
#define VIAC3_RNG_BUFSIZ	16		/* 32bit words */
struct timeout viac3_rnd_tmo;
int viac3_rnd_present;

void
viac3_rnd(void *v)
{
	struct timeout *tmo = v;
	unsigned int *p, i, rv, creg0, len = VIAC3_RNG_BUFSIZ;
	static int buffer[VIAC3_RNG_BUFSIZ + 2];	/* XXX why + 2? */
#ifdef MULTIPROCESSOR
	int s = splipi();
#endif

	creg0 = rcr0();		/* Permit access to SIMD/FPU path */
	lcr0(creg0 & ~(CR0_EM|CR0_TS));

	/*
	 * Here we collect the random data from the VIA C3 RNG.  We make
	 * sure that we turn on maximum whitening (%edx[0,1] == "11"), so
	 * that we get the best random data possible.
	 */
	__asm volatile("rep xstorerng"
	    : "=a" (rv) : "d" (3), "D" (buffer), "c" (len*sizeof(int))
	    : "memory", "cc");

	lcr0(creg0);

#ifdef MULTIPROCESSOR
	splx(s);
#endif

	for (i = 0, p = buffer; i < VIAC3_RNG_BUFSIZ; i++, p++)
		add_true_randomness(*p);

	timeout_add_msec(tmo, 10);
}


code:
/*	$OpenBSD: vm86.c,v 1.22 2014/03/29 18:09:29 guenther Exp $	*/
/*	$NetBSD: vm86.c,v 1.15 1996/05/03 19:42:33 christos Exp $	*/

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

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/signalvar.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/exec.h>
#include <sys/buf.h>
#include <sys/reboot.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/msgbuf.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/device.h>
#include <sys/sysctl.h>
#include <sys/syscallargs.h>
#ifdef SYSVMSG
#include <sys/msg.h>
#endif
#ifdef SYSVSEM
#include <sys/sem.h>
#endif
#ifdef SYSVSHM
#include <sys/shm.h>
#endif

#include <sys/ktrace.h>
#include <machine/sysarch.h>
#include <machine/vm86.h>

static void fast_intxx(struct proc *, int);
static __inline int is_bitset(int, caddr_t);

#define	CS(tf)		(*(u_short *)&tf->tf_cs)
#define	IP(tf)		(*(u_short *)&tf->tf_eip)
#define	SS(tf)		(*(u_short *)&tf->tf_ss)
#define	SP(tf)		(*(u_short *)&tf->tf_esp)

#define putword(base, ptr, val) \
__asm__ volatile( \
	"decw %w0\n\t" \
	"movb %h2,0(%1,%0)\n\t" \
	"decw %w0\n\t" \
	"movb %b2,0(%1,%0)" \
	: "=r" (ptr) \
	: "r" (base), "q" (val), "0" (ptr))

#define putdword(base, ptr, val) \
__asm__ volatile( \
	"rorl $16,%2\n\t" \
	"decw %w0\n\t" \
	"movb %h2,0(%1,%0)\n\t" \
	"decw %w0\n\t" \
	"movb %b2,0(%1,%0)\n\t" \
	"rorl $16,%2\n\t" \
	"decw %w0\n\t" \
	"movb %h2,0(%1,%0)\n\t" \
	"decw %w0\n\t" \
	"movb %b2,0(%1,%0)" \
	: "=r" (ptr) \
	: "r" (base), "q" (val), "0" (ptr))

#define getbyte(base, ptr) \
({ unsigned long __res; \
__asm__ volatile( \
	"movb 0(%1,%0),%b2\n\t" \
	"incw %w0" \
	: "=r" (ptr), "=r" (base), "=q" (__res) \
	: "0" (ptr), "1" (base), "2" (0)); \
__res; })

#define getword(base, ptr) \
({ unsigned long __res; \
__asm__ volatile( \
	"movb 0(%1,%0),%b2\n\t" \
	"incw %w0\n\t" \
	"movb 0(%1,%0),%h2\n\t" \
	"incw %w0" \
	: "=r" (ptr), "=r" (base), "=q" (__res) \
	: "0" (ptr), "1" (base), "2" (0)); \
__res; })

#define getdword(base, ptr) \
({ unsigned long __res; \
__asm__ volatile( \
	"movb 0(%1,%0),%b2\n\t" \
	"incw %w0\n\t" \
	"movb 0(%1,%0),%h2\n\t" \
	"incw %w0\n\t" \
	"rorl $16,%2\n\t" \
	"movb 0(%1,%0),%b2\n\t" \
	"incw %w0\n\t" \
	"movb 0(%1,%0),%h2\n\t" \
	"incw %w0\n\t" \
	"rorl $16,%2" \
	: "=r" (ptr), "=r" (base), "=q" (__res) \
	: "0" (ptr), "1" (base)); \
__res; })

static __inline int
is_bitset(int nr, caddr_t bitmap)
{
	u_int byte;		/* bt instruction doesn't do
					   bytes--it examines ints! */
	bitmap += nr / NBBY;
	nr = nr % NBBY;
	copyin(bitmap, &byte, sizeof(u_char));

	__asm__ volatile("btl %2,%1\n\tsbbl %0,%0"
			     :"=r" (nr)
			     :"r" (byte),"r" (nr));
	return (nr);
}

#define V86_AH(regs)	(((u_char *)&((regs)->tf_eax))[1])
#define V86_AL(regs)	(((u_char *)&((regs)->tf_eax))[0])

static void
fast_intxx(struct proc *p, int intrno)
{
	struct trapframe *tf = p->p_md.md_regs;
	/*
	 * handle certain interrupts directly by pushing the interrupt
	 * frame and resetting registers, but only if user said that's ok
	 * (i.e. not revectored.)  Otherwise bump to 32-bit user handler.
	 */
	struct vm86_struct *u_vm86p;
	struct { u_short ip, cs; } ihand;

	u_long ss, sp;

	/*
	 * Note: u_vm86p points to user-space, we only compute offsets
	 * and don't deref it. is_revectored() above does copyin() to
	 * get stuff from it
	 */
	u_vm86p = (struct vm86_struct *)p->p_addr->u_pcb.vm86_userp;

	/*
	 * If user requested special handling, return to user space with
	 * indication of which INT was requested.
	 */
	if (is_bitset(intrno, &u_vm86p->int_byuser[0]))
		goto vector;

	/*
	 * If it's interrupt 0x21 (special in the DOS world) and the
	 * sub-command (in AH) was requested for special handling,
	 * return to user mode.
	 */
	if (intrno == 0x21 && is_bitset(V86_AH(tf), &u_vm86p->int21_byuser[0]))
		goto vector;

	/*
	 * Fetch intr handler info from "real-mode" IDT based at addr 0 in
	 * the user address space.
	 */
	if (copyin((caddr_t)(intrno * sizeof(ihand)), &ihand, sizeof(ihand)))
		goto bad;

	/*
	 * Otherwise, push flags, cs, eip, and jump to handler to
	 * simulate direct INT call.
	 */
	ss = SS(tf) << 4;
	sp = SP(tf);

	putword(ss, sp, get_vflags_short(p));
	putword(ss, sp, CS(tf));
	putword(ss, sp, IP(tf));
	SP(tf) = sp;

	IP(tf) = ihand.ip;
	CS(tf) = ihand.cs;

	return;

vector:
	vm86_return(p, VM86_MAKEVAL(VM86_INTx, intrno));
	return;

bad:
	vm86_return(p, VM86_UNKNOWN);
	return;
}

void
vm86_return(struct proc *p, int retval)
{
	union sigval sv;

	/*
	 * We can't set the virtual flags in our real trap frame,
	 * since it's used to jump to the signal handler.  Instead we
	 * let sendsig() pull in the vm86_eflags bits.
	 */
	if (p->p_sigmask & sigmask(SIGURG)) {
#ifdef DIAGNOSTIC
		printf("pid %d killed on VM86 protocol screwup (SIGURG blocked)\n",
		       p->p_pid);
#endif
		sigexit(p, SIGILL);
		/* NOTREACHED */
	}
	sv.sival_int = 0;
	trapsignal(p, SIGURG, retval, 0, sv);
}

#define	CLI	0xFA
#define	STI	0xFB
#define	INTxx	0xCD
#define	INTO	0xCE
#define	IRET	0xCF
#define	OPSIZ	0x66
#define	INT3	0xCC	/* Actually the process gets 32-bit IDT to handle it */
#define	LOCK	0xF0
#define	PUSHF	0x9C
#define	POPF	0x9D

/*
 * Handle a GP fault that occurred while in VM86 mode.  Things that are easy
 * to handle here are done here (much more efficient than trapping to 32-bit
 * handler code and then having it restart VM86 mode).
 */
void
vm86_gpfault(struct proc *p, int type)
{
	struct trapframe *tf = p->p_md.md_regs;
	union sigval sv;

	/*
	 * we want to fetch some stuff from the current user virtual
	 * address space for checking.  remember that the frame's
	 * segment selectors are real-mode style selectors.
	 */
	u_long cs, ip, ss, sp;
	u_char tmpbyte;
	int trace;

	cs = CS(tf) << 4;
	ip = IP(tf);
	ss = SS(tf) << 4;
	sp = SP(tf);

	trace = tf->tf_eflags & PSL_T;

	/*
	 * For most of these, we must set all the registers before calling
	 * macros/functions which might do a vm86_return.
	 */
	tmpbyte = getbyte(cs, ip);
	IP(tf) = ip;
	switch (tmpbyte) {
	case CLI:
		/* simulate handling of IF */
		clr_vif(p);
		break;

	case STI:
		/* simulate handling of IF.
		 * XXX the i386 enables interrupts one instruction later.
		 * code here is wrong, but much simpler than doing it Right.
		 */
		set_vif(p);
		break;

	case INTxx:
		/* try fast intxx, or return to 32bit mode to handle it. */
		tmpbyte = getbyte(cs, ip);
		IP(tf) = ip;
		fast_intxx(p, tmpbyte);
		break;

	case INTO:
		if (tf->tf_eflags & PSL_V)
			fast_intxx(p, 4);
		break;

	case PUSHF:
		putword(ss, sp, get_vflags_short(p));
		SP(tf) = sp;
		break;

	case IRET:
		IP(tf) = getword(ss, sp);
		CS(tf) = getword(ss, sp);
	case POPF:
		set_vflags_short(p, getword(ss, sp));
		SP(tf) = sp;
		break;

	case OPSIZ:
		tmpbyte = getbyte(cs, ip);
		IP(tf) = ip;
		switch (tmpbyte) {
		case PUSHF:
			putdword(ss, sp, get_vflags(p) & ~PSL_VM);
			SP(tf) = sp;
			break;

		case IRET:
			IP(tf) = getdword(ss, sp);
			CS(tf) = getdword(ss, sp);
		case POPF:
			set_vflags(p, getdword(ss, sp) | PSL_VM);
			SP(tf) = sp;
			break;

		default:
			IP(tf) -= 2;
			goto bad;
		}
		break;

	case LOCK:
	default:
		IP(tf) -= 1;
		goto bad;
	}

	if (trace && tf->tf_eflags & PSL_VM) {
		sv.sival_int = 0;
		trapsignal(p, SIGTRAP, T_TRCTRAP, TRAP_TRACE, sv);
	}
	return;

bad:
	vm86_return(p, VM86_UNKNOWN);
	return;
}

int
i386_vm86(struct proc *p, char *args, register_t *retval)
{
	struct trapframe *tf = p->p_md.md_regs;
	struct pcb *pcb = &p->p_addr->u_pcb;
	struct vm86_kern vm86s;
	int error;

	error = copyin(args, &vm86s, sizeof(vm86s));
	if (error)
		return (error);

	pcb->vm86_userp = (void *)args;

	/*
	 * Keep mask of flags we simulate to simulate a particular type of
	 * processor.
	 */
	switch (vm86s.ss_cpu_type) {
	case VCPU_086:
	case VCPU_186:
	case VCPU_286:
		pcb->vm86_flagmask = PSL_ID|PSL_AC|PSL_NT|PSL_IOPL;
		break;
	case VCPU_386:
		pcb->vm86_flagmask = PSL_ID|PSL_AC;
		break;
	case VCPU_486:
		pcb->vm86_flagmask = PSL_ID;
		break;
	case VCPU_586:
		pcb->vm86_flagmask = 0;
		break;
	default:
		return (EINVAL);
	}

#define DOVREG(reg) tf->tf_vm86_##reg = (u_short) vm86s.regs.vmsc.sc_##reg
#define DOREG(reg) tf->tf_##reg = (u_short) vm86s.regs.vmsc.sc_##reg

	DOVREG(ds);
	DOVREG(es);
	DOVREG(fs);
	DOVREG(gs);
	DOREG(edi);
	DOREG(esi);
	DOREG(ebp);
	DOREG(eax);
	DOREG(ebx);
	DOREG(ecx);
	DOREG(edx);
	DOREG(eip);
	DOREG(cs);
	DOREG(esp);
	DOREG(ss);

#undef	DOVREG
#undef	DOREG

	/* Going into vm86 mode jumps off the signal stack. */
	p->p_sigstk.ss_flags &= ~SS_ONSTACK;

	set_vflags(p, vm86s.regs.vmsc.sc_eflags | PSL_VM);

	return (EJUSTRETURN);
}


code:
/*	$OpenBSD: vm_machdep.c,v 1.63 2015/05/05 02:13:46 guenther Exp $	*/
/*	$NetBSD: vm_machdep.c,v 1.61 1996/05/03 19:42:35 christos Exp $	*/

/*-
 * Copyright (c) 1995 Charles M. Hannum.  All rights reserved.
 * Copyright (c) 1982, 1986 The Regents of the University of California.
 * Copyright (c) 1989, 1990 William Jolitz
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department, and William Jolitz.
 *
 * 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.
 *
 *	@(#)vm_machdep.c	7.3 (Berkeley) 5/13/91
 */

/*
 *	Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
 */

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

#include <uvm/uvm_extern.h>

#include <machine/cpu.h>
#include <machine/gdt.h>
#include <machine/reg.h>
#include <machine/specialreg.h>

#include "npx.h"

/*
 * Finish a fork operation, with process p2 nearly set up.
 * Copy and update the kernel stack and pcb, making the child
 * ready to run, and marking it so that it can return differently
 * than the parent.  Returns 1 in the child process, 0 in the parent.
 * We currently double-map the user area so that the stack is at the same
 * address in each process; in the future we will probably relocate
 * the frame pointers on the stack after copying.
 */
void
cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize,
    void (*func)(void *), void *arg)
{
	struct pcb *pcb = &p2->p_addr->u_pcb;
	struct trapframe *tf;
	struct switchframe *sf;

#if NNPX > 0
	npxsave_proc(p1, 1);
#endif

	p2->p_md.md_flags = p1->p_md.md_flags;

	/* Copy pcb from proc p1 to p2. */
	if (p1 == curproc) {
		/* Sync the PCB before we copy it. */
		savectx(curpcb);
	}
#ifdef DIAGNOSTIC
	else if (p1 != &proc0)
		panic("cpu_fork: curproc");
#endif
	*pcb = p1->p_addr->u_pcb;

	/* Fix up the TSS. */
	pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
	pcb->pcb_tss.tss_esp0 = (int)p2->p_addr + USPACE - 16;

	p2->p_md.md_tss_sel = tss_alloc(pcb);

	/*
	 * Copy the trapframe, and arrange for the child to return directly
	 */
	p2->p_md.md_regs = tf = (struct trapframe *)pcb->pcb_tss.tss_esp0 - 1;
	*tf = *p1->p_md.md_regs;

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

	sf = (struct switchframe *)tf - 1;
	sf->sf_esi = (int)func;
	sf->sf_ebx = (int)arg;
	sf->sf_eip = (int)proc_trampoline;
	pcb->pcb_esp = (int)sf;
	pcb->pcb_ebp = 0;
}

/*
 * cpu_exit is called as the last action during exit.
 */
void
cpu_exit(struct proc *p)
{
#if NNPX > 0
	/* If we were using the FPU, forget about it. */
	if (p->p_addr->u_pcb.pcb_fpcpu != NULL)
		npxsave_proc(p, 0);
#endif

	tss_free(p->p_md.md_tss_sel);
	sched_exit(p);
}

/*
 * Convert kernel VA to physical address
 */
int
kvtop(caddr_t addr)
{
	paddr_t pa;

	if (pmap_extract(pmap_kernel(), (vaddr_t)addr, &pa) == FALSE)
		panic("kvtop: zero page frame");
	return((int)pa);
}

/*
 * Map an user IO request into kernel virtual address space.
 */
void
vmapbuf(struct buf *bp, vsize_t len)
{
	vaddr_t faddr, taddr, off;
	paddr_t fpa;

	if ((bp->b_flags & B_PHYS) == 0)
		panic("vmapbuf");
	faddr = trunc_page((vaddr_t)(bp->b_saveaddr = bp->b_data));
	off = (vaddr_t)bp->b_data - faddr;
	len = round_page(off + len);
	taddr= uvm_km_valloc_wait(phys_map, len);
	bp->b_data = (caddr_t)(taddr + off);
	/*
	 * The region is locked, so we expect that pmap_pte() will return
	 * non-NULL.
	 * XXX: unwise to expect this in a multithreaded environment.
	 * anything can happen to a pmap between the time we lock a
	 * region, release the pmap lock, and then relock it for
	 * the pmap_extract().
	 *
	 * no need to flush TLB since we expect nothing to be mapped
	 * where we we just allocated (TLB will be flushed when our
	 * mapping is removed).
	 */
	while (len) {
		pmap_extract(vm_map_pmap(&bp->b_proc->p_vmspace->vm_map),
		    faddr, &fpa);
		pmap_kenter_pa(taddr, fpa, PROT_READ | PROT_WRITE);
		faddr += PAGE_SIZE;
		taddr += PAGE_SIZE;
		len -= PAGE_SIZE;
	}
	pmap_update(pmap_kernel());
}

/*
 * Free the io map PTEs associated with this IO operation.
 * We also invalidate the TLB entries and restore the original b_addr.
 */
void
vunmapbuf(struct buf *bp, vsize_t len)
{
	vaddr_t addr, off;

	if ((bp->b_flags & B_PHYS) == 0)
		panic("vunmapbuf");
	addr = trunc_page((vaddr_t)bp->b_data);
	off = (vaddr_t)bp->b_data - addr;
	len = round_page(off + len);
	pmap_kremove(addr, len);
	pmap_update(pmap_kernel());
	uvm_km_free_wakeup(phys_map, addr, len);
	bp->b_data = bp->b_saveaddr;
	bp->b_saveaddr = 0;
}


code:
/*	$OpenBSD: wscons_machdep.c,v 1.18 2011/06/28 20:19:18 matthieu Exp $ */

/*
 * Copyright (c) 2001 Aaron Campbell
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE 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 OR HIS RELATIVES 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 MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

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

#include <machine/bus.h>

#include <dev/cons.h>

#include "vga.h"
#include "pcdisplay.h"
#if (NVGA > 0) || (NPCDISPLAY > 0)
#include <dev/ic/mc6845reg.h>
#include <dev/ic/pcdisplayvar.h>
#if (NVGA > 0)
#include <dev/ic/vgareg.h>
#include <dev/ic/vgavar.h>
#endif
#if (NPCDISPLAY > 0)
#include <dev/isa/pcdisplayvar.h>
#endif
#endif

#include "wsdisplay.h"
#if NWSDISPLAY > 0
#include <dev/wscons/wsdisplayvar.h>
#endif

#include "pckbc.h"
#if (NPCKBC > 0)
#include <dev/isa/isareg.h>
#include <dev/ic/i8042reg.h>
#include <dev/ic/pckbcvar.h>
#endif
#include "pckbd.h"
#include "ukbd.h"
#if (NUKBD > 0)
#include <dev/usb/ukbdvar.h>
#endif
#include "wskbd.h"
#if NWSKBD > 0
#include <dev/wscons/wskbdvar.h>
#endif

void	wscn_video_init(void);
void	wscn_input_init(int);

cons_decl(ws);

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

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

	if (maj == nchrdev) {
		/* we are not in cdevsw[], give up */
		panic("wsdisplay is not in cdevsw[]");
	}

	cp->cn_dev = makedev(maj, 0);
	cp->cn_pri = CN_MIDPRI;
}

void
wscninit(struct consdev *cp)
{
	static int initted = 0;

	if (initted)
		return;
	initted = 1;

	wscn_video_init();
	wscn_input_init(0);
}

void
wscnputc(dev_t dev, int i)
{
	wsdisplay_cnputc(dev, i);
}

int
wscngetc(dev_t dev)
{
	return (wskbd_cngetc(dev));
}

void
wscnpollc(dev_t dev, int on)
{
	wskbd_cnpollc(dev, on);
}

/*
 * Configure the display part of the console.
 */
void
wscn_video_init()
{
#if (NVGA > 0)
	if (vga_cnattach(I386_BUS_SPACE_IO, I386_BUS_SPACE_MEM, -1, 1) == 0)
		return;
#endif
#if (NPCDISPLAY > 0)
	if (pcdisplay_cnattach(I386_BUS_SPACE_IO, I386_BUS_SPACE_MEM) == 0)
		return;
#endif
}

/*
 * Configure the keyboard part of the console.
 * This is tricky, because of the games USB controllers play.
 *
 * On a truly legacy-free design, no PS/2 keyboard controller will be
 * found, so we'll settle for the first USB keyboard as the console
 * input device.
 *
 * Otherwise, the PS/2 controller will claim console, even if no PS/2
 * keyboard is plugged into it.  This is intentional, so that a PS/2
 * keyboard can be plugged late (even though this is theoretically not
 * allowed, most PS/2 controllers survive this).
 *
 * However, if there isn't any PS/2 keyboard connector, but an USB
 * controller in Legacy mode, the kernel will detect a PS/2 keyboard
 * connected (while there really isn't any), until the USB controller
 * driver attaches. At that point the ghost of the legacy keyboard
 * flees away.
 *
 * The pckbc(4) driver will, however, detect that the keyboard is gone
 * missing, and will invoke this function again, allowing a new console
 * input device choice.
 */
void
wscn_input_init(int pass)
{
	if (pass != 0) {
#if NWSKBD > 0
		wskbd_cndetach();
#endif
	}

#if (NPCKBC > 0)
	if (pass == 0 &&
	    pckbc_cnattach(I386_BUS_SPACE_IO, IO_KBD, KBCMDP, 0) == 0)
		return;
#endif
#if (NUKBD > 0)
	if (ukbd_cnattach() == 0)
		return;
#endif
}


code:
/*	$OpenBSD: _float.h,v 1.1 2012/06/26 16:12:44 deraadt Exp $	*/

/*
 * Copyright (c) 1989 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.
 */

#ifndef _MACHINE__FLOAT_H_
#define _MACHINE__FLOAT_H_

#define __FLT_RADIX		2		/* b */
#define __FLT_ROUNDS		__flt_rounds()
#define __FLT_EVAL_METHOD	2		/* long double */

#define __FLT_MANT_DIG		24		/* p */
#define __FLT_EPSILON		1.19209290E-07F	/* b**(1-p) */
#define __FLT_DIG		6		/* floor((p-1)*log10(b))+(b == 10) */
#define __FLT_MIN_EXP		(-125)		/* emin */
#define __FLT_MIN		1.17549435E-38F	/* b**(emin-1) */
#define __FLT_MIN_10_EXP	(-37)		/* ceil(log10(b**(emin-1))) */
#define __FLT_MAX_EXP		128		/* emax */
#define __FLT_MAX		3.40282347E+38F	/* (1-b**(-p))*b**emax */
#define __FLT_MAX_10_EXP	38		/* floor(log10((1-b**(-p))*b**emax)) */

#define __DBL_MANT_DIG		53
#define __DBL_EPSILON		2.2204460492503131E-16
#define __DBL_DIG		15
#define __DBL_MIN_EXP		(-1021)
#define __DBL_MIN		2.2250738585072014E-308
#define __DBL_MIN_10_EXP	(-307)
#define __DBL_MAX_EXP		1024
#define __DBL_MAX		1.7976931348623157E+308
#define __DBL_MAX_10_EXP	308

#define __LDBL_MANT_DIG		64
#define __LDBL_EPSILON		1.08420217248550443401e-19L
#define __LDBL_DIG		18
#define __LDBL_MIN_EXP		(-16381)
#define __LDBL_MIN		3.36210314311209350626e-4932L
#define __LDBL_MIN_10_EXP	(-4931)
#define __LDBL_MAX_EXP		16384
#define __LDBL_MAX		1.18973149535723176502e+4932L
#define __LDBL_MAX_10_EXP	4932

#define __DECIMAL_DIG		21

#endif /* _MACHINE__FLOAT_H_ */


code:
/*	$OpenBSD: _types.h,v 1.21 2014/03/19 05:14:13 guenther Exp $	*/

/*-
 * Copyright (c) 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.
 *
 *	@(#)types.h	8.3 (Berkeley) 1/5/94
 *	@(#)ansi.h	8.2 (Berkeley) 1/4/94
 */

#ifndef _MACHINE__TYPES_H_
#define _MACHINE__TYPES_H_

/*
 * _ALIGN(p) rounds p (pointer or byte index) up to a correctly-aligned
 * value for all data types (int, long, ...).   The result is an
 * unsigned long and must be cast to any desired pointer type.
 *
 * _ALIGNED_POINTER is a boolean macro that checks whether an address
 * is valid to fetch data elements of type t from on this architecture.
 * This does not reflect the optimal alignment, just the possibility
 * (within reasonable limits).
 */
#define	_ALIGNBYTES		(sizeof(int) - 1)
#define	_STACKALIGNBYTES	15
#define	_ALIGN(p)		(((unsigned long)(p) + _ALIGNBYTES) & ~_ALIGNBYTES)
#define	_ALIGNED_POINTER(p,t)	1

#if defined(_KERNEL)
typedef struct label_t {
	long val[6];
} label_t;
#endif

/* 7.18.1.1 Exact-width integer types */
typedef	signed char		__int8_t;
typedef	unsigned char		__uint8_t;
typedef	short			__int16_t;
typedef	unsigned short		__uint16_t;
typedef	int			__int32_t;
typedef	unsigned int		__uint32_t;
/* LONGLONG */
typedef	long long		__int64_t;
/* LONGLONG */
typedef	unsigned long long	__uint64_t;

/* 7.18.1.2 Minimum-width integer types */
typedef	__int8_t		__int_least8_t;
typedef	__uint8_t		__uint_least8_t;
typedef	__int16_t		__int_least16_t;
typedef	__uint16_t		__uint_least16_t;
typedef	__int32_t		__int_least32_t;
typedef	__uint32_t		__uint_least32_t;
typedef	__int64_t		__int_least64_t;
typedef	__uint64_t		__uint_least64_t;

/* 7.18.1.3 Fastest minimum-width integer types */
typedef	__int32_t		__int_fast8_t;
typedef	__uint32_t		__uint_fast8_t;
typedef	__int32_t		__int_fast16_t;
typedef	__uint32_t		__uint_fast16_t;
typedef	__int32_t		__int_fast32_t;
typedef	__uint32_t		__uint_fast32_t;
typedef	__int64_t		__int_fast64_t;
typedef	__uint64_t		__uint_fast64_t;
#define	__INT_FAST8_MIN		INT32_MIN
#define	__INT_FAST16_MIN	INT32_MIN
#define	__INT_FAST32_MIN	INT32_MIN
#define	__INT_FAST64_MIN	INT64_MIN
#define	__INT_FAST8_MAX		INT32_MAX
#define	__INT_FAST16_MAX	INT32_MAX
#define	__INT_FAST32_MAX	INT32_MAX
#define	__INT_FAST64_MAX	INT64_MAX
#define	__UINT_FAST8_MAX	UINT32_MAX
#define	__UINT_FAST16_MAX	UINT32_MAX
#define	__UINT_FAST32_MAX	UINT32_MAX
#define	__UINT_FAST64_MAX	UINT64_MAX

/* 7.18.1.4 Integer types capable of holding object pointers */
typedef	long			__intptr_t;
typedef	unsigned long		__uintptr_t;

/* 7.18.1.5 Greatest-width integer types */
typedef	__int64_t		__intmax_t;
typedef	__uint64_t		__uintmax_t;

/* Register size */
typedef long			__register_t;

/* VM system types */
typedef unsigned long		__vaddr_t;
typedef unsigned long		__paddr_t;
typedef unsigned long		__vsize_t;
typedef unsigned long		__psize_t;

/* Standard system types */
typedef long double		__double_t;
typedef long double		__float_t;
typedef long			__ptrdiff_t;
typedef	unsigned long		__size_t;
typedef	long			__ssize_t;
#if defined(__GNUC__) && __GNUC__ >= 3
typedef	__builtin_va_list	__va_list;
#else
typedef	char *			__va_list;
#endif

/* Wide character support types */
#ifndef __cplusplus
typedef	int			__wchar_t;
#endif
typedef int			__wint_t;
typedef	int			__rune_t;
typedef	void *			__wctrans_t;
typedef	void *			__wctype_t;

#endif	/* _MACHINE__TYPES_H_ */


code:
/*	$OpenBSD: acpiapm.h,v 1.1 2007/11/25 15:45:17 tedu Exp $ */
/*
 * Copyright (c) 2007 Ted Unangst <tedu@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

extern int (*acpiapm_open)(dev_t, int, int, struct proc *);
extern int (*acpiapm_close)(dev_t, int, int, struct proc *);
extern int (*acpiapm_ioctl)(dev_t, u_long, caddr_t, int, struct proc *);
extern int (*acpiapm_kqfilter)(dev_t, struct knote *);


code:
/*	$OpenBSD: amdmsr.h,v 1.4 2011/03/23 16:54:35 pirofti Exp $ */

/*
 * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _MACHINE_AMDMSR_H_
#define _MACHINE_AMDMSR_H_

struct amdmsr_req {
	u_int32_t addr;	/* 32-bit MSR address */
	u_int64_t val;	/* 64-bit MSR value */
};

#define RDMSR	_IOWR('M', 0, struct amdmsr_req)
#define WRMSR	_IOW('M', 1, struct amdmsr_req)

#ifdef _KERNEL
int	amdmsr_probe(void);
#endif

#endif	/* !_MACHINE_AMDMSR_H_ */


code:
/*	$OpenBSD: apicvar.h,v 1.6 2011/03/23 16:54:35 pirofti Exp $	*/
/* $NetBSD: apicvar.h,v 1.1.2.3 2000/02/27 20:25:00 sommerfeld Exp $ */

/*-
 * Copyright (c) 2000 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by RedBack Networks Inc.
 *
 * Author: Bill Sommerfeld
 *
 * 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.
 */

#ifndef _MACHINE_APICVAR_H_
#define _MACHINE_APICVAR_H_

struct apic_attach_args {
	const char *aaa_name;
	int apic_id;
	int apic_version;
	int flags;
#define IOAPIC_PICMODE		0x01
#define IOAPIC_VWIRE		0x02
	u_int32_t apic_address;
	int apic_vecbase;
};

void apic_format_redir(char *, char *, int, u_int32_t, u_int32_t);

#endif /* !_MACHINE_APICVAR_H_ */


code:
/*	$OpenBSD: apmvar.h,v 1.20 2015/02/06 08:16:49 dcoppa Exp $	*/

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

#include <sys/ioccom.h>

/* Advanced Power Management (v1.0 and v1.1 specification)
 * functions/defines/etc.
 */

#define	APM_VERSION	0x0102

/*
 * APM info word from boot loader
 */
#define APM_16BIT_SUPPORTED	0x00010000
#define APM_32BIT_SUPPORTED	0x00020000
#define APM_IDLE_SLOWS		0x00040000
#define APM_BIOS_PM_DISABLED	0x00080000
#define APM_BIOS_PM_DISENGAGED	0x00100000
#define	APM_MAJOR(f)		(((f) >> 8) & 0xff)
#define	APM_MINOR(f)		((f) & 0xff)
#define	APM_VERMASK		0x0000ffff
#define	APM_NOCLI		0x00010000
#define	APM_BEBATT		0x00020000

/* APM error codes */
#define	APM_ERR_CODE(regs)	(((regs)->ax & 0xff00) >> 8)
#define	APM_ERR_PM_DISABLED	0x01
#define	APM_ERR_REALALREADY	0x02
#define	APM_ERR_NOTCONN		0x03
#define	APM_ERR_16ALREADY	0x05
#define	APM_ERR_16NOTSUPP	0x06
#define	APM_ERR_32ALREADY	0x07
#define	APM_ERR_32NOTSUPP	0x08
#define	APM_ERR_UNRECOG_DEV	0x09
#define	APM_ERR_ERANGE		0x0A
#define	APM_ERR_NOTENGAGED	0x0B
#define	APM_ERR_EOPNOSUPP	0x0C
#define	APM_ERR_RTIMER_DISABLED	0x0D
#define APM_ERR_UNABLE		0x60
#define APM_ERR_NOEVENTS	0x80
#define	APM_ERR_NOT_PRESENT	0x86

#define APM_DEV_APM_BIOS	0x0000
#define APM_DEV_ALLDEVS		0x0001
/* device classes are high byte; device IDs go in low byte */
#define		APM_DEV_DISPLAY(x)	(0x0100|((x)&0xff))
#define		APM_DEV_DISK(x)		(0x0200|((x)&0xff))
#define		APM_DEV_PARALLEL(x)	(0x0300|((x)&0xff))
#define		APM_DEV_SERIAL(x)	(0x0400|((x)&0xff))
#define		APM_DEV_NETWORK(x)	(0x0500|((x)&0xff))
#define		APM_DEV_PCMCIA(x)	(0x0600|((x)&0xff))
#define		APM_DEV_BATTERIES(x)	(0x8000|((x)&0xff))
#define		APM_DEV_ALLUNITS	0xff
/* 0x8100-0xDFFF - reserved	*/
/* 0xE000-0xEFFF - OEM-defined	*/
/* 0xF000-0xFFFF - reserved	*/

#define	APM_INSTCHECK		0x5300	/* int15 only */
#define		APM_16BIT_SUPPORT	0x01
#define		APM_32BIT_SUPPORT	0x02
#define		APM_CPUIDLE_SLOW	0x04
#define		APM_DISABLED		0x08
#define		APM_DISENGAGED		0x10

#define	APM_REAL_CONNECT	0x5301	/* int15 only */
#define	APM_PROT16_CONNECT	0x5302	/* int15 only */
#define	APM_PROT32_CONNECT	0x5303	/* int15 only */
#define APM_DISCONNECT		0x5304	/* %bx = APM_DEV_APM_BIOS */

#define APM_CPU_IDLE		0x5305
#define APM_CPU_BUSY		0x5306

#define APM_SET_PWR_STATE	0x5307
#define		APM_SYS_READY		0x0000	/* %cx */
#define		APM_SYS_STANDBY		0x0001
#define		APM_SYS_SUSPEND		0x0002
#define		APM_SYS_OFF		0x0003
#define		APM_LASTREQ_INPROG	0x0004
#define		APM_LASTREQ_REJECTED	0x0005
/* 0x0006 - 0x001f	Reserved system states    */
/* 0x0020 - 0x003f	OEM-defined system states */
/* 0x0040 - 0x007f	OEM-defined device states */
/* 0x0080 - 0xffff	Reserved device states    */

/* system standby is device ID (%bx) 0x0001, APM_SYS_STANDBY */
/* system suspend is device ID (%bx) 0x0001, APM_SYS_SUSPEND */

#define APM_PWR_MGT_ENABLE	0x5308
#define		APM_MGT_ALL	0xffff	/* %bx */
#define		APM_MGT_DISABLE	0x0	/* %cx */
#define		APM_MGT_ENABLE	0x1

#define APM_SYSTEM_DEFAULTS	0x5309
#define		APM_DEFAULTS_ALL	0xffff	/* %bx */

#define APM_POWER_STATUS	0x530a
#define		APM_AC_OFF		0x00
#define		APM_AC_ON		0x01
#define		APM_AC_BACKUP		0x02
#define		APM_AC_UNKNOWN		0xff
#define		APM_BATT_HIGH		0x00
#define		APM_BATT_LOW		0x01
#define		APM_BATT_CRITICAL	0x02
#define		APM_BATT_CHARGING	0x03
#define		APM_BATT_UNKNOWN	0xff
#define		APM_BATT_FLAG_HIGH	0x01
#define		APM_BATT_FLAG_LOW	0x02
#define		APM_BATT_FLAG_CRITICAL	0x04
#define		APM_BATT_FLAG_CHARGING	0x08
#define		APM_BATT_FLAG_NOBATTERY	0x10
#define		APM_BATT_FLAG_NOSYSBATT	0x80
#define		APM_BATT_LIFE_UNKNOWN	0xff
#define		BATT_STATE(regp) ((regp)->bx & 0xff)
#define		BATT_FLAGS(regp) (((regp)->cx & 0xff00) >> 8)
#define		AC_STATE(regp) (((regp)->bx & 0xff00) >> 8)
#define		BATT_LIFE(regp) ((regp)->cx & 0xff) /* in % */
/* Return time in minutes. According to the APM 1.2 spec:
	DX = Remaining battery life -- time units
		Bit 15 = 0	Time units are seconds
		       = 1 	Time units are minutes
		Bits 14-0 =	Number of seconds or minutes */
#define		BATT_REMAINING(regp) (((regp)->dx & 0x8000) ? \
				      ((regp)->dx & 0x7fff) : \
				      ((regp)->dx & 0x7fff)/60)
#define		BATT_REM_VALID(regp) (((regp)->dx & 0xffff) != 0xffff)
#define		BATT_COUNT(regp)	((regp)->si)

#define	APM_GET_PM_EVENT	0x530b
#define		APM_NOEVENT		0x0000
#define		APM_STANDBY_REQ		0x0001 /* %bx on return */
#define		APM_SUSPEND_REQ		0x0002
#define		APM_NORMAL_RESUME	0x0003
#define		APM_CRIT_RESUME		0x0004 /* suspend/resume happened
						  without us */
#define		APM_BATTERY_LOW		0x0005
#define		APM_POWER_CHANGE	0x0006
#define		APM_UPDATE_TIME		0x0007
#define		APM_CRIT_SUSPEND_REQ	0x0008
#define		APM_USER_STANDBY_REQ	0x0009
#define		APM_USER_SUSPEND_REQ	0x000A
#define		APM_SYS_STANDBY_RESUME	0x000B
#define		APM_CAPABILITY_CHANGE	0x000C	/* apm v1.2 */
/* 0x000d - 0x00ff	Reserved system events */
#define		APM_USER_HIBERNATE_REQ	0x000D
/* 0x0100 - 0x01ff	Reserved device events */
/* 0x0200 - 0x02ff	OEM-defined APM events */
/* 0x0300 - 0xffff	Reserved */
#define		APM_EVENT_MASK		0xffff

#define	APM_EVENT_COMPOSE(t,i)	((((i) & 0x7fff) << 16)|((t) & APM_EVENT_MASK))
#define	APM_EVENT_TYPE(e)	((e) & APM_EVENT_MASK)
#define	APM_EVENT_INDEX(e)	((e) >> 16)

#define	APM_GET_POWER_STATE	0x530c
#define	APM_DEVICE_MGMT_ENABLE	0x530d

#define	APM_DRIVER_VERSION	0x530e
/* %bx should be DEV value (APM_DEV_APM_BIOS)
   %ch = driver major vno
   %cl = driver minor vno
   return: %ah = conn major; %al = conn minor
   */
#define		APM_CONN_MINOR(regp) ((regp)->ax & 0xff)
#define		APM_CONN_MAJOR(regp) (((regp)->ax & 0xff00) >> 8)

#define APM_PWR_MGT_ENGAGE	0x530F
#define		APM_MGT_DISENGAGE	0x0	/* %cx */
#define		APM_MGT_ENGAGE		0x1

/* %bx - APM_DEV_APM_BIOS
 * %bl - number of batteries
 * %cx - capabilities
 */
#define	APM_GET_CAPABILITIES	0x5310
#define		APM_NBATTERIES(regp)	((regp)->bx)
#define		APM_GLOBAL_STANDBY	0x0001
#define		APM_GLOBAL_SUSPEND	0x0002
#define		APM_RTIMER_STANDBY	0x0004	/* resume time wakes up */
#define		APM_RTIMER_SUSPEND	0x0008
#define		APM_IRRING_STANDBY	0x0010	/* internal ring wakes up */
#define		APM_IRRING_SUSPEND	0x0020
#define		APM_PCCARD_STANDBY	0x0040	/* pccard wakes up */
#define		APM_PCCARD_SUSPEND	0x0080

/* %bx - APM_DEV_APM_BIOS
 * %cl - function
 *	for %cl=2 (set resume timer)
 * %ch - seconds in BCD
 * %dh - hours in BCD
 * %dl - minutes in BCD
 * %si - month in BCD (high), day in BCD (low)
 * %di - year in BCD
 */
#define	APM_RESUME_TIMER	0x5311
#define		APM_RT_DISABLE	0x0
#define		APM_RT_GET	0x1
#define		APM_RT_SET	0x2

/* %bx - APM_DEV_APM_BIOS
 * %cx - function
 */
#define	APM_RESUME_ON_RING	0x5312
#define		APM_ROR_DISABLE	0x0
#define		APM_ROR_ENABLE	0x1
#define		APM_ROR_STATUS	0x2

/* %bx - APM_EDV_APM_BIOS
 * %cx - function
 */
#define	APM_INACTIVITY_TIMER	0x5313
#define		APM_IT_DISABLE	0x0
#define		APM_IT_ENABLE	0x1
#define		APM_IT_STATUS	0x2

/* %bh - function */
#define APM_OEM			0x5380
#define		APM_OEM_INSTCHECK	0x7f	/* %bx - OEM ID */

/*
 * LP (Laptop Package)
 *
 * Copyright (C) 1994 by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp>
 *
 * This software may be used, modified, copied, and distributed, in
 * both source and binary form provided that the above copyright and
 * these terms are retained. Under no circumstances is the author
 * responsible for the proper functioning of this software, nor does
 * the author assume any responsibility for damages incurred with its
 * use.
 *
 * Sep., 1994	Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
 */

#define APM_BATTERY_ABSENT 4

struct apm_power_info {
	u_char battery_state;
	u_char ac_state;
	u_char battery_life;
	u_char spare1;
	u_int minutes_left;		/* estimate */
	u_int spare2[6];
};

struct apm_ctl {
	u_int dev;
	u_int mode;
};

#define	APM_IOC_REJECT	_IOW('A', 0, struct apm_event_info) /* reject request # */
#define	APM_IOC_STANDBY	_IO('A', 1)	/* put system into standby */
#define	APM_IOC_SUSPEND	_IO('A', 2)	/* put system into suspend */
#define	APM_IOC_GETPOWER _IOR('A', 3, struct apm_power_info) /* fetch battery state */
#define	APM_IOC_DEV_CTL	_IOW('A', 5, struct apm_ctl) /* put device into mode */
#define APM_IOC_PRN_CTL _IOW('A', 6, int ) /* driver power status msg */
#define		APM_PRINT_ON	0	/* driver power status displayed */
#define		APM_PRINT_OFF	1	/* driver power status not displayed */
#define		APM_PRINT_PCT	2	/* driver power status only displayed
					   if the percentage changes */
#define	APM_IOC_STANDBY_REQ	_IO('A', 7)	/* request standby */
#define	APM_IOC_SUSPEND_REQ	_IO('A', 8)	/* request suspend */
#define	APM_IOC_HIBERNATE	_IO('A', 9)	/* put system into hibernate */

#ifdef _KERNEL
extern void apm_cpu_busy(void);
extern void apm_cpu_idle(void);
extern void apminit(void);
int apm_set_powstate(u_int devid, u_int powstate);
#endif /* _KERNEL */

#endif /* _MACHINE_APMVAR_H_ */