/*++ Copyright (c) 1992 Microsoft Corporation Module Name: Startexec.c Abstract: This module contains routines for switching to and from application mode in a vdm Author: Dave Hastings (daveh) 24-Apr-1992 Notes: This code started out in ke\i386\vdm.c Revision History: 23-Sep-1992 sudeepb Formed W_VDMEndExecution from VDMEndExecution for performance. 18-Dec-1992 sudeepb Tuned all the routines for performance 12-Oct-1993 Jonle , removed unneeded endexecution worker functions --*/ #include "vdmp.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, VdmpStartExecution) #pragma alloc_text(PAGE, VdmEndExecution) #endif NTSTATUS VdmpStartExecution( VOID ) /*++ Routine Description: This routine causes execution of dos application code to begin. The Dos application executes on the thread. The Vdms context is loaded from the VDM_TIB for the thread. The 32 bit context is stored into the MonitorContext. Execution in the VDM context will continue until an event occurs that the monitor needs to service. At that point, the information will be put into the VDM_TIB, and the call will return. Arguments: None. Return Value: TrapFrame->Eax for application mode, required for system sevices exit. --*/ { PVDM_TIB VdmTib; PKTRAP_FRAME TrapFrame; PETHREAD Thread; KIRQL OldIrql; BOOLEAN IntsEnabled; NTSTATUS Status; CONTEXT VdmContext; PAGED_CODE(); // // Form a pointer to the trap frame for the current thread // Thread = PsGetCurrentThread (); TrapFrame = VdmGetTrapFrame (&Thread->Tcb); // // Get the VdmTib // Status = VdmpGetVdmTib (&VdmTib); if (!NT_SUCCESS(Status)) { return STATUS_INVALID_SYSTEM_SERVICE; } KeRaiseIrql (APC_LEVEL, &OldIrql); try { // // Determine if interrupts are on or off // IntsEnabled = VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK ? TRUE : FALSE; // // Check for timer ints to dispatch, However if interrupts are disabled // or there are hardware ints pending we postpone dispatching the timer // interrupt until interrupts are enabled. // if ((*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_INT_TIMER) && IntsEnabled && !(*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_INT_HARDWARE)) { VdmTib->EventInfo.Event = VdmIntAck; VdmTib->EventInfo.InstructionSize = 0; VdmTib->EventInfo.IntAckInfo = 0; KeLowerIrql(OldIrql); return STATUS_SUCCESS; } // // Perform IF to VIF translation if the processor // supports IF virtualization // if (((KeI386VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) && (VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK)) || ((KeI386VirtualIntExtensions & PM_VIRTUAL_INT_EXTENSIONS) && !(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK))) { // // Translate IF to VIF // if (IntsEnabled) { VdmTib->VdmContext.EFlags |= EFLAGS_VIF; } else { VdmTib->VdmContext.EFlags &= ~EFLAGS_VIF; VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK; } if (*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_INT_HARDWARE) VdmTib->VdmContext.EFlags |= EFLAGS_VIP; else VdmTib->VdmContext.EFlags &= ~EFLAGS_VIP; // // Else if we are not running in v86 mode, or not using IOPL in // v86 mode // } else if (!(KeI386VdmIoplAllowed) || !(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK)) { // // Translate the real interrupt flag in the VdmContext to the // virtual interrupt flag in the VdmTib, and force real // interrupts enabled. // ASSERT(VDM_VIRTUAL_INTERRUPTS == EFLAGS_INTERRUPT_MASK); if (VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK) { InterlockedOr (FIXED_NTVDMSTATE_LINEAR_PC_AT, VDM_VIRTUAL_INTERRUPTS); } else { InterlockedAnd (FIXED_NTVDMSTATE_LINEAR_PC_AT, ~VDM_VIRTUAL_INTERRUPTS); } // // Insure that real interrupts are always enabled. // VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK; } // // Before working on a trap frame, make sure that it's our own structure // VdmContext = VdmTib->VdmContext; if (!(VdmContext.SegCs & FRAME_EDITED)) { // // We will crash in KiServiceExit // KeLowerIrql(OldIrql); return(STATUS_INVALID_SYSTEM_SERVICE); } // // Switch from MonitorContext to VdmContext // VdmSwapContexts (TrapFrame, &VdmTib->MonitorContext, &VdmContext); // // Check for pending interrupts // if (IntsEnabled && (*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_INT_HARDWARE)) { VdmDispatchInterrupts(TrapFrame, VdmTib); } } except(EXCEPTION_EXECUTE_HANDLER) { KeLowerIrql (OldIrql); Status = GetExceptionCode(); return Status; } KeLowerIrql(OldIrql); return (NTSTATUS) TrapFrame->Eax; } VOID VdmEndExecution( PKTRAP_FRAME TrapFrame, PVDM_TIB VdmTib ) /*++ Routine Description: This routine does the core work to end the execution Arguments: None Return Value: VOID, but exceptions can be thrown due to the user space accesses. --*/ { PAGED_CODE(); ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) || (TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK)) ); // // The return value must be put into the Monitorcontext, and set, // since we are probably returning to user mode via EXIT_ALL, and // the volatile registers will be restored. // VdmTib->MonitorContext.Eax = STATUS_SUCCESS; // // Switch from MonitorContext to VdmContext // VdmSwapContexts( TrapFrame, &(VdmTib->VdmContext), &(VdmTib->MonitorContext) ); // // Perform IF to VIF translation // // // If the processor supports IF virtualization // if (((KeI386VirtualIntExtensions & V86_VIRTUAL_INT_EXTENSIONS) && (VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK)) || ((KeI386VirtualIntExtensions & PM_VIRTUAL_INT_EXTENSIONS) && !(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK))) { // // Translate VIF to IF // if (VdmTib->VdmContext.EFlags & EFLAGS_VIF) { VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK; } else { VdmTib->VdmContext.EFlags &= ~EFLAGS_INTERRUPT_MASK; } // // Turn off VIP and VIF to insure that nothing strange happens // TrapFrame->EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF); VdmTib->VdmContext.EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF); // // Else if we are not running in v86 mode, or not using IOPL in // v86 mode // } else if (!(KeI386VdmIoplAllowed) || !(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK)) { // // Translate the virtual interrupt flag from the VdmTib back to the // real interrupt flag in the VdmContext // VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~EFLAGS_INTERRUPT_MASK) | (*FIXED_NTVDMSTATE_LINEAR_PC_AT & VDM_VIRTUAL_INTERRUPTS); } return; }