/********************************************************************** * DOSVM_Int20Handler * * Handler for int 20h. */ static void WINAPI DOSVM_Int20Handler( CONTEXT86 *context ) { if (DOSVM_IsWin16()) DOSVM_Exit( 0 ); else if(ISV86(context)) MZ_Exit( context, TRUE, 0 ); else ERR( "Called from DOS protected mode\n" ); }
/********************************************************************** * dpmi_exception_handler * * Handle EXCEPTION_VM86_STI exceptions generated * when there are pending asynchronous events. */ static LONG WINAPI dpmi_exception_handler(EXCEPTION_POINTERS *eptr) { EXCEPTION_RECORD *rec = eptr->ExceptionRecord; CONTEXT *context = eptr->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; } else if (rec->ExceptionCode == EXCEPTION_VM86_INTx) { if (ISV86(context)) ERR( "Real mode INTx caught by protected mode handler!\n" ); DPMI_retval = (BYTE)rec->ExceptionInformation[0]; return EXCEPTION_EXECUTE_HANDLER; } return EXCEPTION_CONTINUE_SEARCH; }
/********************************************************************** * 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)) get_vm86_teb_info()->dpmi_vif = 1; }
/********************************************************************** * dpmi_exception_handler * * Handle EXCEPTION_VM86_STI exceptions generated * when there are pending asynchronous events. */ static WINE_EXCEPTION_FILTER(dpmi_exception_handler) { #ifdef __i386__ 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; } else if (rec->ExceptionCode == EXCEPTION_VM86_INTx) { if (ISV86(context)) ERR( "Real mode INTx caught by protected mode handler!\n" ); DPMI_retval = (BYTE)rec->ExceptionInformation[0]; return EXCEPTION_EXECUTE_HANDLER; } #endif return EXCEPTION_CONTINUE_SEARCH; }
/*********************************************************************** * DOSVM_SendQueuedEvents * * 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. */ 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=%d)\n", ISV86(context) ? "real" : "protected", DOSVM_HasPendingEvents() ? "with" : "without", GetTickCount() ); TRACE( "cs:ip=%04x:%08x, ss:sp=%04x:%08x\n", context->SegCs, context->Eip, context->SegSs, context->Esp); while (context->SegCs == old_cs && context->Eip == old_ip && DOSVM_HasPendingEvents()) { DOSVM_SendOneEvent(context); /* * Event handling may have turned pending events flag on. * We disable it here because this prevents some * unnecessary calls to this function. */ get_vm86_teb_info()->vm86_pending = 0; } #ifdef MZ_SUPPORTED if (DOSVM_HasPendingEvents()) { /* * Interrupts disabled, but there are still * pending events, make sure that pending flag is turned on. */ TRACE( "Another event is pending, setting VIP flag.\n" ); get_vm86_teb_info()->vm86_pending |= VIP_MASK; } #else FIXME("No DOS .exe file support on this platform (yet)\n"); #endif /* MZ_SUPPORTED */ LeaveCriticalSection(&qcrit); }
static LONG WINAPI exception_handler(EXCEPTION_POINTERS *eptr) { EXCEPTION_RECORD *rec = eptr->ExceptionRecord; CONTEXT *context = eptr->ContextRecord; int arg = rec->ExceptionInformation[0]; BOOL ret; switch(rec->ExceptionCode) { case EXCEPTION_VM86_INTx: TRACE_(relay)("Call DOS int 0x%02x ret=%04x:%04x\n" " eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n" " ebp=%08x esp=%08x ds=%04x es=%04x fs=%04x gs=%04x flags=%08x\n", arg, context->SegCs, context->Eip, context->Eax, context->Ebx, context->Ecx, context->Edx, context->Esi, context->Edi, context->Ebp, context->Esp, context->SegDs, context->SegEs, context->SegFs, context->SegGs, context->EFlags ); ret = DOSVM_EmulateInterruptRM( context, arg ); TRACE_(relay)("Ret DOS int 0x%02x ret=%04x:%04x\n" " eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n" " ebp=%08x esp=%08x ds=%04x es=%04x fs=%04x gs=%04x flags=%08x\n", arg, context->SegCs, context->Eip, context->Eax, context->Ebx, context->Ecx, context->Edx, context->Esi, context->Edi, 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 (!ISV86(context)) ERR( "Protected mode STI caught by real mode handler!\n" ); DOSVM_SendQueuedEvents(context); return EXCEPTION_CONTINUE_EXECUTION; case EXCEPTION_SINGLE_STEP: ret = DOSVM_EmulateInterruptRM( context, 1 ); return ret ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER; case EXCEPTION_BREAKPOINT: ret = DOSVM_EmulateInterruptRM( context, 3 ); return ret ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER; } return EXCEPTION_CONTINUE_SEARCH; }
INT WINAPI DOSVM_Enter( CONTEXT86 *context ) { INT ret = 0; if (!ISV86(context)) ERR( "Called with protected mode context!\n" ); __TRY { if (!WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)context )) ret = -1; TRACE_(module)( "ret %d err %u\n", ret, GetLastError() ); } __EXCEPT(exception_handler) { TRACE_(module)( "leaving vm86 mode\n" ); } __ENDTRY return ret; }
static void MouseRelay(CONTEXT *context,void *mdata) { MCALLDATA *data = mdata; CONTEXT ctx = *context; if (!ISV86(&ctx)) { ctx.EFlags |= V86_FLAG; ctx.SegSs = 0; /* Allocate new stack. */ } ctx.Eax = data->mask; ctx.Ebx = data->but; ctx.Ecx = data->x; ctx.Edx = data->y; ctx.Esi = data->mx; ctx.Edi = data->my; ctx.SegCs = SELECTOROF(data->proc); ctx.Eip = OFFSETOF(data->proc); HeapFree(GetProcessHeap(), 0, data); DPMI_CallRMProc(&ctx, NULL, 0, 0); }
/*********************************************************************** * INT_Int41Handler (WPROCS.165) * */ void WINAPI INT_Int41Handler( CONTEXT86 *context ) { if ( ISV86(context) ) { /* Real-mode debugger services */ switch ( AX_reg(context) ) { default: INT_BARF( context, 0x41 ); break; } } else { /* Protected-mode debugger services */ switch ( AX_reg(context) ) { case 0x4f: case 0x50: case 0x150: case 0x51: case 0x52: case 0x152: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: /* Notifies the debugger of a lot of stuff. We simply ignore it for now, but some of the info might actually be useful ... */ break; default: INT_BARF( context, 0x41 ); break; } } }
/*********************************************************************** * DOSVM_Wait * * Wait for asynchronous events. This routine temporarily enables * interrupts and waits until some asynchronous event has been * processed. */ void WINAPI DOSVM_Wait( CONTEXT86 *waitctx ) { if (DOSVM_HasPendingEvents()) { CONTEXT86 context = *waitctx; /* * If DOSVM_Wait is called from protected mode we emulate * interrupt reflection and convert context into real mode context. * This is actually the correct thing to do as long as DOSVM_Wait * is only called from those interrupt functions that DPMI reflects * to real mode. * * FIXME: Need to think about where to place real mode stack. * FIXME: If DOSVM_Wait calls are nested stack gets corrupted. * Can this really happen? */ if (!ISV86(&context)) { context.EFlags |= V86_FLAG; context.SegSs = 0xffff; context.Esp = 0; } context.EFlags |= VIF_MASK; context.SegCs = 0; context.Eip = 0; DOSVM_SendQueuedEvents(&context); if(context.SegCs || context.Eip) DPMI_CallRMProc( &context, NULL, 0, TRUE ); } else { HANDLE objs[2]; int objc = DOSVM_IsWin16() ? 2 : 1; DWORD waitret; objs[0] = event_notifier; objs[1] = GetStdHandle(STD_INPUT_HANDLE); waitret = MsgWaitForMultipleObjects( objc, objs, FALSE, INFINITE, QS_ALLINPUT ); if (waitret == WAIT_OBJECT_0) { /* * New pending event has been queued, we ignore it * here because it will be processed on next call to * DOSVM_Wait. */ } else if (objc == 2 && waitret == WAIT_OBJECT_0 + 1) { DOSVM_ProcessConsole(); } else if (waitret == WAIT_OBJECT_0 + objc) { MSG msg; while (PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD)) { /* got a message */ DOSVM_ProcessMessage(&msg); /* we don't need a TranslateMessage here */ DispatchMessageA(&msg); } } else { ERR_(module)( "dosvm wait error=%d\n", GetLastError() ); } } }
/*********************************************************************** * DOSVM_SendOneEvent * * Process single pending event. * * This function should be called with queue critical section locked. * The function temporarily releases the critical section if it is * possible that internal interrupt handler or user procedure will * be called. This is because we may otherwise get a deadlock if * another thread is waiting for the same critical section. */ static void DOSVM_SendOneEvent( CONTEXT86 *context ) { LPDOSEVENT event = pending_event; /* Remove from pending events list. */ pending_event = event->next; /* Process active event. */ if (event->irq >= 0) { BYTE intnum = (event->irq < 8) ? (event->irq + 8) : (event->irq - 8 + 0x70); /* Event is an IRQ, move it to current events list. */ event->next = current_event; current_event = event; TRACE( "Dispatching IRQ %d.\n", event->irq ); if (ISV86(context)) { /* * Note that if DOSVM_HardwareInterruptRM calls an internal * interrupt directly, current_event might be cleared * (and event freed) in this call. */ LeaveCriticalSection(&qcrit); DOSVM_HardwareInterruptRM( context, intnum ); EnterCriticalSection(&qcrit); } else { /* * This routine only modifies current context so it is * not necessary to release critical section. */ DOSVM_HardwareInterruptPM( context, intnum ); } } else { /* Callback event. */ TRACE( "Dispatching callback event.\n" ); 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); } }
/********************************************************************** * INT_Int15Handler (WPROCS.121) * * Handler for int 15h */ void WINAPI INT_Int15Handler( CONTEXT86 *context ) { switch(AH_reg(context)) { case 0x84: /* read joystick information */ FIXME("Read joystick information not implemented\n"); /* FIXME: report status as if no game port exists */ switch(DX_reg(context)) { case 0x0: /* read joystick switches */ AL_reg(context) = 0x0; /* all switches open */ break; case 0x1: /* read joystick position */ AX_reg(context) = 0x0; BX_reg(context) = 0x0; CX_reg(context) = 0x0; DX_reg(context) = 0x0; break; default: INT_BARF( context, 0x15 ); break; } RESET_CFLAG(context); break; case 0x88: /* get size of memory above 1 M */ AX_reg(context) = 64; /* FIXME: are 64K ok? */ RESET_CFLAG(context); break; case 0xc0: /* GET CONFIGURATION */ if (ISV86(context)) /* real */ context->SegEs = 0xf000; else context->SegEs = DOSMEM_BiosSysSeg; BX_reg(context) = 0xe6f5; AH_reg(context) = 0x0; RESET_CFLAG(context); break; case 0xc2: switch(AL_reg(context)) { case 0x00: /* Enable-Disable Pointing Device (mouse) */ /* BH = newstate, 00h = disabled 01h = enabled */ switch(BH_reg(context)) { case 0x00: FIXME("Disable Pointing Device - not implemented\n"); break; case 0x01: FIXME("Enable Pointing Device - not implemented\n"); break; default: INT_BARF( context, 0x15 ); break; } AH_reg(context) = 0x00; /* successful */ break; case 0x02: /* Set Sampling Rate */ /* BH = sampling rate */ FIXME("Set Sampling Rate - not implemented\n"); AH_reg(context) = 0x00; /* successful */ break; case 0x04: /* Get Pointing Device Type */ FIXME("Get Pointing Device Type - not implemented\n"); BH_reg(context) = 0x01;/*Device id FIXME what is it supposed to be?*/ break; default: INT_BARF( context, 0x15 ); } break; default: INT_BARF( context, 0x15 ); } }