summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1996-01-11 17:59:09 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1996-01-11 17:59:09 +0000
commitf217953a217b97d0ebf54cffbe7d6e2472549fc7 (patch)
treec054f8178322c39cfa97df2527c2b43292a166f1 /sys
parent832d7762e107a2d950f138205d9a6980bfba4353 (diff)
from netbsd; VM86 support, by John Kohl, touched up a bit by charles
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/i386/conf/files.i3865
-rw-r--r--sys/arch/i386/i386/machdep.c72
-rw-r--r--sys/arch/i386/i386/sys_machdep.c20
-rw-r--r--sys/arch/i386/i386/trap.c21
-rw-r--r--sys/arch/i386/i386/vm86.c490
-rw-r--r--sys/arch/i386/include/pcb.h9
-rw-r--r--sys/arch/i386/include/signal.h6
-rw-r--r--sys/arch/i386/include/sysarch.h3
-rw-r--r--sys/arch/i386/include/vm86.h79
9 files changed, 668 insertions, 37 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386
index 8d1d4141d51..f636bc170f3 100644
--- a/sys/arch/i386/conf/files.i386
+++ b/sys/arch/i386/conf/files.i386
@@ -1,4 +1,4 @@
-# $NetBSD: files.i386,v 1.60 1995/10/11 04:19:29 mycroft Exp $
+# $NetBSD: files.i386,v 1.61 1996/01/08 13:51:30 mycroft Exp $
#
# new style config file for i386 architecture
#
@@ -126,6 +126,9 @@ file arch/i386/pci/pci_machdep.c pci
# Compatibility modules
#
+# VM86 mode
+file arch/i386/i386/vm86.c vm86
+
# SVR4 binary compatibility (COMPAT_SVR4)
include "../../../compat/svr4/files.svr4"
file arch/i386/i386/svr4_machdep.c compat_svr4
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 9659d1ca71b..46a1e5bf534 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.183 1996/01/04 22:22:01 jtc Exp $ */
+/* $NetBSD: machdep.c,v 1.185 1996/01/08 20:12:20 mycroft Exp $ */
/*-
* Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved.
@@ -92,6 +92,10 @@
#include <i386/isa/isa_machdep.h>
#include <i386/isa/nvram.h>
+#ifdef VM86
+#include <machine/vm86.h>
+#endif
+
#include "isa.h"
#include "npx.h"
#if NNPX > 0
@@ -537,6 +541,8 @@ sendsig(catcher, sig, mask, code)
/*
* Build the signal context to be used by sigreturn.
*/
+ frame.sf_sc.sc_err = tf->tf_err;
+ frame.sf_sc.sc_trapno = tf->tf_trapno;
frame.sf_sc.sc_onstack = oonstack;
frame.sf_sc.sc_mask = mask;
#ifdef VM86
@@ -545,6 +551,9 @@ sendsig(catcher, sig, mask, code)
frame.sf_sc.sc_fs = tf->tf_vm86_fs;
frame.sf_sc.sc_es = tf->tf_vm86_es;
frame.sf_sc.sc_ds = tf->tf_vm86_ds;
+ frame.sf_sc.sc_eflags = tf->tf_eflags;
+ SETFLAGS(frame.sf_sc.sc_eflags, VM86_EFLAGS(p),
+ VM86_FLAGMASK(p)|PSL_VIF);
} else
#endif
{
@@ -552,19 +561,19 @@ sendsig(catcher, sig, mask, code)
__asm("movl %%fs,%w0" : "=r" (frame.sf_sc.sc_fs));
frame.sf_sc.sc_es = tf->tf_es;
frame.sf_sc.sc_ds = tf->tf_ds;
+ frame.sf_sc.sc_eflags = tf->tf_eflags;
}
- frame.sf_sc.sc_edi = tf->tf_edi;
- frame.sf_sc.sc_esi = tf->tf_esi;
- frame.sf_sc.sc_ebp = tf->tf_ebp;
- frame.sf_sc.sc_ebx = tf->tf_ebx;
- frame.sf_sc.sc_edx = tf->tf_edx;
- frame.sf_sc.sc_ecx = tf->tf_ecx;
- frame.sf_sc.sc_eax = tf->tf_eax;
- frame.sf_sc.sc_eip = tf->tf_eip;
- frame.sf_sc.sc_cs = tf->tf_cs;
- frame.sf_sc.sc_eflags = tf->tf_eflags;
- frame.sf_sc.sc_esp = tf->tf_esp;
- frame.sf_sc.sc_ss = tf->tf_ss;
+ frame.sf_sc.sc_edi = tf->tf_edi;
+ frame.sf_sc.sc_esi = tf->tf_esi;
+ frame.sf_sc.sc_ebp = tf->tf_ebp;
+ frame.sf_sc.sc_ebx = tf->tf_ebx;
+ frame.sf_sc.sc_edx = tf->tf_edx;
+ frame.sf_sc.sc_ecx = tf->tf_ecx;
+ frame.sf_sc.sc_eax = tf->tf_eax;
+ frame.sf_sc.sc_eip = tf->tf_eip;
+ frame.sf_sc.sc_cs = tf->tf_cs;
+ frame.sf_sc.sc_esp = tf->tf_esp;
+ frame.sf_sc.sc_ss = tf->tf_ss;
if (copyout(&frame, fp, sizeof(frame)) != 0) {
/*
@@ -578,14 +587,16 @@ sendsig(catcher, sig, mask, code)
/*
* Build context to run handler in.
*/
- tf->tf_esp = (int)fp;
+ __asm("movl %w0,%%gs" : : "r" (GSEL(GUDATA_SEL, SEL_UPL)));
+ __asm("movl %w0,%%fs" : : "r" (GSEL(GUDATA_SEL, SEL_UPL)));
+ tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
+ tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
tf->tf_eip = (int)(((char *)PS_STRINGS) - (esigcode - sigcode));
+ tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
#ifdef VM86
tf->tf_eflags &= ~PSL_VM;
#endif
- tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
- tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
- tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
+ tf->tf_esp = (int)fp;
tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL);
}
@@ -646,25 +657,28 @@ sys_sigreturn(p, v, retval)
tf->tf_vm86_fs = context.sc_fs;
tf->tf_vm86_es = context.sc_es;
tf->tf_vm86_ds = context.sc_ds;
+ tf->tf_eflags = context.sc_eflags;
+ SETFLAGS(VM86_EFLAGS(p), context.sc_eflags,
+ VM86_FLAGMASK(p)|PSL_VIF);
} else
#endif
{
/* %fs and %gs were restored by the trampoline. */
tf->tf_es = context.sc_es;
tf->tf_ds = context.sc_ds;
+ tf->tf_eflags = context.sc_eflags;
}
- tf->tf_edi = context.sc_edi;
- tf->tf_esi = context.sc_esi;
- tf->tf_ebp = context.sc_ebp;
- tf->tf_ebx = context.sc_ebx;
- tf->tf_edx = context.sc_edx;
- tf->tf_ecx = context.sc_ecx;
- tf->tf_eax = context.sc_eax;
- tf->tf_eip = context.sc_eip;
- tf->tf_cs = context.sc_cs;
- tf->tf_eflags = context.sc_eflags;
- tf->tf_esp = context.sc_esp;
- tf->tf_ss = context.sc_ss;
+ tf->tf_edi = context.sc_edi;
+ tf->tf_esi = context.sc_esi;
+ tf->tf_ebp = context.sc_ebp;
+ tf->tf_ebx = context.sc_ebx;
+ tf->tf_edx = context.sc_edx;
+ tf->tf_ecx = context.sc_ecx;
+ tf->tf_eax = context.sc_eax;
+ tf->tf_eip = context.sc_eip;
+ tf->tf_cs = context.sc_cs;
+ tf->tf_esp = context.sc_esp;
+ tf->tf_ss = context.sc_ss;
return (EJUSTRETURN);
}
diff --git a/sys/arch/i386/i386/sys_machdep.c b/sys/arch/i386/i386/sys_machdep.c
index 22dbb2cc21f..412f5f128a9 100644
--- a/sys/arch/i386/i386/sys_machdep.c
+++ b/sys/arch/i386/i386/sys_machdep.c
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_machdep.c,v 1.25.2.1 1995/10/15 06:54:02 mycroft Exp $ */
+/* $NetBSD: sys_machdep.c,v 1.27 1996/01/08 13:51:36 mycroft Exp $ */
/*-
* Copyright (c) 1995 Charles M. Hannum. All rights reserved.
@@ -66,6 +66,10 @@
#include <machine/reg.h>
#include <machine/sysarch.h>
+#ifdef VM86
+#include <machine/vm86.h>
+#endif
+
extern vm_map_t kernel_map;
#ifdef TRACE
@@ -270,6 +274,14 @@ i386_set_ldt(p, args, retval)
if (n == fsslot || n == gsslot)
return (EBUSY);
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)
+ return (EACCES);
+ break;
case SDT_MEMRO:
case SDT_MEMROA:
case SDT_MEMRW:
@@ -411,6 +423,12 @@ sys_sysarch(p, v, retval)
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
+
default:
error = EINVAL;
break;
diff --git a/sys/arch/i386/i386/trap.c b/sys/arch/i386/i386/trap.c
index fb69df71a30..f6feb3f1faf 100644
--- a/sys/arch/i386/i386/trap.c
+++ b/sys/arch/i386/i386/trap.c
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.91 1995/12/09 05:00:27 mycroft Exp $ */
+/* $NetBSD: trap.c,v 1.92 1996/01/08 13:51:38 mycroft Exp $ */
#undef DEBUG
#define DEBUG
@@ -262,9 +262,15 @@ trap(frame)
frame.tf_eip = resume;
return;
+ case T_PROTFLT|T_USER: /* protection fault */
+#ifdef VM86
+ if (frame.tf_eflags & PSL_VM) {
+ vm86_gpfault(p, type & ~T_USER);
+ goto out;
+ }
+#endif
case T_SEGNPFLT|T_USER:
case T_STKFLT|T_USER:
- case T_PROTFLT|T_USER: /* protection fault */
case T_ALIGNFLT|T_USER:
trapsignal(p, SIGBUS, type &~ T_USER);
goto out;
@@ -521,6 +527,17 @@ syscall(frame)
#endif
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
diff --git a/sys/arch/i386/i386/vm86.c b/sys/arch/i386/i386/vm86.c
new file mode 100644
index 00000000000..5797db43e50
--- /dev/null
+++ b/sys/arch/i386/i386/vm86.c
@@ -0,0 +1,490 @@
+/* $NetBSD: vm86.c,v 1.3 1996/01/08 22:23:35 mycroft 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.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/signalvar.h>
+#include <sys/kernel.h>
+#include <sys/map.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/callout.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 return_to_32bit __P((struct proc *, int));
+static void fast_intxx __P((struct proc *, int));
+
+#define SETDIRECT ((~(PSL_USERSTATIC|PSL_NT)) & 0xffff)
+#define GETDIRECT (SETDIRECT|0x02a) /* add in two MBZ bits */
+
+#define IP(tf) (*(u_short *)&tf->tf_eip)
+#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(nr, bitmap)
+ int nr;
+ caddr_t bitmap;
+{
+ u_int byte; /* bt instruction doesn't do
+ bytes--it examines ints! */
+ bitmap += nr / NBBY;
+ nr = nr % NBBY;
+ byte = fubyte(bitmap);
+
+ __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
+ :"=r" (nr)
+ :"r" (byte),"r" (nr));
+ return (nr);
+}
+
+
+static __inline__ void
+set_vif(p)
+ struct proc *p;
+{
+
+ VM86_EFLAGS(p) |= PSL_VIF;
+ if (VM86_EFLAGS(p) & PSL_VIP)
+ return_to_32bit(p, VM86_STI);
+}
+
+static __inline__ void
+set_vflags(p, flags)
+ struct proc *p;
+ int flags;
+{
+ struct trapframe *tf = p->p_md.md_regs;
+
+ SETFLAGS(VM86_EFLAGS(p), flags, VM86_FLAGMASK(p));
+ SETFLAGS(tf->tf_eflags, flags, SETDIRECT);
+ if (flags & PSL_I)
+ set_vif(p);
+}
+
+static __inline__ void
+set_vflags_short(p, flags)
+ struct proc *p;
+ int flags;
+{
+ struct trapframe *tf = p->p_md.md_regs;
+
+ SETFLAGS(VM86_EFLAGS(p), flags, VM86_FLAGMASK(p) & 0xffff);
+ SETFLAGS(tf->tf_eflags, flags, SETDIRECT);
+ if (flags & PSL_I)
+ set_vif(p);
+}
+
+static __inline__ int
+get_vflags(p)
+ struct proc *p;
+{
+ struct trapframe *tf = p->p_md.md_regs;
+ int flags = 0;
+
+ SETFLAGS(flags, VM86_EFLAGS(p), VM86_FLAGMASK(p));
+ SETFLAGS(flags, tf->tf_eflags, GETDIRECT);
+ if (VM86_EFLAGS(p) & PSL_VIF)
+ flags |= PSL_I;
+ return (flags);
+}
+
+
+#define V86_AH(regs) (((u_char *)&((regs)->tf_eax))[1])
+#define V86_AL(regs) (((u_char *)&((regs)->tf_eax))[0])
+
+static void
+fast_intxx(p, intrno)
+ 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_short cs;
+ u_long ss, sp;
+
+ /*
+ * Note: u_vm86p points to user-space, we only compute offsets
+ * and don't deref it. is_revectored() above does fubyte() to
+ * get stuff from it
+ */
+ u_vm86p = (struct vm86_struct *)p->p_addr->u_pcb.vm86_userp;
+
+ /*
+ * If coming from BIOS segment, or going to BIOS segment, or user
+ * requested special handling, return to user space with indication
+ * of which INT was requested.
+ */
+ cs = tf->tf_cs;
+ if (cs == BIOSSEG || 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;
+
+ if (ihand.cs == BIOSSEG)
+ goto vector;
+
+ /*
+ * Otherwise, push flags, cs, eip, and jump to handler to
+ * simulate direct INT call.
+ */
+ ss = tf->tf_ss << 4;
+ sp = SP(tf);
+
+ putword(ss, sp, get_vflags(p));
+ putword(ss, sp, tf->tf_cs);
+ putword(ss, sp, IP(tf));
+ SP(tf) = sp;
+
+ IP(tf) = ihand.ip;
+ tf->tf_cs = ihand.cs;
+
+ /* disable further "hardware" interrupts, turn off any tracing. */
+ VM86_EFLAGS(p) &= ~PSL_VIF;
+ tf->tf_eflags &= ~PSL_VIF|PSL_T;
+ return;
+
+vector:
+ return_to_32bit(p, VM86_MAKEVAL(VM86_INTx, intrno));
+ return;
+
+bad:
+ return_to_32bit(p, VM86_UNKNOWN);
+ return;
+}
+
+static void
+return_to_32bit(p, retval)
+ struct proc *p;
+ int retval;
+{
+
+ /*
+ * 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 */
+ }
+ trapsignal(p, SIGURG, retval);
+}
+
+#define CLI 0xFA
+#define STI 0xFB
+#define INTxx 0xCD
+#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(p, type)
+ struct proc *p;
+ int type;
+{
+ struct trapframe *tf = p->p_md.md_regs;
+ /*
+ * 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_char tmpbyte;
+ u_long cs, ip, ss, sp;
+
+ cs = tf->tf_cs << 4;
+ ip = IP(tf);
+ ss = tf->tf_ss << 4;
+ sp = SP(tf);
+
+ /*
+ * For most of these, we must set all the registers before calling
+ * macros/functions which might do a return_to_32bit.
+ */
+ tmpbyte = getbyte(cs, ip);
+ IP(tf) = ip;
+ switch (tmpbyte) {
+ case CLI:
+ /* simulate handling of IF */
+ VM86_EFLAGS(p) &= ~PSL_VIF;
+ tf->tf_eflags &= ~PSL_VIF;
+ 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 PUSHF:
+ putword(ss, sp, get_vflags(p));
+ SP(tf) = sp;
+ break;
+
+ case IRET:
+ IP(tf) = getword(ss, sp);
+ tf->tf_cs = 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));
+ SP(tf) = sp;
+ break;
+
+ case IRET:
+ IP(tf) = getdword(ss, sp);
+ tf->tf_cs = getdword(ss, sp);
+ case POPF:
+ set_vflags(p, getdword(ss, sp));
+ SP(tf) = sp;
+ break;
+
+ default:
+ IP(tf) -= 2;
+ goto bad;
+ }
+ break;
+
+ case LOCK:
+ default:
+ IP(tf) -= 1;
+ goto bad;
+ }
+ return;
+
+bad:
+ return_to_32bit(p, VM86_UNKNOWN);
+ return;
+}
+
+int
+i386_vm86(p, args, retval)
+ struct proc *p;
+ char *args;
+ register_t *retval;
+{
+ struct trapframe *tf = p->p_md.md_regs;
+ struct vm86_kern vm86s;
+ int err;
+
+ if (err = copyin(args, &vm86s, sizeof(vm86s)))
+ return err;
+
+ p->p_addr->u_pcb.vm86_userp = (void *)args;
+
+#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
+
+ SETFLAGS(VM86_EFLAGS(p), vm86s.regs.vmsc.sc_eflags, VM86_FLAGMASK(p)|PSL_VIF);
+ SETFLAGS(tf->tf_eflags, vm86s.regs.vmsc.sc_eflags, SETDIRECT);
+ tf->tf_eflags |= PSL_VM;
+
+ /*
+ * 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:
+ VM86_FLAGMASK(p) = 0;
+ break;
+ case VCPU_386:
+ VM86_FLAGMASK(p) = PSL_NT|PSL_IOPL;
+ break;
+ case VCPU_486:
+ VM86_FLAGMASK(p) = PSL_AC|PSL_NT|PSL_IOPL;
+ break;
+ case VCPU_586:
+ default:
+ VM86_FLAGMASK(p) = PSL_ID|PSL_AC|PSL_NT|PSL_IOPL;
+ break;
+ }
+
+ /* Going into vm86 mode jumps off the signal stack. */
+ p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
+
+ return (EJUSTRETURN);
+}
diff --git a/sys/arch/i386/include/pcb.h b/sys/arch/i386/include/pcb.h
index 1cb5ad46318..3cff2b28c2d 100644
--- a/sys/arch/i386/include/pcb.h
+++ b/sys/arch/i386/include/pcb.h
@@ -1,4 +1,4 @@
-/* $NetBSD: pcb.h,v 1.20 1995/10/11 04:20:16 mycroft Exp $ */
+/* $NetBSD: pcb.h,v 1.21 1996/01/08 13:51:42 mycroft Exp $ */
/*-
* Copyright (c) 1995 Charles M. Hannum. All rights reserved.
@@ -53,6 +53,8 @@
#include <machine/npx.h>
#include <machine/sysarch.h>
+#define NIOPORTS 1024 /* # of ports we allow to be mapped */
+
struct pcb {
struct i386tss pcb_tss;
#define pcb_cr3 pcb_tss.tss_cr3
@@ -73,7 +75,10 @@ struct pcb {
int pcb_flags;
#define PCB_USER_LDT 0x01 /* has user-set LDT */
caddr_t pcb_onfault; /* copyin/out fault recovery */
- u_long pcb_iomap[1024/32]; /* I/O bitmap */
+ int vm86_eflags; /* virtual eflags for vm86 mode */
+ int vm86_flagmask; /* flag mask for vm86 mode */
+ void *vm86_userp; /* XXX performance hack */
+ u_long pcb_iomap[NIOPORTS/32]; /* I/O bitmap */
};
/*
diff --git a/sys/arch/i386/include/signal.h b/sys/arch/i386/include/signal.h
index ef3f2b95c15..8e35b78ba28 100644
--- a/sys/arch/i386/include/signal.h
+++ b/sys/arch/i386/include/signal.h
@@ -1,4 +1,4 @@
-/* $NetBSD: signal.h,v 1.5 1995/05/01 14:14:11 mycroft Exp $ */
+/* $NetBSD: signal.h,v 1.6 1996/01/08 13:51:43 mycroft Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
@@ -65,6 +65,7 @@ struct sigcontext {
int sc_edx;
int sc_ecx;
int sc_eax;
+ /* XXX */
int sc_eip;
int sc_cs;
int sc_eflags;
@@ -73,6 +74,9 @@ struct sigcontext {
int sc_onstack; /* sigstack state to restore */
int sc_mask; /* signal mask to restore */
+
+ int sc_trapno; /* XXX should be above */
+ int sc_err;
};
#define sc_sp sc_esp
diff --git a/sys/arch/i386/include/sysarch.h b/sys/arch/i386/include/sysarch.h
index a2f440d775c..e6d5dca475b 100644
--- a/sys/arch/i386/include/sysarch.h
+++ b/sys/arch/i386/include/sysarch.h
@@ -1,4 +1,4 @@
-/* $NetBSD: sysarch.h,v 1.7 1995/10/11 04:20:26 mycroft Exp $ */
+/* $NetBSD: sysarch.h,v 1.8 1996/01/08 13:51:44 mycroft Exp $ */
#ifndef _I386_SYSARCH_H_
#define _I386_SYSARCH_H_
@@ -11,6 +11,7 @@
#define I386_IOPL 2
#define I386_GET_IOPERM 3
#define I386_SET_IOPERM 4
+#define I386_VM86 5
struct i386_get_ldt_args {
int start;
diff --git a/sys/arch/i386/include/vm86.h b/sys/arch/i386/include/vm86.h
new file mode 100644
index 00000000000..1f21db3dbdc
--- /dev/null
+++ b/sys/arch/i386/include/vm86.h
@@ -0,0 +1,79 @@
+/* $NetBSD: vm86.h,v 1.1 1996/01/08 13:51:45 mycroft 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.
+ *
+ */
+
+#define SETFLAGS(targ, new, newmask) (targ) = ((targ) & ~(newmask)) | ((new) & (newmask))
+#define VM86_EFLAGS(p) ((p)->p_addr->u_pcb.vm86_eflags)
+#define VM86_FLAGMASK(p) ((p)->p_addr->u_pcb.vm86_flagmask)
+
+#define VM86_TYPE(x) ((x) & 0xff)
+#define VM86_ARG(x) (((x) & 0xff00) >> 8)
+#define VM86_MAKEVAL(type,arg) ((type) | (((arg) & 0xff) << 8))
+#define VM86_STI 0
+#define VM86_INTx 1
+#define VM86_SIGNAL 2
+#define VM86_UNKNOWN 3
+
+struct vm86_regs {
+ struct sigcontext vmsc;
+};
+
+struct vm86_kern { /* kernel uses this stuff */
+ struct vm86_regs regs;
+ unsigned long ss_cpu_type;
+};
+#define cpu_type substr.ss_cpu_type
+
+/*
+ * Kernel keeps copy of user-mode address of this, but doesn't copy it in.
+ */
+struct vm86_struct {
+ struct vm86_kern substr;
+ unsigned long screen_bitmap; /* not used/supported (yet) */
+ unsigned long flags; /* not used/supported (yet) */
+ unsigned char int_byuser[32]; /* 256 bits each: pass control to user */
+ unsigned char int21_byuser[32]; /* otherwise, handle directly */
+};
+
+#define BIOSSEG 0x0f000
+
+#define VCPU_086 0
+#define VCPU_186 1
+#define VCPU_286 2
+#define VCPU_386 3
+#define VCPU_486 4
+#define VCPU_586 5
+
+#ifdef _KERNEL
+int i386_vm86 __P((struct proc *, char *, register_t *));
+void vm86_gpfault __P((struct proc *, int));
+#else
+int i386_vm86 __P((struct vm86_struct *vmcp));
+#endif