winedos / Enable DPMI IRQs
Jukka Heinonen
jhei at iki.fi
Mon Jun 30 13:09:19 CDT 2003
This patch makes DPMI programs process IRQs and other asynchronous
DOS events. The patch is complete enough for Doom Legacy and hopefully
for a large amount of other protected mode programs.
Interrupt reflection is still missing and real mode IRQ handling
seems to contain some nasty races.
Changelog:
Start processing asynchronous DOS events in DPMI mode.
Index: dlls/winedos/himem.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/himem.c,v
retrieving revision 1.3
diff -u -r1.3 himem.c
--- dlls/winedos/himem.c 15 Dec 2002 01:18:40 -0000 1.3
+++ dlls/winedos/himem.c 30 Jun 2003 17:45:39 -0000
@@ -181,7 +181,8 @@
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 @@
/*
* 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);
Index: dlls/winedos/int31.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/int31.c,v
retrieving revision 1.24
diff -u -r1.24 int31.c
--- dlls/winedos/int31.c 27 Jun 2003 19:40:29 -0000 1.24
+++ dlls/winedos/int31.c 30 Jun 2003 17:45:45 -0000
@@ -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 @@
/**********************************************************************
+ * 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 @@
*/
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 @@
#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 @@
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 )
Index: dlls/winedos/interrupts.c
===================================================================
RCS file: /home/wine/wine/dlls/winedos/interrupts.c,v
retrieving revision 1.16
diff -u -r1.16 interrupts.c
--- dlls/winedos/interrupts.c 30 Jun 2003 02:03:48 -0000 1.16
+++ dlls/winedos/interrupts.c 30 Jun 2003 17:45:50 -0000
@@ -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 @@
/**********************************************************************
+ * 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 @@
}
WARN("int%x not implemented, returning dummy handler\n", intnum );
+
+ if (DOSVM_IsIRQ(intnum))
+ return DOSVM_AcknowledgeIRQ;
+
return DOSVM_DefaultHandler;
}
@@ -122,6 +145,33 @@
/**********************************************************************
+ * 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 @@
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 @@
}
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 @@
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 @@
}
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 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 );
}
Index: memory/instr.c
===================================================================
RCS file: /home/wine/wine/memory/instr.c,v
retrieving revision 1.23
diff -u -r1.23 instr.c
--- memory/instr.c 20 May 2003 17:50:59 -0000 1.23
+++ memory/instr.c 30 Jun 2003 17:45:55 -0000
@@ -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 @@
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;
}
Index: dlls/ntdll/signal_i386.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/signal_i386.c,v
retrieving revision 1.64
diff -u -r1.64 signal_i386.c
--- dlls/ntdll/signal_i386.c 16 Jun 2003 01:18:26 -0000 1.64
+++ dlls/ntdll/signal_i386.c 30 Jun 2003 17:46:03 -0000
@@ -943,6 +943,11 @@
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,9 +970,30 @@
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.
+ */
}
}
--
Jukka Heinonen <http://www.iki.fi/jhei/>
More information about the wine-patches
mailing list