windows-nt/Source/XPSP1/NT/base/ntos/vdm/i386/strtexec.c

304 lines
7.6 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}