Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/sommerfeld_i386mp_1]: src/sys/arch/i386/i386 handle IDT-less case just a...



details:   https://anonhg.NetBSD.org/src/rev/f50994148677
branches:  sommerfeld_i386mp_1
changeset: 482555:f50994148677
user:      itojun <itojun%NetBSD.org@localhost>
date:      Mon Jun 24 10:10:18 2002 +0000

description:
handle IDT-less case just as linux does

diffstat:

 sys/arch/i386/i386/vm86.c |  413 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 413 insertions(+), 0 deletions(-)

diffs (truncated from 417 to 300 lines):

diff -r 04b15f519056 -r f50994148677 sys/arch/i386/i386/vm86.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/i386/i386/vm86.c Mon Jun 24 10:10:18 2002 +0000
@@ -0,0 +1,413 @@
+/*     $NetBSD: vm86.c,v 1.27.2.2 2002/06/24 10:10:18 itojun 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: vm86.c,v 1.27.2.2 2002/06/24 10:10:18 itojun Exp $");
+
+#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/syscallargs.h>
+#include <sys/ktrace.h>
+
+#include <machine/sysarch.h>
+#include <machine/vm86.h>
+
+static void fast_intxx __P((struct proc *, int));
+static __inline int is_bitset __P((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) \
+       ({ ptr = (ptr - 1) & 0xffff;                    \
+          subyte((void *)(base+ptr), (val>>8));                        \
+           ptr = (ptr - 1) & 0xffff;                   \
+          subyte((void *)(base+ptr), (val&0xff)); })
+
+#define putdword(base, ptr, val) \
+       ({ putword(base, ptr, (val >> 16));             \
+          putword(base, ptr, (val & 0xffff)); })
+
+#define getbyte(base, ptr) \
+       ({ unsigned long __tmp = fubyte((void *)(base+ptr));     \
+          if (__tmp == ~0) goto bad;                            \
+          ptr = (ptr + 1) & 0xffff; __tmp; })
+
+#define getword(base, ptr) \
+       ({ unsigned long __tmp = getbyte(base, ptr);    \
+          __tmp |= (getbyte(base, ptr) << 8); __tmp;})
+
+#define getdword(base, ptr) \
+       ({ unsigned long __tmp = getword(base, ptr);    \
+          __tmp |= (getword(base, ptr) << 16); __tmp;})
+
+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);
+}
+
+
+#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_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 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))) {
+               /*
+                * No IDT!  What Linux does here is simply call back into
+                * userspace with the VM86_INTx arg as if it was a revectored
+                * int.  Some applications rely on this (i.e. dynamically
+                * emulate an IDT), and those that don't will crash in a
+                * spectacular way, I suppose.
+                *      --thorpej%netbsd.org@localhost
+                */
+               goto vector;
+       }
+
+       /*
+        * 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;
+}
+
+void
+vm86_return(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 (sigismember(&p->p_sigctx.ps_sigmask, SIGURG)) {
+#ifdef DIAGNOSTIC
+               printf("pid %d killed on VM86 protocol screwup (SIGURG blocked)\n",
+                   p->p_pid);
+#endif
+               sigexit(p, SIGILL);
+               /* NOTREACHED */
+       } else if (sigismember(&p->p_sigctx.ps_sigignore, SIGURG)) {
+#ifdef DIAGNOSTIC
+               printf("pid %d killed on VM86 protocol screwup (SIGURG ignored)\n",
+                   p->p_pid);
+#endif
+               sigexit(p, SIGILL);
+       }
+       
+       (*p->p_emul->e_trapsignal)(p, SIGURG, retval);
+}
+
+#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(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_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;



Home | Main Index | Thread Index | Old Index