Interrupts / Move int31 to winedos

Jukka Heinonen jhei at iki.fi
Sat Nov 9 01:03:58 CST 2002


After this patch, winedos will contain handlers for all
int31 functions. If this patch gets applied I shall provide
a patch for deleting deprecated code from msdos/dpmi.c.


Changelog:
  Move all int31 functions to winedos.
  Fix some obvious bugs in int31 functions.


Index: dlls/kernel/kernel32.spec
===================================================================
RCS file: /home/wine/wine/dlls/kernel/kernel32.spec,v
retrieving revision 1.68
diff -u -r1.68 kernel32.spec
--- dlls/kernel/kernel32.spec   6 Nov 2002 20:03:00 -0000       1.68
+++ dlls/kernel/kernel32.spec   9 Nov 2002 06:46:55 -0000
@@ -975,6 +975,7 @@
 ################################################################
 # Wine extensions: Win16 functions that are needed by other dlls
 #
+@ stdcall AllocCStoDSAlias16(long) AllocCStoDSAlias16
 @ stdcall AllocSelectorArray16(long) AllocSelectorArray16
 @ stdcall ConvertDialog32To16(ptr long ptr) ConvertDialog32To16
 @ stdcall DOS3Call(ptr) DOS3Call
@@ -992,9 +993,11 @@
 @ stdcall GetModuleHandle16(str) GetModuleHandle16
 @ stdcall GetModuleName16(long ptr long) GetModuleName16
 @ stdcall GetModuleUsage16(long) GetModuleUsage16
+@ stdcall GetSelectorBase(long) GetSelectorBase
 @ stdcall GetSelectorLimit16(long) GetSelectorLimit16
 @ stdcall GetThreadQueue16(long) GetThreadQueue16
 @ stdcall GlobalDOSAlloc16(long) GlobalDOSAlloc16
+@ stdcall GlobalDOSFree16(long) GlobalDOSFree16
 @ stdcall GlobalFlags16(long) GlobalFlags16
 @ stdcall GlobalReAlloc16(long long long) GlobalReAlloc16
 @ stdcall IsBadReadPtr16(long long) IsBadReadPtr16
@@ -1006,6 +1009,8 @@
 @ stdcall LocalLock16(long) LocalLock16
 @ stdcall LocalUnlock16(long) LocalUnlock16
 @ stdcall LockResource16(long) LockResource16
+@ stdcall MemManInfo16(ptr) MemManInfo16
+@ stdcall SelectorAccessRights16(long long long) SelectorAccessRights16
 @ stdcall SetSelectorBase(long long) SetSelectorBase
 @ stdcall SetSelectorLimit16(long long) SetSelectorLimit16
 @ stdcall SetThreadQueue16(long long) SetThreadQueue16
@@ -1035,6 +1040,7 @@
 # Wine dll separation hacks, these will go away, don't use them
 #
 @ cdecl DOSFS_GetDeviceByHandle(long) DOSFS_GetDeviceByHandle
+@ cdecl DOSMEM_AllocSelector(long) DOSMEM_AllocSelector
 @ cdecl DOSMEM_Available() DOSMEM_Available
 @ cdecl DOSMEM_FreeBlock(ptr) DOSMEM_FreeBlock
 @ cdecl DOSMEM_GetBlock(long ptr) DOSMEM_GetBlock



Index: dlls/winedos/int31.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int31.c,v
retrieving revision 1.13
diff -u -r1.13 int31.c
--- dlls/winedos/int31.c        6 Nov 2002 19:54:39 -0000       1.13
+++ dlls/winedos/int31.c        9 Nov 2002 06:56:00 -0000
@@ -29,6 +29,8 @@
 #include "dosexe.h"
 
 #include "wine/debug.h"
+#include "stackframe.h"
+#include "toolhelp.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(int31);
 
@@ -63,6 +65,7 @@
 
 static RMCB *FirstRMCB = NULL;
 static WORD dpmi_flag;
+static void* lastvalloced = NULL;
 
 /**********************************************************************
  *          DOSVM_IsDos32
@@ -122,6 +125,107 @@
     call->ss  = context->SegSs;
 }
 
+/**********************************************************************
+ *          DPMI_xalloc
+ * special virtualalloc, allocates lineary monoton growing memory.
+ * (the usual VirtualAlloc does not satisfy that restriction)
+ */
+static LPVOID DPMI_xalloc( DWORD len ) 
+{
+    LPVOID  ret;
+    LPVOID  oldlastv = lastvalloced;
+
+    if (lastvalloced) 
+    {
+        int xflag = 0;
+
+        ret = NULL;
+        while (!ret) 
+        {
+            ret = VirtualAlloc( lastvalloced, len,
+                                MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE );
+            if (!ret)
+                lastvalloced = (char *) lastvalloced + 0x10000;
+
+            /* we failed to allocate one in the first round.
+             * try non-linear
+             */
+            if (!xflag && (lastvalloced<oldlastv)) 
+            { 
+                /* wrapped */
+                FIXME( "failed to allocate linearly growing memory (%ld bytes), "
+                       "using non-linear growing...\n", len );
+                xflag++;
+            }
+
+            /* if we even fail to allocate something in the next
+             * round, return NULL
+             */
+            if ((xflag==1) && (lastvalloced >= oldlastv))
+                xflag++;
+
+            if ((xflag==2) && (lastvalloced < oldlastv)) {
+                FIXME( "failed to allocate any memory of %ld bytes!\n", len );
+                return NULL;
+            }
+        }
+    } 
+    else
+    {
+        ret = VirtualAlloc( NULL, len, 
+                            MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE );
+    }
+
+    lastvalloced = (LPVOID)(((DWORD)ret+len+0xffff)&~0xffff);
+    return ret;
+}
+
+/**********************************************************************
+ *          DPMI_xfree
+ */
+static void DPMI_xfree( LPVOID ptr ) 
+{
+    VirtualFree( ptr, 0, MEM_RELEASE );
+}
+
+/**********************************************************************
+ *          DPMI_xrealloc
+ *
+ * FIXME: perhaps we could grow this mapped area... 
+ */
+static LPVOID DPMI_xrealloc( LPVOID ptr, DWORD newsize ) 
+{
+    MEMORY_BASIC_INFORMATION        mbi;
+    LPVOID                          newptr;
+
+    newptr = DPMI_xalloc( newsize );
+    if (ptr) 
+    {
+        if (!VirtualQuery(ptr,&mbi,sizeof(mbi))) 
+        {
+            FIXME( "realloc of DPMI_xallocd region %p?\n", ptr );
+            return NULL;
+        }
+
+        if (mbi.State == MEM_FREE) 
+        {
+            FIXME( "realloc of DPMI_xallocd region %p?\n", ptr );
+            return NULL;
+        }
+
+        /* We do not shrink allocated memory. most reallocs
+         * only do grows anyway
+         */
+        if (newsize <= mbi.RegionSize)
+            return ptr;
+
+        memcpy( newptr, ptr, mbi.RegionSize );
+        DPMI_xfree( ptr );
+    }
+
+    return newptr;
+}
+
 
 #ifdef __i386__
 
@@ -619,6 +723,55 @@
 }
 
 /**********************************************************************
+ *          DOSVM_RawModeSwitchWrapper
+ *
+ * DPMI Raw Mode Switch wrapper.
+ * This routine does all the stack manipulation tricks needed
+ * to return from protected mode interrupt using modified 
+ * code and stack pointers.
+ */
+static void DOSVM_RawModeSwitchWrapper( CONTEXT86 *context )
+{
+    /*
+     * FIXME: This routine will not work if it is called
+     *        from 32 bit DPMI program and the program returns
+     *        to protected mode while ESP or EIP is over 0xffff.
+     * FIXME: This routine will not work if it is not called
+     *        using 16-bit-to-Wine callback glue function.
+     */
+    STACK16FRAME frame = *CURRENT_STACK16;
+  
+    DOSVM_RawModeSwitch( context );
+
+    /*
+     * After this function returns to relay code, protected mode
+     * 16 bit stack will contain STACK16FRAME and single WORD
+     * (EFlags, see next comment).
+     */
+    NtCurrentTeb()->cur_stack =
+        MAKESEGPTR( context->SegSs,
+                    context->Esp - sizeof(STACK16FRAME) - sizeof(WORD) );
+  
+    /*
+     * After relay code returns to glue function, protected
+     * mode 16 bit stack will contain interrupt return record:
+     * IP, CS and EFlags. Since EFlags is ignored, it won't
+     * need to be initialized.
+     */
+    context->Esp -= 3 * sizeof(WORD);
+
+    /*
+     * Restore stack frame so that relay code won't be confused.
+     * It should be noted that relay code overwrites IP and CS
+     * in STACK16FRAME with values taken from current CONTEXT86.
+     * These values are what is returned to glue function
+     * (see previous comment).
+     */
+    *CURRENT_STACK16 = frame;
+}
+
+
+/**********************************************************************
  *         DOSVM_CheckWrappers
  *
  * Check if this was really a wrapper call instead of an interrupt.
@@ -631,10 +784,10 @@
     /* Handle protected mode interrupts. */
     if (!ISV86(context)) {
         if (context->SegCs == DOSVM_dpmi_segments->dpmi_sel) {
-           INT_Int31Handler( context ); /* FIXME: Call RawModeSwitch */
-           return TRUE;
-       }
-       return FALSE;
+            DOSVM_RawModeSwitchWrapper( context );
+            return TRUE;
+        }
+        return FALSE;
     }
 
     /* check if it's our wrapper */
@@ -718,13 +871,78 @@
         break;
 
     case 0x0002:  /* Real mode segment to descriptor */
+        TRACE( "real mode segment to descriptor (0x%04x)\n", BX_reg(context) );
+        {
+            WORD entryPoint = 0;  /* KERNEL entry point for descriptor */
+            switch(BX_reg(context))
+            {
+            case 0x0000: entryPoint = 183; break;  /* __0000H */
+            case 0x0040: entryPoint = 193; break;  /* __0040H */
+            case 0xa000: entryPoint = 174; break;  /* __A000H */
+            case 0xb000: entryPoint = 181; break;  /* __B000H */
+            case 0xb800: entryPoint = 182; break;  /* __B800H */
+            case 0xc000: entryPoint = 195; break;  /* __C000H */
+            case 0xd000: entryPoint = 179; break;  /* __D000H */
+            case 0xe000: entryPoint = 190; break;  /* __E000H */
+            case 0xf000: entryPoint = 194; break;  /* __F000H */
+            default:
+                SET_AX( context, DOSMEM_AllocSelector(BX_reg(context)) );
+                break;
+            }
+            if (entryPoint)
+            {
+                FARPROC16 proc = GetProcAddress16( GetModuleHandle16( "KERNEL" ),
+                                                   (LPCSTR)(ULONG_PTR)entryPoint );
+                SET_AX( context, LOWORD(proc) );
+            }
+        }
+        break;
+
     case 0x0003:  /* Get next selector increment */
+        TRACE("get selector increment (__AHINCR)\n");
+        context->Eax = __AHINCR;
+        break;
+
     case 0x0004:  /* Lock selector (not supported) */
+        FIXME("lock selector not supported\n");
+        context->Eax = 0;  /* FIXME: is this a correct return value? */
+        break;
+
     case 0x0005:  /* Unlock selector (not supported) */
+        FIXME("unlock selector not supported\n");
+        context->Eax = 0;  /* FIXME: is this a correct return value? */
+        break;
+
     case 0x0006:  /* Get selector base address */
+        TRACE( "get selector base address (0x%04x)\n", BX_reg(context) );
+        {
+            WORD sel = BX_reg(context);
+            if (IS_SELECTOR_SYSTEM(sel) || IS_SELECTOR_FREE(sel))
+            {
+                context->Eax = 0x8022;  /* invalid selector */
+                SET_CFLAG(context);
+            }
+            else
+            {
+                DWORD base = GetSelectorBase( sel );
+                SET_CX( context, HIWORD(base) );
+                SET_DX( context, LOWORD(base) );
+            }
+        }
+        break;
+
     case 0x0007:  /* Set selector base address */
-        /* chain to protected mode handler */
-        INT_Int31Handler( context ); /* FIXME: move DPMI code here */
+        {
+            DWORD base = MAKELONG( DX_reg(context), CX_reg(context) );
+            WORD  sel = BX_reg(context);
+            TRACE( "set selector base address (0x%04x,0x%08lx)\n", sel, base );
+
+            /* check if Win16 app wants to access lower 64K of DOS memory */
+            if (base < 0x10000 && DOSVM_IsWin16())
+                DOSMEM_Init(TRUE);
+
+            SetSelectorBase( sel, base );
+        }
         break;
 
     case 0x0008:  /* Set selector limit */
@@ -737,14 +955,83 @@
         break;
 
     case 0x0009:  /* Set selector access rights */
+        TRACE( "set selector access rights(0x%04x,0x%04x)\n",
+               BX_reg(context), CX_reg(context) );
+        SelectorAccessRights16( BX_reg(context), 1, CX_reg(context) );
+        break;
+
     case 0x000a:  /* Allocate selector alias */
+        TRACE( "allocate selector alias (0x%04x)\n", BX_reg(context) );
+        if (!SET_AX( context, AllocCStoDSAlias16( BX_reg(context) )))
+        {
+            SET_AX( context, 0x8011 );  /* descriptor unavailable */
+            SET_CFLAG(context);
+        }
+        break;
+
     case 0x000b:  /* Get descriptor */
+        TRACE( "get descriptor (0x%04x)\n", BX_reg(context) );
+        {
+            LDT_ENTRY *entry = (LDT_ENTRY*)CTX_SEG_OFF_TO_LIN( context,
+                                                               context->SegEs, 
+                                                               context->Edi );
+            wine_ldt_get_entry( BX_reg(context), entry );
+        }
+        break;
+
     case 0x000c:  /* Set descriptor */
+        TRACE( "set descriptor (0x%04x)\n", BX_reg(context) );
+        {
+            LDT_ENTRY *entry = (LDT_ENTRY*)CTX_SEG_OFF_TO_LIN( context,
+                                                               context->SegEs, 
+                                                               context->Edi );
+            wine_ldt_set_entry( BX_reg(context), entry );
+        }
+        break;
+
     case 0x000d:  /* Allocate specific LDT descriptor */
+        FIXME( "allocate descriptor (0x%04x), stub!\n", BX_reg(context) );
+        SET_AX( context, 0x8011 ); /* descriptor unavailable */
+        SET_CFLAG( context );
+        break;
+
+    case 0x000e:  /* Get Multiple Descriptors (1.0) */
+        FIXME( "get multiple descriptors - unimplemented\n" );
+        break;
+
+    case 0x000f:  /* Set Multiple Descriptors (1.0) */
+        FIXME( "set multiple descriptors - unimplemented\n" );
+        break;
+
     case 0x0100:  /* Allocate DOS memory block */
+        TRACE( "allocate DOS memory block (0x%x paragraphs)\n", BX_reg(context) );
+        {
+            DWORD dw = GlobalDOSAlloc16( (DWORD)BX_reg(context) << 4 );
+            if (dw) {
+                SET_AX( context, HIWORD(dw) );
+                SET_DX( context, LOWORD(dw) );
+            } else {
+                SET_AX( context, 0x0008 ); /* insufficient memory */
+                SET_BX( context, DOSMEM_Available() >> 4 );
+                SET_CFLAG(context);
+            }
+            break;
+        }
+
     case 0x0101:  /* Free DOS memory block */
-        /* chain to protected mode handler */
-        INT_Int31Handler( context ); /* FIXME: move DPMI code here */
+        TRACE( "free DOS memory block (0x%04x)\n", DX_reg(context) );
+        {
+            WORD error = GlobalDOSFree16( DX_reg(context) );
+            if (error) {
+                SET_AX( context, 0x0009 ); /* memory block address invalid */
+                SET_CFLAG( context );
+            }
+        }
+        break;
+
+    case 0x0102: /* Resize DOS Memory Block */
+        FIXME( "resize DOS memory block (0x%04x, 0x%x paragraphs) - unimplemented\n", 
+               DX_reg(context), BX_reg(context) );
         break;
 
     case 0x0200: /* get real mode interrupt vector */
@@ -882,12 +1169,79 @@
         }
         break;
 
+    case 0x0401:  /* Get DPMI Capabilities (1.0) */
+        FIXME( "get dpmi capabilities - unimplemented\n");
+        break;
+
     case 0x0500:  /* Get free memory information */
+        TRACE("get free memory information\n");
+        {
+            MEMMANINFO mmi;
+            void *ptr = CTX_SEG_OFF_TO_LIN( context,
+                                            context->SegEs, 
+                                            context->Edi );
+
+            mmi.dwSize = sizeof( mmi );
+            MemManInfo16( &mmi );
+
+            /* the layout is just the same as MEMMANINFO, but without
+             * the dwSize entry.
+             */
+            memcpy( ptr, ((char*)&mmi)+4, sizeof(mmi)-4 );
+            break;
+        }
+
     case 0x0501:  /* Allocate memory block */
+        {
+            DWORD size = MAKELONG( CX_reg(context), BX_reg(context) );
+            BYTE *ptr;
+
+            TRACE( "allocate memory block (%ld bytes)\n", size );
+
+            ptr = (BYTE *)DPMI_xalloc( size );
+            if (!ptr)
+            {
+                SET_AX( context, 0x8012 );  /* linear memory not available */
+                SET_CFLAG(context);
+            } 
+            else 
+            {
+                SET_BX( context, HIWORD(ptr) );
+                SET_CX( context, LOWORD(ptr) );
+                SET_SI( context, HIWORD(ptr) );
+                SET_DI( context, LOWORD(ptr) );
+            }
+            break;
+        }
+
     case 0x0502:  /* Free memory block */
+        {
+            DWORD handle = MAKELONG( DI_reg(context), SI_reg(context) );
+            TRACE( "free memory block (0x%08lx)\n", handle );
+            DPMI_xfree( (void *)handle );
+        }
+        break;
+
     case 0x0503:  /* Resize memory block */
-        /* chain to protected mode handler */
-        INT_Int31Handler( context ); /* FIXME: move DPMI code here */
+        {
+            DWORD size = MAKELONG( CX_reg(context), BX_reg(context) );
+            DWORD handle = MAKELONG( DI_reg(context), SI_reg(context) );
+            BYTE *ptr;
+
+            TRACE( "resize memory block (0x%08lx, %ld bytes)\n", handle, size );
+
+            ptr = (BYTE *)DPMI_xrealloc( (void *)handle, size );
+            if (!ptr)
+            {
+                SET_AX( context, 0x8012 );  /* linear memory not available */
+                SET_CFLAG(context);
+            } else {
+                SET_BX( context, HIWORD(ptr) );
+                SET_CX( context, LOWORD(ptr) );
+                SET_SI( context, HIWORD(ptr) );
+                SET_DI( context, LOWORD(ptr) );
+            }
+        }
         break;
 
     case 0x0507:  /* Set page attributes (1.0) */
@@ -925,8 +1279,8 @@
         break;  /* Just ignore it */
 
     case 0x0800:  /* Physical address mapping */
-        /* chain to protected mode handler */
-        INT_Int31Handler( context ); /* FIXME: move DPMI code here */
+        FIXME( "physical address mapping (0x%08lx) - unimplemented\n", 
+               MAKELONG(CX_reg(context),BX_reg(context)) );
         break;
 
     default:



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



More information about the wine-patches mailing list