This patch prepares things for DPMI IRQ handling. After this patch I have two small patches that are needed in order to get DPMI IRQ handling running. Changelog: Add IRQ acknowledge handler for internal IRQs. Change DPMI asynchronous event handling. Always use alternate stack in DPMI relays and check for pending events after original stack has been restored. Index: dlls/winedos/dosexe.h =================================================================== RCS file: /home/wine/wine/dlls/winedos/dosexe.h,v retrieving revision 1.26 diff -u -r1.26 dosexe.h --- dlls/winedos/dosexe.h 6 Jun 2003 18:09:14 -0000 1.26 +++ dlls/winedos/dosexe.h 22 Jun 2003 16:36:06 -0000 @@ -105,6 +105,8 @@ extern BOOL DOSVM_IsWin16(void); /* dosvm.c */ +extern void DOSVM_SendQueuedEvents( CONTEXT86 * ); +extern void WINAPI DOSVM_AcknowledgeIRQ( CONTEXT86 * ); extern INT WINAPI DOSVM_Enter( CONTEXT86 *context ); extern void WINAPI DOSVM_Wait( CONTEXT86 * ); extern DWORD WINAPI DOSVM_Loop( HANDLE hThread ); Index: dlls/winedos/int09.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/int09.c,v retrieving revision 1.6 diff -u -r1.6 int09.c --- dlls/winedos/int09.c 6 Nov 2002 19:57:49 -0000 1.6 +++ dlls/winedos/int09.c 22 Jun 2003 16:36:15 -0000 @@ -206,7 +206,8 @@ DOSVM_Int16AddChar(0, scan); } } - DOSVM_PIC_ioport_out( 0x20, 0x20 ); /* send EOI */ + + DOSVM_AcknowledgeIRQ( context ); } static void KbdRelay( CONTEXT86 *context, void *data ) Index: dlls/winedos/dosvm.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/dosvm.c,v retrieving revision 1.40 diff -u -r1.40 dosvm.c --- dlls/winedos/dosvm.c 20 Jun 2003 21:27:49 -0000 1.40 +++ dlls/winedos/dosvm.c 22 Jun 2003 16:36:20 -0000 @@ -159,9 +159,23 @@ /* Callback event. */ TRACE( "Dispatching callback event.\n" ); - LeaveCriticalSection(&qcrit); - (*event->relay)( context, event->data ); - EnterCriticalSection(&qcrit); + if (ISV86(context)) + { + /* + * Call relay immediately in real mode. + */ + LeaveCriticalSection(&qcrit); + (*event->relay)( context, event->data ); + EnterCriticalSection(&qcrit); + } + else + { + /* + * Force return to relay code. We do not want to + * call relay directly because we may be inside a signal handler. + */ + DOSVM_BuildCallFrame( context, event->relay, event->data ); + } free(event); } @@ -171,23 +185,30 @@ /*********************************************************************** * DOSVM_SendQueuedEvents * - * As long as interrupts are enabled, process all pending events - * that are not blocked by currently active event. + * As long as context instruction pointer stays unmodified, + * process all pending events that are not blocked by currently + * active event. + * + * This routine assumes that caller has already cleared TEB.vm86_pending + * and checked that interrupts are enabled. */ -static void DOSVM_SendQueuedEvents( CONTEXT86 *context ) -{ +void DOSVM_SendQueuedEvents( CONTEXT86 *context ) +{ + DWORD old_cs = context->SegCs; + DWORD old_ip = context->Eip; + EnterCriticalSection(&qcrit); TRACE( "Called in %s mode %s events pending (time=%ld)\n", ISV86(context) ? "real" : "protected", DOSVM_HasPendingEvents() ? "with" : "without", GetTickCount() ); - TRACE( "cs:ip=%04lx:%08lx, ss:sp=%04lx:%08lx\n", + TRACE( "cs:ip=%04lx:%08lx, ss:sp=%04lx:%08lx\n", context->SegCs, context->Eip, context->SegSs, context->Esp); - while (DOSVM_HasPendingEvents() && - (ISV86(context) ? - (context->EFlags & VIF_MASK) : NtCurrentTeb()->dpmi_vif)) + while (context->SegCs == old_cs && + context->Eip == old_ip && + DOSVM_HasPendingEvents()) { DOSVM_SendOneEvent(context); @@ -199,6 +220,17 @@ NtCurrentTeb()->vm86_pending = 0; } + if (!ISV86(context) && context->SegCs == old_cs && context->Eip == old_ip) + { + /* + * Routine was called from DPMI but there was nothing to do. + * We force a dummy relay call here so that we don't get a race + * if signals are unblocked when we return to DPMI application. + */ + TRACE( "Called but there was nothing to do, calling NULL relay.\n" ); + DOSVM_BuildCallFrame( context, NULL, NULL ); + } + if (DOSVM_HasPendingEvents()) { /* @@ -617,6 +649,27 @@ } #endif + + +/********************************************************************** + * DOSVM_AcknowledgeIRQ + * + * This routine should be called by all internal IRQ handlers. + */ +void WINAPI DOSVM_AcknowledgeIRQ( CONTEXT86 *context ) +{ + /* + * Send EOI to PIC. + */ + DOSVM_PIC_ioport_out( 0x20, 0x20 ); + + /* + * Protected mode IRQ handlers are supposed + * to turn VIF flag on before they return. + */ + if (!ISV86(context)) + NtCurrentTeb()->dpmi_vif = 1; +} /********************************************************************** Index: dlls/winedos/relay.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/relay.c,v retrieving revision 1.1 diff -u -r1.1 relay.c --- dlls/winedos/relay.c 15 Dec 2002 01:18:40 -0000 1.1 +++ dlls/winedos/relay.c 22 Jun 2003 16:36:25 -0000 @@ -31,8 +31,7 @@ #define RELAY_MAGIC 0xabcdef00 /* - * Memory block for temporary 16-bit stacks used when - * 32-bit code calls relay. + * Memory block for temporary 16-bit stacks used with relay calls. */ typedef struct { DWORD inuse; /* non-zero if stack block is in use */ @@ -62,9 +61,8 @@ /********************************************************************** * RELAY_MakeShortContext * - * If context is using 32-bit stack or code segment, allocate - * 16-bit stack, make stack pointer point to this stack and - * make code pointer point to stub that restores everything. + * Allocate separate 16-bit stack, make stack pointer point to this + * stack and make code pointer point to stub that restores everything. * So, after this routine, SS and CS are guaranteed to be 16-bit. * * Note: This might be called from signal handler, so the stack @@ -72,33 +70,30 @@ */ static void RELAY_MakeShortContext( CONTEXT86 *context ) { - if (IS_SELECTOR_32BIT(context->SegCs) || IS_SELECTOR_32BIT(context->SegSs)) - { - DWORD offset = offsetof(RELAY_Stack16, stack_top); - RELAY_Stack16 *stack = RELAY_GetPointer( 0 ); + DWORD offset = offsetof(RELAY_Stack16, stack_top); + RELAY_Stack16 *stack = RELAY_GetPointer( 0 ); - while (stack->inuse && offset < DOSVM_RELAY_DATA_SIZE) { - stack++; - offset += sizeof(RELAY_Stack16); - } + while (stack->inuse && offset < DOSVM_RELAY_DATA_SIZE) { + stack++; + offset += sizeof(RELAY_Stack16); + } - if (offset >= DOSVM_RELAY_DATA_SIZE) - ERR( "Too many nested interrupts!\n" ); + if (offset >= DOSVM_RELAY_DATA_SIZE) + ERR( "Too many nested interrupts!\n" ); - stack->inuse = 1; - stack->eip = context->Eip; - stack->seg_cs = context->SegCs; - stack->esp = context->Esp; - stack->seg_ss = context->SegSs; - - stack->stack_bottom = RELAY_MAGIC; - stack->stack_top = RELAY_MAGIC; - - context->SegSs = DOSVM_dpmi_segments->relay_data_sel; - context->Esp = offset; - context->SegCs = DOSVM_dpmi_segments->relay_code_sel; - context->Eip = 3; - } + stack->inuse = 1; + stack->eip = context->Eip; + stack->seg_cs = context->SegCs; + stack->esp = context->Esp; + stack->seg_ss = context->SegSs; + + stack->stack_bottom = RELAY_MAGIC; + stack->stack_top = RELAY_MAGIC; + + context->SegSs = DOSVM_dpmi_segments->relay_data_sel; + context->Esp = offset; + context->SegCs = DOSVM_dpmi_segments->relay_code_sel; + context->Eip = 3; } @@ -112,7 +107,8 @@ unsigned char *args, void *context ) { - proc( (CONTEXT86*)context, *(LPVOID *)args ); + if (proc) + proc( (CONTEXT86*)context, *(LPVOID *)args ); } @@ -136,6 +132,17 @@ ERR( "Stack corrupted!\n" ); stack->inuse = 0; + + /* + * We have now restored original stack and instruction pointers. + * Because signals are blocked here, this is a safe place to + * check for pending events before we return to application context. + */ + if (NtCurrentTeb()->vm86_pending && NtCurrentTeb()->dpmi_vif) + { + NtCurrentTeb()->vm86_pending = 0; + DOSVM_SendQueuedEvents( context ); + } } @@ -182,7 +189,7 @@ void DOSVM_RestoreCallFrame( CONTEXT86 *context, STACK16FRAME *frame ) { /* - * Make sure that CS and SS are 16-bit. + * Allocate separate stack for relay call. */ RELAY_MakeShortContext( context ); @@ -226,7 +233,7 @@ WORD code_sel = DOSVM_dpmi_segments->relay_code_sel; /* - * Make sure that CS and SS are 16-bit. + * Allocate separate stack for relay call. */ RELAY_MakeShortContext( context ); -- Jukka Heinonen <http://www.iki.fi/jhei/>