This patch speeds up software interrupts in real mode considerably, in addition to making interrupt handling simpler (at least in my opinion). Instead of throwing an exception, vm86 handler calls winedos callback as is done in case of protected mode software interrupts. Next thing would be converting EXCEPTION_VM86_STI into using a similar mechanism. There might be some need for exception stuff, but I would rather handle them inside signal_i386.c. Changelog: Real mode software interrupts now use callback instead of throwing an exception. Interrupt trace messages have been improved. If application copies builtin interrupt vectors, the correct handler will be called. Index: dlls/winedos/winedos.spec =================================================================== RCS file: /home/wine/wine/dlls/winedos/winedos.spec,v retrieving revision 1.15 diff -u -r1.15 winedos.spec --- dlls/winedos/winedos.spec 11 Feb 2003 22:22:50 -0000 1.15 +++ dlls/winedos/winedos.spec 8 Mar 2003 19:19:34 -0000 @@ -1,5 +1,6 @@ @ stdcall LoadDosExe(str long) MZ_LoadImage @ stdcall EmulateInterruptPM(ptr long) DOSVM_EmulateInterruptPM +@ stdcall EmulateInterruptRM(ptr long) DOSVM_EmulateInterruptRM @ stdcall CallBuiltinHandler(ptr long) DOSVM_CallBuiltinHandler # I/O functions Index: include/callback.h =================================================================== RCS file: /home/wine/wine/include/callback.h,v retrieving revision 1.52 diff -u -r1.52 callback.h --- include/callback.h 11 Feb 2003 22:22:50 -0000 1.52 +++ include/callback.h 8 Mar 2003 19:19:36 -0000 @@ -27,6 +27,7 @@ typedef struct { void (WINAPI *LoadDosExe)( LPCSTR filename, HANDLE hFile ); void (WINAPI *EmulateInterruptPM)( CONTEXT86 *context, BYTE intnum ); + BOOL (WINAPI *EmulateInterruptRM)( CONTEXT86 *context, BYTE intnum ); void (WINAPI *CallBuiltinHandler)( CONTEXT86 *context, BYTE intnum ); /* I/O functions */ Index: msdos/dpmi.c =================================================================== RCS file: /home/wine/wine/msdos/dpmi.c,v retrieving revision 1.74 diff -u -r1.74 dpmi.c --- msdos/dpmi.c 11 Feb 2003 22:22:50 -0000 1.74 +++ msdos/dpmi.c 8 Mar 2003 19:19:38 -0000 @@ -51,6 +51,7 @@ GET_ADDR(inport); GET_ADDR(outport); GET_ADDR(EmulateInterruptPM); + GET_ADDR(EmulateInterruptRM); GET_ADDR(CallBuiltinHandler); #undef GET_ADDR return TRUE; Index: dlls/ntdll/signal_i386.c =================================================================== RCS file: /home/wine/wine/dlls/ntdll/signal_i386.c,v retrieving revision 1.53 diff -u -r1.53 signal_i386.c --- dlls/ntdll/signal_i386.c 4 Mar 2003 22:18:44 -0000 1.53 +++ dlls/ntdll/signal_i386.c 8 Mar 2003 19:19:39 -0000 @@ -55,6 +55,7 @@ #include "wine/library.h" #include "selectors.h" +#include "callback.h" /*********************************************************************** * signal context platform-specific definitions @@ -1311,8 +1312,17 @@ do_trap( context, VM86_ARG(res) ); continue; case VM86_INTx: /* int3/int x instruction (ARG = x) */ - rec.ExceptionCode = EXCEPTION_VM86_INTx; - break; + if (Dosvm.EmulateInterruptRM || DPMI_LoadDosSystem()) + { + /* + * If emulate interrupt routine returns FALSE, + * exit from real mode wrapper was called and + * we should return from this routine. + */ + if (!Dosvm.EmulateInterruptRM( context, VM86_ARG(res) )) + return; + } + continue; case VM86_STI: /* sti/popf/iret instruction enabled virtual interrupts */ teb->vm86_pending = 0; rec.ExceptionCode = EXCEPTION_VM86_STI; Index: dlls/winedos/dosvm.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/dosvm.c,v retrieving revision 1.34 diff -u -r1.34 dosvm.c --- dlls/winedos/dosvm.c 4 Mar 2003 02:16:20 -0000 1.34 +++ dlls/winedos/dosvm.c 8 Mar 2003 19:19:41 -0000 @@ -394,34 +394,9 @@ { EXCEPTION_RECORD *rec = GetExceptionInformation()->ExceptionRecord; CONTEXT *context = GetExceptionInformation()->ContextRecord; - int arg = rec->ExceptionInformation[0]; BOOL ret; switch(rec->ExceptionCode) { - case EXCEPTION_VM86_INTx: - if (TRACE_ON(relay)) { - DPRINTF("Call DOS int 0x%02x ret=%04lx:%04lx\n", - arg, context->SegCs, context->Eip ); - DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n", - context->Eax, context->Ebx, context->Ecx, context->Edx, - context->Esi, context->Edi ); - DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n", - context->Ebp, context->Esp, context->SegDs, context->SegEs, - context->SegFs, context->SegGs, context->EFlags ); - } - ret = DOSVM_EmulateInterruptRM( context, arg ); - if (TRACE_ON(relay)) { - DPRINTF("Ret DOS int 0x%02x ret=%04lx:%04lx\n", - arg, context->SegCs, context->Eip ); - DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n", - context->Eax, context->Ebx, context->Ecx, context->Edx, - context->Esi, context->Edi ); - DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n", - context->Ebp, context->Esp, context->SegDs, context->SegEs, - context->SegFs, context->SegGs, context->EFlags ); - } - return ret ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER; - case EXCEPTION_VM86_STI: /* case EXCEPTION_VM86_PICRETURN: */ IF_SET(context); Index: dlls/winedos/interrupts.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/interrupts.c,v retrieving revision 1.14 diff -u -r1.14 interrupts.c --- dlls/winedos/interrupts.c 4 Mar 2003 02:16:20 -0000 1.14 +++ dlls/winedos/interrupts.c 8 Mar 2003 19:19:43 -0000 @@ -36,6 +36,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(int); +WINE_DECLARE_DEBUG_CHANNEL(relay); + static FARPROC16 DOSVM_Vectors16[256]; static FARPROC48 DOSVM_Vectors48[256]; @@ -70,6 +72,14 @@ }; +/* + * Sizes of real mode and protected mode interrupt stubs. + */ +#define DOSVM_STUB_RM 4 +#define DOSVM_STUB_PM16 5 +#define DOSVM_STUB_PM48 6 + + /********************************************************************** * DOSVM_DefaultHandler * @@ -173,6 +183,19 @@ */ void WINAPI DOSVM_EmulateInterruptPM( CONTEXT86 *context, BYTE intnum ) { + if (TRACE_ON(relay)) + { + DPRINTF( "Call DOS int 0x%02x ret=%04lx:%08lx\n", + intnum, context->SegCs, context->Eip ); + DPRINTF( " eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx\n", + context->Eax, context->Ebx, context->Ecx, context->Edx ); + DPRINTF( " esi=%08lx edi=%08lx ebp=%08lx esp=%08lx \n", + context->Esi, context->Edi, context->Ebp, context->Esp ); + DPRINTF( " ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n", + context->SegDs, context->SegEs, + context->SegFs, context->SegGs, context->EFlags ); + } + if (context->SegCs == DOSVM_dpmi_segments->dpmi_sel) { DOSVM_BuildCallFrame( context, @@ -188,6 +211,13 @@ } else if (context->SegCs == DOSVM_dpmi_segments->int48_sel) { + if (intnum != context->Eip / DOSVM_STUB_PM48) + WARN( "interrupt stub has been modified " + "(interrupt is %02x, interrupt stub is %02lx)\n", + intnum, context->Eip / DOSVM_STUB_PM48 ); + + TRACE( "builtin interrupt %02x has been branched to\n", intnum ); + if (intnum == 0x25 || intnum == 0x26) DOSVM_PushFlags( context, TRUE, TRUE ); @@ -197,6 +227,13 @@ } else if (context->SegCs == DOSVM_dpmi_segments->int16_sel) { + if (intnum != context->Eip / DOSVM_STUB_PM16) + WARN( "interrupt stub has been modified " + "(interrupt is %02x, interrupt stub is %02lx)\n", + intnum, context->Eip / DOSVM_STUB_PM16 ); + + TRACE( "builtin interrupt %02x has been branched to\n", intnum ); + if (intnum == 0x25 || intnum == 0x26) DOSVM_PushFlags( context, FALSE, TRUE ); @@ -227,12 +264,17 @@ if (addr.selector == DOSVM_dpmi_segments->int48_sel) { + TRACE( "builtin interrupt %02lx has been invoked " + "(through vector %02x)\n", + addr.offset / DOSVM_STUB_PM48, intnum ); + if (intnum == 0x25 || intnum == 0x26) DOSVM_PushFlags( context, TRUE, FALSE ); - DOSVM_BuildCallFrame( context, - DOSVM_IntProcRelay, - DOSVM_GetBuiltinHandler(intnum) ); + DOSVM_BuildCallFrame( context, + DOSVM_IntProcRelay, + DOSVM_GetBuiltinHandler( + addr.offset / DOSVM_STUB_PM48 ) ); } else { @@ -240,6 +282,9 @@ context->SegSs, context->Esp); + TRACE( "invoking hooked interrupt %02x at %04x:%08lx\n", + intnum, addr.selector, addr.offset ); + /* Push the flags and return address on the stack */ *(--stack) = context->EFlags; *(--stack) = context->SegCs; @@ -257,12 +302,17 @@ if (SELECTOROF(addr) == DOSVM_dpmi_segments->int16_sel) { + TRACE( "builtin interrupt %02x has been invoked " + "(through vector %02x)\n", + OFFSETOF(addr) / DOSVM_STUB_PM16, intnum ); + if (intnum == 0x25 || intnum == 0x26) DOSVM_PushFlags( context, FALSE, FALSE ); - + DOSVM_BuildCallFrame( context, DOSVM_IntProcRelay, - DOSVM_GetBuiltinHandler(intnum) ); + DOSVM_GetBuiltinHandler( + OFFSETOF(addr) / DOSVM_STUB_PM16 ) ); } else { @@ -270,6 +320,9 @@ context->SegSs, context->Esp); + TRACE( "invoking hooked interrupt %02x at %04x:%04x\n", + intnum, SELECTOROF(addr), OFFSETOF(addr) ); + /* Push the flags and return address on the stack */ *(--stack) = LOWORD(context->EFlags); *(--stack) = context->SegCs; @@ -277,7 +330,7 @@ ADD_LOWORD( context->Esp, -6 ); /* Jump to the interrupt handler */ - context->SegCs = HIWORD(addr); + context->SegCs = HIWORD(addr); context->Eip = LOWORD(addr); } } @@ -298,6 +351,19 @@ */ BOOL WINAPI DOSVM_EmulateInterruptRM( CONTEXT86 *context, BYTE intnum ) { + if (TRACE_ON(relay)) + { + DPRINTF( "Call DOS int 0x%02x ret=%04lx:%08lx\n", + intnum, context->SegCs, context->Eip ); + DPRINTF( " eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx\n", + context->Eax, context->Ebx, context->Ecx, context->Edx ); + DPRINTF( " esi=%08lx edi=%08lx ebp=%08lx esp=%08lx \n", + context->Esi, context->Edi, context->Ebp, context->Esp ); + DPRINTF( " ds=%04lx es=%04lx fs=%04lx gs=%04lx flags=%08lx\n", + context->SegDs, context->SegEs, + context->SegFs, context->SegGs, context->EFlags ); + } + /* check for our real-mode hooks */ if (intnum == 0x31) { @@ -312,9 +378,10 @@ /* check if the call is from our fake BIOS interrupt stubs */ if (context->SegCs==0xf000) { - if (intnum != (context->Eip/4)) - TRACE( "something fishy going on here (interrupt stub is %02lx)\n", - context->Eip/4 ); + if (intnum != context->Eip / DOSVM_STUB_RM) + WARN( "interrupt stub has been modified " + "(interrupt is %02x, interrupt stub is %02lx)\n", + intnum, context->Eip / DOSVM_STUB_RM ); TRACE( "builtin interrupt %02x has been branched to\n", intnum ); @@ -345,9 +412,10 @@ if (SELECTOROF(handler) == 0xf000) { /* if so, call it directly */ - TRACE( "builtin interrupt %02x has been invoked (through vector %02x)\n", - OFFSETOF(handler)/4, intnum ); - DOSVM_CallBuiltinHandler( context, OFFSETOF(handler)/4 ); + TRACE( "builtin interrupt %02x has been invoked " + "(through vector %02x)\n", + OFFSETOF(handler) / DOSVM_STUB_RM, intnum ); + DOSVM_CallBuiltinHandler( context, OFFSETOF(handler) / DOSVM_STUB_RM ); } else { @@ -355,8 +423,8 @@ WORD* stack = PTR_REAL_TO_LIN( context->SegSs, context->Esp ); WORD flag = LOWORD( context->EFlags ); - TRACE_(int)( "invoking hooked interrupt %02x at %04x:%04x\n", - intnum, SELECTOROF(handler), OFFSETOF(handler) ); + TRACE( "invoking hooked interrupt %02x at %04x:%04x\n", + intnum, SELECTOROF(handler), OFFSETOF(handler) ); /* Copy virtual interrupt flag to pushed interrupt flag. */ if (context->EFlags & VIF_MASK) @@ -387,6 +455,7 @@ return ((FARPROC16*)0)[intnum]; } + /********************************************************************** * DOSVM_SetRMHandler * @@ -410,7 +479,7 @@ if (!DOSVM_Vectors16[intnum]) { FARPROC16 proc = (FARPROC16)MAKESEGPTR( DOSVM_dpmi_segments->int16_sel, - 5 * intnum ); + DOSVM_STUB_PM16 * intnum ); DOSVM_Vectors16[intnum] = proc; } return DOSVM_Vectors16[intnum]; @@ -429,6 +498,7 @@ DOSVM_Vectors16[intnum] = handler; } + /********************************************************************** * DOSVM_GetPMHandler48 * @@ -440,10 +510,11 @@ if (!DOSVM_Vectors48[intnum].selector) { DOSVM_Vectors48[intnum].selector = DOSVM_dpmi_segments->int48_sel; - DOSVM_Vectors48[intnum].offset = 6 * intnum; + DOSVM_Vectors48[intnum].offset = DOSVM_STUB_PM48 * intnum; } return DOSVM_Vectors48[intnum]; } + /********************************************************************** * DOSVM_SetPMHandler48 -- Jukka Heinonen <http://www.iki.fi/jhei/>