304 lines
7.6 KiB
C
304 lines
7.6 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:
|
||
|
|
||
|
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;
|
||
|
}
|