winedos / Speed up RM software interrupt handling

Jukka Heinonen jhei at iki.fi
Sat Mar 8 14:15:40 CST 2003


This patch speeds up software interrupts in real mode
considerably, in addition to making interrupt handling simpler 
(at least in my opinion). Instead of throwing an exception,
vm86 handler calls winedos callback as is done in case of
protected mode software interrupts.

Next thing would be converting EXCEPTION_VM86_STI into
using a similar mechanism. There might be some need for 
exception stuff, but I would rather handle them inside 
signal_i386.c.



Changelog:
    Real mode software interrupts now use callback instead
    of throwing an exception. Interrupt trace messages have
    been improved. If application copies builtin interrupt
    vectors, the correct handler will be called.



Index: dlls/winedos/winedos.spec
===================================================================
RCS file: /home/wine/wine/dlls/winedos/winedos.spec,v
retrieving revision 1.15
diff -u -r1.15 winedos.spec
--- dlls/winedos/winedos.spec	11 Feb 2003 22:22:50 -0000	1.15
+++ dlls/winedos/winedos.spec	8 Mar 2003 19:19:34 -0000
@@ -1,5 +1,6 @@
 @ stdcall LoadDosExe(str long) MZ_LoadImage
 @ stdcall EmulateInterruptPM(ptr long) DOSVM_EmulateInterruptPM
+@ stdcall EmulateInterruptRM(ptr long) DOSVM_EmulateInterruptRM
 @ stdcall CallBuiltinHandler(ptr long) DOSVM_CallBuiltinHandler
 
 # I/O functions




Index: include/callback.h
===================================================================
RCS file: /home/wine/wine/include/callback.h,v
retrieving revision 1.52
diff -u -r1.52 callback.h
--- include/callback.h	11 Feb 2003 22:22:50 -0000	1.52
+++ include/callback.h	8 Mar 2003 19:19:36 -0000
@@ -27,6 +27,7 @@
 typedef struct {
     void (WINAPI *LoadDosExe)( LPCSTR filename, HANDLE hFile );
     void (WINAPI *EmulateInterruptPM)( CONTEXT86 *context, BYTE intnum );
+    BOOL (WINAPI *EmulateInterruptRM)( CONTEXT86 *context, BYTE intnum );
     void (WINAPI *CallBuiltinHandler)( CONTEXT86 *context, BYTE intnum );
 
     /* I/O functions */




Index: msdos/dpmi.c
===================================================================
RCS file: /home/wine/wine/msdos/dpmi.c,v
retrieving revision 1.74
diff -u -r1.74 dpmi.c
--- msdos/dpmi.c	11 Feb 2003 22:22:50 -0000	1.74
+++ msdos/dpmi.c	8 Mar 2003 19:19:38 -0000
@@ -51,6 +51,7 @@
     GET_ADDR(inport);
     GET_ADDR(outport);
     GET_ADDR(EmulateInterruptPM);
+    GET_ADDR(EmulateInterruptRM);
     GET_ADDR(CallBuiltinHandler);
 #undef GET_ADDR
     return TRUE;




Index: dlls/ntdll/signal_i386.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/signal_i386.c,v
retrieving revision 1.53
diff -u -r1.53 signal_i386.c
--- dlls/ntdll/signal_i386.c	4 Mar 2003 22:18:44 -0000	1.53
+++ dlls/ntdll/signal_i386.c	8 Mar 2003 19:19:39 -0000
@@ -55,6 +55,7 @@
 #include "wine/library.h"
 
 #include "selectors.h"
+#include "callback.h"
 
 /***********************************************************************
  * signal context platform-specific definitions
@@ -1311,8 +1312,17 @@
             do_trap( context, VM86_ARG(res) );
             continue;
         case VM86_INTx: /* int3/int x instruction (ARG = x) */
-            rec.ExceptionCode = EXCEPTION_VM86_INTx;
-            break;
+            if (Dosvm.EmulateInterruptRM || DPMI_LoadDosSystem())
+            {
+                /*
+                 * If emulate interrupt routine returns FALSE,
+                 * exit from real mode wrapper was called and
+                 * we should return from this routine.
+                 */
+                if (!Dosvm.EmulateInterruptRM( context, VM86_ARG(res) ))
+                    return;
+            }
+            continue;
         case VM86_STI: /* sti/popf/iret instruction enabled virtual interrupts */
             teb->vm86_pending = 0;
             rec.ExceptionCode = EXCEPTION_VM86_STI;




Index: dlls/winedos/dosvm.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosvm.c,v
retrieving revision 1.34
diff -u -r1.34 dosvm.c
--- dlls/winedos/dosvm.c	4 Mar 2003 02:16:20 -0000	1.34
+++ dlls/winedos/dosvm.c	8 Mar 2003 19:19:41 -0000
@@ -394,34 +394,9 @@
 {
   EXCEPTION_RECORD *rec = GetExceptionInformation()->ExceptionRecord;
   CONTEXT *context = GetExceptionInformation()->ContextRecord;
-  int arg = rec->ExceptionInformation[0];
   BOOL ret;
 
   switch(rec->ExceptionCode) {
-  case EXCEPTION_VM86_INTx:
-    if (TRACE_ON(relay)) {
-      DPRINTF("Call DOS int 0x%02x ret=%04lx:%04lx\n",
-	      arg, context->SegCs, context->Eip );
-      DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
-	      context->Eax, context->Ebx, context->Ecx, context->Edx,
-	      context->Esi, context->Edi );
-      DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n",
-	      context->Ebp, context->Esp, context->SegDs, context->SegEs,
-	      context->SegFs, context->SegGs, context->EFlags );
-      }
-    ret = DOSVM_EmulateInterruptRM( context, arg );
-    if (TRACE_ON(relay)) {
-      DPRINTF("Ret  DOS int 0x%02x ret=%04lx:%04lx\n",
-	      arg, context->SegCs, context->Eip );
-      DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
-	      context->Eax, context->Ebx, context->Ecx, context->Edx,
-	      context->Esi, context->Edi );
-      DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n",
-	      context->Ebp, context->Esp, context->SegDs, context->SegEs,
-	      context->SegFs, context->SegGs, context->EFlags );
-    }
-    return ret ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER;
-
   case EXCEPTION_VM86_STI:
   /* case EXCEPTION_VM86_PICRETURN: */
     IF_SET(context);




Index: dlls/winedos/interrupts.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/interrupts.c,v
retrieving revision 1.14
diff -u -r1.14 interrupts.c
--- dlls/winedos/interrupts.c	4 Mar 2003 02:16:20 -0000	1.14
+++ dlls/winedos/interrupts.c	8 Mar 2003 19:19:43 -0000
@@ -36,6 +36,8 @@
 
 
 WINE_DEFAULT_DEBUG_CHANNEL(int);
+WINE_DECLARE_DEBUG_CHANNEL(relay);
+
 
 static FARPROC16     DOSVM_Vectors16[256];
 static FARPROC48     DOSVM_Vectors48[256];
@@ -70,6 +72,14 @@
 };
 
 
+/*
+ * Sizes of real mode and protected mode interrupt stubs.
+ */
+#define DOSVM_STUB_RM   4
+#define DOSVM_STUB_PM16 5
+#define DOSVM_STUB_PM48 6
+
+
 /**********************************************************************
  *         DOSVM_DefaultHandler
  *
@@ -173,6 +183,19 @@
  */
 void WINAPI DOSVM_EmulateInterruptPM( CONTEXT86 *context, BYTE intnum ) 
 {
+    if (TRACE_ON(relay)) 
+    {
+        DPRINTF( "Call DOS int 0x%02x ret=%04lx:%08lx\n",
+                 intnum, context->SegCs, context->Eip );
+        DPRINTF( "  eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx\n",
+                 context->Eax, context->Ebx, context->Ecx, context->Edx );
+        DPRINTF( "  esi=%08lx edi=%08lx ebp=%08lx esp=%08lx \n",
+                 context->Esi, context->Edi, context->Ebp, context->Esp );
+        DPRINTF( "  ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n",
+                 context->SegDs, context->SegEs,
+                 context->SegFs, context->SegGs, context->EFlags );
+    }
+
     if (context->SegCs == DOSVM_dpmi_segments->dpmi_sel)
     {
         DOSVM_BuildCallFrame( context, 
@@ -188,6 +211,13 @@
     }
     else if (context->SegCs == DOSVM_dpmi_segments->int48_sel)
     {
+        if (intnum != context->Eip / DOSVM_STUB_PM48)
+            WARN( "interrupt stub has been modified "
+                  "(interrupt is %02x, interrupt stub is %02lx)\n",
+                  intnum, context->Eip / DOSVM_STUB_PM48 );
+
+        TRACE( "builtin interrupt %02x has been branched to\n", intnum );
+
         if (intnum == 0x25 || intnum == 0x26)
             DOSVM_PushFlags( context, TRUE, TRUE );
 
@@ -197,6 +227,13 @@
     }
     else if (context->SegCs == DOSVM_dpmi_segments->int16_sel)
     {
+        if (intnum != context->Eip / DOSVM_STUB_PM16)
+            WARN( "interrupt stub has been modified "
+                  "(interrupt is %02x, interrupt stub is %02lx)\n",
+                  intnum, context->Eip / DOSVM_STUB_PM16 );
+
+        TRACE( "builtin interrupt %02x has been branched to\n", intnum );
+
         if (intnum == 0x25 || intnum == 0x26)
             DOSVM_PushFlags( context, FALSE, TRUE );
 
@@ -227,12 +264,17 @@
         
         if (addr.selector == DOSVM_dpmi_segments->int48_sel)
         {
+            TRACE( "builtin interrupt %02lx has been invoked "
+                   "(through vector %02x)\n", 
+                   addr.offset / DOSVM_STUB_PM48, intnum );
+
             if (intnum == 0x25 || intnum == 0x26)
                 DOSVM_PushFlags( context, TRUE, FALSE );
 
-             DOSVM_BuildCallFrame( context, 
-                                   DOSVM_IntProcRelay,
-                                   DOSVM_GetBuiltinHandler(intnum) );
+            DOSVM_BuildCallFrame( context,
+                                  DOSVM_IntProcRelay,
+                                  DOSVM_GetBuiltinHandler(
+                                      addr.offset / DOSVM_STUB_PM48 ) );
         }
         else
         {
@@ -240,6 +282,9 @@
                                               context->SegSs, 
                                               context->Esp);
             
+            TRACE( "invoking hooked interrupt %02x at %04x:%08lx\n",
+                   intnum, addr.selector, addr.offset );
+            
             /* Push the flags and return address on the stack */
             *(--stack) = context->EFlags;
             *(--stack) = context->SegCs;
@@ -257,12 +302,17 @@
 
         if (SELECTOROF(addr) == DOSVM_dpmi_segments->int16_sel)
         {
+            TRACE( "builtin interrupt %02x has been invoked "
+                   "(through vector %02x)\n", 
+                   OFFSETOF(addr) / DOSVM_STUB_PM16, intnum );
+
             if (intnum == 0x25 || intnum == 0x26)
                 DOSVM_PushFlags( context, FALSE, FALSE );
-
+            
             DOSVM_BuildCallFrame( context, 
                                   DOSVM_IntProcRelay,
-                                  DOSVM_GetBuiltinHandler(intnum) );
+                                  DOSVM_GetBuiltinHandler(
+                                      OFFSETOF(addr) / DOSVM_STUB_PM16 ) );
         }
         else
         {
@@ -270,6 +320,9 @@
                                              context->SegSs, 
                                              context->Esp);
             
+            TRACE( "invoking hooked interrupt %02x at %04x:%04x\n", 
+                   intnum, SELECTOROF(addr), OFFSETOF(addr) );
+
             /* Push the flags and return address on the stack */
             *(--stack) = LOWORD(context->EFlags);
             *(--stack) = context->SegCs;
@@ -277,7 +330,7 @@
             ADD_LOWORD( context->Esp, -6 );
 
             /* Jump to the interrupt handler */
-            context->SegCs  = HIWORD(addr);
+            context->SegCs =  HIWORD(addr);
             context->Eip = LOWORD(addr);
         }
     }
@@ -298,6 +351,19 @@
  */
 BOOL WINAPI DOSVM_EmulateInterruptRM( CONTEXT86 *context, BYTE intnum ) 
 {
+    if (TRACE_ON(relay)) 
+    {
+        DPRINTF( "Call DOS int 0x%02x ret=%04lx:%08lx\n",
+                 intnum, context->SegCs, context->Eip );
+        DPRINTF( "  eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx\n",
+                 context->Eax, context->Ebx, context->Ecx, context->Edx );
+        DPRINTF( "  esi=%08lx edi=%08lx ebp=%08lx esp=%08lx \n",
+                 context->Esi, context->Edi, context->Ebp, context->Esp );
+        DPRINTF( "  ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n",
+                 context->SegDs, context->SegEs,
+                 context->SegFs, context->SegGs, context->EFlags );
+    }
+
     /* check for our real-mode hooks */
     if (intnum == 0x31)
     {
@@ -312,9 +378,10 @@
     /* check if the call is from our fake BIOS interrupt stubs */
     if (context->SegCs==0xf000)
     {
-        if (intnum != (context->Eip/4))
-            TRACE( "something fishy going on here (interrupt stub is %02lx)\n", 
-                   context->Eip/4 );
+        if (intnum != context->Eip / DOSVM_STUB_RM)
+            WARN( "interrupt stub has been modified "
+                  "(interrupt is %02x, interrupt stub is %02lx)\n",
+                  intnum, context->Eip / DOSVM_STUB_RM );
 
         TRACE( "builtin interrupt %02x has been branched to\n", intnum );
         
@@ -345,9 +412,10 @@
      if (SELECTOROF(handler) == 0xf000) 
      {
          /* if so, call it directly */
-         TRACE( "builtin interrupt %02x has been invoked (through vector %02x)\n", 
-                OFFSETOF(handler)/4, intnum );
-         DOSVM_CallBuiltinHandler( context, OFFSETOF(handler)/4 );
+         TRACE( "builtin interrupt %02x has been invoked "
+                "(through vector %02x)\n", 
+                OFFSETOF(handler) / DOSVM_STUB_RM, intnum );
+         DOSVM_CallBuiltinHandler( context, OFFSETOF(handler) / DOSVM_STUB_RM );
      }
      else 
      {
@@ -355,8 +423,8 @@
          WORD* stack = PTR_REAL_TO_LIN( context->SegSs, context->Esp );
          WORD  flag  = LOWORD( context->EFlags );
 
-         TRACE_(int)( "invoking hooked interrupt %02x at %04x:%04x\n", 
-                      intnum, SELECTOROF(handler), OFFSETOF(handler) );
+         TRACE( "invoking hooked interrupt %02x at %04x:%04x\n", 
+                intnum, SELECTOROF(handler), OFFSETOF(handler) );
 
          /* Copy virtual interrupt flag to pushed interrupt flag. */
          if (context->EFlags & VIF_MASK)
@@ -387,6 +455,7 @@
   return ((FARPROC16*)0)[intnum];
 }
 
+
 /**********************************************************************
  *          DOSVM_SetRMHandler
  *
@@ -410,7 +479,7 @@
     if (!DOSVM_Vectors16[intnum])
     {
         FARPROC16 proc = (FARPROC16)MAKESEGPTR( DOSVM_dpmi_segments->int16_sel,
-                                                5 * intnum );
+                                                DOSVM_STUB_PM16 * intnum );
         DOSVM_Vectors16[intnum] = proc;
     }
     return DOSVM_Vectors16[intnum];
@@ -429,6 +498,7 @@
   DOSVM_Vectors16[intnum] = handler;
 }
 
+
 /**********************************************************************
  *         DOSVM_GetPMHandler48
  *
@@ -440,10 +510,11 @@
   if (!DOSVM_Vectors48[intnum].selector)
   {
     DOSVM_Vectors48[intnum].selector = DOSVM_dpmi_segments->int48_sel;
-    DOSVM_Vectors48[intnum].offset = 6 * intnum;
+    DOSVM_Vectors48[intnum].offset = DOSVM_STUB_PM48 * intnum;
   }
   return DOSVM_Vectors48[intnum];
 }
+
 
 /**********************************************************************
  *         DOSVM_SetPMHandler48



-- 
Jukka Heinonen <http://www.iki.fi/jhei/>



More information about the wine-patches mailing list