Ejemplo n.º 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 );
    }
}
Ejemplo n.º 2
0
/**********************************************************************
 *         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 );
        
        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 );
            else if (DOSVM_IsIRQ(intnum))
                DOSVM_PrepareIRQ( context, TRUE );

            DOSVM_BuildCallFrame( context,
                                  DOSVM_IntProcRelay,
                                  DOSVM_GetBuiltinHandler(
                                      addr.offset/DOSVM_STUB_PM48 ) );
        }
        else
        {
            DWORD *stack;
            
            TRACE( "invoking hooked interrupt %02x at %04x:%08lx\n",
                   intnum, addr.selector, addr.offset );
            
            if (DOSVM_IsIRQ(intnum))
                DOSVM_PrepareIRQ( context, FALSE );

            /* Push the flags and return address on the stack */
            stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
            *(--stack) = context->EFlags;
            *(--stack) = context->SegCs;
            *(--stack) = context->Eip;
            context->Esp += -12;

            /* Jump to the interrupt handler */
            context->SegCs  = addr.selector;
            context->Eip = addr.offset;
        }
    }
    else
    {
        FARPROC16 addr = DOSVM_GetPMHandler16( intnum );

        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 );
            else if (DOSVM_IsIRQ(intnum))
                DOSVM_PrepareIRQ( context, TRUE );

            DOSVM_BuildCallFrame( context, 
                                  DOSVM_IntProcRelay,
                                  DOSVM_GetBuiltinHandler(
                                      OFFSETOF(addr)/DOSVM_STUB_PM16 ) );
        }
        else
        {
            TRACE( "invoking hooked interrupt %02x at %04x:%04x\n", 
                   intnum, SELECTOROF(addr), OFFSETOF(addr) );

            if (DOSVM_IsIRQ(intnum))
                DOSVM_PrepareIRQ( context, FALSE );

            /* Push the flags and return address on the stack */
            PUSH_WORD16( context, LOWORD(context->EFlags) );
            PUSH_WORD16( context, context->SegCs );
            PUSH_WORD16( context, LOWORD(context->Eip) );

            /* Jump to the interrupt handler */
            context->SegCs =  HIWORD(addr);
            context->Eip = LOWORD(addr);
        }
    }
}
Ejemplo n.º 3
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);
    }
}