2006-11-08 11:47:44 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Kernel
|
|
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
|
|
* FILE: ntoskrnl/vdm/vdmexec.c
|
|
|
|
* PURPOSE: Support for executing VDM code and context swapping.
|
|
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
|
|
|
#include <ntoskrnl.h>
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
|
|
|
ULONG VdmBopCount;
|
|
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
VdmpGetVdmTib(OUT PVDM_TIB *VdmTib)
|
|
|
|
{
|
|
|
|
PVDM_TIB Tib;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
/* Assume vailure */
|
|
|
|
*VdmTib = NULL;
|
|
|
|
|
|
|
|
/* Get the current TIB */
|
|
|
|
Tib = NtCurrentTeb()->Vdm;
|
|
|
|
if (!Tib) return STATUS_INVALID_SYSTEM_SERVICE;
|
|
|
|
|
|
|
|
/* Validate the size */
|
|
|
|
if (Tib->Size != sizeof(VDM_TIB)) return STATUS_INVALID_SYSTEM_SERVICE;
|
|
|
|
|
|
|
|
/* Return it */
|
|
|
|
*VdmTib = Tib;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
VdmSwapContext(IN PKTRAP_FRAME TrapFrame,
|
|
|
|
IN PCONTEXT OutContext,
|
|
|
|
IN PCONTEXT InContext)
|
|
|
|
{
|
|
|
|
ULONG EFlags, OldEFlags;
|
|
|
|
|
|
|
|
/* Make sure that we're at APC_LEVEL and that this is a valid frame */
|
2007-01-17 20:44:37 +00:00
|
|
|
ASSERT(KeGetCurrentIrql() == APC_LEVEL);
|
2015-09-06 22:29:10 +00:00
|
|
|
ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00);
|
2006-11-08 11:47:44 +00:00
|
|
|
|
|
|
|
/* Check if this is a V86 frame */
|
|
|
|
if (TrapFrame->EFlags & EFLAGS_V86_MASK)
|
|
|
|
{
|
|
|
|
/* Copy segment registers */
|
|
|
|
OutContext->SegGs = TrapFrame->V86Gs;
|
|
|
|
OutContext->SegFs = TrapFrame->V86Fs;
|
|
|
|
OutContext->SegEs = TrapFrame->V86Es;
|
|
|
|
OutContext->SegDs = TrapFrame->V86Ds;
|
|
|
|
}
|
- Fix critical bugs in exception handling: Unwinding was completely broken, using the wrong SEH protector to detect collided unwinding. The correct protector itself also had a broken check.
- Fix architectural bug in the entire TrapFrame<->Context conversion system and Ring Privilege Transitions (Inter-ring and intra-ring) which was lacking proper sanitation and validation of segments, flags and debug registers. Among other things, IOPL is now respected, CS is not KGDT_R0_CODE | RPL_MASK anymore, and the GPF code is now properly being called. This completely fixes exception handling being totally broken and crashing firefox installer, mirc, and other applications.
- Rewrite the page fault handler base code in assembly instead of relying on a broken C routine. Detect VDM, V8086, detecting expected/normal fault in ExpInterlockedPopEntrySList and faults in the system handler code. Rewrite MmAccessFault to be the main function that calls out to other sub-fault functions, and use the same prototype as NT.
- Fix the KGDT boot table to have proper granularity and big flags, and extend it to 256 entries.
- Create proper thread context in RtlInitializeContext and cleanup Rtl Thread routines.
- Remove all int3 and breakpoints from trap handlers, and replace them with a much better "UNHANDLED_PATH" macro which freezes the system, beeps, and displays a message with the line of code that's unhandled. This is to clearly tell the user that something is unhandled, instead of nesting infinite exceptions due to the int3.
- Fix a bug in INT_PROLOG.
- Sanitize EFLAGS and Code Segments in KeContextToTrapFrame and KeTrapFrameToContext.
- Implement KiUpdateDr7 and KiRecordDr7 as well as DR_MASK and other DR-validation macros and functions to protect against DR-vulnerabilites as well as to properly account for each active hardware breakpoint in a per-thread fashion by using the dispatcher header.
- Allow CR0_EM when running in a VDM.
- Fix FPU/NPX Register handling in KeContextToTrapFrame and KeTrapFrameToContext, and also speed it up by manual copying instead of a memory move.
- Properly give IOPL 3 to user-mode threads if they requested it.
- Detect GPF during GPF.
- Detect pagefault with a trap-frame spread over two or more pages and nested.
- Properly sanitize and set correct trap frame in KiInitailizeUserApc.
- Return STATUS_ACCESS_VIOLATION during page faults instead of STATUS_UNSUCESSFUL.
- Fix assert in VdmSwapContext, as well as Code Selector check which was broken.
- Fix delayed object deletion (ObDeferDeleteObject) and the Ob Repear Routine and list.
- Update Kernel Fun.
- BUGBUG: Temporaily hack VMWare to detection to always detect VMWare.
svn path=/trunk/; revision=25238
2006-12-29 18:49:00 +00:00
|
|
|
else if (TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK))
|
2006-11-08 11:47:44 +00:00
|
|
|
{
|
- Fix critical bugs in exception handling: Unwinding was completely broken, using the wrong SEH protector to detect collided unwinding. The correct protector itself also had a broken check.
- Fix architectural bug in the entire TrapFrame<->Context conversion system and Ring Privilege Transitions (Inter-ring and intra-ring) which was lacking proper sanitation and validation of segments, flags and debug registers. Among other things, IOPL is now respected, CS is not KGDT_R0_CODE | RPL_MASK anymore, and the GPF code is now properly being called. This completely fixes exception handling being totally broken and crashing firefox installer, mirc, and other applications.
- Rewrite the page fault handler base code in assembly instead of relying on a broken C routine. Detect VDM, V8086, detecting expected/normal fault in ExpInterlockedPopEntrySList and faults in the system handler code. Rewrite MmAccessFault to be the main function that calls out to other sub-fault functions, and use the same prototype as NT.
- Fix the KGDT boot table to have proper granularity and big flags, and extend it to 256 entries.
- Create proper thread context in RtlInitializeContext and cleanup Rtl Thread routines.
- Remove all int3 and breakpoints from trap handlers, and replace them with a much better "UNHANDLED_PATH" macro which freezes the system, beeps, and displays a message with the line of code that's unhandled. This is to clearly tell the user that something is unhandled, instead of nesting infinite exceptions due to the int3.
- Fix a bug in INT_PROLOG.
- Sanitize EFLAGS and Code Segments in KeContextToTrapFrame and KeTrapFrameToContext.
- Implement KiUpdateDr7 and KiRecordDr7 as well as DR_MASK and other DR-validation macros and functions to protect against DR-vulnerabilites as well as to properly account for each active hardware breakpoint in a per-thread fashion by using the dispatcher header.
- Allow CR0_EM when running in a VDM.
- Fix FPU/NPX Register handling in KeContextToTrapFrame and KeTrapFrameToContext, and also speed it up by manual copying instead of a memory move.
- Properly give IOPL 3 to user-mode threads if they requested it.
- Detect GPF during GPF.
- Detect pagefault with a trap-frame spread over two or more pages and nested.
- Properly sanitize and set correct trap frame in KiInitailizeUserApc.
- Return STATUS_ACCESS_VIOLATION during page faults instead of STATUS_UNSUCESSFUL.
- Fix assert in VdmSwapContext, as well as Code Selector check which was broken.
- Fix delayed object deletion (ObDeferDeleteObject) and the Ob Repear Routine and list.
- Update Kernel Fun.
- BUGBUG: Temporaily hack VMWare to detection to always detect VMWare.
svn path=/trunk/; revision=25238
2006-12-29 18:49:00 +00:00
|
|
|
/* This was kernel mode, copy segment registers */
|
2006-11-08 11:47:44 +00:00
|
|
|
OutContext->SegGs = TrapFrame->SegGs;
|
|
|
|
OutContext->SegFs = TrapFrame->SegFs;
|
|
|
|
OutContext->SegEs = TrapFrame->SegEs;
|
|
|
|
OutContext->SegDs = TrapFrame->SegDs;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy CS and SS */
|
|
|
|
OutContext->SegCs = TrapFrame->SegCs;
|
|
|
|
OutContext->SegSs = TrapFrame->HardwareSegSs;
|
|
|
|
|
|
|
|
/* Copy general purpose registers */
|
|
|
|
OutContext->Eax = TrapFrame->Eax;
|
|
|
|
OutContext->Ebx = TrapFrame->Ebx;
|
|
|
|
OutContext->Ecx = TrapFrame->Ecx;
|
|
|
|
OutContext->Edx = TrapFrame->Edx;
|
|
|
|
OutContext->Esi = TrapFrame->Esi;
|
|
|
|
OutContext->Edi = TrapFrame->Edi;
|
|
|
|
|
|
|
|
/* Copy stack and counter */
|
|
|
|
OutContext->Ebp = TrapFrame->Ebp;
|
|
|
|
OutContext->Esp = TrapFrame->HardwareEsp;
|
|
|
|
OutContext->Eip = TrapFrame->Eip;
|
|
|
|
|
|
|
|
/* Finally the flags */
|
|
|
|
OutContext->EFlags = TrapFrame->EFlags;
|
|
|
|
|
|
|
|
/* Now copy from the in frame to the trap frame */
|
|
|
|
TrapFrame->SegCs = InContext->SegCs;
|
|
|
|
TrapFrame->HardwareSegSs = InContext->SegSs;
|
|
|
|
|
|
|
|
/* Copy the general purpose registers */
|
|
|
|
TrapFrame->Eax = InContext->Eax;
|
|
|
|
TrapFrame->Ebx = InContext->Ebx;
|
|
|
|
TrapFrame->Ecx = InContext->Ecx;
|
|
|
|
TrapFrame->Edx = InContext->Edx;
|
|
|
|
TrapFrame->Esi = InContext->Esi;
|
|
|
|
TrapFrame->Edi = InContext->Edi;
|
|
|
|
|
|
|
|
/* Copy the stack and counter */
|
|
|
|
TrapFrame->Ebp = InContext->Ebp;
|
|
|
|
TrapFrame->HardwareEsp = InContext->Esp;
|
|
|
|
TrapFrame->Eip = InContext->Eip;
|
|
|
|
|
|
|
|
/* Check if the context is from V86 */
|
|
|
|
EFlags = InContext->EFlags;
|
|
|
|
if (EFlags & EFLAGS_V86_MASK)
|
|
|
|
{
|
|
|
|
/* Sanitize the flags for V86 */
|
|
|
|
EFlags &= KeI386EFlagsAndMaskV86;
|
|
|
|
EFlags |= KeI386EFlagsOrMaskV86;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Add RPL_MASK to segments */
|
|
|
|
TrapFrame->SegCs |= RPL_MASK;
|
|
|
|
TrapFrame->HardwareSegSs |= RPL_MASK;
|
|
|
|
|
|
|
|
/* Check for bogus CS */
|
|
|
|
if (TrapFrame->SegCs < KGDT_R0_CODE)
|
|
|
|
{
|
|
|
|
/* Set user-mode */
|
|
|
|
TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sanitize flags and add interrupt mask */
|
|
|
|
EFlags &= EFLAGS_USER_SANITIZE;
|
|
|
|
EFlags |=EFLAGS_INTERRUPT_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save the new eflags */
|
|
|
|
OldEFlags = TrapFrame->EFlags;
|
|
|
|
TrapFrame->EFlags = EFlags;
|
|
|
|
|
|
|
|
/* Check if we need to fixup ESP0 */
|
|
|
|
if ((OldEFlags ^ EFlags) & EFLAGS_V86_MASK)
|
|
|
|
{
|
|
|
|
/* Fix it up */
|
|
|
|
Ki386AdjustEsp0(TrapFrame);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if this is a V86 context */
|
|
|
|
if (InContext->EFlags & EFLAGS_V86_MASK)
|
|
|
|
{
|
|
|
|
/* Copy VDM segments */
|
|
|
|
TrapFrame->V86Gs = InContext->SegGs;
|
|
|
|
TrapFrame->V86Fs = InContext->SegFs;
|
|
|
|
TrapFrame->V86Es = InContext->SegEs;
|
|
|
|
TrapFrame->V86Ds = InContext->SegDs;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Copy monitor segments */
|
|
|
|
TrapFrame->SegGs = InContext->SegGs;
|
|
|
|
TrapFrame->SegFs = InContext->SegFs;
|
|
|
|
TrapFrame->SegEs = InContext->SegEs;
|
|
|
|
TrapFrame->SegDs = InContext->SegDs;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear the exception list and return */
|
|
|
|
TrapFrame->ExceptionList = EXCEPTION_CHAIN_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
VdmpStartExecution(VOID)
|
|
|
|
{
|
|
|
|
PETHREAD Thread = PsGetCurrentThread();
|
|
|
|
PKTRAP_FRAME VdmFrame;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PVDM_TIB VdmTib;
|
|
|
|
BOOLEAN Interrupts;
|
|
|
|
KIRQL OldIrql;
|
|
|
|
CONTEXT VdmContext;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
/* Get the thread's VDM frame and TIB */
|
|
|
|
VdmFrame = (PVOID)((ULONG_PTR)Thread->Tcb.InitialStack -
|
|
|
|
sizeof(FX_SAVE_AREA) -
|
|
|
|
sizeof(KTRAP_FRAME));
|
|
|
|
Status = VdmpGetVdmTib(&VdmTib);
|
|
|
|
if (!NT_SUCCESS(Status)) return STATUS_INVALID_SYSTEM_SERVICE;
|
|
|
|
|
|
|
|
/* Go to APC level */
|
|
|
|
KeRaiseIrql(APC_LEVEL, &OldIrql);
|
|
|
|
|
|
|
|
/* Check if interrupts are enabled */
|
|
|
|
Interrupts = (BOOLEAN)(VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK);
|
|
|
|
|
|
|
|
/* We don't support full VDM yet, this shouldn't happen */
|
|
|
|
ASSERT(*VdmState == 0);
|
|
|
|
ASSERT(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK);
|
|
|
|
|
[NTOS/PERF]: Enable VME support. VME stands for Virtual 8086 Mode Extensions, and it's an Intel optimization that makes changes to the IF bit in EFLAGS (CLI, STI, INT, IRETD, PUSHF, POPF) completely transprent: instead of changing the real (protected) bit, which requires the OS to trap and emulate the behavior, the CPU sets a "Fake" IF bit instead. When you're dong in V8086 mode, you simply update your real flag with whatever the fake flag says.
[NTOS]: Enable V8086 Fast-V86 Trap mode for Trap 6 (Invalid Opcode). Because we are now taking zero traps during V8086 mode, we can't do the "BOP lookahead", so the only trap we do get is when we hit the BOP/invalid opcode itself.
[NTOS]: Multiple fixes to V8086 opcode emulation code that I noticed while looking through the source. Also multiple fixes to VDM code.
This change will only impact real hardware and VMWare, since QEMU does not support VME. On VMWare, performance increased up to 400% during bootup (80 million cycles instead of 300 million, in one test).
svn path=/trunk/; revision=45282
2010-01-27 05:34:38 +00:00
|
|
|
/* Check if VME is supported and V86 mode was enabled */
|
|
|
|
if ((KeI386VirtualIntExtensions) &&
|
|
|
|
(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK))
|
|
|
|
{
|
|
|
|
/* Check if interrupts are enabled */
|
|
|
|
if (Interrupts)
|
|
|
|
{
|
|
|
|
/* Set fake IF flag */
|
|
|
|
VdmTib->VdmContext.EFlags |= EFLAGS_VIF;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Remove fake IF flag, turn on real IF flag */
|
|
|
|
VdmTib->VdmContext.EFlags &= ~EFLAGS_VIF;
|
|
|
|
VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Set interrupt state in the VDM State */
|
|
|
|
if (VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK)
|
|
|
|
{
|
|
|
|
/* Enable them as well */
|
|
|
|
InterlockedOr((PLONG)VdmState, EFLAGS_INTERRUPT_MASK);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Disable them */
|
|
|
|
InterlockedAnd((PLONG)VdmState, ~EFLAGS_INTERRUPT_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable the interrupt flag */
|
|
|
|
VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the VDM context and make sure it's not an edited frame */
|
2006-11-08 11:47:44 +00:00
|
|
|
VdmContext = VdmTib->VdmContext;
|
|
|
|
if (!(VdmContext.SegCs & FRAME_EDITED))
|
|
|
|
{
|
|
|
|
/* Fail */
|
|
|
|
KeLowerIrql(OldIrql);
|
|
|
|
return STATUS_INVALID_SYSTEM_SERVICE;
|
|
|
|
}
|
2017-04-14 11:18:22 +00:00
|
|
|
|
2006-11-08 11:47:44 +00:00
|
|
|
/* Now do the VDM Swap */
|
|
|
|
VdmSwapContext(VdmFrame, &VdmTib->MonitorContext, &VdmContext);
|
|
|
|
|
|
|
|
/* Lower the IRQL and return EAX */
|
|
|
|
KeLowerIrql(OldIrql);
|
|
|
|
return VdmFrame->Eax;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
VdmEndExecution(IN PKTRAP_FRAME TrapFrame,
|
|
|
|
IN PVDM_TIB VdmTib)
|
|
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
|
|
CONTEXT Context;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
/* Sanity check */
|
|
|
|
ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
|
|
|
|
(TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK)));
|
|
|
|
|
|
|
|
/* Raise to APC_LEVEL */
|
|
|
|
KeRaiseIrql(APC_LEVEL, &OldIrql);
|
|
|
|
|
|
|
|
/* Set success */
|
|
|
|
VdmTib->MonitorContext.Eax = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
/* Make a copy of the monitor context */
|
[NTOS/PERF]: Enable VME support. VME stands for Virtual 8086 Mode Extensions, and it's an Intel optimization that makes changes to the IF bit in EFLAGS (CLI, STI, INT, IRETD, PUSHF, POPF) completely transprent: instead of changing the real (protected) bit, which requires the OS to trap and emulate the behavior, the CPU sets a "Fake" IF bit instead. When you're dong in V8086 mode, you simply update your real flag with whatever the fake flag says.
[NTOS]: Enable V8086 Fast-V86 Trap mode for Trap 6 (Invalid Opcode). Because we are now taking zero traps during V8086 mode, we can't do the "BOP lookahead", so the only trap we do get is when we hit the BOP/invalid opcode itself.
[NTOS]: Multiple fixes to V8086 opcode emulation code that I noticed while looking through the source. Also multiple fixes to VDM code.
This change will only impact real hardware and VMWare, since QEMU does not support VME. On VMWare, performance increased up to 400% during bootup (80 million cycles instead of 300 million, in one test).
svn path=/trunk/; revision=45282
2010-01-27 05:34:38 +00:00
|
|
|
Context = VdmTib->MonitorContext;
|
2017-04-14 11:18:22 +00:00
|
|
|
|
[NTOS/PERF]: Enable VME support. VME stands for Virtual 8086 Mode Extensions, and it's an Intel optimization that makes changes to the IF bit in EFLAGS (CLI, STI, INT, IRETD, PUSHF, POPF) completely transprent: instead of changing the real (protected) bit, which requires the OS to trap and emulate the behavior, the CPU sets a "Fake" IF bit instead. When you're dong in V8086 mode, you simply update your real flag with whatever the fake flag says.
[NTOS]: Enable V8086 Fast-V86 Trap mode for Trap 6 (Invalid Opcode). Because we are now taking zero traps during V8086 mode, we can't do the "BOP lookahead", so the only trap we do get is when we hit the BOP/invalid opcode itself.
[NTOS]: Multiple fixes to V8086 opcode emulation code that I noticed while looking through the source. Also multiple fixes to VDM code.
This change will only impact real hardware and VMWare, since QEMU does not support VME. On VMWare, performance increased up to 400% during bootup (80 million cycles instead of 300 million, in one test).
svn path=/trunk/; revision=45282
2010-01-27 05:34:38 +00:00
|
|
|
/* Check if V86 mode was enabled or the trap was edited */
|
|
|
|
if ((Context.EFlags & EFLAGS_V86_MASK) || (Context.SegCs & FRAME_EDITED))
|
|
|
|
{
|
|
|
|
/* Switch contexts */
|
|
|
|
VdmSwapContext(TrapFrame, &VdmTib->VdmContext, &Context);
|
2006-11-08 11:47:44 +00:00
|
|
|
|
[NTOS/PERF]: Enable VME support. VME stands for Virtual 8086 Mode Extensions, and it's an Intel optimization that makes changes to the IF bit in EFLAGS (CLI, STI, INT, IRETD, PUSHF, POPF) completely transprent: instead of changing the real (protected) bit, which requires the OS to trap and emulate the behavior, the CPU sets a "Fake" IF bit instead. When you're dong in V8086 mode, you simply update your real flag with whatever the fake flag says.
[NTOS]: Enable V8086 Fast-V86 Trap mode for Trap 6 (Invalid Opcode). Because we are now taking zero traps during V8086 mode, we can't do the "BOP lookahead", so the only trap we do get is when we hit the BOP/invalid opcode itself.
[NTOS]: Multiple fixes to V8086 opcode emulation code that I noticed while looking through the source. Also multiple fixes to VDM code.
This change will only impact real hardware and VMWare, since QEMU does not support VME. On VMWare, performance increased up to 400% during bootup (80 million cycles instead of 300 million, in one test).
svn path=/trunk/; revision=45282
2010-01-27 05:34:38 +00:00
|
|
|
/* Check if VME is supported and V86 mode was enabled */
|
|
|
|
if ((KeI386VirtualIntExtensions) &&
|
|
|
|
(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK))
|
|
|
|
{
|
|
|
|
/* Check for VIF (virtual interrupt) flag state */
|
|
|
|
if (VdmTib->VdmContext.EFlags & EFLAGS_VIF)
|
|
|
|
{
|
|
|
|
/* Set real IF flag */
|
|
|
|
VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Remove real IF flag */
|
|
|
|
VdmTib->VdmContext.EFlags &= ~EFLAGS_INTERRUPT_MASK;
|
|
|
|
}
|
2017-04-14 11:18:22 +00:00
|
|
|
|
[NTOS/PERF]: Enable VME support. VME stands for Virtual 8086 Mode Extensions, and it's an Intel optimization that makes changes to the IF bit in EFLAGS (CLI, STI, INT, IRETD, PUSHF, POPF) completely transprent: instead of changing the real (protected) bit, which requires the OS to trap and emulate the behavior, the CPU sets a "Fake" IF bit instead. When you're dong in V8086 mode, you simply update your real flag with whatever the fake flag says.
[NTOS]: Enable V8086 Fast-V86 Trap mode for Trap 6 (Invalid Opcode). Because we are now taking zero traps during V8086 mode, we can't do the "BOP lookahead", so the only trap we do get is when we hit the BOP/invalid opcode itself.
[NTOS]: Multiple fixes to V8086 opcode emulation code that I noticed while looking through the source. Also multiple fixes to VDM code.
This change will only impact real hardware and VMWare, since QEMU does not support VME. On VMWare, performance increased up to 400% during bootup (80 million cycles instead of 300 million, in one test).
svn path=/trunk/; revision=45282
2010-01-27 05:34:38 +00:00
|
|
|
/* Turn off VIP and VIF */
|
|
|
|
TrapFrame->EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF);
|
|
|
|
VdmTib->VdmContext.EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Set the EFLAGS based on our software copy of EFLAGS */
|
|
|
|
VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~EFLAGS_INTERRUPT_MASK) |
|
|
|
|
(*VdmState & EFLAGS_INTERRUPT_MASK);
|
|
|
|
}
|
|
|
|
}
|
2006-11-08 11:47:44 +00:00
|
|
|
|
|
|
|
/* Lower IRQL and reutrn */
|
|
|
|
KeLowerIrql(OldIrql);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
|
|
|
VdmDispatchBop(IN PKTRAP_FRAME TrapFrame)
|
|
|
|
{
|
|
|
|
PUCHAR Eip;
|
|
|
|
PVDM_TIB VdmTib;
|
|
|
|
|
|
|
|
/* Check if this is from V86 mode */
|
|
|
|
if (TrapFrame->EFlags & EFLAGS_V86_MASK)
|
|
|
|
{
|
|
|
|
/* Calculate flat EIP */
|
|
|
|
Eip = (PUCHAR)((TrapFrame->Eip & 0xFFFF) +
|
|
|
|
((TrapFrame->SegCs & 0xFFFF) << 4));
|
|
|
|
|
|
|
|
/* Check if this is a BOP */
|
|
|
|
if (*(PUSHORT)Eip == 0xC4C4)
|
|
|
|
{
|
|
|
|
/* Check sure its the DOS Bop */
|
|
|
|
if (Eip[2] == 0x50)
|
|
|
|
{
|
|
|
|
/* FIXME: No VDM Support */
|
|
|
|
ASSERT(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Increase the number of BOP operations */
|
|
|
|
VdmBopCount++;
|
|
|
|
|
|
|
|
/* Get the TIB */
|
|
|
|
VdmTib = NtCurrentTeb()->Vdm;
|
|
|
|
|
|
|
|
/* Fill out a VDM Event */
|
|
|
|
VdmTib->EventInfo.InstructionSize = 3;
|
|
|
|
VdmTib->EventInfo.BopNumber = Eip[2];
|
|
|
|
VdmTib->EventInfo.Event = VdmBop;
|
|
|
|
|
|
|
|
/* End VDM Execution */
|
|
|
|
VdmEndExecution(TrapFrame, VdmTib);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Not a BOP */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* FIXME: Shouldn't happen on ROS */
|
|
|
|
ASSERT(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return success */
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2017-04-14 11:18:22 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
|
|
|
VdmDispatchPageFault(
|
|
|
|
_In_ PKTRAP_FRAME TrapFrame)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
PVDM_TIB VdmTib;
|
|
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
/* Get the VDM TIB so we can terminate V86 execution */
|
|
|
|
Status = VdmpGetVdmTib(&VdmTib);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Not a proper VDM fault, keep looking */
|
|
|
|
DPRINT1("VdmDispatchPageFault: no VDM TIB, Vdm=%p\n", NtCurrentTeb()->Vdm);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Must be coming from V86 code */
|
|
|
|
ASSERT(TrapFrame->EFlags & EFLAGS_V86_MASK);
|
|
|
|
|
|
|
|
_SEH2_TRY
|
|
|
|
{
|
|
|
|
/* Fill out a VDM Event */
|
|
|
|
VdmTib->EventInfo.Event = VdmMemAccess;
|
|
|
|
VdmTib->EventInfo.InstructionSize = 0;
|
|
|
|
|
|
|
|
/* End VDM Execution */
|
|
|
|
VdmEndExecution(TrapFrame, VdmTib);
|
|
|
|
}
|
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
Status = _SEH2_GetExceptionCode();
|
|
|
|
}
|
|
|
|
_SEH2_END;
|
|
|
|
|
|
|
|
/* Consider the exception handled if we succeeded */
|
|
|
|
DPRINT1("VdmDispatchPageFault EFlags %lx exit with 0x%lx\n", TrapFrame->EFlags, Status);
|
|
|
|
return NT_SUCCESS(Status);
|
|
|
|
}
|
2007-01-17 20:44:37 +00:00
|
|
|
|