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