mirror of
https://github.com/reactos/wine.git
synced 2024-11-24 20:30:01 +00:00
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;
|
||||
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" );
|
||||
|
Loading…
Reference in New Issue
Block a user