DPMI programs now handle pending events.
This commit is contained in:
parent
e55a4b634b
commit
54a8a25b5e
|
@ -824,6 +824,7 @@ DWORD INSTR_EmulateInstruction( EXCEPTION_RECORD *rec, CONTEXT86 *context )
|
||||||
context->Eip += prefixlen + 1;
|
context->Eip += prefixlen + 1;
|
||||||
if (NtCurrentTeb()->vm86_pending)
|
if (NtCurrentTeb()->vm86_pending)
|
||||||
{
|
{
|
||||||
|
NtCurrentTeb()->vm86_pending = 0;
|
||||||
rec->ExceptionCode = EXCEPTION_VM86_STI;
|
rec->ExceptionCode = EXCEPTION_VM86_STI;
|
||||||
break; /* Handle the pending event. */
|
break; /* Handle the pending event. */
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,9 @@ extern void Call16_Ret_Start(), Call16_Ret_End();
|
||||||
extern void CallTo16_Ret();
|
extern void CallTo16_Ret();
|
||||||
extern void CALL32_CBClient_Ret();
|
extern void CALL32_CBClient_Ret();
|
||||||
extern void CALL32_CBClientEx_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 DWORD CallTo16_DataSelector;
|
||||||
extern SEGPTR CALL32_CBClient_RetAddr;
|
extern SEGPTR CALL32_CBClient_RetAddr;
|
||||||
extern SEGPTR CALL32_CBClientEx_RetAddr;
|
extern SEGPTR CALL32_CBClientEx_RetAddr;
|
||||||
|
@ -94,6 +97,11 @@ extern void RELAY16_InitDebugLists(void);
|
||||||
static LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs );
|
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 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
|
* WOWTHUNK_Init
|
||||||
*/
|
*/
|
||||||
|
@ -114,6 +122,15 @@ BOOL WOWTHUNK_Init(void)
|
||||||
CALL32_CBClientEx_RetAddr =
|
CALL32_CBClientEx_RetAddr =
|
||||||
MAKESEGPTR( codesel, (char*)CALL32_CBClientEx_Ret - (char*)Call16_Ret_Start );
|
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();
|
if (TRACE_ON(relay) || TRACE_ON(snoop)) RELAY16_InitDebugLists();
|
||||||
|
|
||||||
/* setup emulation of protected instructions from 32-bit code (only for Win9x versions) */
|
/* 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
|
* call16_handler
|
||||||
*
|
*
|
||||||
|
@ -191,6 +277,15 @@ static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RE
|
||||||
SEGPTR gpHandler;
|
SEGPTR gpHandler;
|
||||||
DWORD ret = INSTR_EmulateInstruction( record, context );
|
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;
|
if (ret != ExceptionContinueSearch) return ret;
|
||||||
|
|
||||||
/* check for Win16 __GP handler */
|
/* 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;
|
return ExceptionContinueSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,6 +646,19 @@ BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags,
|
||||||
cbArgs += sizeof(SEGPTR);
|
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();
|
_EnterWin16Lock();
|
||||||
wine_call_to_16_regs( context, cbArgs, call16_handler );
|
wine_call_to_16_regs( context, cbArgs, call16_handler );
|
||||||
_LeaveWin16Lock();
|
_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
|
* BuildRelays16
|
||||||
*
|
*
|
||||||
|
@ -1131,6 +1182,9 @@ void BuildRelays16( FILE *outfile )
|
||||||
/* CBClientThunkSLEx return stub */
|
/* CBClientThunkSLEx return stub */
|
||||||
BuildCallTo32CBClientRet( outfile, TRUE );
|
BuildCallTo32CBClientRet( outfile, TRUE );
|
||||||
|
|
||||||
|
/* Pending DPMI events check stub */
|
||||||
|
BuildPendingEventCheck( outfile );
|
||||||
|
|
||||||
/* End of Call16_Ret segment */
|
/* End of Call16_Ret segment */
|
||||||
fprintf( outfile, "\n\t.globl " __ASM_NAME("Call16_Ret_End") "\n" );
|
fprintf( outfile, "\n\t.globl " __ASM_NAME("Call16_Ret_End") "\n" );
|
||||||
fprintf( outfile, __ASM_NAME("Call16_Ret_End") ":\n" );
|
fprintf( outfile, __ASM_NAME("Call16_Ret_End") ":\n" );
|
||||||
|
|
Loading…
Reference in New Issue