#include "winerror.h"
#include "wownt32.h"
#include "excpt.h"
-#include "winreg.h"
+#include "thread.h"
#include "winternl.h"
-#include "file.h"
-#include "task.h"
-#include "miscemu.h"
-#include "selectors.h"
-#include "stackframe.h"
#include "kernel_private.h"
+#include "kernel16_private.h"
#include "wine/exception.h"
#include "wine/debug.h"
/* symbols exported from relay16.s */
extern DWORD WINAPI wine_call_to_16( FARPROC16 target, DWORD cbArgs, PEXCEPTION_HANDLER handler );
extern void WINAPI wine_call_to_16_regs( CONTEXT86 *context, DWORD cbArgs, PEXCEPTION_HANDLER handler );
-extern void Call16_Ret_Start(), Call16_Ret_End();
-extern void CallTo16_Ret();
+extern void __wine_call_to_16_ret(void);
extern void CALL32_CBClient_Ret();
extern void CALL32_CBClientEx_Ret();
-extern DWORD CallTo16_DataSelector;
-extern SEGPTR CALL32_CBClient_RetAddr;
-extern SEGPTR CALL32_CBClientEx_RetAddr;
-extern BYTE Call16_Start;
-extern BYTE Call16_End;
+extern void DPMI_PendingEventCheck();
+extern void DPMI_PendingEventCheck_Cleanup();
+extern void DPMI_PendingEventCheck_Return();
+extern BYTE __wine_call16_start[];
+extern BYTE __wine_call16_end[];
extern void RELAY16_InitDebugLists(void);
static LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs );
-static SEGPTR call16_ret_addr; /* segptr to CallTo16_Ret routine */
+static SEGPTR call16_ret_addr; /* segptr to __wine_call_to_16_ret routine */
+
+static WORD dpmi_checker_selector;
+static DWORD dpmi_checker_offset_call;
+static DWORD dpmi_checker_offset_cleanup;
+static DWORD dpmi_checker_offset_return;
/***********************************************************************
* WOWTHUNK_Init
BOOL WOWTHUNK_Init(void)
{
/* allocate the code selector for CallTo16 routines */
- WORD codesel = SELECTOR_AllocBlock( (void *)Call16_Ret_Start,
- (char *)Call16_Ret_End - (char *)Call16_Ret_Start,
- WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
+ LDT_ENTRY entry;
+ WORD codesel = wine_ldt_alloc_entries(1);
+
if (!codesel) return FALSE;
+ wine_ldt_set_base( &entry, __wine_call16_start );
+ wine_ldt_set_limit( &entry, (BYTE *)(&CallTo16_TebSelector + 1) - __wine_call16_start - 1 );
+ wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
+ wine_ldt_set_entry( codesel, &entry );
/* Patch the return addresses for CallTo16 routines */
CallTo16_DataSelector = wine_get_ds();
- call16_ret_addr = MAKESEGPTR( codesel, (char*)CallTo16_Ret - (char*)Call16_Ret_Start );
+ call16_ret_addr = MAKESEGPTR( codesel, (BYTE *)__wine_call_to_16_ret - __wine_call16_start );
CALL32_CBClient_RetAddr =
- MAKESEGPTR( codesel, (char*)CALL32_CBClient_Ret - (char*)Call16_Ret_Start );
+ MAKESEGPTR( codesel, (BYTE *)CALL32_CBClient_Ret - __wine_call16_start );
CALL32_CBClientEx_RetAddr =
- MAKESEGPTR( codesel, (char*)CALL32_CBClientEx_Ret - (char*)Call16_Ret_Start );
+ MAKESEGPTR( codesel, (BYTE *)CALL32_CBClientEx_Ret - __wine_call16_start );
+
+ /* Prepare selector and offsets for DPMI event checking. */
+ dpmi_checker_selector = codesel;
+ dpmi_checker_offset_call = (BYTE *)DPMI_PendingEventCheck - __wine_call16_start;
+ dpmi_checker_offset_cleanup = (BYTE *)DPMI_PendingEventCheck_Cleanup - __wine_call16_start;
+ dpmi_checker_offset_return = (BYTE *)DPMI_PendingEventCheck_Return - __wine_call16_start;
if (TRACE_ON(relay) || TRACE_ON(snoop)) RELAY16_InitDebugLists();
WORD *stack;
BYTE *instr = (BYTE *)context->Eip;
- if (instr < &Call16_Start || instr >= &Call16_End) return FALSE;
+ if (instr < __wine_call16_start || instr >= __wine_call16_end) return FALSE;
/* skip prefixes */
while (*instr == 0x66 || *instr == 0x67) instr++;
}
+/*************************************************************
+ * insert_event_check
+ *
+ * Make resuming the context check for pending DPMI events
+ * before the original context is restored. This is required
+ * because DPMI events are asynchronous, they are blocked while
+ * Wine 32-bit code is being executed and we want to prevent
+ * a race when returning back to 16-bit or 32-bit DPMI context.
+ */
+static void insert_event_check( CONTEXT *context )
+{
+ char *stack = wine_ldt_get_ptr( context->SegSs, context->Esp );
+
+ /* don't do event check while in system code */
+ if (wine_ldt_is_system(context->SegCs))
+ return;
+
+ if(context->SegCs == dpmi_checker_selector &&
+ context->Eip >= dpmi_checker_offset_call &&
+ context->Eip <= dpmi_checker_offset_cleanup)
+ {
+ /*
+ * Nested call. Stack will be preserved.
+ */
+ }
+ else if(context->SegCs == dpmi_checker_selector &&
+ context->Eip == dpmi_checker_offset_return)
+ {
+ /*
+ * Nested call. We have just finished popping the fs
+ * register, lets put it back into stack.
+ */
+
+ stack -= sizeof(WORD);
+ *(WORD*)stack = context->SegFs;
+
+ context->Esp -= 2;
+ }
+ else
+ {
+ /*
+ * Call is not nested.
+ * Push modified registers into stack.
+ * These will be popped by the assembler stub.
+ */
+
+ stack -= sizeof(DWORD);
+ *(DWORD*)stack = context->EFlags;
+
+ stack -= sizeof(DWORD);
+ *(DWORD*)stack = context->SegCs;
+
+ stack -= sizeof(DWORD);
+ *(DWORD*)stack = context->Eip;
+
+ stack -= sizeof(WORD);
+ *(WORD*)stack = context->SegFs;
+
+ context->Esp -= 14;
+ }
+
+ /*
+ * Modify the context so that we jump into assembler stub.
+ * TEB access is made easier by providing the stub
+ * with the correct fs register value.
+ */
+
+ context->SegCs = dpmi_checker_selector;
+ context->Eip = dpmi_checker_offset_call;
+ context->SegFs = wine_get_fs();
+}
+
+
/*************************************************************
* call16_handler
*
{
/* unwinding: restore the stack pointer in the TEB, and leave the Win16 mutex */
STACK32FRAME *frame32 = (STACK32FRAME *)((char *)frame - offsetof(STACK32FRAME,frame));
- NtCurrentTeb()->cur_stack = frame32->frame16;
+ NtCurrentTeb()->WOW32Reserved = (void *)frame32->frame16;
_LeaveWin16Lock();
}
else if (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
SEGPTR gpHandler;
DWORD ret = INSTR_EmulateInstruction( record, context );
+ /*
+ * Insert check for pending DPMI events. Note that this
+ * check must be inserted after instructions have been
+ * emulated because the instruction emulation requires
+ * original CS:IP and the emulation may change TEB.dpmi_vif.
+ */
+ if(NtCurrentTeb()->dpmi_vif)
+ insert_event_check( context );
+
if (ret != ExceptionContinueSearch) return ret;
/* check for Win16 __GP handler */
}
}
}
+ else if (record->ExceptionCode == EXCEPTION_VM86_STI)
+ {
+ insert_event_check( context );
+ }
return ExceptionContinueSearch;
}
* (both for PASCAL and CDECL calling convention), so we simply
* copy them to the 16-bit stack ...
*/
- WORD *stack = (WORD *)CURRENT_STACK16 - cbArgs / sizeof(WORD);
+ char *stack = (char *)CURRENT_STACK16 - cbArgs;
memcpy( stack, pArgs, cbArgs );
if (TRACE_ON(relay))
{
DWORD count = cbArgs / sizeof(WORD);
+ WORD * wstack = (WORD *)stack;
DPRINTF("%04lx:CallTo16(func=%04lx:%04x,ds=%04lx",
GetCurrentThreadId(),
context->SegCs, LOWORD(context->Eip), context->SegDs );
- while (count) DPRINTF( ",%04x", stack[--count] );
+ while (count) DPRINTF( ",%04x", wstack[--count] );
DPRINTF(") ss:sp=%04x:%04x",
- SELECTOROF(NtCurrentTeb()->cur_stack), OFFSETOF(NtCurrentTeb()->cur_stack) );
+ SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved) );
DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x es=%04x fs=%04x\n",
(WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
(WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi,
/* push return address */
if (dwFlags & WCB16_REGS_LONG)
{
- *((DWORD *)stack - 1) = HIWORD(call16_ret_addr);
- *((DWORD *)stack - 2) = LOWORD(call16_ret_addr);
+ stack -= sizeof(DWORD);
+ *((DWORD *)stack) = HIWORD(call16_ret_addr);
+ stack -= sizeof(DWORD);
+ *((DWORD *)stack) = LOWORD(call16_ret_addr);
cbArgs += 2 * sizeof(DWORD);
}
else
{
- *((SEGPTR *)stack - 1) = call16_ret_addr;
+ stack -= sizeof(SEGPTR);
+ *((SEGPTR *)stack) = call16_ret_addr;
cbArgs += sizeof(SEGPTR);
}
+ /*
+ * Start call by checking for pending events.
+ * Note that wine_call_to_16_regs overwrites context stack
+ * pointer so we may modify it here without a problem.
+ */
+ if (NtCurrentTeb()->dpmi_vif)
+ {
+ context->SegSs = wine_get_ds();
+ context->Esp = (DWORD)stack;
+ insert_event_check( context );
+ cbArgs += (DWORD)stack - context->Esp;
+ }
+
_EnterWin16Lock();
wine_call_to_16_regs( context, cbArgs, call16_handler );
_LeaveWin16Lock();
if (TRACE_ON(relay))
{
DPRINTF("%04lx:RetFrom16() ss:sp=%04x:%04x ",
- GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->cur_stack),
- OFFSETOF(NtCurrentTeb()->cur_stack));
+ GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->WOW32Reserved),
+ OFFSETOF(NtCurrentTeb()->WOW32Reserved));
DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x bp=%04x sp=%04x\n",
(WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
(WORD)context->Edx, (WORD)context->Ebp, (WORD)context->Esp );
if (TRACE_ON(relay))
{
DWORD count = cbArgs / sizeof(WORD);
+ WORD * wstack = (WORD *)stack;
DPRINTF("%04lx:CallTo16(func=%04x:%04x,ds=%04x",
GetCurrentThreadId(), HIWORD(vpfn16), LOWORD(vpfn16),
- SELECTOROF(NtCurrentTeb()->cur_stack) );
- while (count) DPRINTF( ",%04x", stack[--count] );
+ SELECTOROF(NtCurrentTeb()->WOW32Reserved) );
+ while (count) DPRINTF( ",%04x", wstack[--count] );
DPRINTF(") ss:sp=%04x:%04x\n",
- SELECTOROF(NtCurrentTeb()->cur_stack), OFFSETOF(NtCurrentTeb()->cur_stack) );
+ SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved) );
SYSLEVEL_CheckNotLevel( 2 );
}
/* push return address */
- *((SEGPTR *)stack - 1) = call16_ret_addr;
+ stack -= sizeof(SEGPTR);
+ *((SEGPTR *)stack) = call16_ret_addr;
cbArgs += sizeof(SEGPTR);
/*
if (TRACE_ON(relay))
{
DPRINTF("%04lx:RetFrom16() ss:sp=%04x:%04x retval=%08lx\n",
- GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->cur_stack),
- OFFSETOF(NtCurrentTeb()->cur_stack), ret);
+ GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->WOW32Reserved),
+ OFFSETOF(NtCurrentTeb()->WOW32Reserved), ret);
SYSLEVEL_CheckNotLevel( 2 );
}
}
DWORD WINAPI LoadLibraryEx32W16( LPCSTR lpszLibFile, DWORD hFile, DWORD dwFlags )
{
HMODULE hModule;
- DOS_FULL_NAME full_name;
DWORD mutex_count;
- UNICODE_STRING libfileW;
- LPCWSTR filenameW;
- static const WCHAR dllW[] = {'.','D','L','L',0};
+ OFSTRUCT ofs;
+ const char *p;
if (!lpszLibFile)
{
return 0;
}
- if (!RtlCreateUnicodeStringFromAsciiz(&libfileW, lpszLibFile))
+ /* if the file cannot be found, call LoadLibraryExA anyway, since it might be
+ a builtin module. This case is handled in MODULE_LoadLibraryExA */
+
+ if ((p = strrchr( lpszLibFile, '.' )) && !strchr( p, '\\' )) /* got an extension */
{
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return 0;
+ if (OpenFile16( lpszLibFile, &ofs, OF_EXIST ) != HFILE_ERROR16)
+ lpszLibFile = ofs.szPathName;
+ }
+ else
+ {
+ char buffer[MAX_PATH+4];
+ strcpy( buffer, lpszLibFile );
+ strcat( buffer, ".dll" );
+ if (OpenFile16( buffer, &ofs, OF_EXIST ) != HFILE_ERROR16)
+ lpszLibFile = ofs.szPathName;
}
-
- /* if the file can not be found, call LoadLibraryExA anyway, since it might be
- a buildin module. This case is handled in MODULE_LoadLibraryExA */
-
- filenameW = libfileW.Buffer;
- if ( DIR_SearchPath( NULL, filenameW, dllW, &full_name, FALSE ) )
- filenameW = full_name.short_name;
ReleaseThunkLock( &mutex_count );
- hModule = LoadLibraryExW( filenameW, (HANDLE)hFile, dwFlags );
+ hModule = LoadLibraryExA( lpszLibFile, (HANDLE)hFile, dwFlags );
RestoreThunkLock( mutex_count );
- RtlFreeUnicodeString(&libfileW);
-
return (DWORD)hModule;
}