Move all int31 functions to winedos.

Fix some obvious bugs in int31 functions.
This commit is contained in:
Jukka Heinonen 2002-11-11 19:55:52 +00:00 committed by Alexandre Julliard
parent 9cec0a57b0
commit 69f74dbf0e
2 changed files with 372 additions and 12 deletions

View File

@ -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

View File

@ -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 @@ typedef struct tagRMCB {
static RMCB *FirstRMCB = NULL;
static WORD dpmi_flag;
static void* lastvalloced = NULL;
/**********************************************************************
* DOSVM_IsDos32
@ -122,6 +125,107 @@ static void INT_SetRealModeContext( REALMODECALL *call, CONTEXT86 *context )
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__
@ -618,6 +722,55 @@ void WINAPI DOSVM_FreeRMCB( CONTEXT86 *context )
}
}
/**********************************************************************
* 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
*
@ -631,10 +784,10 @@ static BOOL DOSVM_CheckWrappers( CONTEXT86 *context )
/* 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 @@ void WINAPI DOSVM_Int31Handler( CONTEXT86 *context )
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 @@ void WINAPI DOSVM_Int31Handler( CONTEXT86 *context )
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 @@ void WINAPI DOSVM_Int31Handler( CONTEXT86 *context )
}
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 @@ void WINAPI DOSVM_Int31Handler( CONTEXT86 *context )
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: