This patch reorganizes interrupt handling a bit. RM and PM interrupts are now handled using similar functions. This patch also contains some stuff for handling emulated hardware interrupts in PM. Changelog: Move real mode interrupt emulation code to file interrupts.c. Remove last wrapper check from int31 handler. Move RM/PM hardware interrupt emulation code to separate functions. Index: dlls/winedos/dosexe.h =================================================================== RCS file: /home/wine/wine/dlls/winedos/dosexe.h,v retrieving revision 1.22 diff -u -r1.22 dosexe.h --- dlls/winedos/dosexe.h 11 Feb 2003 22:22:50 -0000 1.22 +++ dlls/winedos/dosexe.h 2 Mar 2003 15:34:41 -0000 @@ -93,7 +93,6 @@ extern void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val ); extern void WINAPI DOSVM_SetTimer( UINT ticks ); extern UINT WINAPI DOSVM_GetTimer( void ); -extern void DOSVM_RealModeInterrupt( BYTE intnum, CONTEXT86 *context ); /* devices.c */ extern void DOSDEV_InstallDOSDevices(void); @@ -198,6 +197,7 @@ extern FARPROC16 WINAPI DPMI_AllocInternalRMCB(RMCBPROC); extern void WINAPI DPMI_FreeInternalRMCB(FARPROC16); extern int DPMI_CallRMProc(CONTEXT86*,LPWORD,int,int); +extern BOOL DOSVM_CheckWrappers(CONTEXT86*); /* int33.c */ extern void WINAPI DOSVM_Int33Handler(CONTEXT86*); @@ -218,13 +218,17 @@ extern void WINAPI EMS_Ioctl_Handler(CONTEXT86*); /* interrupts.c */ -extern FARPROC16 DOSVM_GetRMHandler( BYTE intnum ); -extern void DOSVM_SetRMHandler( BYTE intnum, FARPROC16 handler ); -extern FARPROC16 DOSVM_GetPMHandler16( BYTE intnum ); -extern void DOSVM_SetPMHandler16( BYTE intnum, FARPROC16 handler ); -extern FARPROC48 DOSVM_GetPMHandler48( BYTE intnum ); -extern void DOSVM_SetPMHandler48( BYTE intnum, FARPROC48 handler ); -extern INTPROC DOSVM_GetBuiltinHandler( BYTE intnum ); +extern void WINAPI DOSVM_CallBuiltinHandler( CONTEXT86 *, BYTE ); +extern void WINAPI DOSVM_EmulateInterruptPM( CONTEXT86 *, BYTE ); +extern BOOL WINAPI DOSVM_EmulateInterruptRM( CONTEXT86 *, BYTE ); +extern FARPROC16 DOSVM_GetPMHandler16( BYTE ); +extern FARPROC48 DOSVM_GetPMHandler48( BYTE ); +extern FARPROC16 DOSVM_GetRMHandler( BYTE ); +extern void DOSVM_HardwareInterruptPM( CONTEXT86 *, BYTE ); +extern void DOSVM_HardwareInterruptRM( CONTEXT86 *, BYTE ); +extern void DOSVM_SetPMHandler16( BYTE, FARPROC16 ); +extern void DOSVM_SetPMHandler48( BYTE, FARPROC48 ); +extern void DOSVM_SetRMHandler( BYTE, FARPROC16 ); /* relay.c */ void DOSVM_RelayHandler( CONTEXT86 * ); Index: dlls/winedos/dosvm.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/dosvm.c,v retrieving revision 1.33 diff -u -r1.33 dosvm.c --- dlls/winedos/dosvm.c 12 Feb 2003 01:26:05 -0000 1.33 +++ dlls/winedos/dosvm.c 2 Mar 2003 15:34:55 -0000 @@ -92,53 +92,6 @@ static HANDLE event_notifier; static CONTEXT86 *current_context; -static int DOSVM_SimulateInt( int vect, CONTEXT86 *context, BOOL inwine ) -{ - FARPROC16 handler=DOSVM_GetRMHandler(vect); - - /* check for our real-mode hooks */ - if (vect==0x31) { - if (context->SegCs==DOSVM_dpmi_segments->wrap_seg) { - /* exit from real-mode wrapper */ - return -1; - } - /* we could probably move some other dodgy stuff here too from dpmi.c */ - } - /* check if the call is from our fake BIOS interrupt stubs */ - if ((context->SegCs==0xf000) && !inwine) { - if (vect != (context->Eip/4)) { - TRACE("something fishy going on here (interrupt stub is %02lx)\n", context->Eip/4); - } - TRACE("builtin interrupt %02x has been branched to\n", vect); - DOSVM_RealModeInterrupt(vect, context); - } - /* check if the call goes to an unhooked interrupt */ - else if (SELECTOROF(handler)==0xf000) { - /* if so, call it directly */ - TRACE("builtin interrupt %02x has been invoked (through vector %02x)\n", OFFSETOF(handler)/4, vect); - DOSVM_RealModeInterrupt(OFFSETOF(handler)/4, context); - } - /* the interrupt is hooked, simulate interrupt in DOS space */ - else { - 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", vect, - SELECTOROF(handler), OFFSETOF(handler)); - if (IF_ENABLED(context)) flag|=IF_MASK; - else flag&=~IF_MASK; - - *(--stack)=flag; - *(--stack)=context->SegCs; - *(--stack)=LOWORD(context->Eip); - context->Esp-=6; - context->SegCs=SELECTOROF(handler); - context->Eip=OFFSETOF(handler); - IF_CLR(context); - } - return 0; -} - #define SHOULD_PEND(x) \ (x && ((!current_event) || (x->priority < current_event->priority))) @@ -157,7 +110,8 @@ TRACE("dispatching IRQ %d\n",event->irq); /* note that if DOSVM_SimulateInt calls an internal interrupt directly, * current_event might be cleared (and event freed) in this very call! */ - DOSVM_SimulateInt((event->irq<8)?(event->irq+8):(event->irq-8+0x70),context,TRUE); + DOSVM_HardwareInterruptRM( context, (event->irq < 8) ? + (event->irq + 8) : (event->irq - 8 + 0x70) ); } else { /* callback event */ TRACE("dispatching callback event\n"); @@ -440,7 +394,8 @@ { EXCEPTION_RECORD *rec = GetExceptionInformation()->ExceptionRecord; CONTEXT *context = GetExceptionInformation()->ContextRecord; - int ret, arg = rec->ExceptionInformation[0]; + int arg = rec->ExceptionInformation[0]; + BOOL ret; switch(rec->ExceptionCode) { case EXCEPTION_VM86_INTx: @@ -454,7 +409,7 @@ context->Ebp, context->Esp, context->SegDs, context->SegEs, context->SegFs, context->SegGs, context->EFlags ); } - ret = DOSVM_SimulateInt(arg, context, FALSE); + ret = DOSVM_EmulateInterruptRM( context, arg ); if (TRACE_ON(relay)) { DPRINTF("Ret DOS int 0x%02x ret=%04lx:%04lx\n", arg, context->SegCs, context->Eip ); @@ -465,7 +420,7 @@ context->Ebp, context->Esp, context->SegDs, context->SegEs, context->SegFs, context->SegGs, context->EFlags ); } - return ret ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_EXECUTION; + return ret ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER; case EXCEPTION_VM86_STI: /* case EXCEPTION_VM86_PICRETURN: */ @@ -626,17 +581,6 @@ } #endif - -/********************************************************************** - * DOSVM_RealModeInterrupt - * - * Handle real mode interrupts - */ -void DOSVM_RealModeInterrupt( BYTE intnum, CONTEXT86 *context ) -{ - INTPROC proc = DOSVM_GetBuiltinHandler( intnum ); - proc(context); -} /********************************************************************** Index: dlls/winedos/interrupts.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/interrupts.c,v retrieving revision 1.13 diff -u -r1.13 interrupts.c --- dlls/winedos/interrupts.c 15 Dec 2002 01:18:40 -0000 1.13 +++ dlls/winedos/interrupts.c 2 Mar 2003 15:35:06 -0000 @@ -22,6 +22,19 @@ #include "wine/debug.h" #include "wine/winbase16.h" +#ifdef HAVE_SYS_VM86_H +# include <sys/vm86.h> +#endif + +#ifndef IF_MASK +#define IF_MASK 0x00000200 +#endif + +#ifndef VIF_MASK +#define VIF_MASK 0x00080000 +#endif + + WINE_DEFAULT_DEBUG_CHANNEL(int); static FARPROC16 DOSVM_Vectors16[256]; @@ -69,6 +82,24 @@ /********************************************************************** + * DOSVM_GetBuiltinHandler + * + * Return Wine interrupt handler procedure for a given interrupt. + */ +static INTPROC DOSVM_GetBuiltinHandler( BYTE intnum ) +{ + if (intnum < sizeof(DOSVM_VectorsBuiltin)/sizeof(INTPROC)) { + INTPROC proc = DOSVM_VectorsBuiltin[intnum]; + if (proc) + return proc; + } + + WARN("int%x not implemented, returning dummy handler\n", intnum ); + return DOSVM_DefaultHandler; +} + + +/********************************************************************** * DOSVM_IntProcRelay * * Simple DOSRELAY that interprets its argument as INTPROC and calls it. @@ -173,7 +204,24 @@ DOSVM_IntProcRelay, DOSVM_GetBuiltinHandler(intnum) ); } - else if(DOSVM_IsDos32()) + else + { + DOSVM_HardwareInterruptPM( context, intnum ); + } +} + + +/********************************************************************** + * DOSVM_HardwareInterruptPM + * + * Emulate call to interrupt handler in 16-bit or 32-bit protected mode. + * + * Pushes interrupt frame to stack and changes instruction + * pointer to interrupt handler. + */ +void DOSVM_HardwareInterruptPM( CONTEXT86 *context, BYTE intnum ) +{ + if(DOSVM_IsDos32()) { FARPROC48 addr = DOSVM_GetPMHandler48( intnum ); @@ -235,6 +283,100 @@ } } + +/********************************************************************** + * DOSVM_EmulateInterruptRM + * + * Emulate software interrupt in real mode. + * Called from VM86 emulation when intXX opcode is executed. + * + * Either calls directly builtin handler or pushes interrupt frame to + * stack and changes instruction pointer to interrupt handler. + * + * Returns FALSE if this interrupt was caused by return + * from real mode wrapper. + */ +BOOL WINAPI DOSVM_EmulateInterruptRM( CONTEXT86 *context, BYTE intnum ) +{ + /* check for our real-mode hooks */ + if (intnum == 0x31) + { + /* is this exit from real-mode wrapper */ + if (context->SegCs == DOSVM_dpmi_segments->wrap_seg) + return FALSE; + + if (DOSVM_CheckWrappers( context )) + return TRUE; + } + + /* 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 ); + + TRACE( "builtin interrupt %02x has been branched to\n", intnum ); + + DOSVM_CallBuiltinHandler( context, intnum ); + } + else + { + DOSVM_HardwareInterruptRM( context, intnum ); + } + + return TRUE; +} + + +/********************************************************************** + * DOSVM_HardwareInterruptRM + * + * Emulate call to interrupt handler in real mode. + * + * Either calls directly builtin handler or pushes interrupt frame to + * stack and changes instruction pointer to interrupt handler. + */ +void DOSVM_HardwareInterruptRM( CONTEXT86 *context, BYTE intnum ) +{ + FARPROC16 handler = DOSVM_GetRMHandler( intnum ); + + /* check if the call goes to an unhooked interrupt */ + 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 ); + } + else + { + /* the interrupt is hooked, simulate interrupt in DOS space */ + 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) ); + + /* Copy virtual interrupt flag to pushed interrupt flag. */ + if (context->EFlags & VIF_MASK) + flag |= IF_MASK; + else + flag &= ~IF_MASK; + + *(--stack) = flag; + *(--stack) = context->SegCs; + *(--stack) = LOWORD( context->Eip ); + context->Esp -= 6; + context->SegCs = SELECTOROF( handler ); + context->Eip = OFFSETOF( handler ); + + /* Clear virtual interrupt flag. */ + context->EFlags &= ~VIF_MASK; + } +} + + /********************************************************************** * DOSVM_GetRMHandler * @@ -316,22 +458,6 @@ DOSVM_Vectors48[intnum] = handler; } -/********************************************************************** - * DOSVM_GetBuiltinHandler - * - * Return Wine interrupt handler procedure for a given interrupt. - */ -INTPROC DOSVM_GetBuiltinHandler( BYTE intnum ) -{ - if (intnum < sizeof(DOSVM_VectorsBuiltin)/sizeof(INTPROC)) { - INTPROC proc = DOSVM_VectorsBuiltin[intnum]; - if(proc) - return proc; - } - - WARN("int%x not implemented, returning dummy handler\n", intnum ); - return DOSVM_DefaultHandler; -} /********************************************************************** * DOSVM_CallBuiltinHandler Index: dlls/winedos/int31.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/int31.c,v retrieving revision 1.18 diff -u -r1.18 int31.c --- dlls/winedos/int31.c 26 Feb 2003 20:34:46 -0000 1.18 +++ dlls/winedos/int31.c 2 Mar 2003 15:35:12 -0000 @@ -387,7 +387,7 @@ /* shortcut for chaining to internal interrupt handlers */ if ((context->SegCs == 0xF000) && iret) { - DOSVM_RealModeInterrupt( LOWORD(context->Eip)/4, context); + DOSVM_CallBuiltinHandler( context, LOWORD(context->Eip)/4 ); return 0; } @@ -475,7 +475,7 @@ RESET_CFLAG(context); /* use the IP we have instead of BL_reg, in case some apps decide to move interrupts around for whatever reason... */ - DOSVM_RealModeInterrupt( LOWORD(rm_int)/4, &realmode_ctx ); + DOSVM_CallBuiltinHandler( &realmode_ctx, LOWORD(rm_int)/4 ); } INT_SetRealModeContext( call, &realmode_ctx ); } @@ -744,14 +744,9 @@ * DOSVM_CheckWrappers * * Check if this was really a wrapper call instead of an interrupt. - * FIXME: Protected mode stuff does not work in 32-bit DPMI. - * FIXME: If int31 is called asynchronously (unlikely) - * wrapper checks are wrong (CS/IP must not be used). */ -static BOOL DOSVM_CheckWrappers( CONTEXT86 *context ) +BOOL DOSVM_CheckWrappers( CONTEXT86 *context ) { - /* check if it's our wrapper */ - TRACE("called from real mode\n"); if (context->SegCs==DOSVM_dpmi_segments->dpmi_seg) { /* This is the protected mode switch */ StartPM(context); @@ -788,9 +783,6 @@ */ void WINAPI DOSVM_Int31Handler( CONTEXT86 *context ) { - if (ISV86(context) && DOSVM_CheckWrappers(context)) - return; - RESET_CFLAG(context); switch(AX_reg(context)) { -- Jukka Heinonen <http://www.iki.fi/jhei/>