Commit 2a3ce4c4 authored by Jukka Heinonen's avatar Jukka Heinonen Committed by Alexandre Julliard

Start processing asynchronous DOS events in DPMI mode.

parent aa1bdc42
......@@ -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"
......@@ -79,6 +81,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
*/
static void INT_GetRealModeContext( REALMODECALL *call, CONTEXT86 *context )
......@@ -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
......@@ -81,6 +83,23 @@ static const INTPROC DOSVM_VectorsBuiltin[] =
/**********************************************************************
* 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
*
* Default interrupt handler. This will be used to emulate all
......@@ -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;
}
......@@ -122,6 +145,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
*
* This routine is used to make default int25 and int26 handlers leave the
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment