root/arch/i386/i386/vm86.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_bitset
  2. fast_intxx
  3. vm86_return
  4. vm86_gpfault
  5. i386_vm86

    1 /*      $OpenBSD: vm86.c,v 1.17 2006/09/19 11:06:33 jsg Exp $   */
    2 /*      $NetBSD: vm86.c,v 1.15 1996/05/03 19:42:33 christos Exp $       */
    3 
    4 /*-
    5  * Copyright (c) 1996 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by John T. Kohl and Charles M. Hannum.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *        This product includes software developed by the NetBSD
   22  *        Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
   31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/signalvar.h>
   43 #include <sys/kernel.h>
   44 #include <sys/proc.h>
   45 #include <sys/user.h>
   46 #include <sys/exec.h>
   47 #include <sys/buf.h>
   48 #include <sys/reboot.h>
   49 #include <sys/conf.h>
   50 #include <sys/file.h>
   51 #include <sys/malloc.h>
   52 #include <sys/mbuf.h>
   53 #include <sys/msgbuf.h>
   54 #include <sys/mount.h>
   55 #include <sys/vnode.h>
   56 #include <sys/device.h>
   57 #include <sys/sysctl.h>
   58 #include <sys/syscallargs.h>
   59 #ifdef SYSVMSG
   60 #include <sys/msg.h>
   61 #endif
   62 #ifdef SYSVSEM
   63 #include <sys/sem.h>
   64 #endif
   65 #ifdef SYSVSHM
   66 #include <sys/shm.h>
   67 #endif
   68 
   69 #include <sys/ktrace.h>
   70 #include <machine/sysarch.h>
   71 #include <machine/vm86.h>
   72 
   73 static void fast_intxx(struct proc *, int);
   74 static __inline int is_bitset(int, caddr_t);
   75 
   76 #define CS(tf)          (*(u_short *)&tf->tf_cs)
   77 #define IP(tf)          (*(u_short *)&tf->tf_eip)
   78 #define SS(tf)          (*(u_short *)&tf->tf_ss)
   79 #define SP(tf)          (*(u_short *)&tf->tf_esp)
   80 
   81 
   82 #define putword(base, ptr, val) \
   83 __asm__ __volatile__( \
   84         "decw %w0\n\t" \
   85         "movb %h2,0(%1,%0)\n\t" \
   86         "decw %w0\n\t" \
   87         "movb %b2,0(%1,%0)" \
   88         : "=r" (ptr) \
   89         : "r" (base), "q" (val), "0" (ptr))
   90 
   91 #define putdword(base, ptr, val) \
   92 __asm__ __volatile__( \
   93         "rorl $16,%2\n\t" \
   94         "decw %w0\n\t" \
   95         "movb %h2,0(%1,%0)\n\t" \
   96         "decw %w0\n\t" \
   97         "movb %b2,0(%1,%0)\n\t" \
   98         "rorl $16,%2\n\t" \
   99         "decw %w0\n\t" \
  100         "movb %h2,0(%1,%0)\n\t" \
  101         "decw %w0\n\t" \
  102         "movb %b2,0(%1,%0)" \
  103         : "=r" (ptr) \
  104         : "r" (base), "q" (val), "0" (ptr))
  105 
  106 #define getbyte(base, ptr) \
  107 ({ unsigned long __res; \
  108 __asm__ __volatile__( \
  109         "movb 0(%1,%0),%b2\n\t" \
  110         "incw %w0" \
  111         : "=r" (ptr), "=r" (base), "=q" (__res) \
  112         : "0" (ptr), "1" (base), "2" (0)); \
  113 __res; })
  114 
  115 #define getword(base, ptr) \
  116 ({ unsigned long __res; \
  117 __asm__ __volatile__( \
  118         "movb 0(%1,%0),%b2\n\t" \
  119         "incw %w0\n\t" \
  120         "movb 0(%1,%0),%h2\n\t" \
  121         "incw %w0" \
  122         : "=r" (ptr), "=r" (base), "=q" (__res) \
  123         : "0" (ptr), "1" (base), "2" (0)); \
  124 __res; })
  125 
  126 #define getdword(base, ptr) \
  127 ({ unsigned long __res; \
  128 __asm__ __volatile__( \
  129         "movb 0(%1,%0),%b2\n\t" \
  130         "incw %w0\n\t" \
  131         "movb 0(%1,%0),%h2\n\t" \
  132         "incw %w0\n\t" \
  133         "rorl $16,%2\n\t" \
  134         "movb 0(%1,%0),%b2\n\t" \
  135         "incw %w0\n\t" \
  136         "movb 0(%1,%0),%h2\n\t" \
  137         "incw %w0\n\t" \
  138         "rorl $16,%2" \
  139         : "=r" (ptr), "=r" (base), "=q" (__res) \
  140         : "0" (ptr), "1" (base)); \
  141 __res; })
  142 
  143 
  144 static __inline int
  145 is_bitset(int nr, caddr_t bitmap)
  146 {
  147         u_int byte;             /* bt instruction doesn't do
  148                                            bytes--it examines ints! */
  149         bitmap += nr / NBBY;
  150         nr = nr % NBBY;
  151         copyin(bitmap, &byte, sizeof(u_char));
  152 
  153         __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
  154                              :"=r" (nr)
  155                              :"r" (byte),"r" (nr));
  156         return (nr);
  157 }
  158 
  159 
  160 #define V86_AH(regs)    (((u_char *)&((regs)->tf_eax))[1])
  161 #define V86_AL(regs)    (((u_char *)&((regs)->tf_eax))[0])
  162 
  163 static void
  164 fast_intxx(struct proc *p, int intrno)
  165 {
  166         struct trapframe *tf = p->p_md.md_regs;
  167         /*
  168          * handle certain interrupts directly by pushing the interrupt
  169          * frame and resetting registers, but only if user said that's ok
  170          * (i.e. not revectored.)  Otherwise bump to 32-bit user handler.
  171          */
  172         struct vm86_struct *u_vm86p;
  173         struct { u_short ip, cs; } ihand;
  174 
  175         u_long ss, sp;
  176 
  177         /*
  178          * Note: u_vm86p points to user-space, we only compute offsets
  179          * and don't deref it. is_revectored() above does copyin() to
  180          * get stuff from it
  181          */
  182         u_vm86p = (struct vm86_struct *)p->p_addr->u_pcb.vm86_userp;
  183 
  184         /*
  185          * If user requested special handling, return to user space with
  186          * indication of which INT was requested.
  187          */
  188         if (is_bitset(intrno, &u_vm86p->int_byuser[0]))
  189                 goto vector;
  190 
  191         /*
  192          * If it's interrupt 0x21 (special in the DOS world) and the
  193          * sub-command (in AH) was requested for special handling,
  194          * return to user mode.
  195          */
  196         if (intrno == 0x21 && is_bitset(V86_AH(tf), &u_vm86p->int21_byuser[0]))
  197                 goto vector;
  198 
  199         /*
  200          * Fetch intr handler info from "real-mode" IDT based at addr 0 in
  201          * the user address space.
  202          */
  203         if (copyin((caddr_t)(intrno * sizeof(ihand)), &ihand, sizeof(ihand)))
  204                 goto bad;
  205 
  206         /*
  207          * Otherwise, push flags, cs, eip, and jump to handler to
  208          * simulate direct INT call.
  209          */
  210         ss = SS(tf) << 4;
  211         sp = SP(tf);
  212 
  213         putword(ss, sp, get_vflags_short(p));
  214         putword(ss, sp, CS(tf));
  215         putword(ss, sp, IP(tf));
  216         SP(tf) = sp;
  217 
  218         IP(tf) = ihand.ip;
  219         CS(tf) = ihand.cs;
  220 
  221         return;
  222 
  223 vector:
  224         vm86_return(p, VM86_MAKEVAL(VM86_INTx, intrno));
  225         return;
  226 
  227 bad:
  228         vm86_return(p, VM86_UNKNOWN);
  229         return;
  230 }
  231 
  232 void
  233 vm86_return(struct proc *p, int retval)
  234 {
  235         union sigval sv;
  236 
  237         /*
  238          * We can't set the virtual flags in our real trap frame,
  239          * since it's used to jump to the signal handler.  Instead we
  240          * let sendsig() pull in the vm86_eflags bits.
  241          */
  242         if (p->p_sigmask & sigmask(SIGURG)) {
  243 #ifdef DIAGNOSTIC
  244                 printf("pid %d killed on VM86 protocol screwup (SIGURG blocked)\n",
  245                        p->p_pid);
  246 #endif
  247                 sigexit(p, SIGILL);
  248                 /* NOTREACHED */
  249         }
  250         sv.sival_int = 0;
  251         trapsignal(p, SIGURG, retval, 0, sv);
  252 }
  253 
  254 #define CLI     0xFA
  255 #define STI     0xFB
  256 #define INTxx   0xCD
  257 #define INTO    0xCE
  258 #define IRET    0xCF
  259 #define OPSIZ   0x66
  260 #define INT3    0xCC    /* Actually the process gets 32-bit IDT to handle it */
  261 #define LOCK    0xF0
  262 #define PUSHF   0x9C
  263 #define POPF    0x9D
  264 
  265 /*
  266  * Handle a GP fault that occurred while in VM86 mode.  Things that are easy
  267  * to handle here are done here (much more efficient than trapping to 32-bit
  268  * handler code and then having it restart VM86 mode).
  269  */
  270 void
  271 vm86_gpfault(struct proc *p, int type)
  272 {
  273         struct trapframe *tf = p->p_md.md_regs;
  274         union sigval sv;
  275 
  276         /*
  277          * we want to fetch some stuff from the current user virtual
  278          * address space for checking.  remember that the frame's
  279          * segment selectors are real-mode style selectors.
  280          */
  281         u_long cs, ip, ss, sp;
  282         u_char tmpbyte;
  283         int trace;
  284 
  285         cs = CS(tf) << 4;
  286         ip = IP(tf);
  287         ss = SS(tf) << 4;
  288         sp = SP(tf);
  289 
  290         trace = tf->tf_eflags & PSL_T;
  291 
  292         /*
  293          * For most of these, we must set all the registers before calling
  294          * macros/functions which might do a vm86_return.
  295          */
  296         tmpbyte = getbyte(cs, ip);
  297         IP(tf) = ip;
  298         switch (tmpbyte) {
  299         case CLI:
  300                 /* simulate handling of IF */
  301                 clr_vif(p);
  302                 break;
  303 
  304         case STI:
  305                 /* simulate handling of IF.
  306                  * XXX the i386 enables interrupts one instruction later.
  307                  * code here is wrong, but much simpler than doing it Right.
  308                  */
  309                 set_vif(p);
  310                 break;
  311 
  312         case INTxx:
  313                 /* try fast intxx, or return to 32bit mode to handle it. */
  314                 tmpbyte = getbyte(cs, ip);
  315                 IP(tf) = ip;
  316                 fast_intxx(p, tmpbyte);
  317                 break;
  318 
  319         case INTO:
  320                 if (tf->tf_eflags & PSL_V)
  321                         fast_intxx(p, 4);
  322                 break;
  323 
  324         case PUSHF:
  325                 putword(ss, sp, get_vflags_short(p));
  326                 SP(tf) = sp;
  327                 break;
  328 
  329         case IRET:
  330                 IP(tf) = getword(ss, sp);
  331                 CS(tf) = getword(ss, sp);
  332         case POPF:
  333                 set_vflags_short(p, getword(ss, sp));
  334                 SP(tf) = sp;
  335                 break;
  336 
  337         case OPSIZ:
  338                 tmpbyte = getbyte(cs, ip);
  339                 IP(tf) = ip;
  340                 switch (tmpbyte) {
  341                 case PUSHF:
  342                         putdword(ss, sp, get_vflags(p) & ~PSL_VM);
  343                         SP(tf) = sp;
  344                         break;
  345 
  346                 case IRET:
  347                         IP(tf) = getdword(ss, sp);
  348                         CS(tf) = getdword(ss, sp);
  349                 case POPF:
  350                         set_vflags(p, getdword(ss, sp) | PSL_VM);
  351                         SP(tf) = sp;
  352                         break;
  353 
  354                 default:
  355                         IP(tf) -= 2;
  356                         goto bad;
  357                 }
  358                 break;
  359 
  360         case LOCK:
  361         default:
  362                 IP(tf) -= 1;
  363                 goto bad;
  364         }
  365 
  366         if (trace && tf->tf_eflags & PSL_VM) {
  367                 sv.sival_int = 0;
  368                 trapsignal(p, SIGTRAP, T_TRCTRAP, TRAP_TRACE, sv);
  369         }
  370         return;
  371 
  372 bad:
  373         vm86_return(p, VM86_UNKNOWN);
  374         return;
  375 }
  376 
  377 int
  378 i386_vm86(struct proc *p, char *args, register_t *retval)
  379 {
  380         struct trapframe *tf = p->p_md.md_regs;
  381         struct pcb *pcb = &p->p_addr->u_pcb;
  382         struct vm86_kern vm86s;
  383         int error;
  384 
  385         error = copyin(args, &vm86s, sizeof(vm86s));
  386         if (error)
  387                 return (error);
  388 
  389         pcb->vm86_userp = (void *)args;
  390 
  391         /*
  392          * Keep mask of flags we simulate to simulate a particular type of
  393          * processor.
  394          */
  395         switch (vm86s.ss_cpu_type) {
  396         case VCPU_086:
  397         case VCPU_186:
  398         case VCPU_286:
  399                 pcb->vm86_flagmask = PSL_ID|PSL_AC|PSL_NT|PSL_IOPL;
  400                 break;
  401         case VCPU_386:
  402                 pcb->vm86_flagmask = PSL_ID|PSL_AC;
  403                 break;
  404         case VCPU_486:
  405                 pcb->vm86_flagmask = PSL_ID;
  406                 break;
  407         case VCPU_586:
  408                 pcb->vm86_flagmask = 0;
  409                 break;
  410         default:
  411                 return (EINVAL);
  412         }
  413 
  414 #define DOVREG(reg) tf->tf_vm86_##reg = (u_short) vm86s.regs.vmsc.sc_##reg
  415 #define DOREG(reg) tf->tf_##reg = (u_short) vm86s.regs.vmsc.sc_##reg
  416 
  417         DOVREG(ds);
  418         DOVREG(es);
  419         DOVREG(fs);
  420         DOVREG(gs);
  421         DOREG(edi);
  422         DOREG(esi);
  423         DOREG(ebp);
  424         DOREG(eax);
  425         DOREG(ebx);
  426         DOREG(ecx);
  427         DOREG(edx);
  428         DOREG(eip);
  429         DOREG(cs);
  430         DOREG(esp);
  431         DOREG(ss);
  432 
  433 #undef  DOVREG
  434 #undef  DOREG
  435 
  436         /* Going into vm86 mode jumps off the signal stack. */
  437         p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
  438 
  439         set_vflags(p, vm86s.regs.vmsc.sc_eflags | PSL_VM);
  440 
  441         return (EJUSTRETURN);
  442 }

/* [<][>][^][v][top][bottom][index][help] */