Start processing asynchronous DOS events in DPMI mode.
This commit is contained in:
parent
aa1bdc4263
commit
2a3ce4c425
|
@ -943,6 +943,11 @@ static void set_vm86_pend( CONTEXT *context )
|
|||
teb->vm86_ptr = NULL;
|
||||
rec.ExceptionAddress = (LPVOID)context->Eip;
|
||||
EXC_RtlRaiseException( &rec, context );
|
||||
/*
|
||||
* FIXME: EXC_RtlRaiseException has unblocked all signals.
|
||||
* If we receive nested SIGUSR2 here, VM86 event
|
||||
* handling may lock up!
|
||||
*/
|
||||
teb->vm86_ptr = vm86;
|
||||
}
|
||||
}
|
||||
|
@ -965,10 +970,31 @@ static void set_vm86_pend( CONTEXT *context )
|
|||
save_vm86_context( &vcontext, vm86 );
|
||||
rec.ExceptionAddress = (LPVOID)vcontext.Eip;
|
||||
EXC_RtlRaiseException( &rec, &vcontext );
|
||||
/*
|
||||
* FIXME: EXC_RtlRaiseException has unblocked all signals.
|
||||
* If we receive nested SIGUSR2 here, VM86 event
|
||||
* handling may lock up!
|
||||
*/
|
||||
teb->vm86_ptr = vm86;
|
||||
restore_vm86_context( &vcontext, vm86 );
|
||||
}
|
||||
}
|
||||
else if(teb->dpmi_vif &&
|
||||
!IS_SELECTOR_SYSTEM(context->SegCs) &&
|
||||
!IS_SELECTOR_SYSTEM(context->SegSs))
|
||||
{
|
||||
/* Executing DPMI code and virtual interrupts are enabled. */
|
||||
teb->vm86_pending = 0;
|
||||
rec.ExceptionAddress = (LPVOID)context->Eip;
|
||||
EXC_RtlRaiseException( &rec, context );
|
||||
/*
|
||||
* EXC_RtlRaiseException has unblocked all signals and this
|
||||
* signal handler is about to return to either DOS relay or
|
||||
* IRQ handler. Because both of these will check pending
|
||||
* interrupts again, it is not a problem if we receive
|
||||
* a nested SIGUSR2 here and ignore it.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -181,7 +181,8 @@ void DOSVM_InitSegments( void )
|
|||
static const char relay[]=
|
||||
{
|
||||
0xca, 0x04, 0x00, /* 16-bit far return and pop 4 bytes (relay void* arg) */
|
||||
0xcd, 0x31 /* int 31 */
|
||||
0xcd, 0x31, /* int 31 */
|
||||
0xfb, 0x66, 0xcb /* sti and 32-bit far return */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -253,6 +254,7 @@ void DOSVM_InitSegments( void )
|
|||
/*
|
||||
* PM / offset 0: Stub where __wine_call_from_16_regs returns.
|
||||
* PM / offset 3: Stub which swaps back to 32-bit application code/stack.
|
||||
* PM / offset 5: Stub which enables interrupts
|
||||
*/
|
||||
ptr = DOSVM_AllocCodeUMB( sizeof(relay),
|
||||
0, &DOSVM_dpmi_segments->relay_code_sel);
|
||||
|
|
|
@ -28,7 +28,9 @@
|
|||
#include "msdos.h"
|
||||
#include "dosexe.h"
|
||||
|
||||
#include "excpt.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/exception.h"
|
||||
#include "stackframe.h"
|
||||
#include "toolhelp.h"
|
||||
|
||||
|
@ -78,6 +80,29 @@ BOOL DOSVM_IsDos32(void)
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* dpmi_exception_handler
|
||||
*
|
||||
* Handle EXCEPTION_VM86_STI exceptions generated
|
||||
* when there are pending asynchronous events.
|
||||
*/
|
||||
static WINE_EXCEPTION_FILTER(dpmi_exception_handler)
|
||||
{
|
||||
EXCEPTION_RECORD *rec = GetExceptionInformation()->ExceptionRecord;
|
||||
CONTEXT *context = GetExceptionInformation()->ContextRecord;
|
||||
|
||||
if (rec->ExceptionCode == EXCEPTION_VM86_STI)
|
||||
{
|
||||
if (ISV86(context))
|
||||
ERR( "Real mode STI caught by protected mode handler!\n" );
|
||||
DOSVM_SendQueuedEvents(context);
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* INT_GetRealModeContext
|
||||
*/
|
||||
|
@ -297,10 +322,15 @@ __ASM_GLOBAL_FUNC(DPMI_CallRMCB32,
|
|||
*/
|
||||
static void DPMI_CallRMCBProc( CONTEXT86 *context, RMCB *rmcb, WORD flag )
|
||||
{
|
||||
DWORD old_vif = NtCurrentTeb()->dpmi_vif;
|
||||
|
||||
/* Disable virtual interrupts. */
|
||||
NtCurrentTeb()->dpmi_vif = 0;
|
||||
|
||||
if (IS_SELECTOR_SYSTEM( rmcb->proc_sel )) {
|
||||
/* Wine-internal RMCB, call directly */
|
||||
((RMCBPROC)rmcb->proc_ofs)(context);
|
||||
} else {
|
||||
} else __TRY {
|
||||
#ifdef __i386__
|
||||
UINT16 ss,es;
|
||||
DWORD esp,edi;
|
||||
|
@ -340,7 +370,10 @@ static void DPMI_CallRMCBProc( CONTEXT86 *context, RMCB *rmcb, WORD flag )
|
|||
#else
|
||||
ERR("RMCBs only implemented for i386\n");
|
||||
#endif
|
||||
}
|
||||
} __EXCEPT(dpmi_exception_handler) { } __ENDTRY
|
||||
|
||||
/* Restore virtual interrupt flag. */
|
||||
NtCurrentTeb()->dpmi_vif = old_vif;
|
||||
}
|
||||
|
||||
|
||||
|
@ -548,17 +581,36 @@ static void StartPM( CONTEXT86 *context )
|
|||
|
||||
TRACE("DOS program is now entering %d-bit protected mode\n",
|
||||
DOSVM_IsDos32() ? 32 : 16);
|
||||
wine_call_to_16_regs_short(&pm_ctx, 0);
|
||||
|
||||
/*
|
||||
* Enable interrupts. Note that we also make a dummy
|
||||
* relay call in order to process all pending events.
|
||||
* This is needed in order to prevent event handling from
|
||||
* getting stuck.
|
||||
*/
|
||||
NtCurrentTeb()->dpmi_vif = 1;
|
||||
DOSVM_BuildCallFrame( context, NULL, NULL );
|
||||
|
||||
__TRY
|
||||
{
|
||||
wine_call_to_16_regs_short(&pm_ctx, 0);
|
||||
}
|
||||
__EXCEPT(dpmi_exception_handler)
|
||||
{
|
||||
}
|
||||
__ENDTRY
|
||||
|
||||
/* in the current state of affairs, we won't ever actually return here... */
|
||||
/* we should have int21/ah=4c do it someday, though... */
|
||||
|
||||
#if 0
|
||||
FreeSelector16(psp->environment);
|
||||
psp->environment = env_seg;
|
||||
FreeSelector16(es);
|
||||
if (ds != ss) FreeSelector16(ds);
|
||||
FreeSelector16(ss);
|
||||
FreeSelector16(cs);
|
||||
#endif
|
||||
}
|
||||
|
||||
static RMCB *DPMI_AllocRMCB( void )
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "wine/debug.h"
|
||||
#include "wine/winbase16.h"
|
||||
|
||||
#include "thread.h"
|
||||
|
||||
#ifdef HAVE_SYS_VM86_H
|
||||
# include <sys/vm86.h>
|
||||
#endif
|
||||
|
@ -80,6 +82,23 @@ static const INTPROC DOSVM_VectorsBuiltin[] =
|
|||
#define DOSVM_STUB_PM48 6
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DOSVM_IsIRQ
|
||||
*
|
||||
* Return TRUE if interrupt is an IRQ.
|
||||
*/
|
||||
static BOOL DOSVM_IsIRQ( BYTE intnum )
|
||||
{
|
||||
if (intnum >= 0x08 && intnum <= 0x0f)
|
||||
return TRUE;
|
||||
|
||||
if (intnum >= 0x70 && intnum <= 0x77)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DOSVM_DefaultHandler
|
||||
*
|
||||
|
@ -105,6 +124,10 @@ static INTPROC DOSVM_GetBuiltinHandler( BYTE intnum )
|
|||
}
|
||||
|
||||
WARN("int%x not implemented, returning dummy handler\n", intnum );
|
||||
|
||||
if (DOSVM_IsIRQ(intnum))
|
||||
return DOSVM_AcknowledgeIRQ;
|
||||
|
||||
return DOSVM_DefaultHandler;
|
||||
}
|
||||
|
||||
|
@ -121,6 +144,33 @@ static void DOSVM_IntProcRelay( CONTEXT86 *context, LPVOID data )
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DOSVM_PrepareIRQ
|
||||
*
|
||||
*/
|
||||
static void DOSVM_PrepareIRQ( CONTEXT86 *context, BOOL isbuiltin )
|
||||
{
|
||||
/* Disable virtual interrupts. */
|
||||
NtCurrentTeb()->dpmi_vif = 0;
|
||||
|
||||
if (!isbuiltin)
|
||||
{
|
||||
DWORD *stack = CTX_SEG_OFF_TO_LIN(context,
|
||||
context->SegSs,
|
||||
context->Esp);
|
||||
|
||||
/* Push return address to stack. */
|
||||
*(--stack) = context->SegCs;
|
||||
*(--stack) = context->Eip;
|
||||
context->Esp += -8;
|
||||
|
||||
/* Jump to enable interrupts stub. */
|
||||
context->SegCs = DOSVM_dpmi_segments->relay_code_sel;
|
||||
context->Eip = 5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* DOSVM_PushFlags
|
||||
*
|
||||
|
@ -270,6 +320,8 @@ void DOSVM_HardwareInterruptPM( CONTEXT86 *context, BYTE intnum )
|
|||
|
||||
if (intnum == 0x25 || intnum == 0x26)
|
||||
DOSVM_PushFlags( context, TRUE, FALSE );
|
||||
else if (DOSVM_IsIRQ(intnum))
|
||||
DOSVM_PrepareIRQ( context, TRUE );
|
||||
|
||||
DOSVM_BuildCallFrame( context,
|
||||
DOSVM_IntProcRelay,
|
||||
|
@ -278,14 +330,16 @@ void DOSVM_HardwareInterruptPM( CONTEXT86 *context, BYTE intnum )
|
|||
}
|
||||
else
|
||||
{
|
||||
DWORD *stack = CTX_SEG_OFF_TO_LIN(context,
|
||||
context->SegSs,
|
||||
context->Esp);
|
||||
DWORD *stack;
|
||||
|
||||
TRACE( "invoking hooked interrupt %02x at %04x:%08lx\n",
|
||||
intnum, addr.selector, addr.offset );
|
||||
|
||||
if (DOSVM_IsIRQ(intnum))
|
||||
DOSVM_PrepareIRQ( context, FALSE );
|
||||
|
||||
/* Push the flags and return address on the stack */
|
||||
stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
|
||||
*(--stack) = context->EFlags;
|
||||
*(--stack) = context->SegCs;
|
||||
*(--stack) = context->Eip;
|
||||
|
@ -308,7 +362,9 @@ void DOSVM_HardwareInterruptPM( CONTEXT86 *context, BYTE intnum )
|
|||
|
||||
if (intnum == 0x25 || intnum == 0x26)
|
||||
DOSVM_PushFlags( context, FALSE, FALSE );
|
||||
|
||||
else if (DOSVM_IsIRQ(intnum))
|
||||
DOSVM_PrepareIRQ( context, TRUE );
|
||||
|
||||
DOSVM_BuildCallFrame( context,
|
||||
DOSVM_IntProcRelay,
|
||||
DOSVM_GetBuiltinHandler(
|
||||
|
@ -316,14 +372,16 @@ void DOSVM_HardwareInterruptPM( CONTEXT86 *context, BYTE intnum )
|
|||
}
|
||||
else
|
||||
{
|
||||
WORD *stack = CTX_SEG_OFF_TO_LIN(context,
|
||||
context->SegSs,
|
||||
context->Esp);
|
||||
WORD *stack;
|
||||
|
||||
TRACE( "invoking hooked interrupt %02x at %04x:%04x\n",
|
||||
intnum, SELECTOROF(addr), OFFSETOF(addr) );
|
||||
|
||||
if (DOSVM_IsIRQ(intnum))
|
||||
DOSVM_PrepareIRQ( context, FALSE );
|
||||
|
||||
/* Push the flags and return address on the stack */
|
||||
stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
|
||||
*(--stack) = LOWORD(context->EFlags);
|
||||
*(--stack) = context->SegCs;
|
||||
*(--stack) = LOWORD(context->Eip);
|
||||
|
@ -537,6 +595,12 @@ void DOSVM_SetPMHandler48( BYTE intnum, FARPROC48 handler )
|
|||
*/
|
||||
void WINAPI DOSVM_CallBuiltinHandler( CONTEXT86 *context, BYTE intnum )
|
||||
{
|
||||
/*
|
||||
* FIXME: Make all builtin interrupt calls go via this routine.
|
||||
* FIXME: Check for PM->RM interrupt reflection.
|
||||
* FIXME: Check for RM->PM interrupt reflection.
|
||||
*/
|
||||
|
||||
INTPROC proc = DOSVM_GetBuiltinHandler( intnum );
|
||||
proc( context );
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include "selectors.h"
|
||||
#include "wine/debug.h"
|
||||
#include "callback.h"
|
||||
#include "thread.h"
|
||||
#include "wine/exception.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(int);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(io);
|
||||
|
@ -793,12 +795,19 @@ DWORD INSTR_EmulateInstruction( CONTEXT86 *context )
|
|||
context->Eip += prefixlen + 1;
|
||||
return 0;
|
||||
|
||||
case 0xfa: /* cli, ignored */
|
||||
case 0xfa: /* cli */
|
||||
NtCurrentTeb()->dpmi_vif = 0;
|
||||
context->Eip += prefixlen + 1;
|
||||
return 0;
|
||||
|
||||
case 0xfb: /* sti, ignored */
|
||||
case 0xfb: /* sti */
|
||||
NtCurrentTeb()->dpmi_vif = 1;
|
||||
context->Eip += prefixlen + 1;
|
||||
if (NtCurrentTeb()->vm86_pending)
|
||||
{
|
||||
NtCurrentTeb()->vm86_pending = 0;
|
||||
return EXCEPTION_VM86_STI;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue