Skip to content
Snippets Groups Projects
Commit 54a8a25b authored by Jukka Heinonen's avatar Jukka Heinonen Committed by Alexandre Julliard
Browse files

DPMI programs now handle pending events.

parent e55a4b63
Branches
Tags
No related merge requests found
......@@ -824,6 +824,7 @@ DWORD INSTR_EmulateInstruction( EXCEPTION_RECORD *rec, CONTEXT86 *context )
context->Eip += prefixlen + 1;
if (NtCurrentTeb()->vm86_pending)
{
NtCurrentTeb()->vm86_pending = 0;
rec->ExceptionCode = EXCEPTION_VM86_STI;
break; /* Handle the pending event. */
}
......
......@@ -83,6 +83,9 @@ extern void Call16_Ret_Start(), Call16_Ret_End();
extern void CallTo16_Ret();
extern void CALL32_CBClient_Ret();
extern void CALL32_CBClientEx_Ret();
extern void DPMI_PendingEventCheck();
extern void DPMI_PendingEventCheck_Cleanup();
extern void DPMI_PendingEventCheck_Return();
extern DWORD CallTo16_DataSelector;
extern SEGPTR CALL32_CBClient_RetAddr;
extern SEGPTR CALL32_CBClientEx_RetAddr;
......@@ -94,6 +97,11 @@ extern void RELAY16_InitDebugLists(void);
static LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs );
static SEGPTR call16_ret_addr; /* segptr to CallTo16_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
*/
......@@ -114,6 +122,15 @@ BOOL WOWTHUNK_Init(void)
CALL32_CBClientEx_RetAddr =
MAKESEGPTR( codesel, (char*)CALL32_CBClientEx_Ret - (char*)Call16_Ret_Start );
/* Prepare selector and offsets for DPMI event checking. */
dpmi_checker_selector = codesel;
dpmi_checker_offset_call =
(char*)DPMI_PendingEventCheck - (char*)Call16_Ret_Start;
dpmi_checker_offset_cleanup =
(char*)DPMI_PendingEventCheck_Cleanup - (char*)Call16_Ret_Start;
dpmi_checker_offset_return =
(char*)DPMI_PendingEventCheck_Return - (char*)Call16_Ret_Start;
if (TRACE_ON(relay) || TRACE_ON(snoop)) RELAY16_InitDebugLists();
/* setup emulation of protected instructions from 32-bit code (only for Win9x versions) */
......@@ -164,6 +181,75 @@ static BOOL fix_selector( CONTEXT *context )
}
/*************************************************************
* 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 );
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
*
......@@ -191,6 +277,15 @@ static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RE
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 */
......@@ -212,6 +307,10 @@ static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RE
}
}
}
else if (record->ExceptionCode == EXCEPTION_VM86_STI)
{
insert_event_check( context );
}
return ExceptionContinueSearch;
}
......@@ -547,6 +646,19 @@ BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags,
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();
......
......@@ -1043,6 +1043,57 @@ static void BuildCallFrom32Regs( FILE *outfile )
}
/*******************************************************************
* BuildPendingEventCheck
*
* Build a function that checks whether there are any
* pending DPMI events.
*
* Stack layout:
*
* (sp+12) long eflags
* (sp+6) long cs
* (sp+2) long ip
* (sp) word fs
*
* On entry to function, fs register points to a valid TEB.
* On exit from function, stack will be popped.
*/
void BuildPendingEventCheck( FILE *outfile )
{
/* Function header */
function_header( outfile, "DPMI_PendingEventCheck" );
/* Check for pending events. */
fprintf( outfile, "\t.byte 0x64\n\ttestl $0xffffffff,(%d)\n",
STRUCTOFFSET(TEB,vm86_pending) );
fprintf( outfile, "\tje DPMI_PendingEventCheck_Cleanup\n" );
fprintf( outfile, "\t.byte 0x64\n\ttestl $0xffffffff,(%d)\n",
STRUCTOFFSET(TEB,dpmi_vif) );
fprintf( outfile, "\tje DPMI_PendingEventCheck_Cleanup\n" );
/* Process pending events. */
fprintf( outfile, "\tsti\n" );
/* Start cleanup. Restore fs register. */
fprintf( outfile, ".globl DPMI_PendingEventCheck_Cleanup\n" );
fprintf( outfile, "DPMI_PendingEventCheck_Cleanup:\n" );
fprintf( outfile, "\tpopw %%fs\n" );
/* Return from function. */
fprintf( outfile, ".globl DPMI_PendingEventCheck_Return\n" );
fprintf( outfile, "DPMI_PendingEventCheck_Return:\n" );
fprintf( outfile, "\tiret\n" );
}
/*******************************************************************
* BuildRelays16
*
......@@ -1131,6 +1182,9 @@ void BuildRelays16( FILE *outfile )
/* CBClientThunkSLEx return stub */
BuildCallTo32CBClientRet( outfile, TRUE );
/* Pending DPMI events check stub */
BuildPendingEventCheck( outfile );
/* End of Call16_Ret segment */
fprintf( outfile, "\n\t.globl " __ASM_NAME("Call16_Ret_End") "\n" );
fprintf( outfile, __ASM_NAME("Call16_Ret_End") ":\n" );
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment