Interrupts / Delegate emulation to winedos

Jukka Heinonen jhei at iki.fi
Tue Oct 22 12:47:26 CDT 2002


This patch makes winedos emulate interrupts in Win16, DPMI16 and DPMI32.
This is required in order to prepare for moving almost all interrupt
handling code to winedos. The patch should not have any real effect
on how Wine executes programs. However, Win16 programs now load winedos
the first time they try to use interrupts.

Changelog:
  Move interrupt emulation code from INSTR_EmulateInstruction to
  winedos dll. Make CTX_SEG_OFF_TO_LIN work with 32-bit segmented
  pointers common in DPMI32. Fix winedos initialization so that
  DOSMEM_Init(TRUE) is only called when DOS executable is started.

Notes:
  This patch adds new file dlls/winedos/interrupts.c which shall
  become larger in following patches.

Index: dlls/winedos/dosexe.h
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosexe.h,v
retrieving revision 1.10
diff -u -r1.10 dosexe.h
--- dlls/winedos/dosexe.h       4 Sep 2002 18:52:22 -0000       1.10
+++ dlls/winedos/dosexe.h       22 Oct 2002 17:19:54 -0000
@@ -115,6 +115,7 @@
 
 /* int31.c */
 extern void WINAPI DOSVM_Int31Handler(CONTEXT86*);
+extern BOOL WINAPI DOSVM_IsDos32();
 
 /* int33.c */
 extern void WINAPI DOSVM_Int33Handler(CONTEXT86*);



Index: dlls/winedos/int31.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int31.c,v
retrieving revision 1.8
diff -u -r1.8 int31.c
--- dlls/winedos/int31.c        4 Sep 2002 18:52:22 -0000       1.8
+++ dlls/winedos/int31.c        22 Oct 2002 17:20:11 -0000
@@ -65,6 +65,17 @@
 static WORD dpmi_flag;
 
 /**********************************************************************
+ *          DOSVM_IsDos32
+ * 
+ * Return TRUE if we are in 32-bit protected mode DOS process.
+ */
+BOOL DOSVM_IsDos32()
+{
+  return (dpmi_flag & 1) ? TRUE : FALSE;
+}
+
+
+/**********************************************************************
  *         INT_GetRealModeContext
  */
 static void INT_GetRealModeContext( REALMODECALL *call, CONTEXT86 *context )



Index: dlls/winedos/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/winedos/Makefile.in,v
retrieving revision 1.14
diff -u -r1.14 Makefile.in
--- dlls/winedos/Makefile.in    6 Sep 2002 18:51:32 -0000       1.14
+++ dlls/winedos/Makefile.in    22 Oct 2002 17:20:37 -0000
@@ -25,6 +25,7 @@
        int31.c \
        int33.c \
        int67.c \
+        interrupts.c \
        ioports.c \
        module.c \
        soundblaster.c \



Index: dlls/winedos/winedos.spec
===================================================================
RCS file: /home/wine/wine/dlls/winedos/winedos.spec,v
retrieving revision 1.11
diff -u -r1.11 winedos.spec
--- dlls/winedos/winedos.spec   21 Jun 2002 19:15:50 -0000      1.11
+++ dlls/winedos/winedos.spec   22 Oct 2002 17:20:52 -0000
@@ -1,6 +1,7 @@
 init DOSVM_Init
 
 @ stdcall LoadDosExe(str long) MZ_LoadImage
+@ stdcall EmulateInterruptPM(ptr long) DOSVM_EmulateInterruptPM
 
 # DPMI functions
 @ stdcall CallRMInt(ptr) DOSVM_CallRMInt



Index: msdos/dpmi.c
===================================================================
RCS file: /home/wine/wine/msdos/dpmi.c,v
retrieving revision 1.68
diff -u -r1.68 dpmi.c
--- msdos/dpmi.c        15 Oct 2002 02:18:24 -0000      1.68
+++ msdos/dpmi.c        22 Oct 2002 17:21:13 -0000
@@ -74,6 +74,7 @@
     GET_ADDR(inport);
     GET_ADDR(outport);
     GET_ADDR(ASPIHandler);
+    GET_ADDR(EmulateInterruptPM);
 #undef GET_ADDR
     return TRUE;
 }



Index: memory/instr.c
===================================================================
RCS file: /home/wine/wine/memory/instr.c,v
retrieving revision 1.18
diff -u -r1.18 instr.c
--- memory/instr.c      8 Oct 2002 00:35:03 -0000       1.18
+++ memory/instr.c      22 Oct 2002 17:21:36 -0000
@@ -25,6 +25,7 @@
 #include "miscemu.h"
 #include "selectors.h"
 #include "wine/debug.h"
+#include "callback.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(int);
 WINE_DECLARE_DEBUG_CHANNEL(io);
@@ -684,34 +685,14 @@
             break;  /* Unable to emulate it */
 
         case 0xcd: /* int <XX> */
-            if (long_op)
-            {
-                FARPROC48 addr = INT_GetPMHandler48( instr[1] );
-                DWORD *stack = get_stack( context );
-                /* Push the flags and return address on the stack */
-                *(--stack) = context->EFlags;
-                *(--stack) = context->SegCs;
-                *(--stack) = context->Eip + prefixlen + 2;
-                add_stack(context, -3 * sizeof(DWORD));
-                /* Jump to the interrupt handler */
-                context->SegCs  = addr.selector;
-                context->Eip = addr.offset;
-               return TRUE;
-            }
-            else
-            {
-                FARPROC16 addr = INT_GetPMHandler( instr[1] );
-                WORD *stack = get_stack( context );
-                /* Push the flags and return address on the stack */
-                *(--stack) = LOWORD(context->EFlags);
-                *(--stack) = context->SegCs;
-                *(--stack) = LOWORD(context->Eip) + prefixlen + 2;
-                add_stack(context, -3 * sizeof(WORD));
-                /* Jump to the interrupt handler */
-                context->SegCs  = HIWORD(addr);
-                context->Eip = LOWORD(addr);
-            }
-            return TRUE;
+           if(!Dosvm.EmulateInterruptPM && !DPMI_LoadDosSystem())
+               ERR("could not initialize interrupt handling\n");
+           else {
+               context->Eip += prefixlen + 2;
+               Dosvm.EmulateInterruptPM( context, instr[1] );
+               return TRUE;
+           }
+           break;  /* Unable to emulate it */
 
         case 0xcf: /* iret */
             if (long_op)



Index: include/callback.h
===================================================================
RCS file: /home/wine/wine/include/callback.h,v
retrieving revision 1.48
diff -u -r1.48 callback.h
--- include/callback.h  7 May 2002 17:59:10 -0000       1.48
+++ include/callback.h  22 Oct 2002 17:22:07 -0000
@@ -26,6 +26,7 @@
 
 typedef struct {
     void (WINAPI *LoadDosExe)( LPCSTR filename, HANDLE hFile );
+    void (WINAPI *EmulateInterruptPM)( CONTEXT86 *context, BYTE intnum );
 
     /* DPMI functions */
     void (WINAPI *CallRMInt)( CONTEXT86 *context );



Index: include/miscemu.h
===================================================================
RCS file: /home/wine/wine/include/miscemu.h,v
retrieving revision 1.54
diff -u -r1.54 miscemu.h
--- include/miscemu.h   8 Oct 2002 00:35:03 -0000       1.54
+++ include/miscemu.h   22 Oct 2002 17:22:30 -0000
@@ -270,8 +270,9 @@
 #define PTR_REAL_TO_LIN(seg,off) \
    ((void*)(((unsigned int)(seg) << 4) + LOWORD(off)))
 
-/* NOTE: Interrupts might get called from three modes: real mode, 16-bit, and
- *        (via DeviceIoControl) 32-bit. For automatic conversion of pointer
+/* NOTE: Interrupts might get called from four modes: real mode, 16-bit, 
+ *       32-bit segmented (DPMI32) and 32-bit linear (via DeviceIoControl).
+ *       For automatic conversion of pointer
  *       parameters, interrupt handlers should use CTX_SEG_OFF_TO_LIN with
  *       the contents of a segment register as second and the contents of
  *       a *32-bit* general register as third parameter, e.g.
@@ -279,15 +280,21 @@
  *       This will generate a linear pointer in all three cases:
  *         Real-Mode:   Seg*16 + LOWORD(Offset)
  *         16-bit:      convert (Seg, LOWORD(Offset)) to linear
- *         32-bit:      use Offset as linear address (DeviceIoControl!)
+ *         32-bit segmented: convert (Seg, Offset) to linear
+ *         32-bit linear:    use Offset as linear address (DeviceIoControl!)
  *
  *       Real-mode is recognized by checking the V86 bit in the flags register,
- *       32-bit mode is recognized by checking whether 'seg' is a system selector
- *       (0 counts also as 32-bit segment).
+ *       32-bit linear mode is recognized by checking whether 'seg' is 
+ *       a system selector (0 counts also as 32-bit segment) and 32-bit 
+ *       segmented mode is recognized by checking whether 'seg' is 32-bit
+ *       selector which is neither system selector nor zero.
  */
 #define CTX_SEG_OFF_TO_LIN(context,seg,off) \
     (ISV86(context) ? PTR_REAL_TO_LIN((seg),(off)) : \
-     (!seg || IS_SELECTOR_SYSTEM(seg))? (void *)(ULONG_PTR)(off) : MapSL(MAKESEGPTR((seg),(off))))
+     (!seg || IS_SELECTOR_SYSTEM(seg))? (void *)(ULONG_PTR)(off) : \
+      (IS_SELECTOR_32BIT(seg) ? \
+       (void *)((off) + (char*)MapSL(MAKESEGPTR((seg),0))) : \
+       MapSL(MAKESEGPTR((seg),(off)))))
 
 #define INT_BARF(context,num) \
     ERR( "int%x: unknown/not implemented parameters:\n" \



Index: dlls/winedos/dosvm.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/dosvm.c,v
retrieving revision 1.25
diff -u -r1.25 dosvm.c
--- dlls/winedos/dosvm.c        18 Oct 2002 23:48:58 -0000      1.25
+++ dlls/winedos/dosvm.c        22 Oct 2002 17:22:58 -0000
@@ -696,10 +696,6 @@
 
     if (fdwReason == DLL_PROCESS_ATTACH)
     {
-        /* initialize the memory */
-        TRACE("Initializing DOS memory structures\n");
-        DOSMEM_Init( TRUE );
-        DOSDEV_InstallDOSDevices();
         DOSVM_dpmi_segments = DOSMEM_GetDPMISegments();
 
 #ifdef MZ_SUPPORTED



Index: dlls/winedos/module.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/module.c,v
retrieving revision 1.23
diff -u -r1.23 module.c
--- dlls/winedos/module.c       18 Oct 2002 23:48:58 -0000      1.23
+++ dlls/winedos/module.c       22 Oct 2002 17:23:13 -0000
@@ -198,6 +198,7 @@
     /* initialize the memory */
     TRACE("Initializing DOS memory structures\n");
     DOSMEM_Init(TRUE);
+    DOSDEV_InstallDOSDevices();
 
     MZ_InitHandlers();
     return TRUE;



--- /dev/null   Thu Jan  1 02:00:00 1970
+++ dlls/winedos/interrupts.c   Tue Oct 22 20:07:41 2002
@@ -0,0 +1,84 @@
+/*
+ * Interrupt emulation
+ *
+ * Copyright 2002 Jukka Heinonen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "dosexe.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(int);
+
+/**********************************************************************
+ *         DOSVM_EmulateInterruptPM
+ *
+ * Emulate software interrupt in 16-bit or 32-bit protected mode.
+ * Called from signal handler when intXX opcode is executed. 
+ *
+ * Pushes interrupt frame to stack and changes instruction 
+ * pointer to interrupt handler.
+ */
+void WINAPI DOSVM_EmulateInterruptPM( CONTEXT86 *context, BYTE intnum ) 
+{
+  BOOL islong;
+
+  if(context->SegCs == DOSVM_dpmi_segments->int48_sel) 
+    islong = FALSE;
+  else if(DOSVM_IsDos32())
+    islong = TRUE;
+  else if(IS_SELECTOR_32BIT(context->SegCs)) {
+    WARN("Interrupt in 32-bit code and mode is not DPMI32\n");
+    islong = TRUE;
+  } else
+    islong = FALSE;
+
+  // FIXME: Remove this check when DPMI32 support has been added
+  if(islong) {
+    ERR("Interrupts not supported in 32-bit DPMI\n");
+    islong = FALSE;
+  }
+
+  if(islong)
+  {
+    FARPROC48 addr = {0,0}; // FIXME: INT_GetPMHandler48( intnum );
+    DWORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
+    /* Push the flags and return address on the stack */
+    *(--stack) = context->EFlags;
+    *(--stack) = context->SegCs;
+    *(--stack) = context->Eip;
+    /* Jump to the interrupt handler */
+    context->SegCs  = addr.selector;
+    context->Eip = addr.offset;
+  }
+  else
+  {
+    FARPROC16 addr = INT_GetPMHandler( intnum );
+    WORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
+    /* Push the flags and return address on the stack */
+    *(--stack) = LOWORD(context->EFlags);
+    *(--stack) = context->SegCs;
+    *(--stack) = LOWORD(context->Eip);
+    /* Jump to the interrupt handler */
+    context->SegCs  = HIWORD(addr);
+    context->Eip = LOWORD(addr);
+  }
+
+  if (IS_SELECTOR_32BIT(context->SegSs))
+    context->Esp += islong ? -12 : -6;
+  else
+    ADD_LOWORD( context->Esp, islong ? -12 : -6 );
+}



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



More information about the wine-patches mailing list