[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     ! 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