Example #1
0
/**********************************************************************
 *         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 ) 
{
    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 );

    /* 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)
    {
        /* 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_RM)
            WARN( "interrupt stub has been modified "
                  "(interrupt is %02x, interrupt stub is %02lx)\n",
                  intnum, context->Eip/DOSVM_STUB_RM );

        TRACE( "builtin interrupt %02x has been branched to\n", intnum );
        
        DOSVM_CallBuiltinHandler( context, intnum );

        /* Real mode stubs use IRET so we must put flags back into stack. */
        stack[2] = LOWORD(context->EFlags);
    }
    else
    {
        DOSVM_HardwareInterruptRM( context, intnum );
    }

    return TRUE;
}
Example #2
0
/**********************************************************************
 *         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)/DOSVM_STUB_RM, intnum );
         DOSVM_CallBuiltinHandler( context, OFFSETOF(handler)/DOSVM_STUB_RM );
     }
     else 
     {
         /* the interrupt is hooked, simulate interrupt in DOS space */ 
         WORD  flag  = LOWORD( context->EFlags );

         TRACE( "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;

         PUSH_WORD16( context, flag );
         PUSH_WORD16( context, context->SegCs );
         PUSH_WORD16( context, LOWORD( context->Eip ));
         
         context->SegCs = SELECTOROF( handler );
         context->Eip   = OFFSETOF( handler );

         /* Clear virtual interrupt flag and trap flag. */
         context->EFlags &= ~(VIF_MASK | TF_MASK);
     }
}
Example #3
0
/**********************************************************************
 *	    CallRMInt   (WINEDOS.@)
 */
void WINAPI DOSVM_CallRMInt( CONTEXT86 *context )
{
    CONTEXT86 realmode_ctx;
    FARPROC16 rm_int = DOSVM_GetRMHandler( BL_reg(context) );
    REALMODECALL *call = CTX_SEG_OFF_TO_LIN( context, 
                                             context->SegEs, 
                                             context->Edi );
    INT_GetRealModeContext( call, &realmode_ctx );

    /* we need to check if a real-mode program has hooked the interrupt */
    if (HIWORD(rm_int)!=0xF000) {
        /* yup, which means we need to switch to real mode... */
        realmode_ctx.SegCs = HIWORD(rm_int);
        realmode_ctx.Eip   = LOWORD(rm_int);
        if (DPMI_CallRMProc( &realmode_ctx, NULL, 0, TRUE))
          SET_CFLAG(context);
    } else {
        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_CallBuiltinHandler( &realmode_ctx, LOWORD(rm_int)/4 );
    }
    INT_SetRealModeContext( call, &realmode_ctx );
}
Example #4
0
/**********************************************************************
 *         __wine_call_int_handler    (KERNEL.@)
 */
void __wine_call_int_handler( CONTEXT86 *context, BYTE intnum )
{
    DOSMEM_InitDosMemory();
    DOSVM_CallBuiltinHandler( context, intnum );
}
Example #5
0
/**********************************************************************
 *	    DPMI_CallRMProc
 *
 * This routine does the hard work of calling a real mode procedure.
 */
int DPMI_CallRMProc( CONTEXT86 *context, LPWORD stack, int args, int iret )
{
    LPWORD stack16;
    LPVOID addr = NULL; /* avoid gcc warning */
    RMCB *CurrRMCB;
    int alloc = 0, already = 0;
    BYTE *code;

    TRACE("EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n",
                 context->Eax, context->Ebx, context->Ecx, context->Edx );
    TRACE("ESI=%08lx EDI=%08lx ES=%04lx DS=%04lx CS:IP=%04lx:%04x, %d WORD arguments, %s\n",
                 context->Esi, context->Edi, context->SegEs, context->SegDs,
                 context->SegCs, LOWORD(context->Eip), args, iret?"IRET":"FAR" );

callrmproc_again:

/* there might be some code that just jumps to RMCBs or the like,
   in which case following the jumps here might get us to a shortcut */
    code = CTX_SEG_OFF_TO_LIN(context, context->SegCs, context->Eip);
    switch (*code) {
    case 0xe9: /* JMP NEAR */
      context->Eip += 3 + *(WORD *)(code+1);
      /* yeah, I know these gotos don't look good... */
      goto callrmproc_again;
    case 0xea: /* JMP FAR */
      context->Eip = *(WORD *)(code+1);
      context->SegCs = *(WORD *)(code+3);
      /* ...but since the label is there anyway... */
      goto callrmproc_again;
    case 0xeb: /* JMP SHORT */
      context->Eip += 2 + *(signed char *)(code+1);
      /* ...because of other gotos below, so... */
      goto callrmproc_again;
    }

/* shortcut for chaining to internal interrupt handlers */
    if ((context->SegCs == 0xF000) && iret)
    {
        DOSVM_CallBuiltinHandler( context, LOWORD(context->Eip)/4 );
        return 0;
    }

/* shortcut for RMCBs */
    CurrRMCB = FirstRMCB;

    while (CurrRMCB && (HIWORD(CurrRMCB->address) != context->SegCs))
        CurrRMCB = CurrRMCB->next;

    if (!CurrRMCB && !MZ_Current())
    {
        FIXME("DPMI real-mode call using DOS VM task system, not fully tested!\n");
        TRACE("creating VM86 task\n");
        MZ_AllocDPMITask();
    }
    if (!already) {
        if (!context->SegSs) {
            alloc = 1; /* allocate default stack */
            stack16 = addr = DOSMEM_AllocBlock( 64, (UINT16 *)&(context->SegSs) );
            context->Esp = 64-2;
            stack16 += 32-1;
            if (!addr) {
                ERR("could not allocate default stack\n");
                return 1;
            }
        } else {
            stack16 = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
        }
        context->Esp -= (args + (iret?1:0)) * sizeof(WORD);
        stack16 -= args;
        if (args) memcpy(stack16, stack, args*sizeof(WORD) );
        /* push flags if iret */
        if (iret) {
            stack16--; args++;
            *stack16 = LOWORD(context->EFlags);
        }
        /* push return address (return to interrupt wrapper) */
        *(--stack16) = DOSVM_dpmi_segments->wrap_seg;
        *(--stack16) = 0;
        /* adjust stack */
        context->Esp -= 2*sizeof(WORD);
        already = 1;
    }

    if (CurrRMCB) {
        /* RMCB call, invoke protected-mode handler directly */
        DPMI_CallRMCBProc(context, CurrRMCB, dpmi_flag);
        /* check if we returned to where we thought we would */
        if ((context->SegCs != DOSVM_dpmi_segments->wrap_seg) ||
            (LOWORD(context->Eip) != 0)) {
            /* we need to continue at different address in real-mode space,
               so we need to set it all up for real mode again */
            goto callrmproc_again;
        }
    } else {
        TRACE("entering real mode...\n");
        DOSVM_Enter( context );
        TRACE("returned from real-mode call\n");
    }
    if (alloc) DOSMEM_FreeBlock( addr );
    return 0;
}