mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
7.6 KiB
303 lines
7.6 KiB
/*++
|
|
|
|
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;
|
|
}
|