static DWORD WINAPI MZ_DOSVM( LPVOID lpExtra ) { CONTEXT context; INT ret; dosvm_pid = getpid(); memset( &context, 0, sizeof(context) ); context.SegCs = init_cs; context.Eip = init_ip; context.SegSs = init_ss; context.Esp = init_sp; context.SegDs = DOSVM_psp; context.SegEs = DOSVM_psp; context.EFlags = V86_FLAG | VIF_MASK; DOSVM_SetTimer(0x10000); ret = DOSVM_Enter( &context ); if (ret == -1) { /* fetch the app name from the environment */ PDB16 *psp = PTR_REAL_TO_LIN( DOSVM_psp, 0 ); char *env = PTR_REAL_TO_LIN( psp->environment, 0 ); while (*env) env += strlen(env) + 1; env += 1 + sizeof(WORD); if (GetLastError() == ERROR_NOT_SUPPORTED) MESSAGE( "wine: Cannot start DOS application %s\n" " because vm86 mode is not supported on this platform.\n", debugstr_a(env) ); else FIXME( "vm86 mode failed error %u\n", GetLastError() ); } dosvm_pid = 0; return ret != 0; }
/********************************************************************** * DOSVM_RawModeSwitchHandler * * DPMI Raw Mode Switch handler */ void WINAPI DOSVM_RawModeSwitchHandler( CONTEXT86 *context ) { CONTEXT86 rm_ctx; int ret; /* initialize real-mode context as per spec */ memset(&rm_ctx, 0, sizeof(rm_ctx)); rm_ctx.SegDs = AX_reg(context); rm_ctx.SegEs = CX_reg(context); rm_ctx.SegSs = DX_reg(context); rm_ctx.Esp = context->Ebx; rm_ctx.SegCs = SI_reg(context); rm_ctx.Eip = context->Edi; rm_ctx.Ebp = context->Ebp; rm_ctx.SegFs = 0; rm_ctx.SegGs = 0; /* Copy interrupt state. */ if (NtCurrentTeb()->dpmi_vif) rm_ctx.EFlags = V86_FLAG | VIF_MASK; else rm_ctx.EFlags = V86_FLAG; /* enter real mode again */ TRACE("re-entering real mode at %04lx:%04lx\n",rm_ctx.SegCs,rm_ctx.Eip); ret = DOSVM_Enter( &rm_ctx ); /* when the real-mode stuff call its mode switch address, DOSVM_Enter will return and we will continue here */ if (ret<0) { ERR("Sync lost!\n"); /* if the sync was lost, there's no way to recover */ ExitProcess(1); } /* alter protected-mode context as per spec */ context->SegDs = LOWORD(rm_ctx.Eax); context->SegEs = LOWORD(rm_ctx.Ecx); context->SegSs = LOWORD(rm_ctx.Edx); context->Esp = rm_ctx.Ebx; context->SegCs = LOWORD(rm_ctx.Esi); context->Eip = rm_ctx.Edi; context->Ebp = rm_ctx.Ebp; context->SegFs = 0; context->SegGs = 0; /* Copy interrupt state. */ if (rm_ctx.EFlags & VIF_MASK) NtCurrentTeb()->dpmi_vif = 1; else NtCurrentTeb()->dpmi_vif = 0; /* Return to new address and hope that we didn't mess up */ TRACE("re-entering protected mode at %04lx:%08lx\n", context->SegCs, context->Eip); }
static DWORD WINAPI MZ_DOSVM( LPVOID lpExtra ) { CONTEXT context; DWORD ret; dosvm_pid = getpid(); memset( &context, 0, sizeof(context) ); context.SegCs = init_cs; context.Eip = init_ip; context.SegSs = init_ss; context.Esp = init_sp; context.SegDs = DOSVM_psp; context.SegEs = DOSVM_psp; context.EFlags = V86_FLAG | VIF_MASK; DOSVM_SetTimer(0x10000); ret = DOSVM_Enter( &context ); dosvm_pid = 0; return ret; }
/********************************************************************** * 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; }