set most of trunk svn property eol-style:native
[reactos.git] / reactos / ntoskrnl / vdm / vdmexec.c
index 252d908..947ca03 100644 (file)
-/*\r
- * PROJECT:         ReactOS Kernel\r
- * LICENSE:         GPL - See COPYING in the top level directory\r
- * FILE:            ntoskrnl/vdm/vdmexec.c\r
- * PURPOSE:         Support for executing VDM code and context swapping.\r
- * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)\r
- */\r
-\r
-/* INCLUDES *****************************************************************/\r
-\r
-#include <ntoskrnl.h>\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-/* GLOBALS *******************************************************************/\r
-\r
-ULONG VdmBopCount;\r
-\r
-/* FUNCTIONS *****************************************************************/\r
-\r
-NTSTATUS\r
-NTAPI\r
-VdmpGetVdmTib(OUT PVDM_TIB *VdmTib)\r
-{\r
-    PVDM_TIB Tib;\r
-    PAGED_CODE();\r
-\r
-    /* Assume vailure */\r
-    *VdmTib = NULL;\r
-\r
-    /* Get the current TIB */\r
-    Tib = NtCurrentTeb()->Vdm;\r
-    if (!Tib) return STATUS_INVALID_SYSTEM_SERVICE;\r
-\r
-    /* Validate the size */\r
-    if (Tib->Size != sizeof(VDM_TIB)) return STATUS_INVALID_SYSTEM_SERVICE;\r
-\r
-    /* Return it */\r
-    *VdmTib = Tib;\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-VdmSwapContext(IN PKTRAP_FRAME TrapFrame,\r
-               IN PCONTEXT OutContext,\r
-               IN PCONTEXT InContext)\r
-{\r
-    ULONG EFlags, OldEFlags;\r
-\r
-    /* Make sure that we're at APC_LEVEL and that this is a valid frame */\r
-    ASSERT_IRQL(APC_LEVEL);\r
-    ASSERT(TrapFrame->DbgArgMark = 0xBADB0D00);\r
-\r
-    /* Check if this is a V86 frame */\r
-    if (TrapFrame->EFlags & EFLAGS_V86_MASK)\r
-    {\r
-        /* Copy segment registers */\r
-        OutContext->SegGs = TrapFrame->V86Gs;\r
-        OutContext->SegFs = TrapFrame->V86Fs;\r
-        OutContext->SegEs = TrapFrame->V86Es;\r
-        OutContext->SegDs = TrapFrame->V86Ds;\r
-    }\r
-    else if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))\r
-    {\r
-        /* This was user mode, copy segment registers */\r
-        OutContext->SegGs = TrapFrame->SegGs;\r
-        OutContext->SegFs = TrapFrame->SegFs;\r
-        OutContext->SegEs = TrapFrame->SegEs;\r
-        OutContext->SegDs = TrapFrame->SegDs;\r
-    }\r
-\r
-    /* Copy CS and SS */\r
-    OutContext->SegCs = TrapFrame->SegCs;\r
-    OutContext->SegSs = TrapFrame->HardwareSegSs;\r
-\r
-    /* Copy general purpose registers */\r
-    OutContext->Eax = TrapFrame->Eax;\r
-    OutContext->Ebx = TrapFrame->Ebx;\r
-    OutContext->Ecx = TrapFrame->Ecx;\r
-    OutContext->Edx = TrapFrame->Edx;\r
-    OutContext->Esi = TrapFrame->Esi;\r
-    OutContext->Edi = TrapFrame->Edi;\r
-\r
-    /* Copy stack and counter */\r
-    OutContext->Ebp = TrapFrame->Ebp;\r
-    OutContext->Esp = TrapFrame->HardwareEsp;\r
-    OutContext->Eip = TrapFrame->Eip;\r
-\r
-    /* Finally the flags */\r
-    OutContext->EFlags = TrapFrame->EFlags;\r
-\r
-    /* Now copy from the in frame to the trap frame */\r
-    TrapFrame->SegCs = InContext->SegCs;\r
-    TrapFrame->HardwareSegSs = InContext->SegSs;\r
-\r
-    /* Copy the general purpose registers */\r
-    TrapFrame->Eax = InContext->Eax;\r
-    TrapFrame->Ebx = InContext->Ebx;\r
-    TrapFrame->Ecx = InContext->Ecx;\r
-    TrapFrame->Edx = InContext->Edx;\r
-    TrapFrame->Esi = InContext->Esi;\r
-    TrapFrame->Edi = InContext->Edi;\r
-\r
-    /* Copy the stack and counter */\r
-    TrapFrame->Ebp = InContext->Ebp;\r
-    TrapFrame->HardwareEsp = InContext->Esp;\r
-    TrapFrame->Eip = InContext->Eip;\r
-\r
-    /* Check if the context is from V86 */\r
-    EFlags = InContext->EFlags;\r
-    if (EFlags & EFLAGS_V86_MASK)\r
-    {\r
-        /* Sanitize the flags for V86 */\r
-        EFlags &= KeI386EFlagsAndMaskV86;\r
-        EFlags |= KeI386EFlagsOrMaskV86;\r
-    }\r
-    else\r
-    {\r
-        /* Add RPL_MASK to segments */\r
-        TrapFrame->SegCs |= RPL_MASK;\r
-        TrapFrame->HardwareSegSs |= RPL_MASK;\r
-\r
-        /* Check for bogus CS */\r
-        if (TrapFrame->SegCs < KGDT_R0_CODE)\r
-        {\r
-            /* Set user-mode */\r
-            TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;\r
-        }\r
-\r
-        /* Sanitize flags and add interrupt mask */\r
-        EFlags &= EFLAGS_USER_SANITIZE;\r
-        EFlags |=EFLAGS_INTERRUPT_MASK;\r
-    }\r
-\r
-    /* Save the new eflags */\r
-    OldEFlags = TrapFrame->EFlags;\r
-    TrapFrame->EFlags = EFlags;\r
-\r
-    /* Check if we need to fixup ESP0 */\r
-    if ((OldEFlags ^ EFlags) & EFLAGS_V86_MASK)\r
-    {\r
-        /* Fix it up */\r
-        Ki386AdjustEsp0(TrapFrame);\r
-    }\r
-\r
-    /* Check if this is a V86 context */\r
-    if (InContext->EFlags & EFLAGS_V86_MASK)\r
-    {\r
-        /* Copy VDM segments */\r
-        TrapFrame->V86Gs = InContext->SegGs;\r
-        TrapFrame->V86Fs = InContext->SegFs;\r
-        TrapFrame->V86Es = InContext->SegEs;\r
-        TrapFrame->V86Ds = InContext->SegDs;\r
-    }\r
-    else\r
-    {\r
-        /* Copy monitor segments */\r
-        TrapFrame->SegGs = InContext->SegGs;\r
-        TrapFrame->SegFs = InContext->SegFs;\r
-        TrapFrame->SegEs = InContext->SegEs;\r
-        TrapFrame->SegDs = InContext->SegDs;\r
-    }\r
-\r
-    /* Clear the exception list and return */\r
-    TrapFrame->ExceptionList = EXCEPTION_CHAIN_END;\r
-}\r
-\r
-NTSTATUS\r
-NTAPI\r
-VdmpStartExecution(VOID)\r
-{\r
-    PETHREAD Thread = PsGetCurrentThread();\r
-    PKTRAP_FRAME VdmFrame;\r
-    NTSTATUS Status;\r
-    PVDM_TIB VdmTib;\r
-    BOOLEAN Interrupts;\r
-    KIRQL OldIrql;\r
-    CONTEXT VdmContext;\r
-    PAGED_CODE();\r
-\r
-    /* Get the thread's VDM frame and TIB */\r
-    VdmFrame = (PVOID)((ULONG_PTR)Thread->Tcb.InitialStack -\r
-                                  sizeof(FX_SAVE_AREA) -\r
-                                  sizeof(KTRAP_FRAME));\r
-    Status = VdmpGetVdmTib(&VdmTib);\r
-    if (!NT_SUCCESS(Status)) return STATUS_INVALID_SYSTEM_SERVICE;\r
-\r
-    /* Go to APC level */\r
-    KeRaiseIrql(APC_LEVEL, &OldIrql);\r
-\r
-    /* Check if interrupts are enabled */\r
-    Interrupts = (BOOLEAN)(VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK);\r
-\r
-    /* We don't support full VDM yet, this shouldn't happen */\r
-    ASSERT(*VdmState == 0);\r
-    ASSERT(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK);\r
-\r
-    /*  Get the VDM context and make sure it's an edited frame */\r
-    VdmContext = VdmTib->VdmContext;\r
-    if (!(VdmContext.SegCs & FRAME_EDITED))\r
-    {\r
-        /* Fail */\r
-        KeLowerIrql(OldIrql);\r
-        return STATUS_INVALID_SYSTEM_SERVICE;\r
-    }\r
-\r
-    /* FIXME: Support VME */\r
-    ASSERT(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK);\r
-\r
-    /* Set interrupt state in the VDM State */\r
-    if (VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK)\r
-    {\r
-        /* Enable them as well */\r
-        InterlockedOr((PLONG)VdmState, EFLAGS_INTERRUPT_MASK);\r
-    }\r
-    else\r
-    {\r
-        /* Disable them */\r
-        InterlockedAnd((PLONG)VdmState, ~EFLAGS_INTERRUPT_MASK);\r
-    }\r
-\r
-    /* Enable the interrupt flag */\r
-    VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;\r
-\r
-    /* Now do the VDM Swap */\r
-    VdmSwapContext(VdmFrame, &VdmTib->MonitorContext, &VdmContext);\r
-\r
-    /* Lower the IRQL and return EAX */\r
-    KeLowerIrql(OldIrql);\r
-    return VdmFrame->Eax;\r
-}\r
-\r
-VOID\r
-NTAPI\r
-VdmEndExecution(IN PKTRAP_FRAME TrapFrame,\r
-                IN PVDM_TIB VdmTib)\r
-{\r
-    KIRQL OldIrql;\r
-    CONTEXT Context;\r
-    PAGED_CODE();\r
-\r
-    /* Sanity check */\r
-    ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) ||\r
-           (TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK)));\r
-\r
-    /* Raise to APC_LEVEL */\r
-    KeRaiseIrql(APC_LEVEL, &OldIrql);\r
-\r
-    /* Set success */\r
-    VdmTib->MonitorContext.Eax = STATUS_SUCCESS;\r
-\r
-    /* Make a copy of the monitor context */\r
-    RtlCopyMemory(&Context, &VdmTib->MonitorContext, sizeof(CONTEXT));\r
-\r
-    /* Switch contexts */\r
-    VdmSwapContext(TrapFrame, &VdmTib->VdmContext, &Context);\r
-\r
-    /* FIXME: Support VME */\r
-\r
-    /* Set the EFLAGS */\r
-    VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags &\r
-                                 ~EFLAGS_INTERRUPT_MASK) |\r
-                                (*VdmState & EFLAGS_INTERRUPT_MASK);\r
-\r
-    /* Lower IRQL and reutrn */\r
-    KeLowerIrql(OldIrql);\r
-}\r
-\r
-BOOLEAN\r
-NTAPI\r
-VdmDispatchBop(IN PKTRAP_FRAME TrapFrame)\r
-{\r
-    PUCHAR Eip;\r
-    PVDM_TIB VdmTib;\r
-\r
-    /* Check if this is from V86 mode */\r
-    if (TrapFrame->EFlags & EFLAGS_V86_MASK)\r
-    {\r
-        /* Calculate flat EIP */\r
-        Eip = (PUCHAR)((TrapFrame->Eip & 0xFFFF) +\r
-                      ((TrapFrame->SegCs & 0xFFFF) << 4));\r
-\r
-        /* Check if this is a BOP */\r
-        if (*(PUSHORT)Eip == 0xC4C4)\r
-        {\r
-            /* Check sure its the DOS Bop */\r
-            if (Eip[2] == 0x50)\r
-            {\r
-                /* FIXME: No VDM Support */\r
-                ASSERT(FALSE);\r
-            }\r
-\r
-            /* Increase the number of BOP operations */\r
-            VdmBopCount++;\r
-\r
-            /* Get the TIB */\r
-            VdmTib = NtCurrentTeb()->Vdm;\r
-\r
-            /* Fill out a VDM Event */\r
-            VdmTib->EventInfo.InstructionSize = 3;\r
-            VdmTib->EventInfo.BopNumber = Eip[2];\r
-            VdmTib->EventInfo.Event = VdmBop;\r
-\r
-            /* End VDM Execution */\r
-            VdmEndExecution(TrapFrame, VdmTib);\r
-        }\r
-        else\r
-        {\r
-            /* Not a BOP */\r
-            return FALSE;\r
-        }\r
-    }\r
-    else\r
-    {\r
-        /* FIXME: Shouldn't happen on ROS */\r
-        ASSERT(FALSE);\r
-    }\r
-\r
-    /* Return success */\r
-    return TRUE;\r
-}\r
-\r
+/*
+ * 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 */
+    ASSERT_IRQL(APC_LEVEL);
+    ASSERT(TrapFrame->DbgArgMark = 0xBADB0D00);
+
+    /* 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;
+    }
+    else if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))
+    {
+        /* This was user mode, copy segment registers */
+        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);
+
+    /*  Get the VDM context and make sure it's an edited frame */
+    VdmContext = VdmTib->VdmContext;
+    if (!(VdmContext.SegCs & FRAME_EDITED))
+    {
+        /* Fail */
+        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);
+
+    /* 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 */
+    RtlCopyMemory(&Context, &VdmTib->MonitorContext, sizeof(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);
+
+    /* 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;
+}
+