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