Subject: port-i386/825: no support for Virtual 8086 mode
To: None <gnats-admin@NetBSD.ORG>
From: John Kohl <jtk@kolvir.blrc.ma.us>
List: netbsd-bugs
Date: 02/25/1995 21:20:06
>Number:         825
>Category:       port-i386
>Synopsis:       the i386 port doesn't have support for virtual 8086 mode
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sat Feb 25 21:20:04 1995
>Originator:     John Kohl
>Organization:
NetBSD Kernel Hackers `R` Us
>Release:        -current
>Environment:
	
System: NetBSD kolvir 1.0A NetBSD 1.0A (KOLVIR) #105: Sat Feb 25 23:20:46 EST 1995 jtk@kolvir:/u1/NetBSD-current/src/sys/arch/i386/compile/KOLVIR i386

>Description:
The i386 port doesn't implement v8086 mode.

>How-To-Repeat:
Try using it, or finding an interface for it.

>Fix:

Here is a preliminary implementation.  Known problems:

(a) the syscall glue to get to the alternate interrupt gate is totally
disgusting, but I didn't feel like chewing up SYS.h and the libc build
macros.  Besides, I learned about gcc's asm directives.

(b) The interrupt gate code for the vm86 trap gate is clunky--there is
certainly a more efficient way to jack up the trap frame.

(c) I haven't tested this extensively--there may still be some lurking
problems with interrupts while in v8086 mode?

(d) I rev'ed the minor version on libi386.so (added a function).  Is
this appropriate?

(e) the out-of-band bit passing between Xvm86 and sysarch() is gross
too--maybe there's a better way to do that too?

At the end of the diffs you'll find a program which jumps into a v8086
tight loop.  You should be able to ^C out of it (shows that CPU
rescheduling works), and to give it a SIGQUIT and have it longjmp back
to safety.

===================================================================
RCS file: lib/libarch/RCS/shlib_version,v
retrieving revision 1.1
diff -ubw -r1.1 lib/libarch/shlib_version
--- 1.1	1995/02/25 19:53:55
+++ lib/libarch/shlib_version	1995/02/25 19:54:13
@@ -1,2 +1,2 @@
 major=0
-minor=0
+minor=1
===================================================================
RCS file: lib/libarch/i386/RCS/Makefile.inc,v
retrieving revision 1.1
diff -ubw -r1.1 lib/libarch/i386/Makefile.inc
--- 1.1	1995/02/25 19:43:52
+++ lib/libarch/i386/Makefile.inc	1995/02/25 19:44:11
@@ -2,8 +2,8 @@
 
 .PATH: ${LIBC}/i386
 
-SRCS+=	i386_get_ldt.c i386_set_ldt.c
+SRCS+=	i386_get_ldt.c i386_set_ldt.c i386_vm86.c
 
-MAN+=	i386_get_ldt.2
+MAN+=	i386_get_ldt.2 i386_vm86.2
 
 MLINKS+=i386_get_ldt.2 i386_set_ldt.2
--- /dev/null	Sat Feb 25 23:23:15 1995
+++ lib/libarch/i386/i386_vm86.2	Sat Feb 25 15:29:12 1995
@@ -0,0 +1,66 @@
+.\" Copyright (c) 1980, 1991 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. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"	This product includes software developed by the University of
+.\"	California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     from: @(#)fork.2	6.5 (Berkeley) 3/10/91
+.\"	$Id: i386_vm86.2,v 1.3 1995/02/25 20:29:12 jtk Exp $
+.\"
+.Dd September 20, 1993
+.Dt I386_VM86 2
+.Os NetBSD
+.Sh NAME
+.Nm i386_vm86
+.Nd set virtual 8086 processor registers and mode
+.Sh SYNOPSIS
+.Fd #include <machine/segments.h>
+.Fd #include <machine/sysarch.h>
+.Ft int
+.Fn i386_vm86 "struct vm86_context *vmcp"
+.Sh DESCRIPTION
+.Fn i386_vm86
+will set the process into virtual 8086 mode using the registers and
+selectors specified by the context pointed to by
+.Fa vmcp .
+.Sh RETURN VALUES
+This routine does not normally return--32-bit mode will be restored by
+the delivery of a signal to the process.  In case of an error in setting
+the VM86 mode, a value of -1 is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Fn i386_vm86
+will fail if:
+.Bl -tag -width [EINVAL]
+.It Bq Er EINVAL
+An inappropriate parameter was specified in the signal context.
+.Sh REFERENCES
+i386 Microprocessor Programmer's Reference Manual, Intel
+.Sh WARNING
+You can really hose your process using this.
--- /dev/null	Sat Feb 25 23:23:15 1995
+++ lib/libarch/i386/i386_vm86.c	Sat Feb 25 21:30:13 1995
@@ -0,0 +1,68 @@
+/*
+ *  Copyright (c) 1995 John 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/cdefs.h>
+#include <machine/segments.h>
+#include <machine/sysarch.h>
+#include <errno.h>
+#include <sys/syscall.h>
+
+#define _quote(x) # x
+#define quote(x) _quote(x)
+
+#define concat(a,b) a##b
+
+static int
+int129(int op, void *arg);
+
+__asm(".globl cerror");
+__asm("_int129:");
+__asm("movl $" quote(SYS_sysarch) ",%eax");
+__asm("int $" quote(INT_VM86));
+#ifdef PIC
+    __asm("jc cerror@PLT");
+#else
+    __asm("jc cerror");
+#endif
+__asm("ret");
+
+int
+i386_vm86(register struct vm86_context *vmcp)
+{
+    /* we need a special INT entry into the kernel so that we can
+     * set up the proper stack state to be munged by the trap code
+     * in order to be loaded up by the iret.
+     */
+#if 0
+    __asm(" pushl %0" : : "g" (vmcp));
+    __asm(" pushl $" quote(I386_VM86));
+    return EINVAL;
+#endif
+    return int129(I386_VM86, vmcp);
+}
===================================================================
RCS file: sys/arch/i386/include/RCS/cpu.h,v
retrieving revision 1.1
diff -ubw -r1.1 sys/arch/i386/include/cpu.h
--- 1.1	1995/02/25 20:21:33
+++ sys/arch/i386/include/cpu.h	1995/02/26 03:57:43
@@ -68,7 +68,7 @@
  */
 #define clockframe intrframe
 
-#define	CLKF_USERMODE(frame)	(ISPL((frame)->if_cs) == SEL_UPL)
+#define	CLKF_USERMODE(frame)	(ISPL((frame)->if_cs) == SEL_UPL || ((frame)->if_eflags & PSL_VM))
 #define	CLKF_BASEPRI(frame)	((frame)->if_ppl == 0)
 #define	CLKF_PC(frame)		((frame)->if_eip)
 #define	CLKF_INTR(frame)	(0)	/* XXX should have an interrupt stack */
===================================================================
RCS file: sys/arch/i386/include/RCS/frame.h,v
retrieving revision 1.1
diff -ubw -r1.1 sys/arch/i386/include/frame.h
--- 1.1	1995/02/25 22:27:19
+++ sys/arch/i386/include/frame.h	1995/02/26 02:15:50
@@ -91,6 +91,19 @@
 	int	if_ss;
 };
 
+struct vm86_frame {
+    struct trapframe tframe;
+    int vm_es;
+    int vm_ds;
+    int vm_fs;
+    int vm_gs;
+};
+/*
+ * A kludge for locore to tell the sysarch() handler that this
+ * trap has a VM86 mode frame.
+ */
+#define	VM86_TRAP	0x80000000
+
 /*
  * Signal frame
  */
===================================================================
RCS file: sys/arch/i386/include/RCS/sysarch.h,v
retrieving revision 1.1
diff -ubw -r1.1 sys/arch/i386/include/sysarch.h
--- 1.1	1995/02/25 19:38:01
+++ sys/arch/i386/include/sysarch.h	1995/02/25 22:01:34
@@ -8,10 +8,35 @@
  */
 #define I386_GET_LDT	0
 #define I386_SET_LDT	1
+#define I386_VM86	2
+
+#define INT_VM86	0x81		/* special interrupt gate # */
+
+struct	vm86_context {
+	int	sc_edi;
+	int	sc_esi;
+	int	sc_ebp;
+	int	sc_ebx;
+	int	sc_edx;
+	int	sc_ecx;
+	int	sc_eax;
+    /* hardware stack frame for vm86 iret: */
+	int	sc_eip;
+	int	sc_cs;
+	int	sc_eflags;
+	int	sc_esp;
+	int	sc_ss;
+    /* extra vm86 stuff is: */
+	int	sc_es;
+	int	sc_ds;
+	int	sc_fs;
+	int	sc_gs;
+};
 
 #ifndef KERNEL
 int i386_get_ldt __P((int, union descriptor *, int));
 int i386_set_ldt __P((int, union descriptor *, int));
+int i386_vm86 __P((struct vm86_context *));
 #endif
 
 #endif /* !_I386_SYSARCH_H_ */
===================================================================
RCS file: sys/arch/i386/isa/RCS/icu.s,v
retrieving revision 1.1
diff -ubw -r1.1 sys/arch/i386/isa/icu.s
--- 1.1	1995/02/26 04:15:16
+++ sys/arch/i386/isa/icu.s	1995/02/26 04:16:20
@@ -132,8 +132,10 @@
 	cmpb	$0,_astpending
 	je	3f
 	testb   $SEL_RPL_MASK,TF_CS(%esp)
+	jnz	4f
+	testl	$PSL_VM,TF_EFLAGS(%esp)
 	jz	3f
-	movb	$0,_astpending
+4:	movb	$0,_astpending
 	sti
 	/* Pushed T_ASTFLT into tf_trapno on entry. */
 	call	_trap
===================================================================
RCS file: sys/arch/i386/isa/RCS/npx.c,v
retrieving revision 1.1
diff -ubw -r1.1 sys/arch/i386/isa/npx.c
--- 1.1	1995/02/25 20:21:56
+++ sys/arch/i386/isa/npx.c	1995/02/25 23:44:34
@@ -419,7 +419,8 @@
 	 * Pass exception to process.  If it's the current process, try to do
 	 * it immediately.
 	 */
-	if (p == curproc && ISPL(frame->if_cs) == SEL_UPL) {
+	if (p == curproc &&
+	    (ISPL(frame->if_cs) == SEL_UPL || (frame->if_eflags & PSL_VM))) {
 		/*
 		 * Interrupt is essentially a trap, so we can afford to call
 		 * the SIGFPE handler (if any) as soon as the interrupt
===================================================================
RCS file: sys/arch/i386/i386/RCS/db_interface.c,v
retrieving revision 1.2
diff -ubw -r1.2 sys/arch/i386/i386/db_interface.c
--- 1.2	1995/01/30 02:58:58
+++ sys/arch/i386/i386/db_interface.c	1995/02/25 20:23:17
@@ -79,7 +79,7 @@
 	/* XXX Should switch to kdb`s own stack here. */
 
 	ddb_regs = *regs;
-	if (ISPL(regs->tf_cs) == SEL_KPL) {
+	if (ISPL(regs->tf_cs) == SEL_KPL && !(regs->tf_eflags & PSL_VM)) {
 		/*
 		 * Kernel mode - esp and ss not saved
 		 */
@@ -107,7 +107,7 @@
 	regs->tf_eip    = ddb_regs.tf_eip;
 	regs->tf_cs     = ddb_regs.tf_cs;
 	regs->tf_eflags = ddb_regs.tf_eflags;
-	if (ISPL(regs->tf_cs) != SEL_KPL) {
+	if (ISPL(regs->tf_cs) != SEL_KPL || (regs->tf_eflags & PSL_VM)) {
 		/* ring transit - saved esp and ss valid */
 		regs->tf_esp    = ddb_regs.tf_esp;
 		regs->tf_ss     = ddb_regs.tf_ss;
===================================================================
RCS file: sys/arch/i386/i386/RCS/locore.s,v
retrieving revision 1.1
diff -ubw -r1.1 sys/arch/i386/i386/locore.s
--- 1.1	1995/02/26 04:18:17
+++ sys/arch/i386/i386/locore.s	1995/02/26 04:19:02
@@ -63,7 +63,7 @@
 #define	IOM_BEGIN	0x0a0000	/* start of I/O memory "hole" */
 #define	IOM_END		0x100000	/* end of I/O memory "hole" */
 #define	IOM_SIZE	(IOM_END - IOM_BEGIN)
-
+#define	VM86_TRAP	0x80000000	/* see frame.h ?? */
 
 #define	ALIGN_DATA	.align	2
 #define	ALIGN_TEXT	.align	2,0x90	/* 4-byte boundaries, NOP-filled */
@@ -1973,8 +1973,10 @@
 	cmpb	$0,_astpending
 	je	1f
 	testb	$SEL_RPL_MASK,TF_CS(%esp)
+	jnz	5f
+	testl	$PSL_VM,TF_EFLAGS(%esp)
 	jz	1f
-	movb	$0,_astpending
+5:	movb	$0,_astpending
 	sti
 	movl	$T_ASTFLT,TF_TRAPNO(%esp)
 	call	_trap
@@ -2062,6 +2064,45 @@
 4:	.asciz	"WARNING: SPL NOT LOWERED ON SYSCALL EXIT\n"
 #endif /* DIAGNOSTIC */
 
+	/*
+	 * For VM86 support, we need a special gate that makes room
+	 * on the kernel-mode stack for the extra selectors (gs,fs,ds,es)
+	 * The user-space expects it to behave like the syscall interrupt,
+	 * and calls the sysarch() syscall.
+	 */
+IDTVEC(vm86)
+	cmpl	$SYS_sysarch,%eax
+	jne	1f		# only jack the stack for sysarch
+	testl	$PSL_VM,8(%esp)
+	jnz	1f		# don't jack if already VM86 mode
+	/* We need to jack up the existing stack frame by 4 longwords, */
+	/* and shift the existing 5 longword args to the new top. */
+	subl	$0x10,%esp
+	movl    0x10(%esp),%eax
+	movl	%eax,(%esp)
+	movl    0x14(%esp),%eax
+	movl	%eax,0x4(%esp)
+	movl    0x18(%esp),%eax
+	movl	%eax,0x8(%esp)
+	movl    0x1c(%esp),%eax
+	movl	%eax,0xc(%esp)
+	movl    0x20(%esp),%eax
+	movl	%eax,0x10(%esp)
+	/* and zero out what was there */
+	movl	$0,0x14(%esp)
+	movl	$0,0x18(%esp)
+	movl	$0,0x1c(%esp)
+	movl	$0,0x20(%esp)
+	/* leave marker for sysarch to test in the frame
+	   (unused bits of CS word) */
+	movl	4(%esp),%eax
+	orl	$VM86_TRAP,%eax
+	movl	%eax,4(%esp)
+	movl	$SYS_sysarch,%eax
+1:	
+	pushl	$2		# size of instruction for restart
+	jmp syscall1		# go do real syscall
+	
 #include <i386/isa/vector.s>
 #include <i386/isa/icu.s>
 
===================================================================
RCS file: sys/arch/i386/i386/RCS/machdep.c,v
retrieving revision 1.4
diff -ubw -r1.4 sys/arch/i386/i386/machdep.c
--- 1.4	1995/02/04 14:41:07
+++ sys/arch/i386/i386/machdep.c	1995/02/25 23:23:12
@@ -1004,7 +1004,7 @@
 	IDTVEC(dble),    IDTVEC(fpusegm), IDTVEC(tss),     IDTVEC(missing),
 	IDTVEC(stk),     IDTVEC(prot),    IDTVEC(page),    IDTVEC(rsvd),
 	IDTVEC(fpu),     IDTVEC(align),
-	IDTVEC(syscall), IDTVEC(osyscall);
+	IDTVEC(syscall), IDTVEC(osyscall), IDTVEC(vm86);
 
 void
 sdtossd(sd, ssd)
@@ -1087,6 +1087,7 @@
 	setgate(&idt[ 16], &IDTVEC(fpu),     0, SDT_SYS386TGT, SEL_KPL);
 	setgate(&idt[ 17], &IDTVEC(align),   0, SDT_SYS386TGT, SEL_KPL);
 	setgate(&idt[128], &IDTVEC(syscall), 0, SDT_SYS386TGT, SEL_UPL);
+	setgate(&idt[129], &IDTVEC(vm86),    0, SDT_SYS386TGT, SEL_UPL);
 
 #if NISA > 0
 	isa_defaultirq();
===================================================================
RCS file: sys/arch/i386/i386/RCS/math_emulate.c,v
retrieving revision 1.1
diff -ubw -r1.1 sys/arch/i386/i386/math_emulate.c
--- 1.1	1995/02/25 20:04:28
+++ sys/arch/i386/i386/math_emulate.c	1995/02/25 20:05:03
@@ -75,7 +75,7 @@
 	char * address;
 	u_long oldeip;
 
-	if (ISPL(info->tf_cs) != SEL_UPL)
+	if (ISPL(info->tf_cs) != SEL_UPL && !(frame.tf_eflags & PSL_VM))
 		panic("math emulator called from supervisor mode");
 
 	/* ever used fp? */
===================================================================
RCS file: sys/arch/i386/i386/RCS/sys_machdep.c,v
retrieving revision 1.1
diff -ubw -r1.1 sys/arch/i386/i386/sys_machdep.c
--- 1.1	1995/02/25 19:39:33
+++ sys/arch/i386/i386/sys_machdep.c	1995/02/26 02:49:28
@@ -322,6 +322,63 @@
 #endif	/* USER_LDT */
 
 int
+i386_set_vm86mode(p, vmcp)
+	struct proc *p;
+	struct vm86_context *vmcp;
+{
+    struct vm86_frame *vf;
+    struct trapframe *tf;
+    int error;
+    struct vm86_context vmcontext;
+
+    if (error = copyin(vmcp, &vmcontext, sizeof(vmcontext)))
+	return(error);
+
+    vmcp = &vmcontext;
+
+    if (p->p_addr->u_pcb.pcb_psl & PSL_VM)
+	return EINVAL;			/* already there??! */
+    vf = (struct vm86_frame *)p->p_md.md_regs;
+    tf = &vf->tframe;
+
+    printf("vf=%lx, esp=%lx, ss=%lx\n", vf, tf->tf_esp, tf->tf_ss);
+    printf("es=%lx,ds=%lx,fs=%lx,gs=%lx\n",
+	   vf->vm_es, vf->vm_ds, vf->vm_fs, vf->vm_gs);
+    /*
+     * Check for security violations.  Only let them diddle PSL_VM bit.
+     * They must set PSL_VM bit, it must not be on.
+     */
+    if ((vmcp->sc_eflags & PSL_VM) == 0 || (tf->tf_eflags & PSL_VM) != 0 ||
+	((vmcp->sc_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != PSL_VM)
+	return (EINVAL);
+
+    /*
+     * Restore signal context.
+     */
+/*    tf->tf_es     = vmcp->sc_es;*/
+/*    tf->tf_ds     = vmcp->sc_ds;*/
+    tf->tf_edi    = vmcp->sc_edi;
+    tf->tf_esi    = vmcp->sc_esi;
+    tf->tf_ebp    = vmcp->sc_ebp;
+    tf->tf_ebx    = vmcp->sc_ebx;
+    tf->tf_edx    = vmcp->sc_edx;
+    tf->tf_ecx    = vmcp->sc_ecx;
+    tf->tf_eax    = vmcp->sc_eax;
+    tf->tf_eip    = vmcp->sc_eip;
+    tf->tf_cs     = vmcp->sc_cs;
+    tf->tf_eflags = vmcp->sc_eflags;
+    tf->tf_esp    = vmcp->sc_esp;
+    tf->tf_ss     = vmcp->sc_ss;
+
+    vf->vm_es = vmcp->sc_es;
+    vf->vm_ds = vmcp->sc_ds;
+    vf->vm_fs = vmcp->sc_fs;
+    vf->vm_gs = vmcp->sc_gs;
+    
+    return (EJUSTRETURN);
+}
+
+int
 sysarch(p, uap, retval)
 	struct proc *p;
 	struct sysarch_args /* {
@@ -331,7 +388,20 @@
 	register_t *retval;
 {
 	int error = 0;
+	struct trapframe *tf;
+
+	tf = (struct trapframe *)p->p_md.md_regs;
+	if (tf->tf_cs & VM86_TRAP) {	/* marker for vm86 jacked stack */
+	    tf->tf_cs &= ~VM86_TRAP;
 
+	    printf("vm86: tf %lx endtf %lx\n", tf, tf+1);
+	    printf("op=%x,parms=%x\n", SCARG(uap,op), SCARG(uap,parms));
+	    if (SCARG(uap,op) == I386_VM86)
+		error = i386_set_vm86mode(p, (struct vm86_context *)SCARG(uap, parms));
+	    else
+		error = EINVAL;		/* XXX can we go back and not die? */
+	    printf("vm86: returning %d\n", error);
+	}
 	switch(SCARG(uap, op)) {
 #ifdef	USER_LDT
 	case I386_GET_LDT: 
@@ -342,6 +412,7 @@
 		error = i386_set_ldt(p, SCARG(uap, parms), retval);
 		break;
 #endif
+	case I386_VM86:
 	default:
 		error = EINVAL;
 		break;
===================================================================
RCS file: sys/arch/i386/i386/RCS/trap.c,v
retrieving revision 1.1
diff -ubw -r1.1 sys/arch/i386/i386/trap.c
--- 1.1	1995/02/25 20:03:49
+++ sys/arch/i386/i386/trap.c	1995/02/25 20:18:26
@@ -179,7 +179,7 @@
 	}
 #endif
 
-	if (ISPL(frame.tf_cs) != SEL_KPL) {
+	if (ISPL(frame.tf_cs) != SEL_KPL || (frame.tf_eflags & PSL_VM)) {
 		type |= T_USER;
 		sticks = p->p_sticks;
 		p->p_md.md_regs = (int *)&frame;
@@ -500,8 +500,9 @@
 	extern struct sysent ibcs2_sysent[];
 #endif
 
+
 	cnt.v_syscall++;
-	if (ISPL(frame.tf_cs) != SEL_UPL)
+	if (ISPL(frame.tf_cs) != SEL_UPL && !(frame.tf_eflags & PSL_VM))
 		panic("syscall");
 	p = curproc;
 	sticks = p->p_sticks;
@@ -539,6 +540,9 @@
 #endif
 	}
 
+	if (frame.tf_eflags & PSL_VM)
+	    code = -1;
+	else
 	switch (code) {
 	case SYS_syscall:
 		code = fuword(params);
--- /dev/null	Sat Feb 25 23:23:15 1995
+++ /var/tmp/Makefile	Sat Feb 25 23:27:57 1995
@@ -0,0 +1,2 @@
+sigill: sigill.c
+	$(CC) -static -I/usr/include.current -g -o sigill sigill.c -li386
--- /dev/null	Sat Feb 25 23:23:15 1995
+++ /var/tmp/sigill.c	Sat Feb 25 23:26:52 1995
@@ -0,0 +1,57 @@
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <setjmp.h>
+#include <machine/segments.h>
+#include <machine/sysarch.h>
+#include <machine/psl.h>
+
+jmp_buf jbuf;
+
+void
+sigill(int sig, int code, struct sigcontext *scp)
+{
+    printf("sig %d, code %d, eip %#08lx, eflags=%#08lx\n",
+	   sig, code, scp->sc_eip, scp->sc_eflags);
+    longjmp(jbuf, 1);
+    _exit(2);
+}
+
+unsigned long vmstack[256];
+
+unsigned char ill[] = { 144, 144, 144, 0xeb, 0xfb /* nop, nop, nop, loop */ };
+
+foo()
+{
+    asm("1: nop; nop; nop");
+    asm("jmp 1b");
+}
+
+main()
+{
+    struct vm86_context vmctx;
+    int rval;
+    int psl;
+
+    signal(SIGILL, sigill);
+    signal(SIGBUS, sigill);
+    signal(SIGQUIT, sigill);
+    memset(&vmctx, 0, sizeof(vmctx));
+
+
+    vmctx.sc_esp = (int) &vmstack[sizeof(vmstack)/4-1];
+    vmctx.sc_eip = (int) &ill[0];
+    vmctx.sc_cs = 0;
+    __asm("pushfl");
+    __asm("popl %0" : "=r" (psl));
+    vmctx.sc_eflags = psl | PSL_VM;
+
+    if (setjmp(jbuf)) {
+	printf("jumped out of sighandler, exiting\n");
+	exit(2);
+    }
+    rval = i386_vm86(&vmctx);
+    printf("returning from vm86 with rval=%d?\n", rval);
+    exit(1);
+}
+
>Audit-Trail:
>Unformatted: