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