|
|
1.1 root 1: /*
2: * vm86 linux syscall support
1.1.1.3 ! root 3: *
1.1 root 4: * Copyright (c) 2003 Fabrice Bellard
5: *
6: * This program is free software; you can redistribute it and/or modify
7: * it under the terms of the GNU General Public License as published by
8: * the Free Software Foundation; either version 2 of the License, or
9: * (at your option) any later version.
10: *
11: * This program is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: * GNU General Public License for more details.
15: *
16: * You should have received a copy of the GNU General Public License
17: * along with this program; if not, write to the Free Software
18: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19: */
20: #include <stdlib.h>
21: #include <stdio.h>
22: #include <stdarg.h>
23: #include <string.h>
24: #include <errno.h>
25: #include <unistd.h>
26:
27: #include "qemu.h"
28:
29: //#define DEBUG_VM86
30:
31: #define set_flags(X,new,mask) \
32: ((X) = ((X) & ~(mask)) | ((new) & (mask)))
33:
34: #define SAFE_MASK (0xDD5)
35: #define RETURN_MASK (0xDFF)
36:
37: static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
38: {
39: return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1;
40: }
41:
1.1.1.3 ! root 42: static inline void vm_putw(uint32_t segptr, unsigned int reg16, unsigned int val)
1.1 root 43: {
44: stw(segptr + (reg16 & 0xffff), val);
45: }
46:
1.1.1.3 ! root 47: static inline void vm_putl(uint32_t segptr, unsigned int reg16, unsigned int val)
1.1 root 48: {
49: stl(segptr + (reg16 & 0xffff), val);
50: }
51:
1.1.1.3 ! root 52: static inline unsigned int vm_getb(uint32_t segptr, unsigned int reg16)
! 53: {
! 54: return ldub(segptr + (reg16 & 0xffff));
! 55: }
! 56:
! 57: static inline unsigned int vm_getw(uint32_t segptr, unsigned int reg16)
1.1 root 58: {
59: return lduw(segptr + (reg16 & 0xffff));
60: }
61:
1.1.1.3 ! root 62: static inline unsigned int vm_getl(uint32_t segptr, unsigned int reg16)
1.1 root 63: {
64: return ldl(segptr + (reg16 & 0xffff));
65: }
66:
67: void save_v86_state(CPUX86State *env)
68: {
69: TaskState *ts = env->opaque;
1.1.1.2 root 70: struct target_vm86plus_struct * target_v86;
1.1 root 71:
1.1.1.3 ! root 72: if (!lock_user_struct(VERIFY_WRITE, target_v86, ts->target_v86, 0))
! 73: /* FIXME - should return an error */
! 74: return;
1.1 root 75: /* put the VM86 registers in the userspace register structure */
1.1.1.2 root 76: target_v86->regs.eax = tswap32(env->regs[R_EAX]);
77: target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
78: target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
79: target_v86->regs.edx = tswap32(env->regs[R_EDX]);
80: target_v86->regs.esi = tswap32(env->regs[R_ESI]);
81: target_v86->regs.edi = tswap32(env->regs[R_EDI]);
82: target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
83: target_v86->regs.esp = tswap32(env->regs[R_ESP]);
84: target_v86->regs.eip = tswap32(env->eip);
85: target_v86->regs.cs = tswap16(env->segs[R_CS].selector);
86: target_v86->regs.ss = tswap16(env->segs[R_SS].selector);
87: target_v86->regs.ds = tswap16(env->segs[R_DS].selector);
88: target_v86->regs.es = tswap16(env->segs[R_ES].selector);
89: target_v86->regs.fs = tswap16(env->segs[R_FS].selector);
90: target_v86->regs.gs = tswap16(env->segs[R_GS].selector);
1.1 root 91: set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask);
1.1.1.2 root 92: target_v86->regs.eflags = tswap32(env->eflags);
93: unlock_user_struct(target_v86, ts->target_v86, 1);
1.1 root 94: #ifdef DEBUG_VM86
1.1.1.3 ! root 95: fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n",
1.1 root 96: env->eflags, env->segs[R_CS].selector, env->eip);
97: #endif
98:
99: /* restore 32 bit registers */
100: env->regs[R_EAX] = ts->vm86_saved_regs.eax;
101: env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
102: env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
103: env->regs[R_EDX] = ts->vm86_saved_regs.edx;
104: env->regs[R_ESI] = ts->vm86_saved_regs.esi;
105: env->regs[R_EDI] = ts->vm86_saved_regs.edi;
106: env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
107: env->regs[R_ESP] = ts->vm86_saved_regs.esp;
108: env->eflags = ts->vm86_saved_regs.eflags;
109: env->eip = ts->vm86_saved_regs.eip;
110:
111: cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
112: cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
113: cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
114: cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
115: cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
116: cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
117: }
118:
119: /* return from vm86 mode to 32 bit. The vm86() syscall will return
120: 'retval' */
121: static inline void return_to_32bit(CPUX86State *env, int retval)
122: {
123: #ifdef DEBUG_VM86
124: fprintf(logfile, "return_to_32bit: ret=0x%x\n", retval);
125: #endif
126: save_v86_state(env);
127: env->regs[R_EAX] = retval;
128: }
129:
130: static inline int set_IF(CPUX86State *env)
131: {
132: TaskState *ts = env->opaque;
1.1.1.3 ! root 133:
1.1 root 134: ts->v86flags |= VIF_MASK;
135: if (ts->v86flags & VIP_MASK) {
136: return_to_32bit(env, TARGET_VM86_STI);
137: return 1;
138: }
139: return 0;
140: }
141:
142: static inline void clear_IF(CPUX86State *env)
143: {
144: TaskState *ts = env->opaque;
145:
146: ts->v86flags &= ~VIF_MASK;
147: }
148:
149: static inline void clear_TF(CPUX86State *env)
150: {
151: env->eflags &= ~TF_MASK;
152: }
153:
154: static inline void clear_AC(CPUX86State *env)
155: {
156: env->eflags &= ~AC_MASK;
157: }
158:
159: static inline int set_vflags_long(unsigned long eflags, CPUX86State *env)
160: {
161: TaskState *ts = env->opaque;
162:
163: set_flags(ts->v86flags, eflags, ts->v86mask);
164: set_flags(env->eflags, eflags, SAFE_MASK);
165: if (eflags & IF_MASK)
166: return set_IF(env);
167: else
168: clear_IF(env);
169: return 0;
170: }
171:
172: static inline int set_vflags_short(unsigned short flags, CPUX86State *env)
173: {
174: TaskState *ts = env->opaque;
175:
176: set_flags(ts->v86flags, flags, ts->v86mask & 0xffff);
177: set_flags(env->eflags, flags, SAFE_MASK);
178: if (flags & IF_MASK)
179: return set_IF(env);
180: else
181: clear_IF(env);
182: return 0;
183: }
184:
185: static inline unsigned int get_vflags(CPUX86State *env)
186: {
187: TaskState *ts = env->opaque;
188: unsigned int flags;
189:
190: flags = env->eflags & RETURN_MASK;
191: if (ts->v86flags & VIF_MASK)
192: flags |= IF_MASK;
193: flags |= IOPL_MASK;
194: return flags | (ts->v86flags & ts->v86mask);
195: }
196:
197: #define ADD16(reg, val) reg = (reg & ~0xffff) | ((reg + (val)) & 0xffff)
198:
199: /* handle VM86 interrupt (NOTE: the CPU core currently does not
200: support TSS interrupt revectoring, so this code is always executed) */
201: static void do_int(CPUX86State *env, int intno)
202: {
203: TaskState *ts = env->opaque;
1.1.1.3 ! root 204: uint32_t int_addr, segoffs, ssp;
1.1 root 205: unsigned int sp;
206:
207: if (env->segs[R_CS].selector == TARGET_BIOSSEG)
208: goto cannot_handle;
209: if (is_revectored(intno, &ts->vm86plus.int_revectored))
210: goto cannot_handle;
1.1.1.3 ! root 211: if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
1.1 root 212: &ts->vm86plus.int21_revectored))
213: goto cannot_handle;
1.1.1.3 ! root 214: int_addr = (intno << 2);
! 215: segoffs = ldl(int_addr);
1.1 root 216: if ((segoffs >> 16) == TARGET_BIOSSEG)
217: goto cannot_handle;
218: #if defined(DEBUG_VM86)
1.1.1.3 ! root 219: fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
1.1 root 220: intno, segoffs >> 16, segoffs & 0xffff);
221: #endif
222: /* save old state */
1.1.1.3 ! root 223: ssp = env->segs[R_SS].selector << 4;
1.1 root 224: sp = env->regs[R_ESP] & 0xffff;
225: vm_putw(ssp, sp - 2, get_vflags(env));
226: vm_putw(ssp, sp - 4, env->segs[R_CS].selector);
227: vm_putw(ssp, sp - 6, env->eip);
228: ADD16(env->regs[R_ESP], -6);
229: /* goto interrupt handler */
230: env->eip = segoffs & 0xffff;
231: cpu_x86_load_seg(env, R_CS, segoffs >> 16);
232: clear_TF(env);
233: clear_IF(env);
234: clear_AC(env);
235: return;
236: cannot_handle:
237: #if defined(DEBUG_VM86)
238: fprintf(logfile, "VM86: return to 32 bits int 0x%x\n", intno);
239: #endif
240: return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
241: }
242:
243: void handle_vm86_trap(CPUX86State *env, int trapno)
244: {
245: if (trapno == 1 || trapno == 3) {
246: return_to_32bit(env, TARGET_VM86_TRAP + (trapno << 8));
247: } else {
248: do_int(env, trapno);
249: }
250: }
251:
252: #define CHECK_IF_IN_TRAP() \
253: if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \
254: (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \
255: newflags |= TF_MASK
256:
257: #define VM86_FAULT_RETURN \
258: if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \
259: (ts->v86flags & (IF_MASK | VIF_MASK))) \
260: return_to_32bit(env, TARGET_VM86_PICRETURN); \
261: return
262:
263: void handle_vm86_fault(CPUX86State *env)
264: {
265: TaskState *ts = env->opaque;
1.1.1.3 ! root 266: uint32_t csp, ssp;
1.1 root 267: unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
268: int data32, pref_done;
269:
1.1.1.3 ! root 270: csp = env->segs[R_CS].selector << 4;
1.1 root 271: ip = env->eip & 0xffff;
1.1.1.3 ! root 272:
! 273: ssp = env->segs[R_SS].selector << 4;
1.1 root 274: sp = env->regs[R_ESP] & 0xffff;
275:
276: #if defined(DEBUG_VM86)
1.1.1.3 ! root 277: fprintf(logfile, "VM86 exception %04x:%08x\n",
! 278: env->segs[R_CS].selector, env->eip);
1.1 root 279: #endif
280:
281: data32 = 0;
282: pref_done = 0;
283: do {
1.1.1.3 ! root 284: opcode = vm_getb(csp, ip);
1.1 root 285: ADD16(ip, 1);
286: switch (opcode) {
287: case 0x66: /* 32-bit data */ data32=1; break;
288: case 0x67: /* 32-bit address */ break;
289: case 0x2e: /* CS */ break;
290: case 0x3e: /* DS */ break;
291: case 0x26: /* ES */ break;
292: case 0x36: /* SS */ break;
293: case 0x65: /* GS */ break;
294: case 0x64: /* FS */ break;
295: case 0xf2: /* repnz */ break;
296: case 0xf3: /* rep */ break;
297: default: pref_done = 1;
298: }
299: } while (!pref_done);
300:
301: /* VM86 mode */
302: switch(opcode) {
303: case 0x9c: /* pushf */
304: if (data32) {
305: vm_putl(ssp, sp - 4, get_vflags(env));
306: ADD16(env->regs[R_ESP], -4);
307: } else {
308: vm_putw(ssp, sp - 2, get_vflags(env));
309: ADD16(env->regs[R_ESP], -2);
310: }
311: env->eip = ip;
312: VM86_FAULT_RETURN;
313:
314: case 0x9d: /* popf */
315: if (data32) {
316: newflags = vm_getl(ssp, sp);
317: ADD16(env->regs[R_ESP], 4);
318: } else {
319: newflags = vm_getw(ssp, sp);
320: ADD16(env->regs[R_ESP], 2);
321: }
322: env->eip = ip;
323: CHECK_IF_IN_TRAP();
324: if (data32) {
325: if (set_vflags_long(newflags, env))
326: return;
327: } else {
328: if (set_vflags_short(newflags, env))
329: return;
330: }
331: VM86_FAULT_RETURN;
332:
333: case 0xcd: /* int */
1.1.1.3 ! root 334: intno = vm_getb(csp, ip);
1.1 root 335: ADD16(ip, 1);
336: env->eip = ip;
337: if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) {
1.1.1.3 ! root 338: if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >>
1.1 root 339: (intno &7)) & 1) {
340: return_to_32bit(env, TARGET_VM86_INTx + (intno << 8));
341: return;
342: }
343: }
344: do_int(env, intno);
345: break;
346:
347: case 0xcf: /* iret */
348: if (data32) {
349: newip = vm_getl(ssp, sp) & 0xffff;
350: newcs = vm_getl(ssp, sp + 4) & 0xffff;
351: newflags = vm_getl(ssp, sp + 8);
352: ADD16(env->regs[R_ESP], 12);
353: } else {
354: newip = vm_getw(ssp, sp);
355: newcs = vm_getw(ssp, sp + 2);
356: newflags = vm_getw(ssp, sp + 4);
357: ADD16(env->regs[R_ESP], 6);
358: }
359: env->eip = newip;
360: cpu_x86_load_seg(env, R_CS, newcs);
361: CHECK_IF_IN_TRAP();
362: if (data32) {
363: if (set_vflags_long(newflags, env))
364: return;
365: } else {
366: if (set_vflags_short(newflags, env))
367: return;
368: }
369: VM86_FAULT_RETURN;
1.1.1.3 ! root 370:
1.1 root 371: case 0xfa: /* cli */
372: env->eip = ip;
373: clear_IF(env);
374: VM86_FAULT_RETURN;
1.1.1.3 ! root 375:
1.1 root 376: case 0xfb: /* sti */
377: env->eip = ip;
378: if (set_IF(env))
379: return;
380: VM86_FAULT_RETURN;
381:
382: default:
383: /* real VM86 GPF exception */
384: return_to_32bit(env, TARGET_VM86_UNKNOWN);
385: break;
386: }
387: }
388:
1.1.1.3 ! root 389: int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
1.1 root 390: {
391: TaskState *ts = env->opaque;
1.1.1.2 root 392: struct target_vm86plus_struct * target_v86;
1.1 root 393: int ret;
1.1.1.3 ! root 394:
1.1 root 395: switch (subfunction) {
396: case TARGET_VM86_REQUEST_IRQ:
397: case TARGET_VM86_FREE_IRQ:
398: case TARGET_VM86_GET_IRQ_BITS:
399: case TARGET_VM86_GET_AND_RESET_IRQ:
400: gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction);
1.1.1.3 ! root 401: ret = -TARGET_EINVAL;
1.1 root 402: goto out;
403: case TARGET_VM86_PLUS_INSTALL_CHECK:
404: /* NOTE: on old vm86 stuff this will return the error
405: from verify_area(), because the subfunction is
406: interpreted as (invalid) address to vm86_struct.
407: So the installation check works.
408: */
409: ret = 0;
410: goto out;
411: }
412:
413: /* save current CPU regs */
414: ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */
415: ts->vm86_saved_regs.ebx = env->regs[R_EBX];
416: ts->vm86_saved_regs.ecx = env->regs[R_ECX];
417: ts->vm86_saved_regs.edx = env->regs[R_EDX];
418: ts->vm86_saved_regs.esi = env->regs[R_ESI];
419: ts->vm86_saved_regs.edi = env->regs[R_EDI];
420: ts->vm86_saved_regs.ebp = env->regs[R_EBP];
421: ts->vm86_saved_regs.esp = env->regs[R_ESP];
422: ts->vm86_saved_regs.eflags = env->eflags;
423: ts->vm86_saved_regs.eip = env->eip;
424: ts->vm86_saved_regs.cs = env->segs[R_CS].selector;
425: ts->vm86_saved_regs.ss = env->segs[R_SS].selector;
426: ts->vm86_saved_regs.ds = env->segs[R_DS].selector;
427: ts->vm86_saved_regs.es = env->segs[R_ES].selector;
428: ts->vm86_saved_regs.fs = env->segs[R_FS].selector;
429: ts->vm86_saved_regs.gs = env->segs[R_GS].selector;
430:
1.1.1.2 root 431: ts->target_v86 = vm86_addr;
1.1.1.3 ! root 432: if (!lock_user_struct(VERIFY_READ, target_v86, vm86_addr, 1))
! 433: return -TARGET_EFAULT;
1.1 root 434: /* build vm86 CPU state */
435: ts->v86flags = tswap32(target_v86->regs.eflags);
1.1.1.3 ! root 436: env->eflags = (env->eflags & ~SAFE_MASK) |
1.1 root 437: (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
438:
439: ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type);
440: switch (ts->vm86plus.cpu_type) {
441: case TARGET_CPU_286:
442: ts->v86mask = 0;
443: break;
444: case TARGET_CPU_386:
445: ts->v86mask = NT_MASK | IOPL_MASK;
446: break;
447: case TARGET_CPU_486:
448: ts->v86mask = AC_MASK | NT_MASK | IOPL_MASK;
449: break;
450: default:
451: ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
452: break;
453: }
454:
455: env->regs[R_EBX] = tswap32(target_v86->regs.ebx);
456: env->regs[R_ECX] = tswap32(target_v86->regs.ecx);
457: env->regs[R_EDX] = tswap32(target_v86->regs.edx);
458: env->regs[R_ESI] = tswap32(target_v86->regs.esi);
459: env->regs[R_EDI] = tswap32(target_v86->regs.edi);
460: env->regs[R_EBP] = tswap32(target_v86->regs.ebp);
461: env->regs[R_ESP] = tswap32(target_v86->regs.esp);
462: env->eip = tswap32(target_v86->regs.eip);
463: cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs));
464: cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss));
465: cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds));
466: cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es));
467: cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs));
468: cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs));
469: ret = tswap32(target_v86->regs.eax); /* eax will be restored at
470: the end of the syscall */
1.1.1.3 ! root 471: memcpy(&ts->vm86plus.int_revectored,
1.1 root 472: &target_v86->int_revectored, 32);
1.1.1.3 ! root 473: memcpy(&ts->vm86plus.int21_revectored,
1.1 root 474: &target_v86->int21_revectored, 32);
475: ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags);
1.1.1.3 ! root 476: memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab,
1.1 root 477: target_v86->vm86plus.vm86dbg_intxxtab, 32);
1.1.1.2 root 478: unlock_user_struct(target_v86, vm86_addr, 0);
1.1.1.3 ! root 479:
1.1 root 480: #ifdef DEBUG_VM86
1.1.1.3 ! root 481: fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n",
1.1 root 482: env->segs[R_CS].selector, env->eip);
483: #endif
484: /* now the virtual CPU is ready for vm86 execution ! */
485: out:
486: return ret;
487: }
488:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.