[BACK]Return to vm86.c CVS log [TXT][DIR] Up to [local] / sys / arch / i386 / i386

Annotation of sys/arch/i386/i386/vm86.c, Revision 1.1.1.1

1.1       nbrk        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: }

CVSweb