Пример #1
0
/**********************************************************************
 *         DOSVM_EmulateInterruptPM
 *
 * Emulate software interrupt in 16-bit or 32-bit protected mode.
 * Called from signal handler when intXX opcode is executed. 
 *
 * Pushes interrupt frame to stack and changes instruction 
 * pointer to interrupt handler.
 */
void WINAPI DOSVM_EmulateInterruptPM( CONTEXT86 *context, BYTE intnum ) 
{
    TRACE_(relay)("Call DOS int 0x%02x ret=%04lx:%08lx\n"
                  "  eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx\n"
                  "  esi=%08lx edi=%08lx ebp=%08lx esp=%08lx \n"
                  "  ds=%04lx es=%04lx fs=%04lx gs=%04lx ss=%04lx flags=%08lx\n",
                  intnum, 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->SegSs, context->EFlags );

    if (context->SegCs == DOSVM_dpmi_segments->dpmi_sel)
    {
        DOSVM_BuildCallFrame( context, 
                              DOSVM_IntProcRelay,
                              DOSVM_RawModeSwitchHandler );
    }
    else if (context->SegCs == DOSVM_dpmi_segments->relay_code_sel)
    {
        /*
         * This must not be called using DOSVM_BuildCallFrame.
         */
        DOSVM_RelayHandler( context );
    }
    else if (context->SegCs == DOSVM_dpmi_segments->int48_sel)
    {
        /* Restore original flags stored into the stack by the caller. */
        DWORD *stack = CTX_SEG_OFF_TO_LIN(context, 
                                          context->SegSs, context->Esp);
        context->EFlags = stack[2];

        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 );

        DOSVM_BuildCallFrame( context, 
                              DOSVM_IntProcRelay,
                              DOSVM_GetBuiltinHandler(intnum) );
    }
    else if (context->SegCs == DOSVM_dpmi_segments->int16_sel)
    {
        /* Restore original flags stored into the stack by the caller. */
        WORD *stack = CTX_SEG_OFF_TO_LIN(context, 
                                         context->SegSs, context->Esp);
        context->EFlags = (DWORD)MAKELONG( stack[2], HIWORD(context->EFlags) );

        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 );

        DOSVM_BuildCallFrame( context, 
                              DOSVM_IntProcRelay, 
                              DOSVM_GetBuiltinHandler(intnum) );
    }
    else
    {
        DOSVM_HardwareInterruptPM( context, intnum );
    }
}
Пример #2
0
/***********************************************************************
 *              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);
    }
}