diff --git a/reactos/ntoskrnl/ke/i386/traphdlr.c b/reactos/ntoskrnl/ke/i386/traphdlr.c index eb00b7fe1c6..b54a398a5b0 100644 --- a/reactos/ntoskrnl/ke/i386/traphdlr.c +++ b/reactos/ntoskrnl/ke/i386/traphdlr.c @@ -533,17 +533,57 @@ KiTrap05Handler(IN PKTRAP_FRAME TrapFrame) VOID FASTCALL DECLSPEC_NORETURN -KiTrap06Handler(IN PKTRAP_FRAME TrapFrame) +KiTrap06Handler(IN PKTRAP_FRAME TrapFrame, + IN ULONG EFlags) { PUCHAR Instruction; ULONG i; + KIRQL OldIrql; + /* Check for V86 GPF */ + if (__builtin_expect(EFlags & EFLAGS_V86_MASK, 1)) + { + /* Enter V86 trap */ + KiEnterV86Trap(TrapFrame); + + /* Must be a VDM process */ + if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0)) + { + /* Enable interrupts */ + _enable(); + + /* Setup illegal instruction fault */ + KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, + TrapFrame->Eip, + TrapFrame); + } + + /* Go to APC level */ + OldIrql = KfRaiseIrql(APC_LEVEL); + _enable(); + + /* Check for BOP */ + if (!VdmDispatchBop(TrapFrame)) + { + /* Should only happen in VDM mode */ + UNIMPLEMENTED; + while (TRUE); + } + + /* Bring IRQL back */ + KfLowerIrql(OldIrql); + _disable(); + + /* Do a quick V86 exit if possible */ + if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 1)) KiExitV86Trap(TrapFrame); + + /* Exit trap the slow way */ + KiEoiHelper(TrapFrame); + } + /* Save trap frame */ KiEnterTrap(TrapFrame); - /* Check for VDM trap */ - ASSERT((KiVdmTrap(TrapFrame)) == FALSE); - /* Enable interrupts */ Instruction = (PUCHAR)TrapFrame->Eip; _enable(); @@ -1557,7 +1597,7 @@ KiTrap(KiTrap01, KI_PUSH_FAKE_ERROR_CODE); KiTrap(KiTrap03, KI_PUSH_FAKE_ERROR_CODE); KiTrap(KiTrap04, KI_PUSH_FAKE_ERROR_CODE); KiTrap(KiTrap05, KI_PUSH_FAKE_ERROR_CODE); -KiTrap(KiTrap06, KI_PUSH_FAKE_ERROR_CODE); +KiTrap(KiTrap06, KI_PUSH_FAKE_ERROR_CODE | KI_FAST_V86_TRAP); KiTrap(KiTrap07, KI_PUSH_FAKE_ERROR_CODE); KiTrap(KiTrap08, 0); KiTrap(KiTrap09, KI_PUSH_FAKE_ERROR_CODE); diff --git a/reactos/ntoskrnl/ke/i386/v86vdm.c b/reactos/ntoskrnl/ke/i386/v86vdm.c index ab937ada76d..1771e5874ad 100644 --- a/reactos/ntoskrnl/ke/i386/v86vdm.c +++ b/reactos/ntoskrnl/ke/i386/v86vdm.c @@ -53,14 +53,17 @@ KiVdmOpcodePUSHF(IN PKTRAP_FRAME TrapFrame, { ULONG Esp, V86EFlags, TrapEFlags; + /* Check for VME support */ + ASSERT(KeI386VirtualIntExtensions == FALSE); + /* Get current V8086 flags and mask out interrupt flag */ V86EFlags = *KiNtVdmState; V86EFlags &= ~EFLAGS_INTERRUPT_MASK; - + /* Get trap frame EFLags and leave only align, nested task and interrupt */ TrapEFlags = TrapFrame->EFlags; - TrapEFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK); - + V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK); + /* Add in those flags if they exist, and add in the IOPL flag */ V86EFlags |= TrapEFlags; V86EFlags |= EFLAGS_IOPL; @@ -124,15 +127,18 @@ KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame, /* Now leave only alignment, nested task and interrupt flag */ EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK); - /* FIXME: Check for VME support */ - + /* Get trap EFlags */ + TrapEFlags = TrapFrame->EFlags; + + /* Check for VME support */ + ASSERT(KeI386VirtualIntExtensions == FALSE); + /* Add V86 and Interrupt flag */ V86EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK; - + /* Update EFlags in trap frame */ - TrapEFlags = TrapFrame->EFlags; - TrapFrame->EFlags = (TrapFrame->EFlags & EFLAGS_VIP) | V86EFlags; - + TrapFrame->EFlags |= V86EFlags; + /* Check if ESP0 needs to be fixed up */ if (TrapEFlags & EFLAGS_V86_MASK) Ki386AdjustEsp0(TrapFrame); @@ -166,7 +172,8 @@ KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame, /* Keep only alignment and interrupt flag from the V8086 state */ V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_INTERRUPT_MASK); - /* FIXME: Support VME */ + /* Check for VME support */ + ASSERT(KeI386VirtualIntExtensions == FALSE); /* Mask in the relevant V86 EFlags into the trap flags */ V86EFlags |= (TrapEFlags & ~EFLAGS_INTERRUPT_MASK); @@ -277,7 +284,8 @@ KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame, EFlags &= ~(EFLAGS_IOPL + EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_VIP); V86EFlags = EFlags; - /* FIXME: Check for VME support */ + /* Check for VME support */ + ASSERT(KeI386VirtualIntExtensions == FALSE); /* Add V86 and Interrupt flag */ EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK; @@ -314,7 +322,8 @@ FASTCALL KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame, IN ULONG Flags) { - /* FIXME: Support VME */ + /* Check for VME support */ + ASSERT(KeI386VirtualIntExtensions == FALSE); /* Disable interrupts */ KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK); @@ -331,7 +340,8 @@ FASTCALL KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame, IN ULONG Flags) { - /* FIXME: Support VME */ + /* Check for VME support */ + ASSERT(KeI386VirtualIntExtensions == FALSE); /* Enable interrupts */ KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK); diff --git a/reactos/ntoskrnl/vdm/vdmexec.c b/reactos/ntoskrnl/vdm/vdmexec.c index 067c1cc971d..d305b3d5f1d 100644 --- a/reactos/ntoskrnl/vdm/vdmexec.c +++ b/reactos/ntoskrnl/vdm/vdmexec.c @@ -196,7 +196,42 @@ VdmpStartExecution(VOID) ASSERT(*VdmState == 0); ASSERT(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK); - /* Get the VDM context and make sure it's an edited frame */ + /* 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 */ VdmContext = VdmTib->VdmContext; if (!(VdmContext.SegCs & FRAME_EDITED)) { @@ -204,25 +239,7 @@ VdmpStartExecution(VOID) KeLowerIrql(OldIrql); return STATUS_INVALID_SYSTEM_SERVICE; } - - /* FIXME: Support VME */ - ASSERT(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK); - - /* 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; - + /* Now do the VDM Swap */ VdmSwapContext(VdmFrame, &VdmTib->MonitorContext, &VdmContext); @@ -251,17 +268,41 @@ VdmEndExecution(IN PKTRAP_FRAME TrapFrame, VdmTib->MonitorContext.Eax = STATUS_SUCCESS; /* Make a copy of the monitor context */ - RtlCopyMemory(&Context, &VdmTib->MonitorContext, sizeof(CONTEXT)); + Context = VdmTib->MonitorContext; + + /* 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); - /* Switch contexts */ - VdmSwapContext(TrapFrame, &VdmTib->VdmContext, &Context); - - /* FIXME: Support VME */ - - /* Set the EFLAGS */ - VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & - ~EFLAGS_INTERRUPT_MASK) | - (*VdmState & EFLAGS_INTERRUPT_MASK); + /* 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; + } + + /* 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); + } + } /* Lower IRQL and reutrn */ KeLowerIrql(OldIrql); diff --git a/reactos/ntoskrnl/vdm/vdmmain.c b/reactos/ntoskrnl/vdm/vdmmain.c index ff31403aaa0..c7aa0a2500d 100644 --- a/reactos/ntoskrnl/vdm/vdmmain.c +++ b/reactos/ntoskrnl/vdm/vdmmain.c @@ -20,10 +20,20 @@ VOID NTAPI -Ki386VdmEnablePentiumExtentions(VOID) +Ki386VdmEnablePentiumExtentions(IN BOOLEAN Enable) { - /* FIXME: Support this */ - DPRINT1("VME support detected but not yet taken advantage of\n"); + ULONG EFlags, Cr4; + + /* Save interrupt state and disable them */ + EFlags = __readeflags(); + _disable(); + + /* Enable or disable VME as required */ + Cr4 = __readcr4(); + __writecr4(Enable ? Cr4 | CR4_VME : Cr4 & ~CR4_VME); + + /* Restore interrupt state */ + __writeeflags(EFlags); } VOID @@ -63,7 +73,7 @@ KeI386VdmInitialize(VOID) if (KeGetPcr()->Prcb->FeatureBits & KF_V86_VIS) { /* Enable them. FIXME: Use IPI */ - Ki386VdmEnablePentiumExtentions(); + Ki386VdmEnablePentiumExtentions(TRUE); KeI386VirtualIntExtensions = TRUE; } }