vm86 signal patch

Ove Kaaven ovek at arcticnet.no
Fri Dec 28 04:20:53 CST 2001


Well, it looked like I got all the race conditions fixed in this thing a
few weeks ago, may as well submit it now. (I could have made this code a
lot simpler if the vm86 syscall would check for VIF|VIP on entry by
itself, but noo, so I still need to throw from the signal handler...)

For some reason DOS games still performed quite bad in my restructured
code last time I checked (possibly a number of SIGALRMs are just lost or
something), but perhaps I should just submit that DOS restructure anyway,
might be better than nothing?

Log:
Fixed vm86_enter race conditions.

Index: include/thread.h
===================================================================
RCS file: /home/wine/wine/include/thread.h,v
retrieving revision 1.56
diff -u -r1.56 thread.h
--- include/thread.h	2001/11/30 18:46:46	1.56
+++ include/thread.h	2001/12/28 08:23:52
@@ -101,11 +101,10 @@
     DWORD        alarms;         /* --3 22c Data for vm86 mode */
     DWORD        vm86_pending;   /* --3 230 Data for vm86 mode */
     void        *vm86_ptr;       /* --3 234 Data for vm86 mode */
-    void        *vm86_ctx;       /* --3 238 Data for vm86 mode */
     /* here is plenty space for wine specific fields (don't forget to change pad6!!) */
 
     /* the following are nt specific fields */
-    DWORD        pad6[623];                  /* --n 23c */
+    DWORD        pad6[624];                  /* --n 23c */
     UNICODE_STRING StaticUnicodeString;      /* -2- bf8 used by advapi32 */
     USHORT       StaticUnicodeBuffer[261];   /* -2- c00 used by advapi32 */
     DWORD        pad7;                       /* --n e0c */
Index: dlls/ntdll/signal_i386.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/signal_i386.c,v
retrieving revision 1.30
diff -u -r1.30 signal_i386.c
--- dlls/ntdll/signal_i386.c	2001/10/28 21:16:22	1.30
+++ dlls/ntdll/signal_i386.c	2001/12/28 08:23:53
@@ -115,13 +115,16 @@
 }
 #endif
 
-int vm86_enter( struct vm86plus_struct *ptr );
-void vm86_return();
+#define VM86_EAX 0 /* the %eax value while vm86_enter is executing */
+
+int vm86_enter(void);
+void vm86_return(void);
+void vm86_return_end(void);
 __ASM_GLOBAL_FUNC(vm86_enter,
                   "pushl %ebp\n\t"
                   "movl %esp, %ebp\n\t"
                   "movl $166,%eax\n\t"  /*SYS_vm86*/
-                  "movl 8(%ebp),%ecx\n\t"
+                  ".byte 0x64\n\tmovl (0x234),%ecx\n\t" /* vm86_ptr */
                   "pushl %ebx\n\t"
                   "movl $1,%ebx\n\t"    /*VM86_ENTER*/
                   "pushl %ecx\n\t"      /* put vm86plus_struct ptr somewhere we can find it */
@@ -134,6 +137,16 @@
                   "popl %ecx\n\t"
                   "popl %ebx\n\t"
                   "popl %ebp\n\t"
+                  "testl %eax,%eax\n\t"
+                  "jl 0f\n\t"
+                  "cmpb $0,%al\n\t" /* VM86_SIGNAL */
+                  "je " __ASM_NAME("vm86_enter") "\n\t"
+                  "0:\n\t"
+                  "xorl %ecx,%ecx\n\t"
+                  ".byte 0x64\n\tmovl %ecx,(0x234)\n\t" /* vm86_ptr */
+                  ".globl " __ASM_NAME("vm86_return_end") "\n\t"
+                  ".type " __ASM_NAME("vm86_return_end") ", at function\n"
+                  __ASM_NAME("vm86_return_end") ":\n\t"
                   "ret" );
 
 #define __HAVE_VM86
@@ -474,14 +487,18 @@
 #ifdef __HAVE_VM86
     else if ((void *)EIP_sig(sigcontext) == vm86_return)  /* vm86 mode */
     {
-        /* retrieve pointer to vm86plus struct that was stored in vm86_enter */
-        struct vm86plus_struct *vm86 = *(struct vm86plus_struct **)(ESP_sig(sigcontext) + sizeof(int));
         /* fetch the saved %fs on the stack */
         fs = *(unsigned int *)ESP_sig(sigcontext);
-        __set_fs(fs);
-        /* get context from vm86 struct */
-        save_vm86_context( context, vm86 );
-        return;
+        if (EAX_sig(sigcontext) == VM86_EAX) {
+            struct vm86plus_struct *vm86;
+            __set_fs(fs);
+            /* retrieve pointer to vm86plus struct that was stored in vm86_enter
+             * (but we could also get if from teb->vm86_ptr) */
+            vm86 = *(struct vm86plus_struct **)(ESP_sig(sigcontext) + sizeof(int));
+            /* get context from vm86 struct */
+            save_vm86_context( context, vm86 );
+            return;
+        }
     }
 #endif  /* __HAVE_VM86 */
 
@@ -519,9 +536,11 @@
 #ifdef __HAVE_VM86
     /* check if exception occurred in vm86 mode */
     if ((void *)EIP_sig(sigcontext) == vm86_return &&
-        IS_SELECTOR_SYSTEM(CS_sig(sigcontext)))
+        IS_SELECTOR_SYSTEM(CS_sig(sigcontext)) &&
+        EAX_sig(sigcontext) == VM86_EAX)
     {
-        /* retrieve pointer to vm86plus struct that was stored in vm86_enter */
+        /* retrieve pointer to vm86plus struct that was stored in vm86_enter
+         * (but we could also get it from teb->vm86_ptr) */
         struct vm86plus_struct *vm86 = *(struct vm86plus_struct **)(ESP_sig(sigcontext) + sizeof(int));
         restore_vm86_context( context, vm86 );
         return;
@@ -807,8 +826,10 @@
         if (context->EFlags & VIF_MASK) {
             /* VIF is set, throw exception */
             teb->vm86_pending = 0;
+            teb->vm86_ptr = NULL;
             rec.ExceptionAddress = (LPVOID)context->Eip;
             EXC_RtlRaiseException( &rec, context );
+            teb->vm86_ptr = vm86;
         }
     }
     else if (vm86)
@@ -816,18 +837,22 @@
         /* not in VM86, but possibly setting up for it */
         if (vm86->regs.eflags & VIP_MASK) return;
         vm86->regs.eflags |= VIP_MASK;
+        if (((char*)context->Eip >= (char*)vm86_return) &&
+            ((char*)context->Eip <= (char*)vm86_return_end) &&
+            (VM86_TYPE(context->Eax) != VM86_SIGNAL)) {
+            /* exiting from VM86, can't throw */
+            return;
+        }
         if (vm86->regs.eflags & VIF_MASK) {
             /* VIF is set, throw exception */
             CONTEXT vcontext;
             teb->vm86_pending = 0;
+            teb->vm86_ptr = NULL;
             save_vm86_context( &vcontext, vm86 );
             rec.ExceptionAddress = (LPVOID)vcontext.Eip;
             EXC_RtlRaiseException( &rec, &vcontext );
+            teb->vm86_ptr = vm86;
             restore_vm86_context( &vcontext, vm86 );
-            if (teb->vm86_ctx) {
-                /* must also save here */
-                *(CONTEXT*)(teb->vm86_ctx) = vcontext;
-            }
         }
     }
 }
@@ -1065,7 +1090,7 @@
 
         do
         {
-            res = vm86_enter( &vm86 );
+            res = vm86_enter(); /* uses and clears teb->vm86_ptr */
             if (res < 0)
             {
                 errno = -res;
@@ -1073,10 +1098,7 @@
             }
         } while (VM86_TYPE(res) == VM86_SIGNAL);
 
-        teb->vm86_ctx = context;
         save_vm86_context( context, &vm86 );
-        teb->vm86_ptr = NULL;
-        teb->vm86_ctx = NULL;
         context->EFlags |= teb->vm86_pending;
 
         switch(VM86_TYPE(res))





More information about the wine-patches mailing list