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