290 lines
7.1 KiB
C
290 lines
7.1 KiB
C
/*++
|
|
|
|
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:
|
|
|
|
Return Value:
|
|
|
|
TrapFrame->Eax for application mode, required for system sevices
|
|
exit.
|
|
|
|
|
|
--*/
|
|
{
|
|
PVDM_TIB VdmTib;
|
|
PKTRAP_FRAME TrapFrame;
|
|
PETHREAD Thread;
|
|
KIRQL OldIrql;
|
|
BOOLEAN IntsEnabled;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
KeRaiseIrql(APC_LEVEL, &OldIrql);
|
|
|
|
//
|
|
// Form a pointer to the trap frame for the current thread
|
|
//
|
|
Thread = PsGetCurrentThread();
|
|
TrapFrame = VdmGetTrapFrame(&Thread->Tcb);
|
|
|
|
|
|
// Sudeepb 01-Dec-1992 - There was a try except here which i have
|
|
// taken out, because we come here from SystemServe Entry which
|
|
// already has a top level try except, so no one can blow NT
|
|
// even if we take a fault here becuase user memory was'nt allocated..
|
|
|
|
//
|
|
// Get the VdmTib,
|
|
//
|
|
VdmTib = NtCurrentTeb()->Vdm;
|
|
|
|
|
|
//
|
|
// 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 (*pNtVDMState & VDM_INT_TIMER &&
|
|
IntsEnabled && !(*pNtVDMState & 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 (*pNtVDMState & 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) {
|
|
_asm {
|
|
|
|
mov eax,VdmFixedStateLinear ; get pointer to VDM State
|
|
lock or dword ptr [eax], dword ptr VDM_VIRTUAL_INTERRUPTS
|
|
}
|
|
} else {
|
|
_asm {
|
|
|
|
mov eax,VdmFixedStateLinear ; get pointer to VDM State
|
|
lock and dword ptr [eax], NOT VDM_VIRTUAL_INTERRUPTS
|
|
}
|
|
}
|
|
|
|
//
|
|
// Insure that real interrupts are always enabled.
|
|
//
|
|
VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
|
|
}
|
|
|
|
//
|
|
// Switch from MonitorContext to VdmContext
|
|
//
|
|
VdmSwapContexts(
|
|
TrapFrame,
|
|
&(VdmTib->MonitorContext),
|
|
&(VdmTib->VdmContext)
|
|
);
|
|
|
|
|
|
//
|
|
// Check for pending interrupts
|
|
//
|
|
if (IntsEnabled && (*pNtVDMState & VDM_INT_HARDWARE)) {
|
|
VdmDispatchInterrupts(TrapFrame, VdmTib);
|
|
}
|
|
|
|
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:
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
|
|
(TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK)) );
|
|
|
|
|
|
// Sudeepb 01-Dec-1992 - There was a try except here which i have
|
|
// taken out, because we come here with a top level exception frame,
|
|
// so no one can blow NT even if we take a fault here becuase user
|
|
// memory was'nt allocated.
|
|
|
|
|
|
// 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);
|
|
//
|
|
// 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)
|
|
| (*(PULONG)pNtVDMState & VDM_VIRTUAL_INTERRUPTS);
|
|
}
|
|
|
|
return;
|
|
}
|