symbian-qemu-0.9.1-12/qemu-symbian-svp/linux-user/vm86.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  *  vm86 linux syscall support
       
     3  *
       
     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 
       
    42 static inline void vm_putw(uint32_t segptr, unsigned int reg16, unsigned int val)
       
    43 {
       
    44     stw(segptr + (reg16 & 0xffff), val);
       
    45 }
       
    46 
       
    47 static inline void vm_putl(uint32_t segptr, unsigned int reg16, unsigned int val)
       
    48 {
       
    49     stl(segptr + (reg16 & 0xffff), val);
       
    50 }
       
    51 
       
    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)
       
    58 {
       
    59     return lduw(segptr + (reg16 & 0xffff));
       
    60 }
       
    61 
       
    62 static inline unsigned int vm_getl(uint32_t segptr, unsigned int reg16)
       
    63 {
       
    64     return ldl(segptr + (reg16 & 0xffff));
       
    65 }
       
    66 
       
    67 void save_v86_state(CPUX86State *env)
       
    68 {
       
    69     TaskState *ts = env->opaque;
       
    70     struct target_vm86plus_struct * target_v86;
       
    71 
       
    72     if (!lock_user_struct(VERIFY_WRITE, target_v86, ts->target_v86, 0))
       
    73         /* FIXME - should return an error */
       
    74         return;
       
    75     /* put the VM86 registers in the userspace register structure */
       
    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);
       
    91     set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask);
       
    92     target_v86->regs.eflags = tswap32(env->eflags);
       
    93     unlock_user_struct(target_v86, ts->target_v86, 1);
       
    94 #ifdef DEBUG_VM86
       
    95     fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n",
       
    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;
       
   133 
       
   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;
       
   204     uint32_t int_addr, segoffs, ssp;
       
   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;
       
   211     if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
       
   212                                        &ts->vm86plus.int21_revectored))
       
   213         goto cannot_handle;
       
   214     int_addr = (intno << 2);
       
   215     segoffs = ldl(int_addr);
       
   216     if ((segoffs >> 16) == TARGET_BIOSSEG)
       
   217         goto cannot_handle;
       
   218 #if defined(DEBUG_VM86)
       
   219     fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
       
   220             intno, segoffs >> 16, segoffs & 0xffff);
       
   221 #endif
       
   222     /* save old state */
       
   223     ssp = env->segs[R_SS].selector << 4;
       
   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;
       
   266     uint32_t csp, ssp;
       
   267     unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
       
   268     int data32, pref_done;
       
   269 
       
   270     csp = env->segs[R_CS].selector << 4;
       
   271     ip = env->eip & 0xffff;
       
   272 
       
   273     ssp = env->segs[R_SS].selector << 4;
       
   274     sp = env->regs[R_ESP] & 0xffff;
       
   275 
       
   276 #if defined(DEBUG_VM86)
       
   277     fprintf(logfile, "VM86 exception %04x:%08x\n",
       
   278             env->segs[R_CS].selector, env->eip);
       
   279 #endif
       
   280 
       
   281     data32 = 0;
       
   282     pref_done = 0;
       
   283     do {
       
   284         opcode = vm_getb(csp, ip);
       
   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 */
       
   334         intno = vm_getb(csp, ip);
       
   335         ADD16(ip, 1);
       
   336         env->eip = ip;
       
   337         if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) {
       
   338             if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >>
       
   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;
       
   370 
       
   371     case 0xfa: /* cli */
       
   372         env->eip = ip;
       
   373         clear_IF(env);
       
   374         VM86_FAULT_RETURN;
       
   375 
       
   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 
       
   389 int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
       
   390 {
       
   391     TaskState *ts = env->opaque;
       
   392     struct target_vm86plus_struct * target_v86;
       
   393     int ret;
       
   394 
       
   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);
       
   401         ret = -TARGET_EINVAL;
       
   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 
       
   431     ts->target_v86 = vm86_addr;
       
   432     if (!lock_user_struct(VERIFY_READ, target_v86, vm86_addr, 1))
       
   433         return -TARGET_EFAULT;
       
   434     /* build vm86 CPU state */
       
   435     ts->v86flags = tswap32(target_v86->regs.eflags);
       
   436     env->eflags = (env->eflags & ~SAFE_MASK) |
       
   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 */
       
   471     memcpy(&ts->vm86plus.int_revectored,
       
   472            &target_v86->int_revectored, 32);
       
   473     memcpy(&ts->vm86plus.int21_revectored,
       
   474            &target_v86->int21_revectored, 32);
       
   475     ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags);
       
   476     memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab,
       
   477            target_v86->vm86plus.vm86dbg_intxxtab, 32);
       
   478     unlock_user_struct(target_v86, vm86_addr, 0);
       
   479 
       
   480 #ifdef DEBUG_VM86
       
   481     fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n",
       
   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 }